diff -urN linux-2.4.27/CREDITS linux-2.4.28/CREDITS --- linux-2.4.27/CREDITS 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/CREDITS 2004-11-17 03:54:20.892368866 -0800 @@ -458,6 +458,14 @@ D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver S: Germany +N: Adrian Bunk +E: bunk@stusta.de +P: 1024D/4F12B400 B29C E71E FE19 6755 5C8A 84D4 99FC EA98 4F12 B400 +D: misc kernel hacking and testing +S: Grasmeierstrasse 11 +S: 80805 Muenchen +S: Germany + N: Ray Burr E: ryb@nightmare.com D: Original author of Amiga FFS filesystem @@ -1485,18 +1493,16 @@ S: USA N: Dave Jones -E: davej@suse.de -W: http://www.suse.de/~davej +E: davej@redhat.com +W: http://www.codemonkey.org.uk D: Moved PCI bridge tuning to userspace (Powertweak). D: Various x86 (& clones) setup code hacking. D: AFFS fixes for 2.3.x D: Various Janitorial hacks. (kernel-janitor.sourceforge.net) -S: c/o SuSE Linux UK Ltd -S: The Kinetic Centre -S: Theobald Street -S: Borehamwood -S: Herts, WD6 4PJ -S: United Kingdom +S: Red Hat +S: 10, Technology Park +S: Westford, MA 01863 +S: USA N: Ani Joshi E: ajoshi@kernel.crashing.org @@ -1809,10 +1815,10 @@ S: Germany N: Achim Leubner -E: achim@vortex.de -D: GDT SCSI Disk Array Controller driver -S: ICP vortex Computersysteme GmbH -S: Flein +E: achim_leubner@adaptec.com +D: GDT Disk Array Controller/Storage RAID controller driver +S: ICP vortex GmbH +S: Neckarsulm S: Germany N: Phil Lewis @@ -2130,14 +2136,13 @@ S: Netherlands N: David S. Miller -E: davem@redhat.com +E: davem@davemloft.net D: Sparc and blue box hacker D: Vger Linux mailing list co-maintainer D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) -S: 750 N. Shoreline Blvd. -S: Apt. #111 -S: Mountain View, California 94043 +S: 575 Harrison St. #103 +S: San Francisco, California 94105 S: USA N: Rick Miller diff -urN linux-2.4.27/Documentation/Configure.help linux-2.4.28/Documentation/Configure.help --- linux-2.4.27/Documentation/Configure.help 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/Documentation/Configure.help 2004-11-17 03:54:20.924370182 -0800 @@ -696,6 +696,24 @@ could say N here, and select the "Old hard disk driver" below instead to save about 13 KB of memory in the kernel. +Support for SATA (deprecated; conflicts with libata SATA driver) +CONFIG_BLK_DEV_IDE_SATA + There are two drivers for Serial ATA controllers. + + The main driver, "libata", exists inside the SCSI subsystem + and supports most modern SATA controllers. + + The IDE driver (which you are currently configuring) supports + a few first-generation SATA controllers. + + In order to eliminate conflicts between the two subsystems, + this config option enables the IDE driver's SATA support. + Normally this is disabled, as it is preferred that libata + supports SATA controllers, and this (IDE) driver supports + PATA controllers. + + If unsure, say N. + Old hard disk (MFM/RLL/IDE) driver CONFIG_BLK_DEV_HD_ONLY There are two drivers for MFM/RLL/IDE hard disks. Most people use @@ -763,6 +781,13 @@ . The module will be called ide-cs.o +Cardbus IDE support (Delkin/ASKA/Workbit) +CONFIG_BLK_DEV_DELKIN + Support for Delkin/ASKA/Workbit cardbus CompactFlash Adapters. + This may also work for similar SD and XD adapters. If you want + to be able to use one of these, then say M here. The module will + be called delkin_cb.o + Include IDE/ATAPI CD-ROM support CONFIG_BLK_DEV_IDECD If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is @@ -4678,12 +4703,6 @@ ld.so (check the file for location and latest version). - 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 . The module - will be called binfmt_elf.o. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - Kernel support for a.out binaries CONFIG_BINFMT_AOUT A.out (Assembler.OUTput) is a set of formats for libraries and @@ -7953,7 +7972,7 @@ QDIO base support for IBM S/390 and zSeries CONFIG_QDIO This driver provides the Queued Direct I/O base support for the - IBM S/390 (G5 and G6) and eServer zSeries (z800 and z900). + IBM S/390 (G5 and G6) and eServer zSeries (z800, z900 and z990). For details please refer to the documentation provided by IBM at @@ -7971,6 +7990,37 @@ If unsure, say N. +IBM S/390 and zSeries OSA-Express and HiperSockets device driver +CONFIG_QETH + This driver supports the IBM S/390 and zSeries OSA Express adapters + in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN + interfaces in QDIO and HIPER mode. + + For details please refer to the documentation provided by IBM at + + + This driver is also available as a module (code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say 'M' here and + read file Documentation/modules.txt. + +IPv6 support for qeth +CONFIG_QETH_IPV6 + If CONFIG_QETH is switched on, this option will include IPv6 + support in the qeth device driver. + +IEEE 802.1q VLAN support for qeth +CONFIG_QETH_VLAN + If CONFIG_QETH is switched on, this option will include IEEE + 802.1q VLAN support in the qeth device driver. + +Performance statistics for the qeth drivers +CONFIG_QETH_PERF_STATS + When switched on, this option will add a file in the proc-fs + (/proc/qeth_perf_stats) containing performance statistics. It + may slightly impact performance, so this is only recommended for + internal tuning of the device driver. + SGI WD93C93 SCSI Driver CONFIG_SCSI_SGIWD93 Say Y here to support the on-board WD93C93 SCSI controller found (a) @@ -9281,6 +9331,16 @@ If unsure, say N. +CONFIG_SCSI_ATA_PIIX + This option enables support for ICH5 Serial ATA. + + If unsure, say N. + +CONFIG_SCSI_SATA_NV + This option enables support for NVIDIA Serial ATA. + + If unsure, say N. + CONFIG_SCSI_SATA_PROMISE This option enables support for Promise Serial ATA TX2/TX4. @@ -9301,6 +9361,11 @@ If unsure, say N. +CONFIG_SCSI_SATA_ULI + This option enables support for ULi Electronics SATA. + + If unsure, say N. + CONFIG_SCSI_SATA_VIA This option enables support for VIA Serial ATA. @@ -10077,6 +10142,49 @@ compile it as a module, say M here and read . +Intersil 802.11(a/b/g) Prism GT/Duette/Indigo support +CONFIG_PRISM54 + Enable PCI and Cardbus support for the following chipset based cards: + + ISL3880 - Prism GT 802.11 b/g + ISL3877 - Prism Indigo 802.11 a + ISL3890 - Prism Duette 802.11 a/b/g + + For a complete list of supported cards visit . + Here is the latest confirmed list of supported cards: + + 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 + Allnet ALL0271 PCI Card + Compex WL54G Cardbus Card + Corega CG-WLCB54GT Cardbus Card + D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 + I-O Data WN-G54/CB Cardbus Card + Kobishi XG-300 aka Z-Com Cardbus Card + Netgear WG511 Cardbus Card + Ovislink WL-5400PCI PCI Card + Peabird WLG-PCI PCI Card + Sitecom WL-100i Cardbus Card + Sitecom WL-110i PCI Card + SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card + SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card + Z-Com XG-900 PCI Card + Zyxel G-100 Cardbus Card + + If you enable this, you require a firmware file as well. + You will need to copy this to /usr/lib/hotplug/firmware/isl3890. + You can get this non-GPL'd firmware file from the Prism54 project page: + . + You will also need the /etc/hotplug/firmware.agent script from + a current hotplug package. + + + Note: You need a motherboard with DMA support to use any of these cards + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called prism54.o. + Aironet 4500/4800 PROC interface CONFIG_AIRONET4500_PROC If you say Y here (and to the "/proc file system" below), you will @@ -17211,10 +17319,11 @@ If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. -Provide NFS over TCP server support EXPERIMENTAL +Provide NFS over TCP server support CONFIG_NFSD_TCP - Enable NFS service over TCP connections. This the officially - still experimental, but seems to work well. + If you want your NFS server to support TCP connections, say Y here. + TCP connections usually perform better than the default UDP when + the network is lossy or congested. If unsure, say Y. OS/2 HPFS file system support CONFIG_HPFS_FS @@ -25344,13 +25453,13 @@ Support for DASD hard disks CONFIG_DASD Enable this option if you want to access DASDs directly utilizing - S/390s channel subsystem commands. This is necessary for running + S/390's or zSeries' channel subsystem commands. This is necessary for running natively on a single image or an LPAR. Support for ECKD hard disks CONFIG_DASD_ECKD ECKD (Extended Count Key Data) devices are the most commonly used - devices on S/390s. You should enable this option unless you are + devices on zSeries and S/390. You should enable this option unless you are very sure you have no ECKD device. ECKD demand loading @@ -28864,6 +28973,15 @@ This code also includes SHA-384, a 384 bit hash with 192 bits of security against collision attacks. +CONFIG_CRYPTO_WP512 + Whirlpool hash algorithm 512, 384 and 256-bit hashes + + Whirlpool-512 is part of the NESSIE cryptographic primitives. + Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard + + See also: + http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html + CONFIG_CRYPTO_DES DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). @@ -28891,7 +29009,8 @@ Serpent cipher algorithm, by Anderson, Biham & Knudsen. Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. + of 8 bits. Also includes the 'Tnepres' algorithm, a reversed + variant of Serpent for compatibility with old kerneli code. See also: http://www.cl.cam.ac.uk/~rja14/serpent.html @@ -28932,7 +29051,7 @@ many rounds for security. It is very fast and uses little memory. - Xtendend Tiny Encryption Algorithm is a modifcation to + Xtendend Tiny Encryption Algorithm is a modification to the TEA algorithm to address a potential key weakness in the TEA algorithm. @@ -28944,6 +29063,27 @@ WEP, but it should not be for other purposes because of the weakness of the algorithm. +CONFIG_CRYPTO_KHAZAD + Khazad cipher algorithm. + + Khazad was a finalist in the initial NESSIE competition. It is + an algorithm optimized for 64-bit processors with good performance + on 32-bit processors. Khazad uses an 128 bit key size. + + See also: + http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html + +CONFIG_CRYPTO_ANUBIS + Anubis cipher algorithm. + + Anubis is a variable key length cipher which can use keys from + 128 bits to 320 bits in length. It was evaluated as a entrant + in the NESSIE competition. + + See also: + https://www.cosic.esat.kuleuven.ac.be/nessie/reports/ + http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html + CONFIG_CRYPTO_DEFLATE This is the Deflate algorithm (RFC1951), specified for use in IPSec with the IPCOMP protocol (RFC3173, RFC2394). diff -urN linux-2.4.27/Documentation/crypto/api-intro.txt linux-2.4.28/Documentation/crypto/api-intro.txt --- linux-2.4.27/Documentation/crypto/api-intro.txt 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/Documentation/crypto/api-intro.txt 2004-11-17 03:54:20.976372320 -0800 @@ -219,6 +219,19 @@ CAST5/CAST6 algorithm contributors: Kartikey Mahendra Bhatt (original developers unknown, FSF copyright). +TEA/XTEA algorithm contributors: + Aaron Grothe + +Khazad algorithm contributors: + Aaron Grothe + +Whirlpool algorithm contributors: + Aaron Grothe + Jean-Luc Cooke + +Anubis algorithm contributors: + Aaron Grothe + Generic scatterwalk code by Adam J. Richter Please send any credits updates or corrections to: diff -urN linux-2.4.27/Documentation/filesystems/xfs.txt linux-2.4.28/Documentation/filesystems/xfs.txt --- linux-2.4.27/Documentation/filesystems/xfs.txt 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/Documentation/filesystems/xfs.txt 2004-11-17 03:54:20.976372320 -0800 @@ -120,19 +120,19 @@ fs.xfs.stats_clear (Min: 0 Default: 0 Max: 1) Setting this to "1" clears accumulated XFS statistics - in /proc/fs/xfs/stat. It then immediately reset to "0". + in /proc/fs/xfs/stat. It then immediately resets to "0". - fs.xfs.sync_interval (Min: HZ Default: 30*HZ Max: 60*HZ) + fs.xfs.xfssyncd_centisecs (Min: 100 Default: 3000 Max: 6000) The interval at which the xfssyncd thread flushes metadata out to disk. This thread will flush log activity out, and do some processing on unlinked inodes. - fs.xfs.age_buffer (Min: 1*HZ Default: 15*HZ Max: 300*HZ) - The age at which xfsbufd flushes dirty metadata buffers to disk. - - fs.xfs.flush_interval (Min: HZ/2 Default: HZ Max: 30*HZ) + fs.xfs.xfsbufd_centisecs (Min: 50 Default: 100 Max: 3000) The interval at which xfsbufd scans the dirty metadata buffers list. + fs.xfs.age_buffer_centisecs (Min: 100 Default: 1500 Max: 30000) + The age at which xfsbufd flushes dirty metadata buffers to disk. + fs.xfs.error_level (Min: 0 Default: 3 Max: 11) A volume knob for error reporting when internal errors occur. This will generate detailed messages & backtraces for filesystem diff -urN linux-2.4.27/Documentation/ftape.txt linux-2.4.28/Documentation/ftape.txt --- linux-2.4.27/Documentation/ftape.txt 1999-11-06 10:38:40.000000000 -0800 +++ linux-2.4.28/Documentation/ftape.txt 2004-11-17 03:54:20.977372361 -0800 @@ -15,7 +15,7 @@ ftape has a home page at -http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape +http://www.instmath.rwth-aachen.de/~heine/ftape/ which contains further information about ftape. Please cross check this WWW address against the address given (if any) in the MAINTAINERS @@ -58,7 +58,7 @@ versions of ftape and useful links to related topics can be found at the ftape home page at -http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape +http://www.instmath.rwth-aachen.de/~heine/ftape/ ******************************************************************************* @@ -132,7 +132,7 @@ or from the ftape home page at - http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape + http://www.instmath.rwth-aachen.de/~heine/ftape/ `ftformat' is contained in the `./contrib/' subdirectory of that separate ftape package. diff -urN linux-2.4.27/Documentation/i2c/writing-clients linux-2.4.28/Documentation/i2c/writing-clients --- linux-2.4.27/Documentation/i2c/writing-clients 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/Documentation/i2c/writing-clients 2004-11-17 03:54:20.978372402 -0800 @@ -24,24 +24,25 @@ routines, a client structure specific information like the actual I2C address. - struct i2c_driver foo_driver - { - /* name */ "Foo version 2.3 and later driver", - /* id */ I2C_DRIVERID_FOO, - /* flags */ I2C_DF_NOTIFY, - /* attach_adapter */ &foo_attach_adapter, - /* detach_client */ &foo_detach_client, - /* command */ &foo_command, /* May be NULL */ - /* inc_use */ &foo_inc_use, /* May be NULL */ - /* dec_use */ &foo_dec_use /* May be NULL */ - } +static struct i2c_driver foo_driver = { + .name = "Foo version 2.3 driver", + .id = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = &foo_attach_adapter, + .detach_client = &foo_detach_client, + .command = &foo_command, /* may be NULL */ + .inc_use = &foo_inc_use, /* May be NULL */ + .dec_use = &foo_dec_use, /* May be NULL */ +} The name can be chosen freely, and may be upto 40 characters long. Please use something descriptive here. -The id should be a unique ID. The range 0xf000 to 0xffff is reserved for -local use, and you can use one of those until you start distributing the -driver. Before you do that, contact the i2c authors to get your own ID(s). +If used, the id should be a unique ID. The range 0xf000 to 0xffff is +reserved for local use, and you can use one of those until you start +distributing the driver, at which time you should contact the i2c authors +to get your own ID(s). Note that most of the time you don't need an ID +at all so you can just omit it. Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This means that your driver will be notified when new adapters are found. diff -urN linux-2.4.27/Documentation/isdn/CREDITS linux-2.4.28/Documentation/isdn/CREDITS --- linux-2.4.27/Documentation/isdn/CREDITS 2000-02-15 11:40:42.000000000 -0800 +++ linux-2.4.28/Documentation/isdn/CREDITS 2004-11-17 03:54:20.987372772 -0800 @@ -37,7 +37,7 @@ Andreas Kool (akool@Kool.f.EUnet.de) For contribution of the isdnlog/isdnrep-tool -Pedro Roque Marques (roque@di.fc.ul.pt) +Pedro Roque Marques (pedro_m@yahoo.com) For lot of new ideas and the pcbit driver. Eberhard Moenkeberg (emoenke@gwdg.de) diff -urN linux-2.4.27/Documentation/isdn/README.pcbit linux-2.4.28/Documentation/isdn/README.pcbit --- linux-2.4.27/Documentation/isdn/README.pcbit 1999-11-07 16:34:00.000000000 -0800 +++ linux-2.4.28/Documentation/isdn/README.pcbit 2004-11-17 03:54:20.999373265 -0800 @@ -37,4 +37,4 @@ regards, Pedro. - + diff -urN linux-2.4.27/Documentation/networking/proc_net_tcp.txt linux-2.4.28/Documentation/networking/proc_net_tcp.txt --- linux-2.4.27/Documentation/networking/proc_net_tcp.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/Documentation/networking/proc_net_tcp.txt 2004-11-17 03:54:21.000373307 -0800 @@ -0,0 +1,47 @@ +This document describes the interfaces /proc/net/tcp and /proc/net/tcp6. + +These /proc interfaces provide information about currently active TCP +connections, and are implemented by tcp_get_info() in net/ipv4/tcp_ipv4.c and +tcp6_get_info() in net/ipv6/tcp_ipv6.c, respectively. + +It will first list all listening TCP sockets, and next list all established +TCP connections. A typical entry of /proc/net/tcp would look like this (split +up into 3 parts because of the length of the line): + + 46: 010310AC:9C4C 030310AC:1770 01 + | | | | | |--> connection state + | | | | |------> remote TCP port number + | | | |-------------> remote IPv4 address + | | |--------------------> local TCP port number + | |---------------------------> local IPv4 address + |----------------------------------> number of entry + + 00000150:00000000 01:00000019 00000000 + | | | | |--> number of unrecovered RTO timeouts + | | | |----------> number of jiffies until timer expires + | | |----------------> timer_active (see below) + | |----------------------> receive-queue + |-------------------------------> transmit-queue + + 1000 0 54165785 4 cd1e6040 25 4 27 3 -1 + | | | | | | | | | |--> slow start size threshold, + | | | | | | | | | or -1 if the treshold + | | | | | | | | | is >= 0xFFFF + | | | | | | | | |----> sending congestion window + | | | | | | | |-------> (ack.quick<<1)|ack.pingpong + | | | | | | |---------> Predicted tick of soft clock + | | | | | | (delayed ACK control data) + | | | | | |------------> retransmit timeout + | | | | |------------------> location of socket in memory + | | | |-----------------------> socket reference count + | | |-----------------------------> inode + | |----------------------------------> unanswered 0-window probes + |---------------------------------------------> uid + +timer_active: + 0 no timer is pending + 1 retransmit-timer is pending + 2 another timer (e.g. delayed ack or keepalive) is pending + 3 this is a socket in TIME_WAIT state. Not all fields will contain + data (or even exist) + 4 zero window probe timer is pending diff -urN linux-2.4.27/MAINTAINERS linux-2.4.28/MAINTAINERS --- linux-2.4.27/MAINTAINERS 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/MAINTAINERS 2004-11-17 03:54:21.002373389 -0800 @@ -177,10 +177,8 @@ AD1816 SOUND DRIVER P: Thorsten Knabe -M: Thorsten Knabe -M: Thorsten Knabe -W: http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html -W: http://www.tu-darmstadt.de/~tek01/projects/linux.html +M: Thorsten Knabe +W: http://linux.thorsten-knabe.de S: Maintained ADVANSYS SCSI DRIVER @@ -456,14 +454,20 @@ S: Maintained +HP 66Mhz FIBRE CHANNEL DRIVER +P: Chirag Kantharia +M: chirag.kantharia@hp.com +L: iss_storagedev@hp.com +S: Maintained + HP SMART2 RAID DRIVER -P: Francis Wiran -M: francis.wiran@hp.com +P: Chirag Kantharia +M: chirag.kantharia@hp.com L: iss_storagedev@hp.com -S: Odd Fixes +S: Maintained -HP SMART CISS RAID DRIVER -P: Mike Miller, Michael Ni +HP SMART ARRAY CISS RAID DRIVER (cciss) +P: Mike Miller M: mike.miller@hp.com L: iss_storagedev@hp.com S: Supported @@ -530,15 +534,7 @@ P: James Morris M: jmorris@intercode.com.au P: David S. Miller -M: davem@redhat.com -MARVELL YUKON / SYSKONNECT DRIVER -P: Mirko Lindner -M: mlindner@syskonnect.de -P: Ralph Roesler -M: rroesler@syskonnect.de -W: http://www.syskonnect.com -S: Supported -M: davem@redhat.com +M: davem@davemloft.net W http://samba.org/~jamesm/crypto/ L: linux-kernel@vger.kernel.org S: Maintained @@ -577,9 +573,9 @@ S: Maintained DECnet NETWORK LAYER -P: Steven Whitehouse -M: SteveW@ACM.org -W: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html +P: Patrick Caulfield +M: patrick@tykepenguin.com +W: http://linux-decnet.sourceforge.net L: linux-decnet-user@lists.sourceforge.net S: Maintained @@ -770,7 +766,7 @@ GDT SCSI DISK ARRAY CONTROLLER DRIVER P: Achim Leubner -M: achim@vortex.de +M: achim_leubner@adaptec.com L: linux-scsi@vger.kernel.org W: http://www.icp-vortex.com/ S: Supported @@ -997,6 +993,14 @@ M: jjciarla@raiz.uncu.edu.ar S: Maintained +IPVS +P: Wensong Zhang +M: wensong@linux-vs.org +P: Julian Anastasov +M: ja@ssi.bg +L: lvs-users@linuxvirtualserver.org +S: Maintained + IPX NETWORK LAYER P: Arnaldo Carvalho de Melo M: acme@conectiva.com.br @@ -1188,6 +1192,14 @@ L: netdev@oss.sgi.com S: Supported +MARVELL YUKON / SYSKONNECT DRIVER +P: Mirko Lindner +M: mlindner@syskonnect.de +P: Ralph Roesler +M: rroesler@syskonnect.de +W: http://www.syskonnect.com +S: Supported + MATROX FRAMEBUFFER DRIVER P: Petr Vandrovec M: vandrove@vc.cvut.cz @@ -1312,7 +1324,7 @@ NETWORKING [IPv4/IPv6] P: David S. Miller -M: davem@redhat.com +M: davem@davemloft.net P: Alexey Kuznetsov M: kuznet@ms2.inr.ac.ru P: Pekka Savola (ipv6) @@ -1448,9 +1460,8 @@ S: Odd Fixes PCI HOTPLUG CORE -P: Greg Kroah-Hartman -M: greg@kroah.com -M: gregkh@us.ibm.com +P: Gary Hade +M: garyhade@us.ibm.com S: Supported PCI HOTPLUG COMPAQ DRIVER @@ -1525,6 +1536,13 @@ M: mostrows@styx.uwaterloo.ca S: Maintained +PRISM54 WIRELESS DRIVER +P: Prism54 Development Team +M: prism54-private@prism54.org +L: netdev@oss.sgi.com +W: http://prism54.org +S: Maintained + PROMISE DC4030 CACHING DISK CONTROLLER DRIVER P: Peter Denison M: promise@pnd-pc.demon.co.uk @@ -1689,10 +1707,8 @@ SMB FILESYSTEM P: Urban Widmark -M: urban@teststation.com -W: http://samba.org/ -L: samba@samba.org -S: Maintained +M: Urban.Widmark@enlight.net +S: Odd Fixes SNA NETWORK LAYER P: Jay Schulist @@ -1723,7 +1739,7 @@ UltraSPARC (sparc64): P: David S. Miller -M: davem@redhat.com +M: davem@davemloft.net P: Eddie C. Dost M: ecd@skynet.be P: Jakub Jelinek @@ -1735,8 +1751,8 @@ S: Maintained SPARC (sparc32): -P: Keith M. Wesolowski -M: wesolows@foobazco.org +P: William L. Irwin +M: wli@holomorphy.com L: sparclinux@vger.kernel.org S: Maintained diff -urN linux-2.4.27/Makefile linux-2.4.28/Makefile --- linux-2.4.27/Makefile 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/Makefile 2004-11-17 03:54:22.250424702 -0800 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 27 +SUBLEVEL = 28 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.4.27/arch/alpha/boot/bootloader.lds linux-2.4.28/arch/alpha/boot/bootloader.lds --- linux-2.4.27/arch/alpha/boot/bootloader.lds 2001-07-02 14:40:14.000000000 -0700 +++ linux-2.4.28/arch/alpha/boot/bootloader.lds 2004-11-17 03:54:21.003373430 -0800 @@ -1,5 +1,6 @@ OUTPUT_FORMAT("elf64-alpha") ENTRY(__start) +printk = srm_printk; SECTIONS { . = 0x20000000; diff -urN linux-2.4.27/arch/alpha/boot/bootp.c linux-2.4.28/arch/alpha/boot/bootp.c --- linux-2.4.27/arch/alpha/boot/bootp.c 2001-10-04 18:47:08.000000000 -0700 +++ linux-2.4.28/arch/alpha/boot/bootp.c 2004-11-17 03:54:21.003373430 -0800 @@ -26,6 +26,8 @@ struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, unsigned long *vptb); +extern void move_stack(unsigned long new_stack); + struct hwrpb_struct *hwrpb = INIT_HWRPB; static struct pcb_struct pcb_va[1]; @@ -118,12 +120,10 @@ runkernel(void) { __asm__ __volatile__( - "bis %1,%1,$30\n\t" "bis %0,%0,$27\n\t" "jmp ($27)" : /* no outputs: it doesn't even return */ - : "r" (START_ADDR), - "r" (PAGE_SIZE + INIT_STACK)); + : "r" (START_ADDR)); } extern char _end; @@ -147,9 +147,7 @@ */ static long nbytes; static char envval[256] __attribute__((aligned(8))); -#ifdef INITRD_IMAGE_SIZE static unsigned long initrd_start; -#endif srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n"); if (INIT_HWRPB->pagesize != 8192) { @@ -164,13 +162,20 @@ } pal_init(); -#ifdef INITRD_IMAGE_SIZE /* The initrd must be page-aligned. See below for the cause of the magic number 5. */ - initrd_start = ((START_ADDR + 5*KERNEL_SIZE) | (PAGE_SIZE-1)) + 1; + initrd_start = ((START_ADDR + 5*KERNEL_SIZE + PAGE_SIZE) | + (PAGE_SIZE-1)) + 1; +#ifdef INITRD_IMAGE_SIZE srm_printk("Initrd positioned at %#lx\n", initrd_start); #endif + /* + * Move the stack to a safe place to ensure it won't be + * overwritten by kernel image. + */ + move_stack(initrd_start - PAGE_SIZE); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0 || nbytes >= sizeof(envval)) { nbytes = 0; diff -urN linux-2.4.27/arch/alpha/boot/bootpz.c linux-2.4.28/arch/alpha/boot/bootpz.c --- linux-2.4.27/arch/alpha/boot/bootpz.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/alpha/boot/bootpz.c 2004-11-17 03:54:21.004373471 -0800 @@ -32,9 +32,6 @@ #undef DEBUG_CHECK_RANGE #define DEBUG_ADDRESSES -#define DEBUG_SP(x) \ - {register long sp asm("30"); srm_printk("%s (sp=%lx)\n", x, sp);} - extern unsigned long switch_to_osf_pal(unsigned long nr, struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, unsigned long *vptb); @@ -42,6 +39,8 @@ extern int decompress_kernel(void* destination, void *source, size_t ksize, size_t kzsize); +extern void move_stack(unsigned long new_stack); + struct hwrpb_struct *hwrpb = INIT_HWRPB; static struct pcb_struct pcb_va[1]; @@ -154,12 +153,10 @@ runkernel(void) { __asm__ __volatile__( - "bis %1,%1,$30\n\t" "bis %0,%0,$27\n\t" "jmp ($27)" : /* no outputs: it doesn't even return */ - : "r" (START_ADDR), - "r" (PAGE_SIZE + INIT_STACK)); + : "r" (START_ADDR)); } /* Must record the SP (it is virtual) on entry, so we can make sure @@ -244,7 +241,9 @@ for "bootmem" anyway. */ #define K_COPY_IMAGE_START NEXT_PAGE(K_KERNEL_IMAGE_END) -#define K_INITRD_START NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE) +/* Reserve one page below INITRD for the new stack. */ +#define K_INITRD_START \ + NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE) #define K_COPY_IMAGE_END \ (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE) #define K_COPY_IMAGE_SIZE \ @@ -410,8 +409,7 @@ initrd_image_start, INITRD_IMAGE_SIZE); #endif - memcpy((void *)initrd_image_start, - (void *)V_INITRD_START, + memcpy((void *)initrd_image_start, (void *)V_INITRD_START, INITRD_IMAGE_SIZE); #endif /* INITRD_IMAGE_SIZE */ @@ -427,9 +425,14 @@ K_KERNEL_IMAGE_START, (unsigned)KERNEL_SIZE); #endif + /* + * Move the stack to a safe place to ensure it won't be + * overwritten by kernel image. + */ + move_stack(initrd_image_start - PAGE_SIZE); + memcpy((void *)K_KERNEL_IMAGE_START, - (void *)uncompressed_image_start, - KERNEL_SIZE); + (void *)uncompressed_image_start, KERNEL_SIZE); } /* Clear the zero page, then move the argument list in. */ diff -urN linux-2.4.27/arch/alpha/boot/head.S linux-2.4.28/arch/alpha/boot/head.S --- linux-2.4.27/arch/alpha/boot/head.S 1998-10-12 11:40:12.000000000 -0700 +++ linux-2.4.28/arch/alpha/boot/head.S 2004-11-17 03:54:21.005373512 -0800 @@ -100,3 +100,24 @@ .prologue 0 call_pal PAL_halt .end halt + +/* $16 - new stack page */ + .align 3 + .globl move_stack + .ent move_stack +move_stack: + .prologue 0 + lda $0, 0x1fff($31) + and $0, $30, $1 /* Stack offset */ + or $1, $16, $16 /* New stack pointer */ + mov $30, $1 + mov $16, $2 +1: ldq $3, 0($1) /* Move the stack */ + addq $1, 8, $1 + stq $3, 0($2) + and $0, $1, $4 + addq $2, 8, $2 + bne $4, 1b + mov $16, $30 + ret ($26) + .end move_stack diff -urN linux-2.4.27/arch/alpha/config.in linux-2.4.28/arch/alpha/config.in --- linux-2.4.27/arch/alpha/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/alpha/config.in 2004-11-17 03:54:21.005373512 -0800 @@ -314,7 +314,7 @@ bool ' OSF/1 v4 readv/writev compatibility' CONFIG_OSF4_COMPAT fi -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 source drivers/parport/Config.in diff -urN linux-2.4.27/arch/arm/config.in linux-2.4.28/arch/arm/config.in --- linux-2.4.27/arch/arm/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/arm/config.in 2004-11-17 03:54:21.006373553 -0800 @@ -498,7 +498,7 @@ "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 +bool '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 diff -urN linux-2.4.27/arch/cris/config.in linux-2.4.28/arch/cris/config.in --- linux-2.4.27/arch/cris/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/cris/config.in 2004-11-17 03:54:21.006373553 -0800 @@ -30,7 +30,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF string 'Kernel command line' CONFIG_ETRAX_CMDLINE "root=/dev/mtdblock3" diff -urN linux-2.4.27/arch/i386/Makefile linux-2.4.28/arch/i386/Makefile --- linux-2.4.27/arch/i386/Makefile 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.28/arch/i386/Makefile 2004-11-17 03:54:21.007373594 -0800 @@ -94,6 +94,10 @@ CFLAGS += $(call check_gcc,-march=c3-2,-march=i686) endif +# Disable unit-at-a-time mode, it makes gcc use a lot more stack +# due to the lack of sharing of stacklots. +CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) + HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib diff -urN linux-2.4.27/arch/i386/boot/compressed/misc.c linux-2.4.28/arch/i386/boot/compressed/misc.c --- linux-2.4.27/arch/i386/boot/compressed/misc.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.28/arch/i386/boot/compressed/misc.c 2004-11-17 03:54:21.008373636 -0800 @@ -104,7 +104,7 @@ static void *malloc(int size); static void free(void *where); -static void puts(const char *); +static void putstr(const char *); extern int end; static long free_mem_ptr = (long)&end; @@ -165,7 +165,7 @@ vidmem[i] = ' '; } -static void puts(const char *s) +static void putstr(const char *s) { int x,y,pos; char c; @@ -283,9 +283,9 @@ static void error(char *x) { - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); + putstr("\n\n"); + putstr(x); + putstr("\n\n -- System halted"); while(1); /* Halt */ } @@ -369,9 +369,9 @@ else setup_output_buffer_if_we_run_high(mv); makecrc(); - puts("Uncompressing Linux... "); + putstr("Uncompressing Linux... "); gunzip(); - puts("Ok, booting the kernel.\n"); + putstr("Ok, booting the kernel.\n"); if (high_loaded) close_output_buffer_if_we_run_high(mv); return high_loaded; } diff -urN linux-2.4.27/arch/i386/config.in linux-2.4.28/arch/i386/config.in --- linux-2.4.27/arch/i386/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/i386/config.in 2004-11-17 03:54:21.008373636 -0800 @@ -326,7 +326,7 @@ A.OUT CONFIG_KCORE_AOUT" ELF fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER diff -urN linux-2.4.27/arch/i386/defconfig linux-2.4.28/arch/i386/defconfig --- linux-2.4.27/arch/i386/defconfig 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/defconfig 2004-11-17 03:54:21.009373677 -0800 @@ -758,7 +758,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -urN linux-2.4.27/arch/i386/kernel/acpi.c linux-2.4.28/arch/i386/kernel/acpi.c --- linux-2.4.27/arch/i386/kernel/acpi.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/acpi.c 2004-11-17 03:54:21.010373718 -0800 @@ -389,6 +389,8 @@ } +extern int mp_irqs_alloc(void); + /* * acpi_boot_init() * called from setup_arch(), always. diff -urN linux-2.4.27/arch/i386/kernel/apic.c linux-2.4.28/arch/i386/kernel/apic.c --- linux-2.4.27/arch/i386/kernel/apic.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/i386/kernel/apic.c 2004-11-17 03:54:21.011373759 -0800 @@ -658,6 +658,12 @@ if (!cpu_has_apic) { /* + * Over-ride BIOS and try to enable LAPIC + * only if "lapic" specified + */ + if (enable_local_apic != 1) + goto no_apic; + /* * Some BIOSes disable the local APIC in the * APIC_BASE MSR. This can only be done in * software for Intel P6 and AMD K7 (Model > 1). diff -urN linux-2.4.27/arch/i386/kernel/dmi_scan.c linux-2.4.28/arch/i386/kernel/dmi_scan.c --- linux-2.4.27/arch/i386/kernel/dmi_scan.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/dmi_scan.c 2004-11-17 03:54:21.012373800 -0800 @@ -328,26 +328,6 @@ } /* - * Some machines, usually laptops, can't handle an enabled local APIC. - * The symptoms include hangs or reboots when suspending or resuming, - * attaching or detaching the power cord, or entering BIOS setup screens - * through magic key sequences. - */ -static int __init local_apic_kills_bios(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int enable_local_apic; - if (enable_local_apic == 0) { - enable_local_apic = -1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - -/* * Check for clue free BIOS implementations who use * the following QA technique * @@ -459,6 +439,22 @@ } /* + * Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to + * IRQ 11 even though it is actually wired to IRQ 10 + */ +static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d) +{ +#ifdef CONFIG_PCI + extern int acer_tm360_irqrouting; + if (acer_tm360_irqrouting == 0) { + acer_tm360_irqrouting = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } +#endif + return 0; +} + +/* * Exploding PnPBIOS. Don't yet know if its the BIOS or us for * some entries */ @@ -776,26 +772,6 @@ MATCH(DMI_PRODUCT_NAME, "P14H") } }, - /* Machines which have problems handling enabled local APICs */ - - { local_apic_kills_bios, "Dell Inspiron", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Inspiron"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "Dell Latitude", { - MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_PRODUCT_NAME, "Latitude"), - NO_MATCH, NO_MATCH - } }, - - { local_apic_kills_bios, "IBM Thinkpad T20", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "264741U"), - NO_MATCH, NO_MATCH - } }, - { init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */ MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), NO_MATCH, NO_MATCH, NO_MATCH @@ -820,6 +796,12 @@ MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") } }, + { fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", { + MATCH(DMI_SYS_VENDOR, "Acer"), + MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + NO_MATCH, NO_MATCH + } }, + /* * Generic per vendor APM settings */ @@ -935,6 +917,13 @@ /* newer BIOS, Revision 1011, does work */ MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"), NO_MATCH }}, + + { disable_acpi_pci, "Acer TravelMate 36x Laptop", { + MATCH(DMI_SYS_VENDOR, "Acer"), + MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + NO_MATCH, NO_MATCH + } }, + #endif /* CONFIG_ACPI_PCI */ { NULL, } diff -urN linux-2.4.27/arch/i386/kernel/io_apic.c linux-2.4.28/arch/i386/kernel/io_apic.c --- linux-2.4.27/arch/i386/kernel/io_apic.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/io_apic.c 2004-11-17 03:54:21.013373841 -0800 @@ -1349,7 +1349,7 @@ #ifndef CONFIG_SMP -void send_IPI_self(int vector) +void fastcall send_IPI_self(int vector) { unsigned int cfg; diff -urN linux-2.4.27/arch/i386/kernel/mpparse.c linux-2.4.28/arch/i386/kernel/mpparse.c --- linux-2.4.27/arch/i386/kernel/mpparse.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/mpparse.c 2004-11-17 03:54:21.014373882 -0800 @@ -1105,7 +1105,7 @@ /* allocate mp_irqs[] for ACPI parsing table parsing */ -int __init mp_irqs_alloc() +int __init mp_irqs_alloc(void) { int size = (MAX_IRQ_SOURCES * sizeof(int)) * 4; diff -urN linux-2.4.27/arch/i386/kernel/pci-irq.c linux-2.4.28/arch/i386/kernel/pci-irq.c --- linux-2.4.27/arch/i386/kernel/pci-irq.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/pci-irq.c 2004-11-17 03:54:21.015373923 -0800 @@ -23,6 +23,7 @@ #define PIRQ_VERSION 0x0100 int broken_hp_bios_irq9; +int acer_tm360_irqrouting; static struct irq_routing_table *pirq_table; @@ -894,6 +895,14 @@ r->set(pirq_router_dev, dev, pirq, 11); } + /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ + if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { + pirq = 0x68; + mask = 0x400; + dev->irq = r->get(pirq_router_dev, dev, pirq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + /* * Find the best IRQ to assign: use the one * reported by the device if possible. @@ -1103,10 +1112,6 @@ } dev = temp_dev; if (irq >= 0) { -#ifdef CONFIG_PCI_USE_VECTOR - if (!platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); -#endif printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); dev->irq = irq; @@ -1124,6 +1129,6 @@ /* VIA bridges use interrupt line for apic/pci steering across the V-Link */ else if (interrupt_line_quirk) - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15); } diff -urN linux-2.4.27/arch/i386/kernel/pci-pc.c linux-2.4.28/arch/i386/kernel/pci-pc.c --- linux-2.4.27/arch/i386/kernel/pci-pc.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/pci-pc.c 2004-11-17 03:54:21.016373964 -0800 @@ -177,6 +177,7 @@ }; #endif /* !CONFIG_MULTIQUAD */ +#undef PCI_CONF1_ADDRESS #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) @@ -1017,11 +1018,13 @@ "1:" : "=a" (ret), "=b" (map), - "+m" (opt) + "=m" (opt) : "0" (PCIBIOS_GET_ROUTING_OPTIONS), "1" (0), "D" ((long) &opt), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "m" (opt) + : "memory"); DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); if (ret & 0xff00) printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff); diff -urN linux-2.4.27/arch/i386/kernel/process.c linux-2.4.28/arch/i386/kernel/process.c --- linux-2.4.27/arch/i386/kernel/process.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/i386/kernel/process.c 2004-11-17 03:54:21.017374006 -0800 @@ -644,7 +644,7 @@ * More important, however, is the fact that this allows us much * more flexibility. */ -void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +void fastcall __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; diff -urN linux-2.4.27/arch/i386/kernel/signal.c linux-2.4.28/arch/i386/kernel/signal.c --- linux-2.4.27/arch/i386/kernel/signal.c 2002-08-02 17:39:42.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/signal.c 2004-11-17 03:54:21.048375280 -0800 @@ -581,7 +581,7 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; diff -urN linux-2.4.27/arch/i386/kernel/smp.c linux-2.4.28/arch/i386/kernel/smp.c --- linux-2.4.27/arch/i386/kernel/smp.c 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/smp.c 2004-11-17 03:54:21.049375321 -0800 @@ -150,7 +150,7 @@ apic_write_around(APIC_ICR, cfg); } -void send_IPI_self(int vector) +void fastcall send_IPI_self(int vector) { __send_IPI_shortcut(APIC_DEST_SELF, vector); } @@ -497,7 +497,7 @@ * anything. Worst case is that we lose a reschedule ... */ -void smp_send_reschedule(int cpu) +void fastcall smp_send_reschedule(int cpu) { send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); } diff -urN linux-2.4.27/arch/i386/kernel/vm86.c linux-2.4.28/arch/i386/kernel/vm86.c --- linux-2.4.27/arch/i386/kernel/vm86.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.28/arch/i386/kernel/vm86.c 2004-11-17 03:54:21.050375362 -0800 @@ -91,7 +91,7 @@ #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1) struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); -struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) +struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) { struct tss_struct *tss; struct pt_regs *ret; diff -urN linux-2.4.27/arch/ia64/config.in linux-2.4.28/arch/ia64/config.in --- linux-2.4.27/arch/ia64/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/ia64/config.in 2004-11-17 03:54:21.050375362 -0800 @@ -123,7 +123,7 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then diff -urN linux-2.4.27/arch/ia64/defconfig linux-2.4.28/arch/ia64/defconfig --- linux-2.4.27/arch/ia64/defconfig 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/ia64/defconfig 2004-11-17 03:54:21.051375403 -0800 @@ -755,7 +755,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/m68k/atari/stram.c linux-2.4.28/arch/m68k/atari/stram.c --- linux-2.4.27/arch/m68k/atari/stram.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.28/arch/m68k/atari/stram.c 2004-11-17 03:54:21.071376226 -0800 @@ -190,7 +190,7 @@ * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of * total memory */ -static int max_swap_size = -1; +static int max_swap_size = 0; /* start and end of swapping area */ static void *swap_start, *swap_end; @@ -306,7 +306,7 @@ reserve_bootmem (0, PAGE_SIZE); #ifdef CONFIG_STRAM_SWAP - { + if (max_swap_size) { void *swap_data; start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem); @@ -961,14 +961,33 @@ return( max_start ); } +#ifdef CONFIG_STRAM_SWAP /* setup parameters from command line */ -void __init stram_swap_setup(char *str, int *ints) +void __init stram_swap_setup(char *str) { - if (ints[0] >= 1) - max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK; + int ints[3]; + get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] >= 1) { + if (ints[1] == 1) { + /* always use ST-RAM as swap */ + max_swap_size = -1; + if (ints[0] == 2) { + max_swap_size = ((ints[2] < 0 ? 0 : ints[2]) * 1024) & PAGE_MASK; + } + } + else if (ints[1] == 0) { + /* never use ST-RAM as swap */ + max_swap_size = 0; + } + else { + printk( KERN_WARNING "stram_swap=%d - invalid value\n", ints[1] ); + } + } } +#endif /* CONFIG_STRAM_SWAP */ + /* ------------------------------------------------------------------------ */ /* ST-RAM device */ diff -urN linux-2.4.27/arch/m68k/config.in linux-2.4.28/arch/m68k/config.in --- linux-2.4.27/arch/m68k/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/m68k/config.in 2004-11-17 03:54:21.073376308 -0800 @@ -98,7 +98,7 @@ A.OUT CONFIG_KCORE_AOUT" ELF fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_AMIGA" = "y" ]; then diff -urN linux-2.4.27/arch/m68k/kernel/setup.c linux-2.4.28/arch/m68k/kernel/setup.c --- linux-2.4.27/arch/m68k/kernel/setup.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/m68k/kernel/setup.c 2004-11-17 03:54:21.073376308 -0800 @@ -290,13 +290,20 @@ i = 1; } #ifdef CONFIG_ATARI - /* This option must be parsed very early */ + /* These options must be parsed very early */ if (!strncmp( p, "switches=", 9 )) { extern void atari_switches_setup( const char *, int ); atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? (q - (p+9)) : strlen(p+9) ); i = 1; } +#ifdef CONFIG_STRAM_SWAP + if (!strncmp( p, "stram_swap=", 11 )) { + extern void stram_swap_setup( char * ); + stram_swap_setup( p+11 ); + i = 1; + } +#endif /* CONFIG_STRAM_SWAP */ #endif if (i) { diff -urN linux-2.4.27/arch/m68k/mm/motorola.c linux-2.4.28/arch/m68k/mm/motorola.c --- linux-2.4.27/arch/m68k/mm/motorola.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.28/arch/m68k/mm/motorola.c 2004-11-17 03:54:21.074376349 -0800 @@ -264,7 +264,7 @@ printk ("before free_area_init\n"); #endif zones_size[0] = (mach_max_dma_address < (unsigned long)high_memory ? - mach_max_dma_address : (unsigned long)high_memory); + (mach_max_dma_address+1) : (unsigned long)high_memory); zones_size[1] = (unsigned long)high_memory - zones_size[0]; zones_size[0] = (zones_size[0] - PAGE_OFFSET) >> PAGE_SHIFT; diff -urN linux-2.4.27/arch/mips/config-shared.in linux-2.4.28/arch/mips/config-shared.in --- linux-2.4.27/arch/mips/config-shared.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/mips/config-shared.in 2004-11-17 03:54:21.075376390 -0800 @@ -943,7 +943,7 @@ define_bool CONFIG_KCORE_ELF y define_bool CONFIG_KCORE_AOUT n define_bool CONFIG_BINFMT_AOUT n -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF dep_bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT $CONFIG_MIPS64 dep_bool 'Kernel support for o32 binaries' CONFIG_MIPS32_O32 $CONFIG_MIPS32_COMPAT dep_bool 'Kernel support for n32 binaries' CONFIG_MIPS32_N32 $CONFIG_MIPS32_COMPAT diff -urN linux-2.4.27/arch/mips/defconfig linux-2.4.28/arch/mips/defconfig --- linux-2.4.27/arch/mips/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/mips/defconfig 2004-11-17 03:54:21.076376431 -0800 @@ -607,7 +607,7 @@ CONFIG_ROOT_NFS=y CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -urN linux-2.4.27/arch/mips64/defconfig linux-2.4.28/arch/mips64/defconfig --- linux-2.4.27/arch/mips64/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/mips64/defconfig 2004-11-17 03:54:21.076376431 -0800 @@ -563,7 +563,7 @@ CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/mips64/kernel/linux32.c linux-2.4.28/arch/mips64/kernel/linux32.c --- linux-2.4.27/arch/mips64/kernel/linux32.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/mips64/kernel/linux32.c 2004-11-17 03:54:21.078376514 -0800 @@ -1568,7 +1568,7 @@ asmlinkage int sys32_setsockopt(int fd, int level, int optname, char *optval, int optlen) { - if (optname == SO_ATTACH_FILTER) + if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) diff -urN linux-2.4.27/arch/parisc/config.in linux-2.4.28/arch/parisc/config.in --- linux-2.4.27/arch/parisc/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/parisc/config.in 2004-11-17 03:54:21.079376555 -0800 @@ -88,7 +88,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL define_bool CONFIG_KCORE_ELF y -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff -urN linux-2.4.27/arch/ppc/defconfig linux-2.4.28/arch/ppc/defconfig --- linux-2.4.27/arch/ppc/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/ppc/defconfig 2004-11-17 03:54:21.080376596 -0800 @@ -812,7 +812,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -urN linux-2.4.27/arch/ppc/kernel/cputable.c linux-2.4.28/arch/ppc/kernel/cputable.c --- linux-2.4.27/arch/ppc/kernel/cputable.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.28/arch/ppc/kernel/cputable.c 2004-11-17 03:54:21.081376637 -0800 @@ -51,10 +51,20 @@ #define CPU_FTR_ALTIVEC_COMP 0 #endif +/* We need to mark all pages as being coherent if we're SMP or we + * have a 754x and an MPC107 host bridge. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE) +#define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT +#else +#define CPU_FTR_COMMON 0 +#endif + struct cpu_spec cpu_specs[] = { #if CLASSIC_PPC { /* 601 */ 0xffff0000, 0x00010000, "601", + CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_601_INSTR | PPC_FEATURE_UNIFIED_CACHE, 32, 32, @@ -62,6 +72,7 @@ }, { /* 603 */ 0xffff0000, 0x00030000, "603", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -70,6 +81,7 @@ }, { /* 603e */ 0xffff0000, 0x00060000, "603e", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -78,6 +90,7 @@ }, { /* 603ev */ 0xffff0000, 0x00070000, "603ev", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -86,6 +99,7 @@ }, { /* 604 */ 0xffff0000, 0x00040000, "604", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, COMMON_PPC, @@ -94,6 +108,7 @@ }, { /* 604e */ 0xfffff000, 0x00090000, "604e", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, COMMON_PPC, @@ -102,6 +117,7 @@ }, { /* 604r */ 0xffff0000, 0x00090000, "604r", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, COMMON_PPC, @@ -110,6 +126,7 @@ }, { /* 604ev */ 0xffff0000, 0x000a0000, "604ev", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, COMMON_PPC, @@ -118,6 +135,7 @@ }, { /* 740/750 (0x4202, don't support TAU ?) */ 0xffffffff, 0x00084202, "740/750", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -126,6 +144,7 @@ }, { /* 745/755 */ 0xfffff000, 0x00083000, "745/755", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -134,6 +153,7 @@ }, { /* 750CX */ 0xffffff00, 0x00082200, "750CX", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -142,6 +162,7 @@ }, { /* 750FX rev 1.x */ 0xffffff00, 0x70000100, "750FX", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | CPU_FTR_750FX | CPU_FTR_NO_DPM, @@ -151,6 +172,7 @@ }, { /* 750FX rev 2.0 must disable HID0[DPM] */ 0xffffffff, 0x70000200, "750FX", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | CPU_FTR_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NO_DPM, @@ -160,6 +182,7 @@ }, { /* 750FX (All revs > 2.0) */ 0xffff0000, 0x70000000, "750FX", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | CPU_FTR_750FX | CPU_FTR_HAS_HIGH_BATS, @@ -169,6 +192,7 @@ }, { /* 740/750 (L2CR bit need fixup for 740) */ 0xffff0000, 0x00080000, "740/750", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, @@ -177,6 +201,7 @@ }, { /* 7400 rev 1.1 ? (no TAU) */ 0xffffffff, 0x000c1101, "7400 (1.1)", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, @@ -186,6 +211,7 @@ }, { /* 7400 */ 0xffff0000, 0x000c0000, "7400", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, @@ -195,6 +221,7 @@ }, { /* 7410 */ 0xffff0000, 0x800c0000, "7410", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, @@ -204,82 +231,104 @@ }, { /* 7450 1.x - no doze/nap */ 0xffffff00, 0x80000100, "7450", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7450 2.0 - no doze/nap */ 0xffffffff, 0x80000200, "7450", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7450 2.1 */ 0xffffffff, 0x80000201, "7450", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | - CPU_FTR_L3_DISABLE_NAP, + CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7450 2.3 and newer */ 0xffff0000, 0x80000000, "7450", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR, + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | + CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7455 rev 1.x */ 0xffffff00, 0x80010100, "7455", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | + CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7455 rev 2.0 */ 0xffffffff, 0x80010200, "7455", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | - CPU_FTR_L3_DISABLE_NAP | CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_L3_DISABLE_NAP | CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7455 others */ 0xffff0000, 0x80010000, "7455", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | - CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 7457 */ 0xffff0000, 0x80020000, "7457", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | - CPU_FTR_HAS_HIGH_BATS, + CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, + COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, + 32, 32, + __setup_cpu_745x + }, + { /* 7447A */ + 0xffff0000, 0x80030000, "7447A", + CPU_FTR_COMMON | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | + CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_745x }, { /* 82xx (8240, 8245, 8260 are all 603e cores) */ 0x7fff0000, 0x00810000, "82xx", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, COMMON_PPC, 32, 32, @@ -295,6 +344,7 @@ }, { /* default match, we assume split I/D cache & TB (non-601)... */ 0x00000000, 0x00000000, "(generic PPC)", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC, 32, 32, @@ -304,6 +354,7 @@ #ifdef CONFIG_PPC64BRIDGE { /* Power3 */ 0xffff0000, 0x00400000, "Power3 (630)", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_64, 128, 128, @@ -311,6 +362,7 @@ }, { /* Power3+ */ 0xffff0000, 0x00410000, "Power3 (630+)", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_64, 128, 128, @@ -318,6 +370,7 @@ }, { /* I-star */ 0xffff0000, 0x00360000, "I-star", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_64, 128, 128, @@ -325,6 +378,7 @@ }, { /* S-star */ 0xffff0000, 0x00370000, "S-star", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_64, 128, 128, @@ -334,6 +388,7 @@ #ifdef CONFIG_POWER4 { /* Power4 */ 0xffff0000, 0x00350000, "Power4", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_64, 128, 128, @@ -341,6 +396,7 @@ }, { /* PPC970 */ 0xffff0000, 0x00390000, "PPC970", + CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP, COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC, @@ -435,7 +491,7 @@ #if !CLASSIC_PPC { /* default match */ 0x00000000, 0x00000000, "(generic PPC)", - 0, + CPU_FTR_COMMON, PPC_FEATURE_32, 32, 32, 0, diff -urN linux-2.4.27/arch/ppc/kernel/ppc_htab.c linux-2.4.28/arch/ppc/kernel/ppc_htab.c --- linux-2.4.27/arch/ppc/kernel/ppc_htab.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/ppc/kernel/ppc_htab.c 2004-11-17 03:54:21.082376678 -0800 @@ -489,7 +489,7 @@ if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; diff -urN linux-2.4.27/arch/ppc/mm/hashtable.S linux-2.4.28/arch/ppc/mm/hashtable.S --- linux-2.4.27/arch/ppc/mm/hashtable.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/arch/ppc/mm/hashtable.S 2004-11-17 03:54:21.083376719 -0800 @@ -327,9 +327,9 @@ rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */ ori r8,r8,0xe14 /* clear out reserved bits and M */ andc r8,r5,r8 /* PP = user? (rw&dirty? 2: 3): 0 */ -#ifdef CONFIG_SMP +BEGIN_FTR_SECTION ori r8,r8,_PAGE_COHERENT /* set M (coherence required) */ -#endif +END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT) /* Construct the high word of the PPC-style PTE (r5) */ #ifndef CONFIG_PPC64BRIDGE diff -urN linux-2.4.27/arch/ppc/mm/ppc_mmu.c linux-2.4.28/arch/ppc/mm/ppc_mmu.c --- linux-2.4.27/arch/ppc/mm/ppc_mmu.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/ppc/mm/ppc_mmu.c 2004-11-17 03:54:21.083376719 -0800 @@ -106,10 +106,10 @@ int wimgxpp; union ubat *bat = BATS[index]; -#ifdef CONFIG_SMP - if ((flags & _PAGE_NO_CACHE) == 0) + if (((flags & _PAGE_NO_CACHE) == 0) && + (cur_cpu_spec[0]->cpu_features & CPU_FTR_NEED_COHERENT)) flags |= _PAGE_COHERENT; -#endif + bl = (size >> 17) - 1; if (PVR_VER(mfspr(PVR)) != 1) { /* 603, 604, etc. */ diff -urN linux-2.4.27/arch/ppc/platforms/residual.c linux-2.4.28/arch/ppc/platforms/residual.c --- linux-2.4.27/arch/ppc/platforms/residual.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/arch/ppc/platforms/residual.c 2004-11-17 03:54:21.084376760 -0800 @@ -493,7 +493,7 @@ size=tag_small_count(pkt->S1_Pack.Tag)+1; printsmallpacket(pkt, size); } - (unsigned char *) pkt+=size; + pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size); } while (pkt->S1_Pack.Tag != END_TAG); } diff -urN linux-2.4.27/arch/ppc64/defconfig linux-2.4.28/arch/ppc64/defconfig --- linux-2.4.27/arch/ppc64/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/ppc64/defconfig 2004-11-17 03:54:21.085376801 -0800 @@ -668,7 +668,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/ppc64/kernel/rtas-proc.c linux-2.4.28/arch/ppc64/kernel/rtas-proc.c --- linux-2.4.27/arch/ppc64/kernel/rtas-proc.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/ppc64/kernel/rtas-proc.c 2004-11-17 03:54:21.086376843 -0800 @@ -406,7 +406,7 @@ n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, tmpbuf + pos), n) { + if (copy_to_user(buf, tmpbuf + pos, n)) { kfree(tmpbuf); return -EFAULT; } diff -urN linux-2.4.27/arch/ppc64/kernel/sys_ppc32.c linux-2.4.28/arch/ppc64/kernel/sys_ppc32.c --- linux-2.4.27/arch/ppc64/kernel/sys_ppc32.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/ppc64/kernel/sys_ppc32.c 2004-11-17 03:54:21.088376925 -0800 @@ -3221,7 +3221,7 @@ PPCDBG(PPCDBG_SYS32,"sys32_setsockopt - running - pid=%ld, comm=%s\n", current->pid, current->comm); - if (optname == SO_ATTACH_FILTER) { + if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) { struct sock_fprog32 { __u16 len; __u32 filter; diff -urN linux-2.4.27/arch/s390/config.in linux-2.4.28/arch/s390/config.in --- linux-2.4.27/arch/s390/config.in 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/s390/config.in 2004-11-17 03:54:21.089376966 -0800 @@ -57,7 +57,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL define_bool CONFIG_KCORE_ELF y -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool '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 bool 'Pseudo page fault support' CONFIG_PFAULT diff -urN linux-2.4.27/arch/s390/defconfig linux-2.4.28/arch/s390/defconfig --- linux-2.4.27/arch/s390/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/s390/defconfig 2004-11-17 03:54:21.090377007 -0800 @@ -129,6 +129,14 @@ # CONFIG_CHANDEV=y CONFIG_HOTPLUG=y +CONFIG_QETH=m + +# +# Gigabit Ethernet default settings +# +CONFIG_QETH_IPV6=y +CONFIG_QETH_VLAN=y +# CONFIG_QETH_PERF_STATS is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -242,7 +250,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=m # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set CONFIG_VLAN_8021Q=m @@ -351,7 +358,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/s390/kernel/entry.S linux-2.4.28/arch/s390/kernel/entry.S --- linux-2.4.27/arch/s390/kernel/entry.S 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/s390/kernel/entry.S 2004-11-17 03:54:21.091377048 -0800 @@ -690,7 +690,12 @@ io_int_handler: SAVE_ALL_BASE SAVE_ALL __LC_IO_OLD_PSW,0 + mc 0,0 GET_CURRENT # load pointer to task_struct to R9 + stck __LC_INT_CLOCK + clc __LC_INT_CLOCK(8),__LC_JIFFY_TIMER + bhe BASED(io_handle_tick) +io_call_handler: l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 @@ -725,6 +730,15 @@ RESTORE_ALL 0 # +# account tick +# +io_handle_tick: + l %r1,BASED(.Laccount_ticks) + la %r2,SP_PTREGS(%r15) # address of register-save area + la %r14,BASED(io_call_handler) + br %r1 + +# # call do_softirq # io_handle_bottom_half: @@ -758,8 +772,13 @@ ext_int_handler: SAVE_ALL_BASE SAVE_ALL __LC_EXT_OLD_PSW,0 - GET_CURRENT # load pointer to task_struct to R9 + mc 0, 0 + GET_CURRENT # load pointer to task_struct to R9 lh %r6,__LC_EXT_INT_CODE # get interruption code + stck __LC_INT_CLOCK + clc __LC_INT_CLOCK(8),__LC_JIFFY_TIMER + bhe BASED(ext_handle_tick) +ext_call_handler: lr %r1,%r6 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) sll %r1,2 @@ -770,7 +789,8 @@ ext_int_loop: ch %r6,8(%r7) # compare external interrupt code bne BASED(ext_int_next) - l %r1,4(%r7) # get handler address + icm %r1,15,4(%r7) # get handler address + bz BASED(ext_int_next) la %r2,SP_PTREGS(%r15) # address of register-save area lr %r3,%r6 # interruption code basr %r14,%r1 # call handler @@ -779,6 +799,15 @@ bnz BASED(ext_int_loop) b BASED(io_return) +# +# account tick +# +ext_handle_tick: + l %r1,BASED(.Laccount_ticks) + la %r2,SP_PTREGS(%r15) # address of register-save area + la %r14,BASED(ext_call_handler) + br %r1 + /* * Machine check handler routines */ @@ -787,6 +816,7 @@ mcck_int_handler: SAVE_ALL_BASE SAVE_ALL __LC_MCK_OLD_PSW,0 + mc 0, 0 l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler mcck_return: @@ -869,4 +899,4 @@ .Lvfork: .long sys_vfork .Lschedtail: .long schedule_tail - +.Laccount_ticks:.long account_ticks diff -urN linux-2.4.27/arch/s390/kernel/s390_ksyms.c linux-2.4.28/arch/s390/kernel/s390_ksyms.c --- linux-2.4.27/arch/s390/kernel/s390_ksyms.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/s390/kernel/s390_ksyms.c 2004-11-17 03:54:21.091377048 -0800 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -66,3 +67,7 @@ EXPORT_SYMBOL(get_storage_key); EXPORT_SYMBOL_NOVERS(do_call_softirq); EXPORT_SYMBOL(sys_wait4); +EXPORT_SYMBOL(smp_call_function_on); +EXPORT_SYMBOL(show_trace); +EXPORT_SYMBOL(cpcmd); + diff -urN linux-2.4.27/arch/s390/kernel/smp.c linux-2.4.28/arch/s390/kernel/smp.c --- linux-2.4.27/arch/s390/kernel/smp.c 2002-11-28 15:53:11.000000000 -0800 +++ linux-2.4.28/arch/s390/kernel/smp.c 2004-11-17 03:54:21.092377089 -0800 @@ -92,7 +92,7 @@ extern void reipl(unsigned long devno); -static sigp_ccode smp_ext_bitcall(int, ec_bit_sig); +static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); /* @@ -131,7 +131,7 @@ * in the system. */ -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, int wait) /* * [SUMMARY] Run a function on all other CPUs. @@ -162,7 +162,7 @@ spin_lock_bh(&call_lock); call_data = &data; /* Send a message to all other CPUs and wait for them to respond */ - smp_ext_bitcall_others(ec_call_function); + smp_ext_bitcall_others(ec_call_function); /* Wait for response */ while (atomic_read(&data.started) != cpus) @@ -176,9 +176,54 @@ return 0; } +/* + * Call a function on one CPU + * cpu : the CPU the function should be executed on + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +int smp_call_function_on(void (*func) (void *info), void *info, + int nonatomic, int wait, int cpu) +{ + struct call_data_struct data; + + if (!atomic_read(&smp_commenced)) + return 0; + + if (smp_processor_id() == cpu) { + /* direct call to function */ + func(info); + return 0; + } + + data.func = func; + data.info = info; + + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + smp_ext_bitcall(cpu, ec_call_function); + + /* Wait for response */ + while (atomic_read(&data.started) != 1) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != 1) + barrier(); + + spin_unlock_bh(&call_lock); + return 0; +} + static inline void do_send_stop(void) { - u32 dummy; + unsigned long dummy; int i; /* stop all processors */ @@ -199,7 +244,7 @@ static inline void do_store_status(void) { unsigned long low_core_addr; - u32 dummy; + unsigned long dummy; int i; /* store status of all processors in their lowcores (real 0) */ @@ -328,42 +373,41 @@ } /* - * Send an external call sigp to another cpu and return without waiting + * Send an external call sigp to another cpu and wait * for its completion. */ -static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig) +static void smp_ext_bitcall(int cpu, ec_bit_sig sig) { - struct _lowcore *lowcore = get_cpu_lowcore(cpu); - sigp_ccode ccode; + struct _lowcore *lowcore = get_cpu_lowcore(cpu); - /* - * Set signaling bit in lowcore of target cpu and kick it - */ - atomic_set_mask(1<ext_call_fast); - ccode = signal_processor(cpu, sigp_external_call); - return ccode; + /* + * Set signaling bit in lowcore of target cpu and kick it + */ + atomic_set_mask(1<ext_call_fast); + while(signal_processor(cpu, sigp_external_call) == sigp_busy) + udelay(10); } /* * Send an external call sigp to every other cpu in the system and - * return without waiting for its completion. + * wait for its completion. */ static void smp_ext_bitcall_others(ec_bit_sig sig) { - struct _lowcore *lowcore; - int i; + struct _lowcore *lowcore; + int i; - for (i = 0; i < smp_num_cpus; i++) { - if (smp_processor_id() == i) - continue; - lowcore = get_cpu_lowcore(i); - /* - * Set signaling bit in lowcore of target cpu and kick it - */ - atomic_set_mask(1<ext_call_fast); - while (signal_processor(i, sigp_external_call) == sigp_busy) + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() == i) + continue; + lowcore = get_cpu_lowcore(i); + /* + * Set signaling bit in lowcore of target cpu and kick it + */ + atomic_set_mask(1<ext_call_fast); + while (signal_processor(i, sigp_external_call) == sigp_busy) udelay(10); - } + } } /* diff -urN linux-2.4.27/arch/s390/kernel/time.c linux-2.4.28/arch/s390/kernel/time.c --- linux-2.4.27/arch/s390/kernel/time.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/s390/kernel/time.c 2004-11-17 03:54:21.093377130 -0800 @@ -34,13 +34,20 @@ #include /* change this if you have some constant time drift */ -#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) +/* + * Create a small time difference between the timer interrupts + * on the different cpus to avoid lock contention. + */ +#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) +#define CPU_DEVIATION (smp_processor_id() << 12) + #define TICK_SIZE tick static ext_int_info_t ext_int_info_timer; -static uint64_t init_timer_cc; +static u64 init_timer_cc; +static u64 xtime_cc; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; @@ -83,7 +90,7 @@ { __u64 now; - asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); + asm volatile ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); now = (now - init_timer_cc) >> 12; /* We require the offset from the latest update of xtime */ now -= (__u64) wall_jiffies*USECS_PER_JIFFY; @@ -137,41 +144,72 @@ write_unlock_irq(&xtime_lock); } +static inline __u32 div64_32(__u64 dividend, __u32 divisor) +{ + register_pair rp; + + rp.pair = dividend; + asm ("dr %0,%1" : "+d" (rp) : "d" (divisor)); + return rp.subreg.odd; +} + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ - -#ifdef CONFIG_SMP -extern __u16 boot_cpu_addr; -#endif - -static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) +void account_ticks(struct pt_regs *regs) { int cpu = smp_processor_id(); + __u64 tmp; + __u32 ticks; + + /* Calculate how many ticks have passed. */ + tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; + if (tmp >= 2*CLK_TICKS_PER_JIFFY) { + ticks = div64_32(tmp >> 1, CLK_TICKS_PER_JIFFY >> 1) + 1; + S390_lowcore.jiffy_timer += + CLK_TICKS_PER_JIFFY * (__u64) ticks; + } else if (tmp > CLK_TICKS_PER_JIFFY) { + ticks = 2; + S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY; + } else { + ticks = 1; + S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; + } + + /* set clock comparator for next tick */ + tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; + asm volatile ("SCKC %0" : : "m" (tmp)); irq_enter(cpu, 0); +#ifdef CONFIG_SMP /* - * set clock comparator for next tick + * Do not rely on the boot cpu to do the calls to do_timer. + * Spread it over all cpus instead. */ - S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); - -#ifdef CONFIG_SMP - if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) - write_lock(&xtime_lock); - - update_process_times(user_mode(regs)); - - if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) { - do_timer(regs); - write_unlock(&xtime_lock); + write_lock(&xtime_lock); + if (S390_lowcore.jiffy_timer > xtime_cc) { + __u32 xticks; + + tmp = S390_lowcore.jiffy_timer - xtime_cc; + if (tmp >= 2*CLK_TICKS_PER_JIFFY) { + xticks = div64_32(tmp >> 1, CLK_TICKS_PER_JIFFY >> 1); + xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; + } else { + xticks = 1; + xtime_cc += CLK_TICKS_PER_JIFFY; + } + while (xticks--) + do_timer(regs); } + write_unlock(&xtime_lock); + while (ticks--) + update_process_times(user_mode(regs)); #else - do_timer(regs); + while (ticks--) + do_timer(regs); #endif - irq_exit(cpu, 0); } @@ -180,11 +218,13 @@ */ void init_cpu_timer(void) { - unsigned long cr0; + unsigned long cr0; + __u64 timer; - S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY; - S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); + timer = init_timer_cc + (__u64) jiffies * CLK_TICKS_PER_JIFFY; + S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; + timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; + asm volatile ("SCKC %0" : : "m" (timer)); /* allow clock comparator timer interrupt */ asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory"); cr0 |= 0x800; @@ -220,12 +260,13 @@ } /* set xtime */ + xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; set_time_cc = init_timer_cc - 0x8126d60e46000000LL + (0x3c26700LL*1000000*4096); tod_to_timeval(set_time_cc, &xtime); /* request the 0x1004 external interrupt */ - if (register_early_external_interrupt(0x1004, do_comparator_interrupt, + if (register_early_external_interrupt(0x1004, NULL, &ext_int_info_timer) != 0) panic("Couldn't request external interrupt 0x1004"); diff -urN linux-2.4.27/arch/s390x/config.in linux-2.4.28/arch/s390x/config.in --- linux-2.4.27/arch/s390x/config.in 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/s390x/config.in 2004-11-17 03:54:21.093377130 -0800 @@ -60,7 +60,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL define_bool CONFIG_KCORE_ELF y -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool '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 bool 'Pseudo page fault support' CONFIG_PFAULT diff -urN linux-2.4.27/arch/s390x/defconfig linux-2.4.28/arch/s390x/defconfig --- linux-2.4.27/arch/s390x/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/s390x/defconfig 2004-11-17 03:54:21.094377171 -0800 @@ -129,6 +129,14 @@ # CONFIG_CHANDEV=y CONFIG_HOTPLUG=y +CONFIG_QETH=m + +# +# Gigabit Ethernet default settings +# +CONFIG_QETH_IPV6=y +CONFIG_QETH_VLAN=y +# CONFIG_QETH_PERF_STATS is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -291,7 +299,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/s390x/kernel/entry.S linux-2.4.28/arch/s390x/kernel/entry.S --- linux-2.4.27/arch/s390x/kernel/entry.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/arch/s390x/kernel/entry.S 2004-11-17 03:54:21.095377213 -0800 @@ -722,7 +722,12 @@ .globl io_int_handler io_int_handler: SAVE_ALL __LC_IO_OLD_PSW,0 + mc 0, 0 GET_CURRENT # load pointer to task_struct to R9 + stck __LC_INT_CLOCK + clc __LC_INT_CLOCK(8),__LC_JIFFY_TIMER + jhe io_handle_tick +io_call_handler: 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 interuption parm @@ -780,14 +785,27 @@ larl %r14,io_leave jg do_signal # return point is io_leave +# +# account tick +# +io_handle_tick: + la %r2,SP_PTREGS(%r15) # address of register-save area + larl %r14,io_call_handler + jg account_ticks + /* * External interrupt handler routine */ .globl ext_int_handler ext_int_handler: SAVE_ALL __LC_EXT_OLD_PSW,0 + mc 0, 0 GET_CURRENT # load pointer to task_struct to R9 llgh %r6,__LC_EXT_INT_CODE # get interruption code + stck __LC_INT_CLOCK + clc __LC_INT_CLOCK(8),__LC_JIFFY_TIMER + jhe ext_handle_tick +ext_call_handler: lgr %r1,%r6 # calculate index = code & 0xff nill %r1,0xff sll %r1,3 @@ -799,6 +817,8 @@ ch %r6,16(%r7) # compare external interrupt code jne ext_int_next lg %r1,8(%r7) # get handler address + ltgr %r1,%r1 + jz ext_int_next la %r2,SP_PTREGS(%r15) # address of register-save area lgr %r3,%r6 # interruption code basr %r14,%r1 # call handler @@ -808,12 +828,21 @@ jnz ext_int_loop j io_return +# +# account tick +# +ext_handle_tick: + la %r2,SP_PTREGS(%r15) # address of register-save area + larl %r14,ext_call_handler + jg account_ticks + /* * Machine check handler routines */ .globl mcck_int_handler mcck_int_handler: SAVE_ALL __LC_MCK_OLD_PSW,0 + mc 0, 0 brasl %r14,s390_do_machine_check mcck_return: RESTORE_ALL 0 diff -urN linux-2.4.27/arch/s390x/kernel/ioctl32.c linux-2.4.28/arch/s390x/kernel/ioctl32.c --- linux-2.4.27/arch/s390x/kernel/ioctl32.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/arch/s390x/kernel/ioctl32.c 2004-11-17 03:54:21.096377254 -0800 @@ -34,6 +34,7 @@ #include #include #include +#include "../../../drivers/s390/char/tubio.h" #include "linux32.h" @@ -535,6 +536,12 @@ IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl), + IOCTL32_DEFAULT(TUBICMD), + IOCTL32_DEFAULT(TUBOCMD), + IOCTL32_DEFAULT(TUBGETI), + IOCTL32_DEFAULT(TUBGETO), + IOCTL32_DEFAULT(TUBSETMOD), + IOCTL32_DEFAULT(TUBGETMOD), IOCTL32_DEFAULT(TCGETA), IOCTL32_DEFAULT(TCSETA), IOCTL32_DEFAULT(TCSETAW), diff -urN linux-2.4.27/arch/s390x/kernel/linux32.c linux-2.4.28/arch/s390x/kernel/linux32.c --- linux-2.4.27/arch/s390x/kernel/linux32.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/s390x/kernel/linux32.c 2004-11-17 03:54:21.099377377 -0800 @@ -4427,7 +4427,7 @@ ret = sys_newstat(tmp, &s); set_fs (old_fs); putname(tmp); - if (putstat64 (statbuf, &s)) + if (!ret && putstat64 (statbuf, &s)) return -EFAULT; return ret; } @@ -4451,7 +4451,7 @@ ret = sys_newlstat(tmp, &s); set_fs (old_fs); putname(tmp); - if (putstat64 (statbuf, &s)) + if (!ret && putstat64 (statbuf, &s)) return -EFAULT; return ret; } @@ -4467,7 +4467,7 @@ set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); - if (putstat64 (statbuf, &s)) + if (!ret && putstat64 (statbuf, &s)) return -EFAULT; return ret; } @@ -4507,7 +4507,7 @@ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { /* Result is out of bounds. */ - do_munmap(current->mm, addr, len); + do_munmap(current->mm, error, len); error = -ENOMEM; } up_write(¤t->mm->mmap_sem); diff -urN linux-2.4.27/arch/s390x/kernel/s390_ksyms.c linux-2.4.28/arch/s390x/kernel/s390_ksyms.c --- linux-2.4.27/arch/s390x/kernel/s390_ksyms.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/s390x/kernel/s390_ksyms.c 2004-11-17 03:54:21.099377377 -0800 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -83,3 +84,7 @@ EXPORT_SYMBOL(console_device); EXPORT_SYMBOL_NOVERS(do_call_softirq); EXPORT_SYMBOL(sys_wait4); +EXPORT_SYMBOL(smp_call_function_on); +EXPORT_SYMBOL(show_trace); +EXPORT_SYMBOL(cpcmd); + diff -urN linux-2.4.27/arch/s390x/kernel/smp.c linux-2.4.28/arch/s390x/kernel/smp.c --- linux-2.4.27/arch/s390x/kernel/smp.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/s390x/kernel/smp.c 2004-11-17 03:54:21.100377418 -0800 @@ -92,7 +92,7 @@ extern void reipl(unsigned long devno); -static sigp_ccode smp_ext_bitcall(int, ec_bit_sig); +static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); /* @@ -131,7 +131,7 @@ * in the system. */ -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, int wait) /* * [SUMMARY] Run a function on all other CPUs. @@ -176,46 +176,92 @@ return 0; } +/* + * Call a function only on one CPU + * cpu : the CPU the function should be executed on + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +int smp_call_function_on(void (*func) (void *info), void *info, + int nonatomic, int wait, int cpu) +{ + struct call_data_struct data; + + if (!atomic_read(&smp_commenced)) + return 0; + + if (smp_processor_id() == cpu) { + /* direct call to function */ + func(info); + return 0; + } + + data.func = func; + data.info = info; + + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + smp_ext_bitcall(cpu, ec_call_function); + + /* Wait for response */ + while (atomic_read(&data.started) != 1) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != 1) + barrier(); + + spin_unlock_bh(&call_lock); + return 0; +} + + static inline void do_send_stop(void) { - u32 dummy; - int i; + unsigned long dummy; + int i; - /* stop all processors */ - for (i = 0; i < smp_num_cpus; i++) { - if (smp_processor_id() != i) { - int ccode; - do { - ccode = signal_processor_ps( - &dummy, - 0, - i, - sigp_stop); - } while(ccode == sigp_busy); - } - } + /* stop all processors */ + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() != i) { + int ccode; + do { + ccode = signal_processor_ps( + &dummy, + 0, + i, + sigp_stop); + } while(ccode == sigp_busy); + } + } } static inline void do_store_status(void) { - unsigned long low_core_addr; - u32 dummy; - int i; + unsigned long low_core_addr; + unsigned long dummy; + int i; - /* store status of all processors in their lowcores (real 0) */ - for (i = 0; i < smp_num_cpus; i++) { - if (smp_processor_id() != i) { - int ccode; - low_core_addr = (unsigned long)get_cpu_lowcore(i); - do { - ccode = signal_processor_ps( - &dummy, - low_core_addr, - i, - sigp_store_status_at_address); - } while(ccode == sigp_busy); - } - } + /* store status of all processors in their lowcores (real 0) */ + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() != i) { + int ccode; + low_core_addr = (unsigned long)get_cpu_lowcore(i); + do { + ccode = signal_processor_ps( + &dummy, + low_core_addr, + i, + sigp_store_status_at_address); + } while(ccode == sigp_busy); + } + } } /* @@ -224,8 +270,8 @@ */ void smp_send_stop(void) { - /* write magic number to zero page (absolute 0) */ - get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC; + /* write magic number to zero page (absolute 0) */ + get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC; /* stop other processors. */ do_send_stop(); @@ -263,7 +309,7 @@ void machine_restart_smp(char * __unused) { cpu_restart_map = cpu_online_map; - smp_call_function(do_machine_restart, NULL, 0, 0); + smp_call_function(do_machine_restart, NULL, 0, 0); do_machine_restart(NULL); } @@ -282,7 +328,7 @@ void machine_halt_smp(void) { - smp_call_function(do_machine_halt, NULL, 0, 0); + smp_call_function(do_machine_halt, NULL, 0, 0); do_machine_halt(NULL); } @@ -301,7 +347,7 @@ void machine_power_off_smp(void) { - smp_call_function(do_machine_power_off, NULL, 0, 0); + smp_call_function(do_machine_power_off, NULL, 0, 0); do_machine_power_off(NULL); } @@ -312,55 +358,52 @@ void do_ext_call_interrupt(struct pt_regs *regs, __u16 code) { - unsigned long bits; + unsigned long bits; - /* - * handle bit signal external calls - * - * For the ec_schedule signal we have to do nothing. All the work - * is done automatically when we return from the interrupt. - */ + /* + * handle bit signal external calls + * + * For the ec_schedule signal we have to do nothing. All the work + * is done automatically when we return from the interrupt. + */ bits = xchg(&S390_lowcore.ext_call_fast, 0); - if (test_bit(ec_call_function, &bits)) + if (test_bit(ec_call_function, &bits)) do_call_function(); } /* - * Send an external call sigp to another cpu and return without waiting + * Send an external call sigp to another cpu and wait * for its completion. */ -static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig) +static void smp_ext_bitcall(int cpu, ec_bit_sig sig) { - sigp_ccode ccode; - - /* - * Set signaling bit in lowcore of target cpu and kick it - */ + /* + * Set signaling bit in lowcore of target cpu and kick it + */ set_bit(sig, &(get_cpu_lowcore(cpu)->ext_call_fast)); - ccode = signal_processor(cpu, sigp_external_call); - return ccode; + while (signal_processor(cpu, sigp_external_call) == sigp_busy) + udelay(10); } /* * Send an external call sigp to every other cpu in the system and - * return without waiting for its completion. + * wait for its completion. */ static void smp_ext_bitcall_others(ec_bit_sig sig) { - sigp_ccode ccode; - int i; + int i; - for (i = 0; i < smp_num_cpus; i++) { - if (smp_processor_id() == i) - continue; - /* - * Set signaling bit in lowcore of target cpu and kick it - */ + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() == i) + continue; + /* + * Set signaling bit in lowcore of target cpu and kick it + */ set_bit(sig, &(get_cpu_lowcore(i)->ext_call_fast)); - while (signal_processor(i, sigp_external_call) == sigp_busy) + while (signal_processor(i, sigp_external_call) == sigp_busy) udelay(10); - } + } } /* @@ -650,3 +693,4 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(smp_call_function); + diff -urN linux-2.4.27/arch/s390x/kernel/time.c linux-2.4.28/arch/s390x/kernel/time.c --- linux-2.4.27/arch/s390x/kernel/time.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/s390x/kernel/time.c 2004-11-17 03:54:21.101377459 -0800 @@ -37,10 +37,17 @@ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) +/* + * Create a small time difference between the timer interrupts + * on the different cpus to avoid lock contention. + */ +#define CPU_DEVIATION (smp_processor_id() << 12) + #define TICK_SIZE tick static ext_int_info_t ext_int_info_timer; -static uint64_t init_timer_cc; +static u64 init_timer_cc; +static u64 xtime_cc; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; @@ -56,7 +63,7 @@ { __u64 now; - asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); + asm volatile ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); now = (now - init_timer_cc) >> 12; /* We require the offset from the latest update of xtime */ now -= (__u64) wall_jiffies*USECS_PER_JIFFY; @@ -114,35 +121,58 @@ * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ - -#ifdef CONFIG_SMP -extern __u16 boot_cpu_addr; -#endif - -static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) +void account_ticks(struct pt_regs *regs) { int cpu = smp_processor_id(); + __u64 tmp; + __u32 ticks; + + /* Calculate how many ticks have passed. */ + tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; + if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than one tick ? */ + ticks = tmp / CLK_TICKS_PER_JIFFY + 1; + S390_lowcore.jiffy_timer += + CLK_TICKS_PER_JIFFY * (__u64) ticks; + } else if (tmp > CLK_TICKS_PER_JIFFY) { + ticks = 2; + S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY; + } else { + ticks = 1; + S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; + } + + /* set clock comparator for next tick */ + tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; + asm volatile ("SCKC %0" : : "m" (tmp)); irq_enter(cpu, 0); +#ifdef CONFIG_SMP /* - * set clock comparator for next tick + * Do not rely on the boot cpu to do the calls to do_timer. + * Spread it over all cpus instead. */ - S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); - -#ifdef CONFIG_SMP - if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) - write_lock(&xtime_lock); - - update_process_times(user_mode(regs)); - - if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) { - do_timer(regs); - write_unlock(&xtime_lock); + write_lock(&xtime_lock); + if (S390_lowcore.jiffy_timer > xtime_cc) { + __u32 xticks; + + tmp = S390_lowcore.jiffy_timer - xtime_cc; + if (tmp >= 2*CLK_TICKS_PER_JIFFY) { + xticks = tmp / CLK_TICKS_PER_JIFFY; + xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; + } else { + xticks = 1; + xtime_cc += CLK_TICKS_PER_JIFFY; + } + while (xticks--) + do_timer(regs); } + write_unlock(&xtime_lock); + while (ticks--) + update_process_times(user_mode(regs)); #else - do_timer(regs); + while (ticks--) + do_timer(regs); #endif irq_exit(cpu, 0); @@ -153,11 +183,13 @@ */ void init_cpu_timer(void) { - unsigned long cr0; + unsigned long cr0; + __u64 timer; - S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY; - S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); + timer = init_timer_cc + (__u64) jiffies * CLK_TICKS_PER_JIFFY; + S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; + timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; + asm volatile ("SCKC %0" : : "m" (timer)); /* allow clock comparator timer interrupt */ asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory"); cr0 |= 0x800; @@ -193,12 +225,13 @@ } /* set xtime */ + xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; set_time_cc = init_timer_cc - 0x8126d60e46000000LL + (0x3c26700LL*1000000*4096); tod_to_timeval(set_time_cc, &xtime); /* request the 0x1004 external interrupt */ - if (register_early_external_interrupt(0x1004, do_comparator_interrupt, + if (register_early_external_interrupt(0x1004, NULL, &ext_int_info_timer) != 0) panic("Couldn't request external interrupt 0x1004"); diff -urN linux-2.4.27/arch/sh/config.in linux-2.4.28/arch/sh/config.in --- linux-2.4.27/arch/sh/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/sh/config.in 2004-11-17 03:54:21.102377500 -0800 @@ -282,7 +282,7 @@ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF fi -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER diff -urN linux-2.4.27/arch/sh64/config.in linux-2.4.28/arch/sh64/config.in --- linux-2.4.27/arch/sh64/config.in 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sh64/config.in 2004-11-17 03:54:21.102377500 -0800 @@ -150,7 +150,7 @@ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF fi -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER diff -urN linux-2.4.27/arch/sh64/defconfig linux-2.4.28/arch/sh64/defconfig --- linux-2.4.27/arch/sh64/defconfig 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sh64/defconfig 2004-11-17 03:54:21.103377542 -0800 @@ -386,7 +386,7 @@ CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set +CONFIG_NFSD_TCP=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -urN linux-2.4.27/arch/sparc/config.in linux-2.4.28/arch/sparc/config.in --- linux-2.4.27/arch/sparc/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.28/arch/sparc/config.in 2004-11-17 03:54:21.103377542 -0800 @@ -73,7 +73,7 @@ define_bool CONFIG_KCORE_ELF y fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER diff -urN linux-2.4.27/arch/sparc/lib/copy_user.S linux-2.4.28/arch/sparc/lib/copy_user.S --- linux-2.4.27/arch/sparc/lib/copy_user.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/sparc/lib/copy_user.S 2004-11-17 03:54:21.104377583 -0800 @@ -65,52 +65,52 @@ /* Both these macros have to start with exactly the same insn */ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - st %t0, [%dst + offset + 0x00]; \ - st %t1, [%dst + offset + 0x04]; \ - st %t2, [%dst + offset + 0x08]; \ - st %t3, [%dst + offset + 0x0c]; \ - st %t4, [%dst + offset + 0x10]; \ - st %t5, [%dst + offset + 0x14]; \ - st %t6, [%dst + offset + 0x18]; \ - st %t7, [%dst + offset + 0x1c]; + ldd [%src + (offset) + 0x00], %t0; \ + ldd [%src + (offset) + 0x08], %t2; \ + ldd [%src + (offset) + 0x10], %t4; \ + ldd [%src + (offset) + 0x18], %t6; \ + st %t0, [%dst + (offset) + 0x00]; \ + st %t1, [%dst + (offset) + 0x04]; \ + st %t2, [%dst + (offset) + 0x08]; \ + st %t3, [%dst + (offset) + 0x0c]; \ + st %t4, [%dst + (offset) + 0x10]; \ + st %t5, [%dst + (offset) + 0x14]; \ + st %t6, [%dst + (offset) + 0x18]; \ + st %t7, [%dst + (offset) + 0x1c]; #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - std %t0, [%dst + offset + 0x00]; \ - std %t2, [%dst + offset + 0x08]; \ - std %t4, [%dst + offset + 0x10]; \ - std %t6, [%dst + offset + 0x18]; + ldd [%src + (offset) + 0x00], %t0; \ + ldd [%src + (offset) + 0x08], %t2; \ + ldd [%src + (offset) + 0x10], %t4; \ + ldd [%src + (offset) + 0x18], %t6; \ + std %t0, [%dst + (offset) + 0x00]; \ + std %t2, [%dst + (offset) + 0x08]; \ + std %t4, [%dst + (offset) + 0x10]; \ + std %t6, [%dst + (offset) + 0x18]; #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ldd [%src - offset - 0x10], %t0; \ - ldd [%src - offset - 0x08], %t2; \ - st %t0, [%dst - offset - 0x10]; \ - st %t1, [%dst - offset - 0x0c]; \ - st %t2, [%dst - offset - 0x08]; \ - st %t3, [%dst - offset - 0x04]; + ldd [%src - (offset) - 0x10], %t0; \ + ldd [%src - (offset) - 0x08], %t2; \ + st %t0, [%dst - (offset) - 0x10]; \ + st %t1, [%dst - (offset) - 0x0c]; \ + st %t2, [%dst - (offset) - 0x08]; \ + st %t3, [%dst - (offset) - 0x04]; #define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduh [%src + offset + 0x00], %t0; \ - lduh [%src + offset + 0x02], %t1; \ - lduh [%src + offset + 0x04], %t2; \ - lduh [%src + offset + 0x06], %t3; \ - sth %t0, [%dst + offset + 0x00]; \ - sth %t1, [%dst + offset + 0x02]; \ - sth %t2, [%dst + offset + 0x04]; \ - sth %t3, [%dst + offset + 0x06]; + lduh [%src + (offset) + 0x00], %t0; \ + lduh [%src + (offset) + 0x02], %t1; \ + lduh [%src + (offset) + 0x04], %t2; \ + lduh [%src + (offset) + 0x06], %t3; \ + sth %t0, [%dst + (offset) + 0x00]; \ + sth %t1, [%dst + (offset) + 0x02]; \ + sth %t2, [%dst + (offset) + 0x04]; \ + sth %t3, [%dst + (offset) + 0x06]; #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ - ldub [%src - offset - 0x02], %t0; \ - ldub [%src - offset - 0x01], %t1; \ - stb %t0, [%dst - offset - 0x02]; \ - stb %t1, [%dst - offset - 0x01]; + ldub [%src - (offset) - 0x02], %t0; \ + ldub [%src - (offset) - 0x01], %t1; \ + stb %t0, [%dst - (offset) - 0x02]; \ + stb %t1, [%dst - (offset) - 0x01]; .text .align 4 diff -urN linux-2.4.27/arch/sparc64/config.in linux-2.4.28/arch/sparc64/config.in --- linux-2.4.27/arch/sparc64/config.in 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/config.in 2004-11-17 03:54:21.105377624 -0800 @@ -78,7 +78,7 @@ tristate ' Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32 bool ' Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32 fi -tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -urN linux-2.4.27/arch/sparc64/defconfig linux-2.4.28/arch/sparc64/defconfig --- linux-2.4.27/arch/sparc64/defconfig 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/defconfig 2004-11-17 03:54:21.106377665 -0800 @@ -375,7 +375,7 @@ CONFIG_NET_SCH_TEQL=m CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_NETEM=m CONFIG_NET_SCH_DSMARK=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_QOS=y @@ -410,6 +410,7 @@ # # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_IDEDISK_STROKE is not set @@ -1134,6 +1135,8 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m diff -urN linux-2.4.27/arch/sparc64/kernel/head.S linux-2.4.28/arch/sparc64/kernel/head.S --- linux-2.4.27/arch/sparc64/kernel/head.S 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/head.S 2004-11-17 03:54:21.106377665 -0800 @@ -50,7 +50,7 @@ */ .global root_flags, ram_flags, root_dev .global sparc_ramdisk_image, sparc_ramdisk_size - .globl silo_args + .global sparc_ramdisk_image64 .ascii "HdrS" .word LINUX_VERSION_CODE @@ -61,7 +61,7 @@ * 0x0202 : Supports kernel params string * 0x0201 : Supports reboot_command */ - .half 0x0300 /* HdrS version */ + .half 0x0301 /* HdrS version */ root_flags: .half 1 @@ -75,6 +75,8 @@ .word 0 .xword reboot_command .xword bootstr_info +sparc_ramdisk_image64: + .xword 0 .word _end /* We must be careful, 32-bit OpenBOOT will get confused if it diff -urN linux-2.4.27/arch/sparc64/kernel/ioctl32.c linux-2.4.28/arch/sparc64/kernel/ioctl32.c --- linux-2.4.27/arch/sparc64/kernel/ioctl32.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/ioctl32.c 2004-11-17 03:54:21.110377829 -0800 @@ -2948,7 +2948,7 @@ case LV_REMOVE: case LV_RENAME: case LV_STATUS_BYNAME: - err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); + err = copy_from_user(&u.lv_req, arg, sizeof(u.lv_req.lv_name)); if (err) return -EFAULT; if (cmd != LV_REMOVE) { @@ -2991,7 +2991,7 @@ case PV_CHANGE: case PV_STATUS: - err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name)); + err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); if (err) return -EFAULT; err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv); @@ -3063,7 +3063,7 @@ if (u.lv_bydev.lv) { if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv); - put_lv_t(u.lv_byindex.lv); + put_lv_t(u.lv_bydev.lv); } break; diff -urN linux-2.4.27/arch/sparc64/kernel/itlb_base.S linux-2.4.28/arch/sparc64/kernel/itlb_base.S --- linux-2.4.27/arch/sparc64/kernel/itlb_base.S 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/itlb_base.S 2004-11-17 03:54:21.111377870 -0800 @@ -41,6 +41,9 @@ CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE 1: brgez,pn %g5, 3f ! Not valid, branch out + sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot + andcc %g5, %g4, %g0 ! Executable? + be,pn %xcc, 3f ! Nope, branch. nop ! Delay-slot 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB retry ! Trap return @@ -73,9 +76,6 @@ nop nop nop - nop - nop - nop CREATE_VPTE_NOP #undef CREATE_VPTE_OFFSET1 diff -urN linux-2.4.27/arch/sparc64/kernel/pci_iommu.c linux-2.4.28/arch/sparc64/kernel/pci_iommu.c --- linux-2.4.27/arch/sparc64/kernel/pci_iommu.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/pci_iommu.c 2004-11-17 03:54:21.124378405 -0800 @@ -56,6 +56,39 @@ } } +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) + +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) + +/* Existing mappings are never marked invalid, instead they + * are pointed to a dummy page. + */ +#define IOPTE_IS_DUMMY(iommu, iopte) \ + ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) + +static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) +{ + unsigned long val = iopte_val(*iopte); + + val &= ~IOPTE_PAGE; + val |= iommu->dummy_page_pa; + + iopte_val(*iopte) = val; +} + +void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize) +{ + int i; + + tsbsize /= sizeof(iopte_t); + + for (i = 0; i < tsbsize; i++) + iopte_make_dummy(iommu, &iommu->page_table[i]); +} + static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) { iopte_t *iopte, *limit, *first; @@ -79,7 +112,7 @@ first = iopte; for (;;) { - if (iopte_val(*iopte) == 0UL) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { if ((iopte + (1 << cnum)) >= limit) ent = 0; else @@ -142,12 +175,12 @@ iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); while (iopte > iommu->page_table) { iopte--; - if (!(iopte_val(*iopte) & IOPTE_VALID)) { + if (IOPTE_IS_DUMMY(iommu, iopte)) { unsigned long tmp = npages; while (--tmp) { iopte--; - if (iopte_val(*iopte) & IOPTE_VALID) + if (!IOPTE_IS_DUMMY(iommu, iopte)) break; } if (tmp == 0) { @@ -162,15 +195,6 @@ return NULL; } -#define IOPTE_CONSISTENT(CTX) \ - (IOPTE_VALID | IOPTE_CACHE | \ - (((CTX) << 47) & IOPTE_CONTEXT)) - -#define IOPTE_STREAMING(CTX) \ - (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) - -#define IOPTE_INVALID 0UL - /* Allocate and map kernel buffer of size SIZE using consistent mode * DMA for PCI device PDEV. Return non-NULL cpu-side address if * successful and set *DMA_ADDRP to the PCI side dma address. @@ -261,7 +285,7 @@ limit = (iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); while (walk < limit) { - if (iopte_val(*walk) != IOPTE_INVALID) + if (!IOPTE_IS_DUMMY(iommu, walk)) break; walk++; } @@ -280,7 +304,7 @@ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; for (i = 0; i < npages; i++, iopte++) - iopte_val(*iopte) = IOPTE_INVALID; + iopte_make_dummy(iommu, iopte); if (iommu->iommu_ctxflush) { pci_iommu_write(iommu->iommu_ctxflush, ctx); @@ -377,7 +401,7 @@ base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0)); #endif @@ -416,7 +440,7 @@ } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); @@ -617,7 +641,7 @@ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU - if (iopte_val(*base) == IOPTE_INVALID) + if (IOPTE_IS_DUMMY(iommu, base)) printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0)); #endif @@ -654,7 +678,7 @@ } /* Step 2: Clear out first TSB entry. */ - iopte_val(*base) = IOPTE_INVALID; + iopte_make_dummy(iommu, base); free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); diff -urN linux-2.4.27/arch/sparc64/kernel/pci_psycho.c linux-2.4.28/arch/sparc64/kernel/pci_psycho.c --- linux-2.4.27/arch/sparc64/kernel/pci_psycho.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/pci_psycho.c 2004-11-17 03:54:21.126378487 -0800 @@ -1106,17 +1106,17 @@ * bits for each PBM. */ tmp = psycho_read(base + PSYCHO_PCIA_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIA_CTRL, tmp); tmp = psycho_read(base + PSYCHO_PCIB_CTRL); - tmp |= (PSYCHO_PCICTRL_SBH_ERR | - PSYCHO_PCICTRL_SERR | - PSYCHO_PCICTRL_SBH_INT | + tmp |= (PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); + tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIB_CTRL, tmp); } @@ -1373,6 +1373,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1386,7 +1394,7 @@ iommu->page_table_sz_bits = 17; iommu->page_table_map_base = 0xc0000000; iommu->dma_addr_mask = 0xffffffff; - memset((char *)tsbbase, 0, IO_TSB_SIZE); + pci_iommu_table_init(iommu, IO_TSB_SIZE); /* We start with no consistent mappings. */ iommu->lowest_consistent_map = diff -urN linux-2.4.27/arch/sparc64/kernel/pci_sabre.c linux-2.4.28/arch/sparc64/kernel/pci_sabre.c --- linux-2.4.27/arch/sparc64/kernel/pci_sabre.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/pci_sabre.c 2004-11-17 03:54:21.128378569 -0800 @@ -1315,6 +1315,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); @@ -1323,7 +1331,7 @@ iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = dvma_offset; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); diff -urN linux-2.4.27/arch/sparc64/kernel/pci_schizo.c linux-2.4.28/arch/sparc64/kernel/pci_schizo.c --- linux-2.4.27/arch/sparc64/kernel/pci_schizo.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/pci_schizo.c 2004-11-17 03:54:21.130378652 -0800 @@ -1423,10 +1423,10 @@ SCHIZO_PCICTRL_RTRY_ERR | SCHIZO_PCICTRL_SBH_ERR | SCHIZO_PCICTRL_SERR | - SCHIZO_PCICTRL_SBH_INT | SCHIZO_PCICTRL_EEN); - err_no_mask = SCHIZO_PCICTRL_DTO_ERR; + err_no_mask = (SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SBH_INT); /* Enable PCI Error interrupts and clear error * bits for each PBM. @@ -1843,6 +1843,14 @@ * in pci_iommu.c */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); + prom_halt(); + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. @@ -1857,7 +1865,7 @@ iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = vdma[0]; iommu->dma_addr_mask = dma_mask; - memset((char *)tsbbase, 0, PAGE_SIZE << order); + pci_iommu_table_init(iommu, PAGE_SIZE << order); switch (tsbsize) { case 64: diff -urN linux-2.4.27/arch/sparc64/kernel/process.c linux-2.4.28/arch/sparc64/kernel/process.c --- linux-2.4.27/arch/sparc64/kernel/process.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/process.c 2004-11-17 03:54:21.131378693 -0800 @@ -503,7 +503,7 @@ distance = fp - psp; rval = (csp - distance); - if (copy_in_user(rval, psp, distance)) + if (copy_in_user((void *)rval, (void *)psp, distance)) rval = 0; else if (current->thread.flags & SPARC_FLAG_32BIT) { if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) diff -urN linux-2.4.27/arch/sparc64/kernel/sbus.c linux-2.4.28/arch/sparc64/kernel/sbus.c --- linux-2.4.27/arch/sparc64/kernel/sbus.c 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/sbus.c 2004-11-17 03:54:21.132378734 -0800 @@ -27,10 +27,10 @@ * * On SYSIO, using an 8K page size we have 1GB of SBUS * DMA space mapped. We divide this space into equally - * sized clusters. Currently we allow clusters up to a - * size of 1MB. If anything begins to generate DMA - * mapping requests larger than this we will need to - * increase things a bit. + * sized clusters. We allocate a DMA mapping from the + * cluster that matches the order of the allocation, or + * if the order is greater than the number of clusters, + * we try to allocate from the last cluster. */ #define NCLUSTERS 8UL @@ -133,12 +133,17 @@ static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) { - iopte_t *iopte, *limit, *first; - unsigned long cnum, ent, flush_point; + iopte_t *iopte, *limit, *first, *cluster; + unsigned long cnum, ent, nent, flush_point, found; cnum = 0; + nent = 1; while ((1UL << cnum) < npages) cnum++; + if(cnum >= NCLUSTERS) { + nent = 1UL << (cnum - NCLUSTERS); + cnum = NCLUSTERS - 1; + } iopte = iommu->page_table + (cnum * CLUSTER_NPAGES); if (cnum == 0) @@ -151,22 +156,31 @@ flush_point = iommu->alloc_info[cnum].flush; first = iopte; + cluster = NULL; + found = 0; for (;;) { if (iopte_val(*iopte) == 0UL) { - if ((iopte + (1 << cnum)) >= limit) - ent = 0; - else - ent = ent + 1; - iommu->alloc_info[cnum].next = ent; - if (ent == flush_point) - __iommu_flushall(iommu); - break; + found++; + if (!cluster) + cluster = iopte; + } else { + /* Used cluster in the way */ + cluster = NULL; + found = 0; } + + if (found == nent) + break; + iopte += (1 << cnum); ent++; if (iopte >= limit) { iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES)); ent = 0; + + /* Multiple cluster allocations must not wrap */ + cluster = NULL; + found = 0; } if (ent == flush_point) __iommu_flushall(iommu); @@ -174,8 +188,19 @@ goto bad; } + /* ent/iopte points to the last cluster entry we're going to use, + * so save our place for the next allocation. + */ + if ((iopte + (1 << cnum)) >= limit) + ent = 0; + else + ent = ent + 1; + iommu->alloc_info[cnum].next = ent; + if (ent == flush_point) + __iommu_flushall(iommu); + /* I've got your streaming cluster right here buddy boy... */ - return iopte; + return cluster; bad: printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n", @@ -185,15 +210,23 @@ static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages) { - unsigned long cnum, ent; + unsigned long cnum, ent, nent; iopte_t *iopte; cnum = 0; + nent = 1; while ((1UL << cnum) < npages) cnum++; + if(cnum >= NCLUSTERS) { + nent = 1UL << (cnum - NCLUSTERS); + cnum = NCLUSTERS - 1; + } ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum); iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT); - iopte_val(*iopte) = 0UL; + do { + iopte_val(*iopte) = 0UL; + iopte += 1 << cnum; + } while(--nent); /* If the global flush might not have caught this entry, * adjust the flush point such that we will flush before diff -urN linux-2.4.27/arch/sparc64/kernel/signal.c linux-2.4.28/arch/sparc64/kernel/signal.c --- linux-2.4.27/arch/sparc64/kernel/signal.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/signal.c 2004-11-17 03:54:21.133378775 -0800 @@ -116,8 +116,8 @@ regs->tnpc = npc; err |= __get_user(regs->y, &((*grp)[MC_Y])); err |= __get_user(tstate, &((*grp)[MC_TSTATE])); - regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); + regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC); + regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); @@ -437,9 +437,9 @@ err |= __get_user(tstate, &sf->regs.tstate); err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs)); - /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); + /* User can only change condition codes and %asi in %tstate. */ + regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC); + regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) diff -urN linux-2.4.27/arch/sparc64/kernel/signal32.c linux-2.4.28/arch/sparc64/kernel/signal32.c --- linux-2.4.27/arch/sparc64/kernel/signal32.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/signal32.c 2004-11-17 03:54:21.134378816 -0800 @@ -62,6 +62,16 @@ unsigned extramask[_NSIG_WORDS32 - 1]; }; +/* This magic should be in g_upper[0] for all upper parts + * to be valid. + */ +#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 +typedef struct { + unsigned int g_upper[8]; + unsigned int o_upper[8]; + unsigned int asi; +} siginfo_extra_v8plus_t; + /* * And the new one, intended to be used for Linux applications only * (we have enough in there to work with clone). @@ -292,8 +302,13 @@ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { err |= __get_user(i, &sf->v8plus.g_upper[0]); if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + unsigned long asi; + for (i = UREG_G1; i <= UREG_I7; i++) err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __get_user(asi, &sf->v8plus.asi); + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= ((asi & 0xffUL) << 24UL); } } @@ -431,8 +446,13 @@ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { err |= __get_user(i, &sf->v8plus.g_upper[0]); if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + unsigned long asi; + for (i = UREG_G1; i <= UREG_I7; i++) err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __get_user(asi, &sf->v8plus.asi); + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= ((asi & 0xffUL) << 24UL); } } @@ -728,7 +748,10 @@ err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); for (i = 1; i < 16; i++) - err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __put_user(((u32 *)regs->u_regs)[2*i], + &sf->v8plus.g_upper[i]); + err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL, + &sf->v8plus.asi); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); @@ -1175,7 +1198,10 @@ err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); for (i = 1; i < 16; i++) - err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + err |= __put_user(((u32 *)regs->u_regs)[2*i], + &sf->v8plus.g_upper[i]); + err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL, + &sf->v8plus.asi); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); diff -urN linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.28/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/sparc64_ksyms.c 2004-11-17 03:54:21.135378857 -0800 @@ -324,8 +324,6 @@ #endif /* Special internal versions of library functions. */ -EXPORT_SYMBOL(__memcpy); -EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(copy_user_page); @@ -334,14 +332,17 @@ EXPORT_SYMBOL(__memscan_generic); EXPORT_SYMBOL(__memcmp); EXPORT_SYMBOL(__strncmp); -EXPORT_SYMBOL(__memmove); +EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(csum_partial_copy_sparc64); /* Moving data to/from userspace. */ -EXPORT_SYMBOL(__copy_to_user); -EXPORT_SYMBOL(__copy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(___copy_to_user); +EXPORT_SYMBOL(___copy_from_user); +EXPORT_SYMBOL(___copy_in_user); +EXPORT_SYMBOL(copy_to_user_fixup); +EXPORT_SYMBOL(copy_from_user_fixup); +EXPORT_SYMBOL(copy_in_user_fixup); EXPORT_SYMBOL(__bzero_noasi); /* Various address conversion macros use this. */ diff -urN linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c linux-2.4.28/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/kernel/sys_sparc32.c 2004-11-17 03:54:21.138378981 -0800 @@ -2996,10 +2996,11 @@ if (optname == IPT_SO_SET_REPLACE) return do_netfilter_replace(fd, level, optname, optval, optlen); - if (optname == SO_ATTACH_FILTER) + if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); - if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) + if (level == SOL_SOCKET && + (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) return do_set_sock_timeout(fd, level, optname, optval, optlen); return sys_setsockopt(fd, level, optname, optval, optlen); diff -urN linux-2.4.27/arch/sparc64/kernel/time.c linux-2.4.28/arch/sparc64/kernel/time.c --- linux-2.4.27/arch/sparc64/kernel/time.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/sparc64/kernel/time.c 2004-11-17 03:54:21.139379022 -0800 @@ -432,18 +432,12 @@ extern int _stext; extern int rwlock_impl_begin, rwlock_impl_end; extern int atomic_impl_begin, atomic_impl_end; - extern int __memcpy_begin, __memcpy_end; - extern int __bzero_begin, __bzero_end; extern int __bitops_begin, __bitops_end; if ((pc >= (unsigned long) &atomic_impl_begin && pc < (unsigned long) &atomic_impl_end) || (pc >= (unsigned long) &rwlock_impl_begin && pc < (unsigned long) &rwlock_impl_end) || - (pc >= (unsigned long) &__memcpy_begin && - pc < (unsigned long) &__memcpy_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || (pc >= (unsigned long) &__bitops_begin && pc < (unsigned long) &__bitops_end)) pc = o7; diff -urN linux-2.4.27/arch/sparc64/lib/Makefile linux-2.4.28/arch/sparc64/lib/Makefile --- linux-2.4.27/arch/sparc64/lib/Makefile 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.28/arch/sparc64/lib/Makefile 2004-11-17 03:54:21.139379022 -0800 @@ -8,9 +8,11 @@ L_TARGET = lib.a obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ + VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ - dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o + U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ + U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ + copy_in_user.o user_fixup.o memmove.o \ + dec_and_lock.o mcount.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.27/arch/sparc64/lib/U1copy_from_user.S linux-2.4.28/arch/sparc64/lib/U1copy_from_user.S --- linux-2.4.27/arch/sparc64/lib/U1copy_from_user.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U1copy_from_user.S 2004-11-17 03:54:21.140379063 -0800 @@ -0,0 +1,33 @@ +/* U1copy_from_user.S: UltraSparc-I/II/IIi/IIe optimized copy from userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_AIUS, dest +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff -urN linux-2.4.27/arch/sparc64/lib/U1copy_to_user.S linux-2.4.28/arch/sparc64/lib/U1copy_to_user.S --- linux-2.4.27/arch/sparc64/lib/U1copy_to_user.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U1copy_to_user.S 2004-11-17 03:54:21.141379104 -0800 @@ -0,0 +1,33 @@ +/* U1copy_to_user.S: UltraSparc-I/II/IIi/IIe optimized copy to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME ___copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 + + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ + +#include "U1memcpy.S" diff -urN linux-2.4.27/arch/sparc64/lib/U1memcpy.S linux-2.4.28/arch/sparc64/lib/U1memcpy.S --- linux-2.4.27/arch/sparc64/lib/U1memcpy.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U1memcpy.S 2004-11-17 03:54:21.142379145 -0800 @@ -0,0 +1,552 @@ +/* U1memcpy.S: UltraSPARC-I/II/IIi/IIe optimized memcpy. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#ifdef __KERNEL__ +#include +#include +#else +#define ASI_BLK_P 0xf0 +#define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else +#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs +#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef LOAD_BLK +#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_P, dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif + +#ifndef XCC +#define XCC xcc +#endif + +#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + faligndata %f1, %f2, %f48; \ + faligndata %f2, %f3, %f50; \ + faligndata %f3, %f4, %f52; \ + faligndata %f4, %f5, %f54; \ + faligndata %f5, %f6, %f56; \ + faligndata %f6, %f7, %f58; \ + faligndata %f7, %f8, %f60; \ + faligndata %f8, %f9, %f62; + +#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ + EX_LD(LOAD_BLK(%src, %fdest)); \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %src, 0x40, %src; \ + subcc %len, 0x40, %len; \ + be,pn %xcc, jmptgt; \ + add %dest, 0x40, %dest; \ + +#define LOOP_CHUNK1(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f0, f48, len, branch_dest) +#define LOOP_CHUNK2(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest) +#define LOOP_CHUNK3(src, dest, len, branch_dest) \ + MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest) + +#define STORE_SYNC(dest, fsrc) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; + +#define STORE_JUMP(dest, fsrc, target) \ + EX_ST(STORE_BLK(%fsrc, %dest)); \ + add %dest, 0x40, %dest; \ + ba,pt %xcc, target; + +#define FINISH_VISCHUNK(dest, f0, f1, left) \ + subcc %left, 8, %left;\ + bl,pn %xcc, 95f; \ + faligndata %f0, %f1, %f48; \ + EX_ST(STORE(std, %f48, %dest)); \ + add %dest, 8, %dest; + +#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + subcc %left, 8, %left; \ + bl,pn %xcc, 95f; \ + fsrc1 %f0, %f1; + +#define UNEVEN_VISCHUNK(dest, f0, f1, left) \ + UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ + ba,a,pt %xcc, 93f; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 64 + + .globl FUNC_NAME +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE + mov %o0, %g5 + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + blu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + cmp %o2, (5 * 64) + blu,pt %XCC, 70f + andcc %o3, 0x7, %g0 + + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. */ + VISEntry + + /* Is 'dst' already aligned on an 64-byte boundary? */ + andcc %o0, 0x3f, %g2 + be,pt %XCC, 2f + + /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number + * of bytes to copy to make 'dst' 64-byte aligned. We pre- + * subtract this from 'len'. + */ + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 + +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 + + add %o1, %o4, %o0 + +2: cmp %g2, 0x0 + and %o1, 0x7, %g1 + be,pt %icc, 3f + alignaddr %o1, %g0, %o1 + + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f0 + EX_ST(STORE(std, %f0, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + + /* Destination is 64-byte aligned. */ +3: + membar #LoadStore | #StoreStore | #StoreLoad + + subcc %o2, 0x40, %o4 + add %o1, %g1, %g1 + andncc %o4, (0x40 - 1), %o4 + srl %g1, 3, %g2 + sub %o2, %o4, %g3 + andn %o1, (0x40 - 1), %o1 + and %g2, 7, %g2 + andncc %g3, 0x7, %g3 + fmovd %f0, %f2 + sub %g3, 0x8, %g3 + sub %o2, %o4, %o2 + + add %g1, %o4, %g1 + subcc %o2, %g3, %o2 + + EX_LD(LOAD_BLK(%o1, %f0)) + add %o1, 0x40, %o1 + add %g1, %g3, %g1 + EX_LD(LOAD_BLK(%o1, %f16)) + add %o1, 0x40, %o1 + sub %o4, 0x80, %o4 + EX_LD(LOAD_BLK(%o1, %f32)) + add %o1, 0x40, %o1 + + /* There are 8 instances of the unrolled loop, + * one for each possible alignment of the + * source buffer. Each loop instance is 452 + * bytes. + */ + sll %g2, 3, %o3 + sub %o3, %g2, %o3 + sllx %o3, 4, %o3 + add %o3, %g2, %o3 + sllx %o3, 2, %g2 +1: rd %pc, %o3 + add %o3, %lo(1f - 1b), %o3 + jmpl %o3 + %g2, %g0 + nop + + .align 64 +1: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f0, %f2, %f48 +1: FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_JUMP(o0, f48, 40f) membar #Sync +2: FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_JUMP(o0, f48, 48f) membar #Sync +3: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) + STORE_JUMP(o0, f48, 56f) membar #Sync + +1: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f2, %f4, %f48 +1: FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_JUMP(o0, f48, 41f) membar #Sync +2: FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_JUMP(o0, f48, 49f) membar #Sync +3: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) + STORE_JUMP(o0, f48, 57f) membar #Sync + +1: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f4, %f6, %f48 +1: FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_JUMP(o0, f48, 42f) membar #Sync +2: FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_JUMP(o0, f48, 50f) membar #Sync +3: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) + STORE_JUMP(o0, f48, 58f) membar #Sync + +1: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f6, %f8, %f48 +1: FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_JUMP(o0, f48, 43f) membar #Sync +2: FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_JUMP(o0, f48, 51f) membar #Sync +3: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) + STORE_JUMP(o0, f48, 59f) membar #Sync + +1: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f8, %f10, %f48 +1: FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_JUMP(o0, f48, 44f) membar #Sync +2: FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_JUMP(o0, f48, 52f) membar #Sync +3: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) + STORE_JUMP(o0, f48, 60f) membar #Sync + +1: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f10, %f12, %f48 +1: FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_JUMP(o0, f48, 45f) membar #Sync +2: FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_JUMP(o0, f48, 53f) membar #Sync +3: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) + STORE_JUMP(o0, f48, 61f) membar #Sync + +1: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f12, %f14, %f48 +1: FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_JUMP(o0, f48, 46f) membar #Sync +2: FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_JUMP(o0, f48, 54f) membar #Sync +3: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) + STORE_JUMP(o0, f48, 62f) membar #Sync + +1: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + LOOP_CHUNK1(o1, o0, o4, 1f) + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + LOOP_CHUNK2(o1, o0, o4, 2f) + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + LOOP_CHUNK3(o1, o0, o4, 3f) + ba,pt %xcc, 1b+4 + faligndata %f14, %f16, %f48 +1: FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_JUMP(o0, f48, 47f) membar #Sync +2: FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_JUMP(o0, f48, 55f) membar #Sync +3: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) + STORE_SYNC(o0, f48) membar #Sync + FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) + STORE_JUMP(o0, f48, 63f) membar #Sync + +40: FINISH_VISCHUNK(o0, f0, f2, g3) +41: FINISH_VISCHUNK(o0, f2, f4, g3) +42: FINISH_VISCHUNK(o0, f4, f6, g3) +43: FINISH_VISCHUNK(o0, f6, f8, g3) +44: FINISH_VISCHUNK(o0, f8, f10, g3) +45: FINISH_VISCHUNK(o0, f10, f12, g3) +46: FINISH_VISCHUNK(o0, f12, f14, g3) +47: UNEVEN_VISCHUNK(o0, f14, f0, g3) +48: FINISH_VISCHUNK(o0, f16, f18, g3) +49: FINISH_VISCHUNK(o0, f18, f20, g3) +50: FINISH_VISCHUNK(o0, f20, f22, g3) +51: FINISH_VISCHUNK(o0, f22, f24, g3) +52: FINISH_VISCHUNK(o0, f24, f26, g3) +53: FINISH_VISCHUNK(o0, f26, f28, g3) +54: FINISH_VISCHUNK(o0, f28, f30, g3) +55: UNEVEN_VISCHUNK(o0, f30, f0, g3) +56: FINISH_VISCHUNK(o0, f32, f34, g3) +57: FINISH_VISCHUNK(o0, f34, f36, g3) +58: FINISH_VISCHUNK(o0, f36, f38, g3) +59: FINISH_VISCHUNK(o0, f38, f40, g3) +60: FINISH_VISCHUNK(o0, f40, f42, g3) +61: FINISH_VISCHUNK(o0, f42, f44, g3) +62: FINISH_VISCHUNK(o0, f44, f46, g3) +63: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3) + +93: EX_LD(LOAD(ldd, %o1, %f2)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f0, %f2, %f8 + EX_ST(STORE(std, %f8, %o0)) + bl,pn %xcc, 95f + add %o0, 8, %o0 + EX_LD(LOAD(ldd, %o1, %f0)) + add %o1, 8, %o1 + subcc %g3, 8, %g3 + faligndata %f2, %f0, %f8 + EX_ST(STORE(std, %f8, %o0)) + bge,pt %xcc, 93b + add %o0, 8, %o0 + +95: brz,pt %o2, 2f + mov %g1, %o1 + +1: EX_LD(LOAD(ldub, %o1, %o3)) + add %o1, 1, %o1 + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %o3, %o0)) + bne,pt %xcc, 1b + add %o0, 1, %o0 + +2: membar #StoreLoad | #StoreStore + VISExit + retl + mov EX_RETVAL(%g5), %o0 + + .align 64 +70: /* 16 < len <= (5 * 64) */ + bne,pn %XCC, 75f + sub %o0, %o1, %o3 + +72: andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + subcc %o4, 0x10, %o4 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(ldx, %o1, %o5)) + sub %o2, 0x8, %o2 + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + EX_LD(LOAD(lduw, %o1, %o5)) + sub %o2, 0x4, %o2 + EX_ST(STORE(stw, %o5, %o1 + %o3)) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +75: andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: EX_LD(LOAD(ldub, %o1, %o5)) + subcc %g1, 1, %g1 + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 + + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b + +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 + add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) + add %o0, 0x8, %o0 + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 + + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +1: EX_LD(LOAD(lduw, %o1, %g1)) + subcc %o2, 4, %o2 + EX_ST(STORE(stw, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 4, %o1 + +85: retl + mov EX_RETVAL(%g5), %o0 + + .align 32 +90: EX_LD(LOAD(ldub, %o1, %g1)) + subcc %o2, 1, %o2 + EX_ST(STORE(stb, %g1, %o1 + %o3)) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + mov EX_RETVAL(%g5), %o0 diff -urN linux-2.4.27/arch/sparc64/lib/U3copy_from_user.S linux-2.4.28/arch/sparc64/lib/U3copy_from_user.S --- linux-2.4.27/arch/sparc64/lib/U3copy_from_user.S 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U3copy_from_user.S 2004-11-17 03:54:21.143379186 -0800 @@ -1,519 +1,22 @@ -/* $Id: U3copy_from_user.S,v 1.3.2.1 2002/01/15 07:17:47 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy from userspace. +/* U3copy_from_user.S: UltraSparc-III optimized copy from userspace. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#ifdef __KERNEL__ -#include -#include -#include -#include -#undef SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - ba U3cfu_fixup; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, %o4, %o1; \ - ba U3cfu_fixup; \ - add %o1, 0x1c0, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - sll %g3, 6, %g3; \ - add %o1, 0x80, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o1; \ - add %o1, 0x40, %o1; \ - ba U3cfu_fixup; \ - add %o1, %g3, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#else -#define ASI_BLK_P 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EX2(x,y) x,y; -#define EX3(x,y) x,y; -#define EX4(x,y) x,y; -#endif - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ - - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_from_user -U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */ -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_from_user_short_ret! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_from_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_from_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_from_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_from_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_from_user_short ! BR - stb %o3, [%o0 + -1] ! MS Group (1-cycle stall) - -U3copy_from_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif - - /* Here len >= (6 * 64) and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -U3copy_from_user_enter: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_from_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) - - .align 64 -U3copy_from_user_begin: -#ifdef __KERNEL__ - .globl U3copy_from_user_nop_1_6 -U3copy_from_user_nop_1_6: - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - sethi %uhi(DCU_PE), %o3 - sllx %o3, 32, %o3 - or %g3, %o3, %o3 - stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache - membar #Sync -#endif - prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1 - prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4 - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6 -1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7 -1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_from_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_from_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_from_user_loop1: - EX2(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - EX2(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - stda %f16, [%o0] ASI_BLK_P ! MS - EX2(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - EX2(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - EX2(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - EX2(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - EX2(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - EX2(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19) - prefetcha [%o1 + 0x180] %asi, #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_from_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_from_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_from_user_loop2: - EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - stda %f16, [%o0] ASI_BLK_P ! MS - EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - EX3(ldda [%o1 + 0x040] %asi, %f0) ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_from_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - - /* Finally we copy the last full 64-byte block. */ -U3copy_from_user_loopfini: - EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA - EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - stda %f16, [%o0] ASI_BLK_P ! MS Group20 - EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - EX4(ldda [%o1 + 0x040] %asi, %f0) ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - stda %f16, [%o0] ASI_BLK_P ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 -#ifdef __KERNEL__ - .globl U3copy_from_user_nop_2_3 -U3copy_from_user_nop_2_3: - mov PRIMARY_CONTEXT, %o3 - stxa %g0, [%o3] ASI_DMMU ! Flush P-cache - stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache -#endif - membar #Sync ! MS Group26 (7-cycle stall) - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_from_user_toosmall processing. - */ -U3copy_from_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_from_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_from_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_from_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -U3copy_from_user_endcruft: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %icc, U3copy_from_user_short_ret - nop - ba,a,pt %xcc, U3copy_from_user_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_from_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_from_user_short_ret! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_from_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_from_user_short - andcc %o1, 0x7, %g2 - - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - stb %o3, [%o0 + -1] - -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 - -3: EXNV(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - stx %o3, [%o0 + -8] - - cmp %o2, 0 - bne,pn %icc, U3copy_from_user_short - nop - ba,a,pt %xcc, U3copy_from_user_short_ret - -#endif /* !(SMALL_COPY_USES_FPU) */ - -#ifdef __KERNEL__ - .globl U3cfu_fixup -U3cfu_fixup: - /* Since this is copy_from_user(), zero out the rest of the - * kernel buffer. - */ - cmp %o1, 0 - ble,pn %icc, 2f - mov %o1, %g2 -1: subcc %g2, 1, %g2 - stb %g0, [%o0] - bne,pt %icc, 1b - add %o0, 1, %o0 +#define FUNC_NAME U3copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest +#define EX_RETVAL(x) 0 -2: retl - mov %o1, %o0 -#endif +#include "U3memcpy.S" diff -urN linux-2.4.27/arch/sparc64/lib/U3copy_in_user.S linux-2.4.28/arch/sparc64/lib/U3copy_in_user.S --- linux-2.4.27/arch/sparc64/lib/U3copy_in_user.S 2001-03-25 18:14:21.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U3copy_in_user.S 1969-12-31 16:00:00.000000000 -0800 @@ -1,531 +0,0 @@ -/* $Id: U3copy_in_user.S,v 1.4 2001/03/21 05:58:47 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy within userspace. - * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) - */ - -#ifdef __KERNEL__ -#include -#include -#undef SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV2(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 1, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV3(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK1(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - add %o4, 0x1c0, %o1; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - sll %o3, 6, %o3; \ - and %o2, (0x40 - 1), %o2; \ - add %o3, 0x80, %o1; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x80, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x40, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#else -#define ASI_AIUS 0x80 -#define ASI_BLK_AIUS 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EXNV2(x,y,a,b) x,y; -#define EXNV3(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EXBLK1(x,y) x,y; -#define EXBLK2(x,y) x,y; -#define EXBLK3(x,y) x,y; -#define EXBLK4(x,y) x,y; -#endif - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - * - * XXX Actually, Cheetah can buffer up to 8 concurrent - * XXX prefetches, revisit this... - */ - - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_in_user -U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */ - /* Writing to %asi is _expensive_ so we hardcode it. - * Reading %asi to check for KERNEL_DS is comparatively - * cheap. - */ - rd %asi, %g1 ! MS Group (4 cycles) - cmp %g1, ASI_AIUS ! A0 Group - bne U3memcpy ! BR - nop ! A1 -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_in_user_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_in_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_in_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_in_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_in_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_in_user_short ! BR - EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall) - -U3copy_in_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif - - /* Here len >= (6 * 64) and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -U3copy_in_user_enter: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_in_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) - - .align 64 -U3copy_in_user_begin: - prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1 - prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4 - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6 -1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7 -1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_in_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_in_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_in_user_loop1: - EXBLK1(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - EXBLK1(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - EXBLK1(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - EXBLK1(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - EXBLK1(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - EXBLK1(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - EXBLK1(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - EXBLK1(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19) - prefetcha [%o1 + 0x180] %asi, #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_in_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_in_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_in_user_loop2: - EXBLK2(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - EXBLK2(ldda [%o1 + 0x010] %asi, %f4) ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - EXBLK2(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - EXBLK2(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - EXBLK2(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - EXBLK2(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - EXBLK2(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - EXBLK2(ldda [%o1 + 0x040] %asi, %f0) ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_in_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - - /* Finally we copy the last full 64-byte block. */ -U3copy_in_user_loopfini: - EXBLK3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA - EXBLK3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20 - EXBLK4(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - EXBLK4(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - EXBLK4(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - EXBLK4(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - EXBLK4(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - EXBLK4(ldda [%o1 + 0x040] %asi, %f0) ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 - membar #Sync ! MS Group26 (7-cycle stall) - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_in_user_toosmall processing. - */ -U3copy_in_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_in_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_in_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_in_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -U3copy_in_user_endcruft: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %icc, U3copy_in_user_short_ret - nop - ba,a,pt %xcc, U3copy_in_user_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_in_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_in_user_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_in_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_in_user_short - andcc %o1, 0x7, %g2 - - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - -1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) - -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 - -3: EXNV3(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2) - - cmp %o2, 0 - bne,pn %icc, U3copy_in_user_short - nop - ba,a,pt %xcc, U3copy_in_user_short_ret - -#endif /* !(SMALL_COPY_USES_FPU) */ diff -urN linux-2.4.27/arch/sparc64/lib/U3copy_to_user.S linux-2.4.28/arch/sparc64/lib/U3copy_to_user.S --- linux-2.4.27/arch/sparc64/lib/U3copy_to_user.S 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U3copy_to_user.S 2004-11-17 03:54:21.147379351 -0800 @@ -1,547 +1,33 @@ -/* $Id: U3copy_to_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy to userspace. +/* U3copy_to_user.S: UltraSparc-III optimized copy to userspace. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#ifdef __KERNEL__ -#include -#include -#include -#include -#undef SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV2(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 1, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXNV3(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: a, b, %o0; \ - retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK1(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - add %o4, 0x1c0, %o1; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - sll %o3, 6, %o3; \ - and %o2, (0x40 - 1), %o2; \ - add %o3, 0x80, %o1; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x80, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK4(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x40, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#else -#define ASI_AIUS 0x80 -#define ASI_BLK_AIUS 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EXNV2(x,y,a,b) x,y; -#define EXNV3(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EXBLK1(x,y) x,y; -#define EXBLK2(x,y) x,y; -#define EXBLK3(x,y) x,y; -#define EXBLK4(x,y) x,y; -#endif - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - */ +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME U3copy_to_user +#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS +#define EX_RETVAL(x) 0 - .text - .align 32 - - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. - */ - - .globl U3copy_to_user -U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */ /* Writing to %asi is _expensive_ so we hardcode it. * Reading %asi to check for KERNEL_DS is comparatively * cheap. */ - rd %asi, %g1 ! MS Group (4 cycles) - cmp %g1, ASI_AIUS ! A0 Group - bne U3memcpy ! BR - nop ! A1 -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_to_user_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_to_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_to_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_to_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_to_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - ldub [%o1 + 0x00], %o3 ! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_to_user_short ! BR - EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall) - -U3copy_to_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif - - /* Here len >= (6 * 64) and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -U3copy_to_user_enter: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_to_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) - - .align 64 -U3copy_to_user_begin: -#ifdef __KERNEL__ - .globl U3copy_to_user_nop_1_6 -U3copy_to_user_nop_1_6: - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - sethi %uhi(DCU_PE), %o3 - sllx %o3, 32, %o3 - or %g3, %o3, %o3 - stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache - membar #Sync -#endif - prefetch [%o1 + 0x000], #one_read ! MS Group1 - prefetch [%o1 + 0x040], #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetch [%o1 + 0x080], #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetch [%o1 + 0x0c0], #one_read ! MS Group4 - ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x100], #one_read ! MS Group6 -1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x140], #one_read ! MS Group7 -1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x180], #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_to_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_to_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_to_user_loop1: - ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19) - prefetch [%o1 + 0x180], #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_to_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_to_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_to_user_loop2: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - ldd [%o1 + 0x010], %f4 ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - ldd [%o1 + 0x040], %f0 ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_to_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - - /* Finally we copy the last full 64-byte block. */ -U3copy_to_user_loopfini: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA - ldd [%o1 + 0x010], %f4 ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20 - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - ldd [%o1 + 0x040], %f0 ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 -#ifdef __KERNEL__ - .globl U3copy_to_user_nop_2_3 -U3copy_to_user_nop_2_3: - mov PRIMARY_CONTEXT, %o3 - stxa %g0, [%o3] ASI_DMMU ! Flush P-cache - stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache -#endif - membar #Sync ! MS Group26 (7-cycle stall) - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_to_user_toosmall processing. - */ -U3copy_to_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_to_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_to_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - ldd [%o1 + 0x00], %f0 ! MS - -1: ldd [%o1 + 0x08], %f2 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_to_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - ldd [%o1 + 0x08], %f0 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -U3copy_to_user_endcruft: - cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %icc, U3copy_to_user_short_ret - nop - ba,a,pt %xcc, U3copy_to_user_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_to_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: ldd [%g1 + 0x00], %f2 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - ldd [%g1 + 0x00], %f0 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_to_user_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_to_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_to_user_short - andcc %o1, 0x7, %g2 - - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) - -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 - -3: ldx [%o1 + 0x00], %o3 - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2) - - cmp %o2, 0 - bne,pn %icc, U3copy_to_user_short - nop - ba,a,pt %xcc, U3copy_to_user_short_ret +#define PREAMBLE \ + rd %asi, %g1; \ + cmp %g1, ASI_AIUS; \ + bne,pn %icc, memcpy_user_stub; \ + nop; \ -#endif /* !(SMALL_COPY_USES_FPU) */ +#include "U3memcpy.S" diff -urN linux-2.4.27/arch/sparc64/lib/U3memcpy.S linux-2.4.28/arch/sparc64/lib/U3memcpy.S --- linux-2.4.27/arch/sparc64/lib/U3memcpy.S 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U3memcpy.S 2004-11-17 03:54:21.149379433 -0800 @@ -1,23 +1,63 @@ -/* $Id: U3memcpy.S,v 1.2 2000/11/01 09:29:19 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized memcpy. +/* U3memcpy.S: UltraSparc-III optimized memcpy. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ #ifdef __KERNEL__ #include #include -#include -#include -#undef SMALL_COPY_USES_FPU #else #define ASI_BLK_P 0xf0 #define FPRS_FEF 0x04 +#ifdef MEMCPY_DEBUG +#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \ + clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0; +#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs +#else #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU +#endif +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x #endif +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef STORE_BLK +#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_P +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME U3memcpy +#endif + +#ifndef PREAMBLE +#define PREAMBLE +#endif + +#ifndef XCC +#define XCC xcc +#endif + + .register %g2,#scratch + .register %g3,#scratch + /* Special/non-trivial issues of this code: * * 1) %o5 is preserved from VISEntryHalf to VISExitHalf @@ -29,7 +69,7 @@ */ .text - .align 32 + .align 64 /* The cheetah's flexible spine, oversized liver, enlarged heart, * slender muscular body, and claws make it the swiftest hunter @@ -37,392 +77,338 @@ * of up to 2.4GB per second. */ - .globl U3memcpy -U3memcpy: /* %o0=dst, %o1=src, %o2=len */ -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3memcpy_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3memcpy_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3memcpy_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3memcpy_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3memcpy_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - ldub [%o1 + 0x00], %o3 ! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3memcpy_short ! BR - stb %o3, [%o0 + -1] ! MS Group (1-cycle stall) - -U3memcpy_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif + .globl FUNC_NAME +FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ + PREAMBLE + mov %o0, %g5 + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + blu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + cmp %o2, (3 * 64) + blu,pt %XCC, 70f + andcc %o3, 0x7, %g0 - /* Here len >= (6 * 64) and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. + /* Clobbers o5/g1/g2/g3/g7/icc/xcc. We must preserve + * o5 from here until we hit VISExitHalf. */ - .align 64 -U3memcpy_enter: + VISEntryHalf + /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR + andcc %o0, 0x3f, %g2 + be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3memcpy_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) + sub %o0, %o1, %o4 + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 + andcc %g2, 0x7, %g1 + be,pt %icc, 2f + and %g2, 0x38, %g2 + +1: subcc %g1, 0x1, %g1 + EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) + EX_ST(STORE(stb, %o3, %o1 + %o4)) + bgu,pt %XCC, 1b + add %o1, 0x1, %o1 + + add %o1, %o4, %o0 + +2: cmp %g2, 0x0 + and %o1, 0x7, %g1 + be,pt %icc, 3f + alignaddr %o1, %g0, %o1 + + EX_LD(LOAD(ldd, %o1, %f4)) +1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f4, %f6, %f0 + EX_ST(STORE(std, %f0, %o0)) + be,pn %icc, 3f + add %o0, 0x8, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f6, %f4, %f2 + EX_ST(STORE(std, %f2, %o0)) + bne,pt %icc, 1b + add %o0, 0x8, %o0 + +3: LOAD(prefetch, %o1 + 0x000, #one_read) + LOAD(prefetch, %o1 + 0x040, #one_read) + andn %o2, (0x40 - 1), %o4 + LOAD(prefetch, %o1 + 0x080, #one_read) + LOAD(prefetch, %o1 + 0x0c0, #one_read) + LOAD(prefetch, %o1 + 0x100, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x000, %f0)) + LOAD(prefetch, %o1 + 0x140, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) + LOAD(prefetch, %o1 + 0x180, #one_read) + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) + faligndata %f0, %f2, %f16 + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) + faligndata %f2, %f4, %f18 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) + faligndata %f4, %f6, %f20 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) + faligndata %f6, %f8, %f22 + + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) + faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) + faligndata %f10, %f12, %f26 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) + + subcc %o4, 0x80, %o4 + add %o1, 0x40, %o1 + bgu,pt %XCC, 1f + srl %o4, 6, %o3 + ba,pt %xcc, 2f + nop .align 64 -U3memcpy_begin: -#ifdef __KERNEL__ - .globl U3memcpy_nop_1_6 -U3memcpy_nop_1_6: - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - sethi %uhi(DCU_PE), %o3 - sllx %o3, 32, %o3 - or %g3, %o3, %o3 - stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache - membar #Sync -#endif - prefetch [%o1 + 0x000], #one_read ! MS Group1 - prefetch [%o1 + 0x040], #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetch [%o1 + 0x080], #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetch [%o1 + 0x0c0], #one_read ! MS Group4 - ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x100], #one_read ! MS Group6 -1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x140], #one_read ! MS Group7 -1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x180], #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3memcpy_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3memcpy_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3memcpy_loop1: - ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - stda %f16, [%o0] ASI_BLK_P ! MS - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19) - prefetch [%o1 + 0x180], #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3memcpy_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3memcpy_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3memcpy_loop2: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - ldd [%o1 + 0x010], %f4 ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - stda %f16, [%o0] ASI_BLK_P ! MS - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - ldd [%o1 + 0x040], %f0 ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3memcpy_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 +1: + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) + faligndata %f12, %f14, %f28 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) + faligndata %f14, %f0, %f30 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) + faligndata %f0, %f2, %f16 + add %o0, 0x40, %o0 + + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) + faligndata %f2, %f4, %f18 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) + faligndata %f4, %f6, %f20 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) + subcc %o3, 0x01, %o3 + faligndata %f6, %f8, %f22 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) + + faligndata %f8, %f10, %f24 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) + LOAD(prefetch, %o1 + 0x1c0, #one_read) + faligndata %f10, %f12, %f26 + bg,pt %XCC, 1b + add %o1, 0x40, %o1 /* Finally we copy the last full 64-byte block. */ -U3memcpy_loopfini: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA - ldd [%o1 + 0x010], %f4 ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - stda %f16, [%o0] ASI_BLK_P ! MS Group20 - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - ldd [%o1 + 0x040], %f0 ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - stda %f16, [%o0] ASI_BLK_P ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 -#ifdef __KERNEL__ - .globl U3memcpy_nop_2_3 -U3memcpy_nop_2_3: - mov PRIMARY_CONTEXT, %o3 - stxa %g0, [%o3] ASI_DMMU ! Flush P-cache - stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache -#endif - membar #Sync ! MS Group26 (7-cycle stall) +2: + EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) + faligndata %f12, %f14, %f28 + EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) + faligndata %f14, %f0, %f30 + EX_ST(STORE_BLK(%f16, %o0)) + EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) + faligndata %f0, %f2, %f16 + EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) + faligndata %f2, %f4, %f18 + EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) + faligndata %f4, %f6, %f20 + EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) + faligndata %f6, %f8, %f22 + EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) + faligndata %f8, %f10, %f24 + cmp %g1, 0 + be,pt %XCC, 1f + add %o0, 0x40, %o0 + EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) +1: faligndata %f10, %f12, %f26 + faligndata %f12, %f14, %f28 + faligndata %f14, %f0, %f30 + EX_ST(STORE_BLK(%f16, %o0)) + add %o0, 0x40, %o0 + add %o1, 0x40, %o1 + membar #Sync /* Now we copy the (len modulo 64) bytes at the end. * Note how we borrow the %f0 loaded above. * * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3memcpy_toosmall processing. + * load past the end of the src buffer. */ -U3memcpy_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3memcpy_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3memcpy_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - ldd [%o1 + 0x00], %f0 ! MS - -1: ldd [%o1 + 0x08], %f2 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - be,pn %icc, U3memcpy_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - ldd [%o1 + 0x08], %f0 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group + and %o2, 0x3f, %o2 + andcc %o2, 0x38, %g2 + be,pn %XCC, 2f + subcc %g2, 0x8, %g2 + be,pn %XCC, 2f + cmp %g1, 0 + + sub %o2, %g2, %o2 + be,a,pt %XCC, 1f + EX_LD(LOAD(ldd, %o1 + 0x00, %f0)) + +1: EX_LD(LOAD(ldd, %o1 + 0x08, %f2)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f0, %f2, %f8 + EX_ST(STORE(std, %f8, %o0)) + be,pn %XCC, 2f + add %o0, 0x8, %o0 + EX_LD(LOAD(ldd, %o1 + 0x08, %f0)) + add %o1, 0x8, %o1 + subcc %g2, 0x8, %g2 + faligndata %f2, %f0, %f8 + EX_ST(STORE(std, %f8, %o0)) + bne,pn %XCC, 1b + add %o0, 0x8, %o0 /* If anything is left, we copy it one byte at a time. * Note that %g1 is (src & 0x3) saved above before the * alignaddr was performed. */ -U3memcpy_endcruft: +2: cmp %o2, 0 add %o1, %g1, %o1 VISExitHalf - be,pn %icc, U3memcpy_short_ret - nop - ba,a,pt %xcc, U3memcpy_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3memcpy_toosmall: + be,pn %XCC, 85f + sub %o0, %o1, %o3 -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group + andcc %g1, 0x7, %g0 + bne,pn %icc, 90f + andcc %o2, 0x8, %g0 + be,pt %icc, 1f + nop + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 -2: VISEntryHalf ! MS+MS +1: andcc %o2, 0x4, %g0 + be,pt %icc, 1f + nop + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) + add %o1, 0x4, %o1 - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group +1: andcc %o2, 0x2, %g0 + be,pt %icc, 1f + nop + EX_LD(LOAD(lduh, %o1, %o5)) + EX_ST(STORE(sth, %o5, %o1 + %o3)) + add %o1, 0x2, %o1 - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: ldd [%g1 + 0x00], %f2 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - ldd [%g1 + 0x00], %f0 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3memcpy_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3memcpy_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3memcpy_short - andcc %o1, 0x7, %g2 +1: andcc %o2, 0x1, %g0 + be,pt %icc, 85f + nop + EX_LD(LOAD(ldub, %o1, %o5)) + ba,pt %xcc, 85f + EX_ST(STORE(stb, %o5, %o1 + %o3)) - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 + .align 64 +70: /* 16 < len <= 64 */ + bne,pn %XCC, 75f + sub %o0, %o1, %o3 + +72: + andn %o2, 0xf, %o4 + and %o2, 0xf, %o2 +1: subcc %o4, 0x10, %o4 + EX_LD(LOAD(ldx, %o1 + 0x00, %o5)) + EX_LD(LOAD(ldx, %o1 + 0x08, %g1)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 + EX_ST(STORE(stx, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 +73: andcc %o2, 0x8, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x8, %o2 + EX_LD(LOAD(ldx, %o1, %o5)) + EX_ST(STORE(stx, %o5, %o1 + %o3)) + add %o1, 0x8, %o1 +1: andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EX_LD(LOAD(lduw, %o1, %o5)) + EX_ST(STORE(stw, %o5, %o1 + %o3)) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - stb %o3, [%o0 + -1] +75: + andcc %o0, 0x7, %g1 + sub %g1, 0x8, %g1 + be,pn %icc, 2f + sub %g0, %g1, %g1 + sub %o2, %g1, %o2 + +1: subcc %g1, 1, %g1 + EX_LD(LOAD(ldub, %o1, %o5)) + EX_ST(STORE(stb, %o5, %o1 + %o3)) + bgu,pt %icc, 1b + add %o1, 1, %o1 + +2: add %o1, %o3, %o0 + andcc %o1, 0x7, %g1 + bne,pt %icc, 8f + sll %g1, 3, %g1 -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 + cmp %o2, 16 + bgeu,pt %icc, 72b + nop + ba,a,pt %xcc, 73b -3: ldx [%o1 + 0x00], %o3 +8: mov 64, %o3 + andn %o1, 0x7, %o1 + EX_LD(LOAD(ldx, %o1, %g2)) + sub %o3, %g1, %o3 + andn %o2, 0x7, %o4 + sllx %g2, %g1, %g2 +1: EX_LD(LOAD(ldx, %o1 + 0x8, %g3)) + subcc %o4, 0x8, %o4 add %o1, 0x8, %o1 + srlx %g3, %o3, %o5 + or %o5, %g2, %o5 + EX_ST(STORE(stx, %o5, %o0)) add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - stx %o3, [%o0 + -8] + bgu,pt %icc, 1b + sllx %g3, %g1, %g2 - cmp %o2, 0 - bne,pn %icc, U3memcpy_short - nop - ba,a,pt %xcc, U3memcpy_short_ret + srl %g1, 3, %g1 + andcc %o2, 0x7, %o2 + be,pn %icc, 85f + add %o1, %g1, %o1 + ba,pt %xcc, 90f + sub %o0, %o1, %o3 + + .align 64 +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +1: + subcc %o2, 4, %o2 + EX_LD(LOAD(lduw, %o1, %g1)) + EX_ST(STORE(stw, %g1, %o1 + %o3)) + bgu,pt %XCC, 1b + add %o1, 4, %o1 -#endif /* !(SMALL_COPY_USES_FPU) */ +85: retl + mov EX_RETVAL(%g5), %o0 + + .align 32 +90: + subcc %o2, 1, %o2 + EX_LD(LOAD(ldub, %o1, %g1)) + EX_ST(STORE(stb, %g1, %o1 + %o3)) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + mov EX_RETVAL(%g5), %o0 diff -urN linux-2.4.27/arch/sparc64/lib/U3patch.S linux-2.4.28/arch/sparc64/lib/U3patch.S --- linux-2.4.27/arch/sparc64/lib/U3patch.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/U3patch.S 2004-11-17 03:54:21.150379474 -0800 @@ -0,0 +1,30 @@ +/* U3patch.S: Patch Ultra-I routines with Ultra-III variant. + * + * Copyright (C) 2004 David S. Miller + */ + +#define BRANCH_ALWAYS 0x10680000 +#define NOP 0x01000000 +#define ULTRA3_DO_PATCH(OLD, NEW) \ + sethi %hi(NEW), %g1; \ + or %g1, %lo(NEW), %g1; \ + sethi %hi(OLD), %g2; \ + or %g2, %lo(OLD), %g2; \ + sub %g1, %g2, %g1; \ + sethi %hi(BRANCH_ALWAYS), %g3; \ + srl %g1, 2, %g1; \ + or %g3, %lo(BRANCH_ALWAYS), %g3; \ + or %g3, %g1, %g3; \ + stw %g3, [%g2]; \ + sethi %hi(NOP), %g3; \ + or %g3, %lo(NOP), %g3; \ + stw %g3, [%g2 + 0x4]; \ + flush %g2; + + .globl cheetah_patch_copyops +cheetah_patch_copyops: + ULTRA3_DO_PATCH(memcpy, U3memcpy) + ULTRA3_DO_PATCH(___copy_from_user, U3copy_from_user) + ULTRA3_DO_PATCH(___copy_to_user, U3copy_to_user) + retl + nop diff -urN linux-2.4.27/arch/sparc64/lib/VIScopy.S linux-2.4.28/arch/sparc64/lib/VIScopy.S --- linux-2.4.27/arch/sparc64/lib/VIScopy.S 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/VIScopy.S 1969-12-31 16:00:00.000000000 -0800 @@ -1,1187 +0,0 @@ -/* $Id: VIScopy.S,v 1.26 2001/09/27 04:36:24 kanoj Exp $ - * VIScopy.S: High speed copy operations utilizing the UltraSparc - * Visual Instruction Set. - * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include "VIS.h" - - /* VIS code can be used for numerous copy/set operation variants. - * It can be made to work in the kernel, one single instance, - * for all of memcpy, copy_to_user, and copy_from_user by setting - * the ASI src/dest globals correctly. Furthermore it can - * be used for kernel-->kernel page copies as well, a hook label - * is put in here just for this purpose. - * - * For userland, compiling this without __KERNEL__ defined makes - * it work just fine as a generic libc bcopy and memcpy. - * If for userland it is compiled with a 32bit gcc (but you need - * -Wa,-Av9a for as), the code will just rely on lower 32bits of - * IEU registers, if you compile it with 64bit gcc (ie. define - * __sparc_v9__), the code will use full 64bit. - */ - -#ifdef __KERNEL__ - -#include -#include - -#define FPU_CLEAN_RETL \ - ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ - VISExit \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define FPU_RETL \ - ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ - VISExit \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define NORMAL_RETL \ - ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ - clr %o0; \ - retl; \ - wr %o1, %g0, %asi; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: ba VIScopyfixup_ret; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX2(x,y,c,d,e,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: c, d, e; \ - ba VIScopyfixup_ret; \ - a, b, %o1; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXO2(x,y) \ -98: x,y; \ - .section __ex_table; \ - .align 4; \ - .word 98b, VIScopyfixup_reto2; \ - .text; \ - .align 4; -#define EXVISN(x,y,n) \ -98: x,y; \ - .section __ex_table; \ - .align 4; \ - .word 98b, VIScopyfixup_vis##n; \ - .text; \ - .align 4; -#define EXT(start,end,handler) \ - .section __ex_table; \ - .align 4; \ - .word start, 0, end, handler; \ - .text; \ - .align 4; -#else -#ifdef REGS_64BIT -#define FPU_CLEAN_RETL \ - retl; \ - mov %g6, %o0; -#define FPU_RETL \ - retl; \ - mov %g6, %o0; -#else -#define FPU_CLEAN_RETL \ - wr %g0, FPRS_FEF, %fprs; \ - retl; \ - mov %g6, %o0; -#define FPU_RETL \ - wr %g0, FPRS_FEF, %fprs; \ - retl; \ - mov %g6, %o0; -#endif -#define NORMAL_RETL \ - retl; \ - mov %g6, %o0; -#define EX(x,y,a,b) x,y -#define EX2(x,y,c,d,e,a,b) x,y -#define EXO2(x,y) x,y -#define EXVISN(x,y,n) x,y -#define EXT(a,b,c) -#endif -#define EXVIS(x,y) EXVISN(x,y,0) -#define EXVIS1(x,y) EXVISN(x,y,1) -#define EXVIS2(x,y) EXVISN(x,y,2) -#define EXVIS3(x,y) EXVISN(x,y,3) -#define EXVIS4(x,y) EXVISN(x,y,4) - -#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9) \ - faligndata %f1, %f2, %f48; \ - faligndata %f2, %f3, %f50; \ - faligndata %f3, %f4, %f52; \ - faligndata %f4, %f5, %f54; \ - faligndata %f5, %f6, %f56; \ - faligndata %f6, %f7, %f58; \ - faligndata %f7, %f8, %f60; \ - faligndata %f8, %f9, %f62; - -#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ - EXVIS(LDBLK [%src] ASIBLK, %fdest); \ - ASI_SETDST_BLK \ - EXVIS(STBLK %fsrc, [%dest] ASIBLK); \ - add %src, 0x40, %src; \ - subcc %len, 0x40, %len; \ - be,pn %xcc, jmptgt; \ - add %dest, 0x40, %dest; \ - ASI_SETSRC_BLK - -#define LOOP_CHUNK1(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f0, f48, len, branch_dest) -#define LOOP_CHUNK2(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest) -#define LOOP_CHUNK3(src, dest, len, branch_dest) \ - MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest) - -#define STORE_SYNC(dest, fsrc) \ - EXVIS(STBLK %fsrc, [%dest] ASIBLK); \ - add %dest, 0x40, %dest; - -#ifdef __KERNEL__ -#define STORE_JUMP(dest, fsrc, target) \ - srl asi_dest, 3, %g5; \ - EXVIS2(STBLK %fsrc, [%dest] ASIBLK); \ - xor asi_dest, ASI_BLK_XOR1, asi_dest;\ - add %dest, 0x40, %dest; \ - xor asi_dest, %g5, asi_dest; \ - ba,pt %xcc, target; -#else -#define STORE_JUMP(dest, fsrc, target) \ - EXVIS2(STBLK %fsrc, [%dest] ASIBLK); \ - add %dest, 0x40, %dest; \ - ba,pt %xcc, target; -#endif - -#ifndef __KERNEL__ -#define VISLOOP_PAD nop; nop; nop; nop; \ - nop; nop; nop; nop; \ - nop; nop; nop; nop; \ - nop; nop; nop; -#else -#define VISLOOP_PAD -#endif - -#define FINISH_VISCHUNK(dest, f0, f1, left) \ - ASI_SETDST_NOBLK \ - subcc %left, 8, %left; \ - bl,pn %xcc, vis_out; \ - faligndata %f0, %f1, %f48; \ - EXVIS3(STDF %f48, [%dest] ASINORMAL); \ - add %dest, 8, %dest; - -#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ - subcc %left, 8, %left; \ - bl,pn %xcc, vis_out; \ - fsrc1 %f0, %f1; -#define UNEVEN_VISCHUNK(dest, f0, f1, left) \ - UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \ - ba,a,pt %xcc, vis_out_slk; - - /* Macros for non-VIS memcpy code. */ -#ifdef REGS_64BIT - -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x00] ASINORMAL, %t0; \ - LDX [%src + offset + 0x08] ASINORMAL, %t1; \ - LDX [%src + offset + 0x10] ASINORMAL, %t2; \ - LDX [%src + offset + 0x18] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STW %t0, [%dst + offset + 0x04] ASINORMAL; \ - srlx %t0, 32, %t0; \ - STW %t0, [%dst + offset + 0x00] ASINORMAL; \ - STW %t1, [%dst + offset + 0x0c] ASINORMAL; \ - srlx %t1, 32, %t1; \ - STW %t1, [%dst + offset + 0x08] ASINORMAL; \ - STW %t2, [%dst + offset + 0x14] ASINORMAL; \ - srlx %t2, 32, %t2; \ - STW %t2, [%dst + offset + 0x10] ASINORMAL; \ - STW %t3, [%dst + offset + 0x1c] ASINORMAL; \ - srlx %t3, 32, %t3; \ - STW %t3, [%dst + offset + 0x18] ASINORMAL; - -#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x00] ASINORMAL, %t0; \ - LDX [%src + offset + 0x08] ASINORMAL, %t1; \ - LDX [%src + offset + 0x10] ASINORMAL, %t2; \ - LDX [%src + offset + 0x18] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst + offset + 0x00] ASINORMAL; \ - STX %t1, [%dst + offset + 0x08] ASINORMAL; \ - STX %t2, [%dst + offset + 0x10] ASINORMAL; \ - STX %t3, [%dst + offset + 0x18] ASINORMAL; \ - ASI_SETSRC_NOBLK \ - LDX [%src + offset + 0x20] ASINORMAL, %t0; \ - LDX [%src + offset + 0x28] ASINORMAL, %t1; \ - LDX [%src + offset + 0x30] ASINORMAL, %t2; \ - LDX [%src + offset + 0x38] ASINORMAL, %t3; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst + offset + 0x20] ASINORMAL; \ - STX %t1, [%dst + offset + 0x28] ASINORMAL; \ - STX %t2, [%dst + offset + 0x30] ASINORMAL; \ - STX %t3, [%dst + offset + 0x38] ASINORMAL; - -#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ASI_SETSRC_NOBLK \ - LDX [%src - offset - 0x10] ASINORMAL, %t0; \ - LDX [%src - offset - 0x08] ASINORMAL, %t1; \ - ASI_SETDST_NOBLK \ - STW %t0, [%dst - offset - 0x0c] ASINORMAL; \ - srlx %t0, 32, %t2; \ - STW %t2, [%dst - offset - 0x10] ASINORMAL; \ - STW %t1, [%dst - offset - 0x04] ASINORMAL; \ - srlx %t1, 32, %t3; \ - STW %t3, [%dst - offset - 0x08] ASINORMAL; - -#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1) \ - ASI_SETSRC_NOBLK \ - LDX [%src - offset - 0x10] ASINORMAL, %t0; \ - LDX [%src - offset - 0x08] ASINORMAL, %t1; \ - ASI_SETDST_NOBLK \ - STX %t0, [%dst - offset - 0x10] ASINORMAL; \ - STX %t1, [%dst - offset - 0x08] ASINORMAL; - -#else /* !REGS_64BIT */ - -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduw [%src + offset + 0x00], %t0; \ - lduw [%src + offset + 0x04], %t1; \ - lduw [%src + offset + 0x08], %t2; \ - lduw [%src + offset + 0x0c], %t3; \ - stw %t0, [%dst + offset + 0x00]; \ - stw %t1, [%dst + offset + 0x04]; \ - stw %t2, [%dst + offset + 0x08]; \ - stw %t3, [%dst + offset + 0x0c]; \ - lduw [%src + offset + 0x10], %t0; \ - lduw [%src + offset + 0x14], %t1; \ - lduw [%src + offset + 0x18], %t2; \ - lduw [%src + offset + 0x1c], %t3; \ - stw %t0, [%dst + offset + 0x10]; \ - stw %t1, [%dst + offset + 0x14]; \ - stw %t2, [%dst + offset + 0x18]; \ - stw %t3, [%dst + offset + 0x1c]; - -#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduw [%src - offset - 0x10], %t0; \ - lduw [%src - offset - 0x0c], %t1; \ - lduw [%src - offset - 0x08], %t2; \ - lduw [%src - offset - 0x04], %t3; \ - stw %t0, [%dst - offset - 0x10]; \ - stw %t1, [%dst - offset - 0x0c]; \ - stw %t2, [%dst - offset - 0x08]; \ - stw %t3, [%dst - offset - 0x04]; - -#endif /* !REGS_64BIT */ - -#ifdef __KERNEL__ - .section __ex_table,#alloc - .section .fixup,#alloc,#execinstr -#endif - - .text - .align 32 - .globl memcpy - .type memcpy,@function - - .globl bcopy - .type bcopy,@function - -#ifdef __KERNEL__ - .globl __memcpy_begin -__memcpy_begin: - - .globl __memcpy - .type __memcpy,@function - -memcpy_private: -__memcpy: -memcpy: mov ASI_P, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov ASI_P, asi_dest ! IEU1 - retl - clr %o0 - - .align 32 - .globl __copy_from_user - .type __copy_from_user,@function -__copy_from_user:rd %asi, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov ASI_P, asi_dest ! IEU1 - - .globl __copy_to_user - .type __copy_to_user,@function -__copy_to_user: mov ASI_P, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - rd %asi, asi_dest ! IEU1 - retl ! CTI Group - clr %o0 ! IEU0 Group - - .globl __copy_in_user - .type __copy_in_user,@function -__copy_in_user: rd %asi, asi_src ! IEU0 Group - brnz,pt %o2, __memcpy_entry ! CTI - mov asi_src, asi_dest ! IEU1 - retl ! CTI Group - clr %o0 ! IEU0 Group -#endif - -bcopy: or %o0, 0, %g3 ! IEU0 Group - addcc %o1, 0, %o0 ! IEU1 - brgez,pt %o2, memcpy_private ! CTI - or %g3, 0, %o1 ! IEU0 Group - retl ! CTI Group brk forced - clr %o0 ! IEU0 - - -#ifdef __KERNEL__ -#define BRANCH_ALWAYS 0x10680000 -#define NOP 0x01000000 -#define ULTRA3_DO_PATCH(OLD, NEW) \ - sethi %hi(NEW), %g1; \ - or %g1, %lo(NEW), %g1; \ - sethi %hi(OLD), %g2; \ - or %g2, %lo(OLD), %g2; \ - sub %g1, %g2, %g1; \ - sethi %hi(BRANCH_ALWAYS), %g3; \ - srl %g1, 2, %g1; \ - or %g3, %lo(BRANCH_ALWAYS), %g3; \ - or %g3, %g1, %g3; \ - stw %g3, [%g2]; \ - sethi %hi(NOP), %g3; \ - or %g3, %lo(NOP), %g3; \ - stw %g3, [%g2 + 0x4]; \ - flush %g2; -#define ULTRA3_PCACHE_DO_NOP(symbol) \ - sethi %hi(symbol##_nop_1_6), %g1; \ - or %g1, %lo(symbol##_nop_1_6), %g1; \ - sethi %hi(NOP), %g2; \ - stw %g2, [%g1 + 0x00]; \ - stw %g2, [%g1 + 0x04]; \ - flush %g1 + 0x00; \ - stw %g2, [%g1 + 0x08]; \ - stw %g2, [%g1 + 0x0c]; \ - flush %g1 + 0x08; \ - stw %g2, [%g1 + 0x10]; \ - stw %g2, [%g1 + 0x04]; \ - flush %g1 + 0x10; \ - sethi %hi(symbol##_nop_2_3), %g1; \ - or %g1, %lo(symbol##_nop_2_3), %g1; \ - stw %g2, [%g1 + 0x00]; \ - stw %g2, [%g1 + 0x04]; \ - flush %g1 + 0x00; \ - stw %g2, [%g1 + 0x08]; \ - flush %g1 + 0x08; - -#include - - .globl cheetah_patch_copyops -cheetah_patch_copyops: - ULTRA3_DO_PATCH(memcpy, U3memcpy) - ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user) - ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user) - ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user) -#if 0 /* Causes data corruption, nop out the optimization - * for now -DaveM - */ - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - sethi %uhi(DCU_PE), %o3 - sllx %o3, 32, %o3 - andcc %g3, %o3, %g0 - be,pn %xcc, pcache_disabled - nop -#endif - ULTRA3_PCACHE_DO_NOP(U3memcpy) - ULTRA3_PCACHE_DO_NOP(U3copy_from_user) - ULTRA3_PCACHE_DO_NOP(U3copy_to_user) - ULTRA3_PCACHE_DO_NOP(cheetah_copy_user_page) -#if 0 -pcache_disabled: -#endif - retl - nop -#undef BRANCH_ALWAYS -#undef NOP -#undef ULTRA3_DO_PATCH -#endif /* __KERNEL__ */ - - .align 32 -#ifdef __KERNEL__ - andcc %o0, 7, %g2 ! IEU1 Group -#endif -VIS_enter: - be,pt %xcc, dest_is_8byte_aligned ! CTI -#ifdef __KERNEL__ - nop ! IEU0 Group -#else - andcc %o0, 0x38, %g5 ! IEU1 Group -#endif -do_dest_8byte_align: - mov 8, %g1 ! IEU0 - sub %g1, %g2, %g2 ! IEU0 Group - andcc %o0, 1, %g0 ! IEU1 - be,pt %icc, 2f ! CTI - sub %o2, %g2, %o2 ! IEU0 Group -1: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %o5, - add %o2, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 1, %g2 ! IEU1 Group - be,pn %xcc, 3f ! CTI - EX2(STB %o5, [%o0 - 1] ASINORMAL, - add %g2, 1, %g2, - add %o2, %g2) ! Store -2: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %o5, - add %o2, %g2) ! Load Group - add %o0, 2, %o0 ! IEU0 - EX2(LDUB [%o1 + 1] ASINORMAL, %g3, - sub %o0, 2, %o0, - add %o2, %g2) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 2, %g2 ! IEU1 Group - EX2(STB %o5, [%o0 - 2] ASINORMAL, - add %g2, 2, %g2, - add %o2, %g2) ! Store - add %o1, 2, %o1 ! IEU0 - bne,pt %xcc, 2b ! CTI Group - EX2(STB %g3, [%o0 - 1] ASINORMAL, - add %g2, 1, %g2, - add %o2, %g2) ! Store -#ifdef __KERNEL__ -3: -dest_is_8byte_aligned: - VISEntry - andcc %o0, 0x38, %g5 ! IEU1 Group -#else -3: andcc %o0, 0x38, %g5 ! IEU1 Group -dest_is_8byte_aligned: -#endif - be,pt %icc, dest_is_64byte_aligned ! CTI - mov 64, %g1 ! IEU0 - fmovd %f0, %f2 ! FPU - sub %g1, %g5, %g5 ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - alignaddr %o1, %g0, %g1 ! GRU Group - EXO2(LDDF [%g1] ASINORMAL, %f4) ! Load Group - sub %o2, %g5, %o2 ! IEU0 -1: EX(LDDF [%g1 + 0x8] ASINORMAL, %f6, - add %o2, %g5) ! Load Group - add %g1, 0x8, %g1 ! IEU0 Group - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f4, %f6, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %g5, 8, %g5, - add %o2, %g5) ! Store - add %o1, 8, %o1 ! IEU0 Group - be,pn %xcc, dest_is_64byte_aligned ! CTI - add %o0, 8, %o0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDDF [%g1 + 0x8] ASINORMAL, %f4, - add %o2, %g5) ! Load Group - add %g1, 8, %g1 ! IEU0 - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f6, %f4, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %g5, 8, %g5, - add %o2, %g5) ! Store - add %o1, 8, %o1 ! IEU0 - ASI_SETSRC_NOBLK ! LSU Group - bne,pt %xcc, 1b ! CTI Group - add %o0, 8, %o0 ! IEU0 -dest_is_64byte_aligned: - membar #LoadStore | #StoreStore | #StoreLoad ! LSU Group -#ifndef __KERNEL__ - wr %g0, ASI_BLK_P, %asi ! LSU Group -#endif - subcc %o2, 0x40, %g7 ! IEU1 Group - mov %o1, %g1 ! IEU0 - andncc %g7, (0x40 - 1), %g7 ! IEU1 Group - srl %g1, 3, %g2 ! IEU0 - sub %o2, %g7, %g3 ! IEU0 Group - andn %o1, (0x40 - 1), %o1 ! IEU1 - and %g2, 7, %g2 ! IEU0 Group - andncc %g3, 0x7, %g3 ! IEU1 - fmovd %f0, %f2 ! FPU - sub %g3, 0x10, %g3 ! IEU0 Group - sub %o2, %g7, %o2 ! IEU1 -#ifdef __KERNEL__ - or asi_src, ASI_BLK_OR, asi_src ! IEU0 Group - or asi_dest, ASI_BLK_OR, asi_dest ! IEU1 -#endif - alignaddr %g1, %g0, %g0 ! GRU Group - add %g1, %g7, %g1 ! IEU0 Group - subcc %o2, %g3, %o2 ! IEU1 - ASI_SETSRC_BLK ! LSU Group - EXVIS1(LDBLK [%o1 + 0x00] ASIBLK, %f0) ! LSU Group - add %g1, %g3, %g1 ! IEU0 - EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group - sub %g7, 0x80, %g7 ! IEU0 - EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group -#ifdef __KERNEL__ -vispc: sll %g2, 9, %g2 ! IEU0 Group - sethi %hi(vis00), %g5 ! IEU1 - or %g5, %lo(vis00), %g5 ! IEU0 Group - jmpl %g5 + %g2, %g0 ! CTI Group brk forced - addcc %o1, 0xc0, %o1 ! IEU1 Group -#else - ! Clk1 Group 8-( - ! Clk2 Group 8-( - ! Clk3 Group 8-( - ! Clk4 Group 8-( -vispc: rd %pc, %g5 ! PDU Group 8-( - addcc %g5, %lo(vis00 - vispc), %g5 ! IEU1 Group - sll %g2, 9, %g2 ! IEU0 - jmpl %g5 + %g2, %g0 ! CTI Group brk forced - addcc %o1, 0xc0, %o1 ! IEU1 Group -#endif - .align 512 /* OK, here comes the fun part... */ -vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01) - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02) - FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) LOOP_CHUNK3(o1, o0, g7, vis03) - b,pt %xcc, vis00+4; faligndata %f0, %f2, %f48 -vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_JUMP(o0, f48, finish_f0) membar #Sync -vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync -vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync - VISLOOP_PAD -vis10:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) LOOP_CHUNK1(o1, o0, g7, vis11) - FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) LOOP_CHUNK2(o1, o0, g7, vis12) - FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) LOOP_CHUNK3(o1, o0, g7, vis13) - b,pt %xcc, vis10+4; faligndata %f2, %f4, %f48 -vis11:FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) STORE_JUMP(o0, f48, finish_f2) membar #Sync -vis12:FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_JUMP(o0, f48, finish_f18) membar #Sync -vis13:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_JUMP(o0, f48, finish_f34) membar #Sync - VISLOOP_PAD -vis20:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) LOOP_CHUNK1(o1, o0, g7, vis21) - FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) LOOP_CHUNK2(o1, o0, g7, vis22) - FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) LOOP_CHUNK3(o1, o0, g7, vis23) - b,pt %xcc, vis20+4; faligndata %f4, %f6, %f48 -vis21:FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) STORE_JUMP(o0, f48, finish_f4) membar #Sync -vis22:FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_JUMP(o0, f48, finish_f20) membar #Sync -vis23:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_JUMP(o0, f48, finish_f36) membar #Sync - VISLOOP_PAD -vis30:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) LOOP_CHUNK1(o1, o0, g7, vis31) - FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) LOOP_CHUNK2(o1, o0, g7, vis32) - FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) LOOP_CHUNK3(o1, o0, g7, vis33) - b,pt %xcc, vis30+4; faligndata %f6, %f8, %f48 -vis31:FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) STORE_JUMP(o0, f48, finish_f6) membar #Sync -vis32:FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_JUMP(o0, f48, finish_f22) membar #Sync -vis33:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_JUMP(o0, f48, finish_f38) membar #Sync - VISLOOP_PAD -vis40:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) LOOP_CHUNK1(o1, o0, g7, vis41) - FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) LOOP_CHUNK2(o1, o0, g7, vis42) - FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) LOOP_CHUNK3(o1, o0, g7, vis43) - b,pt %xcc, vis40+4; faligndata %f8, %f10, %f48 -vis41:FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) STORE_JUMP(o0, f48, finish_f8) membar #Sync -vis42:FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_JUMP(o0, f48, finish_f24) membar #Sync -vis43:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_JUMP(o0, f48, finish_f40) membar #Sync - VISLOOP_PAD -vis50:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) LOOP_CHUNK1(o1, o0, g7, vis51) - FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) LOOP_CHUNK2(o1, o0, g7, vis52) - FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) LOOP_CHUNK3(o1, o0, g7, vis53) - b,pt %xcc, vis50+4; faligndata %f10, %f12, %f48 -vis51:FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_JUMP(o0, f48, finish_f10) membar #Sync -vis52:FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_JUMP(o0, f48, finish_f26) membar #Sync -vis53:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_JUMP(o0, f48, finish_f42) membar #Sync - VISLOOP_PAD -vis60:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) LOOP_CHUNK1(o1, o0, g7, vis61) - FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) LOOP_CHUNK2(o1, o0, g7, vis62) - FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) LOOP_CHUNK3(o1, o0, g7, vis63) - b,pt %xcc, vis60+4; faligndata %f12, %f14, %f48 -vis61:FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_JUMP(o0, f48, finish_f12) membar #Sync -vis62:FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_JUMP(o0, f48, finish_f28) membar #Sync -vis63:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_JUMP(o0, f48, finish_f44) membar #Sync - VISLOOP_PAD -vis70:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) LOOP_CHUNK1(o1, o0, g7, vis71) - FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) LOOP_CHUNK2(o1, o0, g7, vis72) - FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) LOOP_CHUNK3(o1, o0, g7, vis73) - b,pt %xcc, vis70+4; faligndata %f14, %f16, %f48 -vis71:FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_JUMP(o0, f48, finish_f14) membar #Sync -vis72:FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_JUMP(o0, f48, finish_f30) membar #Sync -vis73:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_JUMP(o0, f48, finish_f46) membar #Sync - VISLOOP_PAD -finish_f0: FINISH_VISCHUNK(o0, f0, f2, g3) -finish_f2: FINISH_VISCHUNK(o0, f2, f4, g3) -finish_f4: FINISH_VISCHUNK(o0, f4, f6, g3) -finish_f6: FINISH_VISCHUNK(o0, f6, f8, g3) -finish_f8: FINISH_VISCHUNK(o0, f8, f10, g3) -finish_f10: FINISH_VISCHUNK(o0, f10, f12, g3) -finish_f12: FINISH_VISCHUNK(o0, f12, f14, g3) -finish_f14: UNEVEN_VISCHUNK(o0, f14, f0, g3) -finish_f16: FINISH_VISCHUNK(o0, f16, f18, g3) -finish_f18: FINISH_VISCHUNK(o0, f18, f20, g3) -finish_f20: FINISH_VISCHUNK(o0, f20, f22, g3) -finish_f22: FINISH_VISCHUNK(o0, f22, f24, g3) -finish_f24: FINISH_VISCHUNK(o0, f24, f26, g3) -finish_f26: FINISH_VISCHUNK(o0, f26, f28, g3) -finish_f28: FINISH_VISCHUNK(o0, f28, f30, g3) -finish_f30: UNEVEN_VISCHUNK(o0, f30, f0, g3) -finish_f32: FINISH_VISCHUNK(o0, f32, f34, g3) -finish_f34: FINISH_VISCHUNK(o0, f34, f36, g3) -finish_f36: FINISH_VISCHUNK(o0, f36, f38, g3) -finish_f38: FINISH_VISCHUNK(o0, f38, f40, g3) -finish_f40: FINISH_VISCHUNK(o0, f40, f42, g3) -finish_f42: FINISH_VISCHUNK(o0, f42, f44, g3) -finish_f44: FINISH_VISCHUNK(o0, f44, f46, g3) -finish_f46: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3) -vis_out_slk: -#ifdef __KERNEL__ - srl asi_src, 3, %g5 ! IEU0 Group - xor asi_src, ASI_BLK_XOR1, asi_src ! IEU1 - xor asi_src, %g5, asi_src ! IEU0 Group -#endif -vis_slk:ASI_SETSRC_NOBLK ! LSU Group - EXVIS3(LDDF [%o1] ASINORMAL, %f2) ! Load Group - add %o1, 8, %o1 ! IEU0 - subcc %g3, 8, %g3 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f0, %f2, %f8 ! GRU Group - EXVIS4(STDF %f8, [%o0] ASINORMAL) ! Store - bl,pn %xcc, vis_out_slp ! CTI - add %o0, 8, %o0 ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - EXVIS3(LDDF [%o1] ASINORMAL, %f0) ! Load Group - add %o1, 8, %o1 ! IEU0 - subcc %g3, 8, %g3 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f2, %f0, %f8 ! GRU Group - EXVIS4(STDF %f8, [%o0] ASINORMAL) ! Store - bge,pt %xcc, vis_slk ! CTI - add %o0, 8, %o0 ! IEU0 Group -vis_out_slp: -#ifdef __KERNEL__ - brz,pt %o2, vis_ret ! CTI Group - mov %g1, %o1 ! IEU0 - ba,pt %xcc, vis_slp+4 ! CTI Group - ASI_SETSRC_NOBLK ! LSU Group -#endif -vis_out:brz,pt %o2, vis_ret ! CTI Group - mov %g1, %o1 ! IEU0 -#ifdef __KERNEL__ - srl asi_src, 3, %g5 ! IEU0 Group - xor asi_src, ASI_BLK_XOR1, asi_src ! IEU1 - xor asi_src, %g5, asi_src ! IEU0 Group -#endif -vis_slp:ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 - bne,pt %xcc, vis_slp ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store Group -vis_ret:membar #StoreLoad | #StoreStore ! LSU Group - FPU_CLEAN_RETL - - -__memcpy_short: - andcc %o2, 1, %g0 ! IEU1 Group - be,pt %icc, 2f ! CTI -1: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 Group - be,pn %xcc, short_ret ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -2: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group - add %o0, 2, %o0 ! IEU0 - EX2(LDUB [%o1 + 1] ASINORMAL, %o5, - sub %o0, 2, %o0, - add %o2, %g0) ! LOAD Group - add %o1, 2, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 2, %o2 ! IEU1 Group - EX(STB %g5, [%o0 - 2] ASINORMAL, - add %o2, 2) ! Store - bne,pt %xcc, 2b ! CTI - EX(STB %o5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -short_ret: - NORMAL_RETL - -#ifndef __KERNEL__ -memcpy_private: -memcpy: -#ifndef REGS_64BIT - srl %o2, 0, %o2 ! IEU1 Group -#endif - brz,pn %o2, short_ret ! CTI Group - mov %o0, %g6 ! IEU0 -#endif -__memcpy_entry: - cmp %o2, 15 ! IEU1 Group - bleu,pn %xcc, __memcpy_short ! CTI - cmp %o2, (64 * 6) ! IEU1 Group - bgeu,pn %xcc, VIS_enter ! CTI - andcc %o0, 7, %g2 ! IEU1 Group - sub %o0, %o1, %g5 ! IEU0 - andcc %g5, 3, %o5 ! IEU1 Group - bne,pn %xcc, memcpy_noVIS_misaligned ! CTI - andcc %o1, 3, %g0 ! IEU1 Group -#ifdef REGS_64BIT - be,a,pt %xcc, 3f ! CTI - andcc %o1, 4, %g0 ! IEU1 Group - andcc %o1, 1, %g0 ! IEU1 Group -#else /* !REGS_64BIT */ - be,pt %xcc, 5f ! CTI - andcc %o1, 1, %g0 ! IEU1 Group -#endif /* !REGS_64BIT */ - be,pn %xcc, 4f ! CTI - andcc %o1, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUB [%o1] ASINORMAL, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - sub %o2, 1, %o2 ! IEU0 Group - ASI_SETDST_NOBLK ! LSU Group - bne,pn %xcc, 5f ! CTI Group - EX(STB %g2, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store -4: ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUH [%o1] ASINORMAL, %g2) ! Load Group - add %o1, 2, %o1 ! IEU0 - add %o0, 2, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - sub %o2, 2, %o2 ! IEU0 - EX(STH %g2, [%o0 - 2] ASINORMAL, - add %o2, 2) ! Store Group + bubble -#ifdef REGS_64BIT -5: andcc %o1, 4, %g0 ! IEU1 -3: be,a,pn %xcc, 2f ! CTI - andcc %o2, -128, %g7 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EXO2(LDUW [%o1] ASINORMAL, %g5) ! Load Group - add %o1, 4, %o1 ! IEU0 - add %o0, 4, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - sub %o2, 4, %o2 ! IEU0 Group - EX(STW %g5, [%o0 - 4] ASINORMAL, - add %o2, 4) ! Store - andcc %o2, -128, %g7 ! IEU1 Group -2: be,pn %xcc, 3f ! CTI - andcc %o0, 4, %g0 ! IEU1 Group - be,pn %xcc, 82f + 4 ! CTI Group -#else /* !REGS_64BIT */ -5: andcc %o2, -128, %g7 ! IEU1 - be,a,pn %xcc, 41f ! CTI - andcc %o2, 0x70, %g7 ! IEU1 Group -#endif /* !REGS_64BIT */ -5: MOVE_BIGCHUNK(o1, o0, 0x00, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x20, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x40, g1, g3, g5, o5) - MOVE_BIGCHUNK(o1, o0, 0x60, g1, g3, g5, o5) - EXT(5b,35f,VIScopyfixup1) -35: subcc %g7, 128, %g7 ! IEU1 Group - add %o1, 128, %o1 ! IEU0 - bne,pt %xcc, 5b ! CTI - add %o0, 128, %o0 ! IEU0 Group -3: andcc %o2, 0x70, %g7 ! IEU1 Group -41: be,pn %xcc, 80f ! CTI - andcc %o2, 8, %g0 ! IEU1 Group -#ifdef __KERNEL__ -79: sethi %hi(80f), %o5 ! IEU0 - sll %g7, 1, %g5 ! IEU0 Group - add %o1, %g7, %o1 ! IEU1 - srl %g7, 1, %g2 ! IEU0 Group - sub %o5, %g5, %o5 ! IEU1 - sub %o5, %g2, %o5 ! IEU0 Group - jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#else - ! Clk1 8-( - ! Clk2 8-( - ! Clk3 8-( - ! Clk4 8-( -79: rd %pc, %o5 ! PDU Group - sll %g7, 1, %g5 ! IEU0 Group - add %o1, %g7, %o1 ! IEU1 - sub %o5, %g5, %o5 ! IEU0 Group - jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#endif -36: MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g5, o5) - MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g5, o5) - EXT(36b,80f,VIScopyfixup2) -80: be,pt %xcc, 81f ! CTI - andcc %o2, 4, %g0 ! IEU1 -#ifdef REGS_64BIT - ASI_SETSRC_NOBLK ! LSU Group - EX(LDX [%o1] ASINORMAL, %g2, - and %o2, 0xf) ! Load Group - add %o0, 8, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STW %g2, [%o0 - 0x4] ASINORMAL, - and %o2, 0xf) ! Store Group - add %o1, 8, %o1 ! IEU1 - srlx %g2, 32, %g2 ! IEU0 Group - EX2(STW %g2, [%o0 - 0x8] ASINORMAL, - and %o2, 0xf, %o2, - sub %o2, 4) ! Store -#else /* !REGS_64BIT */ - lduw [%o1], %g2 ! Load Group - add %o0, 8, %o0 ! IEU0 - lduw [%o1 + 0x4], %g3 ! Load Group - add %o1, 8, %o1 ! IEU0 - stw %g2, [%o0 - 0x8] ! Store Group - stw %g3, [%o0 - 0x4] ! Store Group -#endif /* !REGS_64BIT */ -81: be,pt %xcc, 1f ! CTI - andcc %o2, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUW [%o1] ASINORMAL, %g2, - and %o2, 0x7) ! Load Group - add %o1, 4, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STW %g2, [%o0] ASINORMAL, - and %o2, 0x7) ! Store Group - add %o0, 4, %o0 ! IEU0 -1: be,pt %xcc, 1f ! CTI - andcc %o2, 1, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUH [%o1] ASINORMAL, %g2, - and %o2, 0x3) ! Load Group - add %o1, 2, %o1 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - EX(STH %g2, [%o0] ASINORMAL, - and %o2, 0x3) ! Store Group - add %o0, 2, %o0 ! IEU0 -1: be,pt %xcc, normal_retl ! CTI - nop ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g2, - add %g0, 1) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - EX(STB %g2, [%o0] ASINORMAL, - add %g0, 1) ! Store Group + bubble -normal_retl: - NORMAL_RETL - -#ifdef REGS_64BIT -82: MOVE_BIGALIGNCHUNK(o1, o0, 0x00, g1, g3, g5, o5) - MOVE_BIGALIGNCHUNK(o1, o0, 0x40, g1, g3, g5, o5) - EXT(82b,37f,VIScopyfixup3) -37: subcc %g7, 128, %g7 ! IEU1 Group - add %o1, 128, %o1 ! IEU0 - bne,pt %xcc, 82b ! CTI - add %o0, 128, %o0 ! IEU0 Group - andcc %o2, 0x70, %g7 ! IEU1 - be,pn %xcc, 84f ! CTI - andcc %o2, 8, %g0 ! IEU1 Group -#ifdef __KERNEL__ -83: srl %g7, 1, %g5 ! IEU0 - sethi %hi(84f), %o5 ! IEU0 Group - add %g7, %g5, %g5 ! IEU1 - add %o1, %g7, %o1 ! IEU0 Group - sub %o5, %g5, %o5 ! IEU1 - jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#else - ! Clk1 8-( - ! Clk2 8-( - ! Clk3 8-( - ! Clk4 8-( -83: rd %pc, %o5 ! PDU Group - add %o1, %g7, %o1 ! IEU0 Group - sub %o5, %g7, %o5 ! IEU1 - jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#endif -38: MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3) - MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3) - EXT(38b,84f,VIScopyfixup4) -84: be,pt %xcc, 85f ! CTI Group - andcc %o2, 4, %g0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDX [%o1] ASINORMAL, %g2, - and %o2, 0xf) ! Load Group - add %o0, 8, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 8, %o1 ! IEU0 Group - EX(STX %g2, [%o0 - 0x8] ASINORMAL, - and %o2, 0xf) ! Store -85: be,pt %xcc, 1f ! CTI - andcc %o2, 2, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUW [%o1] ASINORMAL, %g2, - and %o2, 0x7) ! Load Group - add %o0, 4, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 4, %o1 ! IEU0 Group - EX(STW %g2, [%o0 - 0x4] ASINORMAL, - and %o2, 0x7) ! Store -1: be,pt %xcc, 1f ! CTI - andcc %o2, 1, %g0 ! IEU1 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUH [%o1] ASINORMAL, %g2, - and %o2, 0x3) ! Load Group - add %o0, 2, %o0 ! IEU0 - ASI_SETDST_NOBLK ! LSU Group - add %o1, 2, %o1 ! IEU0 Group - EX(STH %g2, [%o0 - 0x2] ASINORMAL, - and %o2, 0x3) ! Store -1: be,pt %xcc, 1f ! CTI - nop ! IEU0 Group - ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g2, - add %g0, 1) ! Load Group - ASI_SETDST_NOBLK ! LSU Group - EX(STB %g2, [%o0] ASINORMAL, - add %g0, 1) ! Store Group + bubble -1: NORMAL_RETL -#endif /* REGS_64BIT */ - -memcpy_noVIS_misaligned: - brz,pt %g2, 2f ! CTI Group - mov 8, %g1 ! IEU0 - sub %g1, %g2, %g2 ! IEU0 Group - sub %o2, %g2, %o2 ! IEU0 Group -1: ASI_SETSRC_NOBLK ! LSU Group - EX(LDUB [%o1] ASINORMAL, %g5, - add %o2, %g2) ! Load Group - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %g2, 1, %g2 ! IEU1 Group - bne,pt %xcc, 1b ! CTI - EX2(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, %g2, %o2, - add %o2, 1) ! Store -2: -#ifdef __KERNEL__ - VISEntry -#endif - andn %o2, 7, %g5 ! IEU0 Group - and %o2, 7, %o2 ! IEU1 - fmovd %f0, %f2 ! FPU - ASI_SETSRC_NOBLK ! LSU Group - alignaddr %o1, %g0, %g1 ! GRU Group - EXO2(LDDF [%g1] ASINORMAL, %f4) ! Load Group -1: EX(LDDF [%g1 + 0x8] ASINORMAL, %f6, - add %o2, %g5) ! Load Group - add %g1, 0x8, %g1 ! IEU0 Group - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f4, %f6, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %o2, %g5, %o2, - add %o2, 8) ! Store - add %o1, 8, %o1 ! IEU0 Group - be,pn %xcc, end_cruft ! CTI - add %o0, 8, %o0 ! IEU1 - ASI_SETSRC_NOBLK ! LSU Group - EX(LDDF [%g1 + 0x8] ASINORMAL, %f4, - add %o2, %g5) ! Load Group - add %g1, 8, %g1 ! IEU0 - subcc %g5, 8, %g5 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - faligndata %f6, %f4, %f0 ! GRU Group - EX2(STDF %f0, [%o0] ASINORMAL, - add %o2, %g5, %o2, - add %o2, 8) ! Store - add %o1, 8, %o1 ! IEU0 - ASI_SETSRC_NOBLK ! LSU Group - bne,pn %xcc, 1b ! CTI Group - add %o0, 8, %o0 ! IEU0 -end_cruft: - brz,pn %o2, fpu_retl ! CTI Group -#ifndef __KERNEL__ - nop ! IEU0 -#else - ASI_SETSRC_NOBLK ! LSU Group -#endif - EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD - add %o1, 1, %o1 ! IEU0 - add %o0, 1, %o0 ! IEU1 - ASI_SETDST_NOBLK ! LSU Group - subcc %o2, 1, %o2 ! IEU1 - bne,pt %xcc, vis_slp ! CTI - EX(STB %g5, [%o0 - 1] ASINORMAL, - add %o2, 1) ! Store Group -fpu_retl: - FPU_RETL - -#ifdef __KERNEL__ - .globl __memcpy_end -__memcpy_end: - - .section .fixup - .align 4 -VIScopyfixup_reto2: - mov %o2, %o1 -VIScopyfixup_ret: - /* If this is copy_from_user(), zero out the rest of the - * kernel buffer. - */ - ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o4 - andcc asi_src, 0x1, %g0 - be,pt %icc, 1f - VISExit - andcc asi_dest, 0x1, %g0 - bne,pn %icc, 1f - nop - save %sp, -160, %sp - mov %i0, %o0 - call __bzero - mov %i1, %o1 - restore -1: mov %o1, %o0 - retl - wr %o4, %g0, %asi -VIScopyfixup1: subcc %g2, 18, %g2 - add %o0, 32, %o0 - bgeu,a,pt %icc, VIScopyfixup1 - sub %g7, 32, %g7 - sub %o0, 32, %o0 - rd %pc, %g5 - add %g2, (18 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 2f -.byte 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 12, 12, 16, 20, 20, 24, 28, 28 - .align 4 -VIScopyfixup2: mov (7 * 16), %g7 -1: subcc %g2, 10, %g2 - bgeu,a,pt %icc, 1b - sub %g7, 16, %g7 - sub %o0, %g7, %o0 - rd %pc, %g5 - add %g2, (10 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 4f -.byte 0, 0, 0, 0, 0, 4, 4, 8, 12, 12 - .align 4 -VIScopyfixup3: subcc %g2, 10, %g2 - add %o0, 32, %o0 - bgeu,a,pt %icc, VIScopyfixup3 - sub %g7, 32, %g7 - sub %o0, 32, %o0 - rd %pc, %g5 - add %g2, (10 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 2f -.byte 0, 0, 0, 0, 0, 0, 0, 8, 16, 24 - .align 4 -2: and %o2, 0x7f, %o2 - sub %g7, %g2, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %g7, %o2, %o1 -VIScopyfixup4: mov (7 * 16), %g7 -3: subcc %g2, 6, %g2 - bgeu,a,pt %icc, 3b - sub %g7, 16, %g7 - sub %o0, %g7, %o0 - rd %pc, %g5 - add %g2, (6 + 16), %g2 - ldub [%g5 + %g2], %g2 - ba,a,pt %xcc, 4f -.byte 0, 0, 0, 0, 0, 8 - .align 4 -4: and %o2, 0xf, %o2 - sub %g7, %g2, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %g7, %o2, %o1 -VIScopyfixup_vis2: - sub %o2, 0x40, %o2 -VIScopyfixup_vis0: - add %o2, 0x80, %o2 -VIScopyfixup_vis1: - add %g7, %g3, %g7 - ba,pt %xcc, VIScopyfixup_ret - add %o2, %g7, %o1 -VIScopyfixup_vis4: - add %g3, 8, %g3 -VIScopyfixup_vis3: - add %g3, 8, %g3 - ba,pt %xcc, VIScopyfixup_ret - add %o2, %g3, %o1 -#endif - -#ifdef __KERNEL__ - .text - .align 32 - - .globl __memmove - .type __memmove,@function - - .globl memmove - .type memmove,@function - -memmove: -__memmove: cmp %o0, %o1 - blu,pt %xcc, memcpy_private - sub %o0, %o1, %g5 - add %o1, %o2, %g3 - cmp %g3, %o0 - bleu,pt %xcc, memcpy_private - add %o1, %o2, %g5 - add %o0, %o2, %o5 - - sub %g5, 1, %o1 - sub %o5, 1, %o0 -1: ldub [%o1], %g5 - subcc %o2, 1, %o2 - sub %o1, 1, %o1 - stb %g5, [%o0] - bne,pt %icc, 1b - sub %o0, 1, %o0 - - retl - clr %o0 -#endif diff -urN linux-2.4.27/arch/sparc64/lib/copy_in_user.S linux-2.4.28/arch/sparc64/lib/copy_in_user.S --- linux-2.4.27/arch/sparc64/lib/copy_in_user.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/copy_in_user.S 2004-11-17 03:54:21.154379638 -0800 @@ -0,0 +1,114 @@ +/* copy_in_user.S: Copy from userspace to userspace. + * + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) + */ + +#include + +#define XCC xcc + +#define EX(x,y) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov 1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + + .register %g2,#scratch + .register %g3,#scratch + + .text + .align 32 + + /* Don't try to get too fancy here, just nice and + * simple. This is predominantly used for well aligned + * small copies in the compat layer. It is also used + * to copy register windows around during thread cloning. + */ + + .globl ___copy_in_user +___copy_in_user: /* %o0=dst, %o1=src, %o2=len */ + /* Writing to %asi is _expensive_ so we hardcode it. + * Reading %asi to check for KERNEL_DS is comparatively + * cheap. + */ + rd %asi, %g1 + cmp %g1, ASI_AIUS + bne,pn %icc, memcpy_user_stub + nop + + cmp %o2, 0 + be,pn %XCC, 85f + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, 80f + or %o3, %o2, %o3 + + /* 16 < len <= 64 */ + andcc %o3, 0x7, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + EX(ldxa [%o1] %asi, %o5) + EX(stxa %o5, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EX(lduwa [%o1] %asi, %o5) + EX(stwa %o5, [%o1 + %o3] ASI_AIUS) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, 85f + nop + ba,pt %xcc, 90f + nop + +80: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, 90f + sub %o0, %o1, %o3 + +82: + subcc %o2, 4, %o2 + EX(lduwa [%o1] %asi, %g1) + EX(stwa %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 82b + add %o1, 4, %o1 + +85: retl + clr %o0 + + .align 32 +90: + subcc %o2, 1, %o2 + EX(lduba [%o1] %asi, %g1) + EX(stba %g1, [%o1 + %o3] ASI_AIUS) + bgu,pt %XCC, 90b + add %o1, 1, %o1 + retl + clr %o0 + + /* Act like copy_{to,in}_user(), ie. return zero instead + * of original destination pointer. This is invoked when + * copy_{to,in}_user() finds that %asi is kernel space. + */ + .globl memcpy_user_stub +memcpy_user_stub: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + call memcpy + mov %i2, %o2 + ret + restore %g0, %g0, %o0 diff -urN linux-2.4.27/arch/sparc64/lib/memmove.S linux-2.4.28/arch/sparc64/lib/memmove.S --- linux-2.4.27/arch/sparc64/lib/memmove.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/memmove.S 2004-11-17 03:54:21.155379680 -0800 @@ -0,0 +1,31 @@ +/* memmove.S: Simple memmove implementation. + * + * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + + .text + .align 32 + .globl memmove +memmove: + mov %o0, %g1 + cmp %o0, %o1 + blu,pt %xcc, memcpy + sub %o0, %o1, %g5 + add %o1, %o2, %g3 + cmp %g3, %o0 + bleu,pt %xcc, memcpy + add %o1, %o2, %g5 + add %o0, %o2, %o5 + + sub %g5, 1, %o1 + sub %o5, 1, %o0 +1: ldub [%o1], %g5 + subcc %o2, 1, %o2 + sub %o1, 1, %o1 + stb %g5, [%o0] + bne,pt %icc, 1b + sub %o0, 1, %o0 + + retl + mov %g1, %o0 diff -urN linux-2.4.27/arch/sparc64/lib/user_fixup.c linux-2.4.28/arch/sparc64/lib/user_fixup.c --- linux-2.4.27/arch/sparc64/lib/user_fixup.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/arch/sparc64/lib/user_fixup.c 2004-11-17 03:54:21.155379680 -0800 @@ -0,0 +1,68 @@ +/* user_fixup.c: Fix up user copy faults. + * + * Copyright (C) 2004 David S. Miller + */ + +#include +#include +#include +#include +#include + +/* Calculating the exact fault address when using + * block loads and stores can be very complicated. + * Instead of trying to be clever and handling all + * of the cases, just fix things up simply here. + */ + +unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) +{ + char *dst = to; + const char __user *src = from; + + while (size--) { + if (__get_user(*dst, src)) + break; + dst++; + src++; + } + + if (size) + memset(dst, 0, size); + + return size; +} + +unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) +{ + char __user *dst = to; + const char *src = from; + + while (size--) { + if (__put_user(*src, dst)) + break; + dst++; + src++; + } + + return size; +} + +unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) +{ + char __user *dst = to; + char __user *src = from; + + while (size--) { + char tmp; + + if (__get_user(tmp, src)) + break; + if (__put_user(tmp, dst)) + break; + dst++; + src++; + } + + return size; +} diff -urN linux-2.4.27/arch/sparc64/mm/fault.c linux-2.4.28/arch/sparc64/mm/fault.c --- linux-2.4.27/arch/sparc64/mm/fault.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/mm/fault.c 2004-11-17 03:54:21.156379721 -0800 @@ -253,7 +253,7 @@ * in that case. */ - if (!(fault_code & FAULT_CODE_WRITE) && + if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && (insn & 0xc0800000) == 0xc0800000) { if (insn & 0x2000) asi = (regs->tstate >> 24); @@ -404,6 +404,16 @@ */ good_area: si_code = SEGV_ACCERR; + + /* If we took a ITLB miss on a non-executable page, catch + * that here. + */ + if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { + BUG_ON(address != regs->tpc); + BUG_ON(regs->tstate & TSTATE_PRIV); + goto bad_area; + } + if (fault_code & FAULT_CODE_WRITE) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; diff -urN linux-2.4.27/arch/sparc64/mm/init.c linux-2.4.28/arch/sparc64/mm/init.c --- linux-2.4.27/arch/sparc64/mm/init.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/arch/sparc64/mm/init.c 2004-11-17 03:54:21.158379803 -0800 @@ -63,6 +63,7 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; /* Initial ramdisk setup */ +extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; extern unsigned int sparc_ramdisk_size; @@ -1251,10 +1252,12 @@ #ifdef CONFIG_BLK_DEV_INITRD /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ - if (sparc_ramdisk_image) { - if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) - sparc_ramdisk_image -= KERNBASE; - initrd_start = sparc_ramdisk_image + phys_base; + if (sparc_ramdisk_image || sparc_ramdisk_image64) { + unsigned long ramdisk_image = sparc_ramdisk_image ? + sparc_ramdisk_image : sparc_ramdisk_image64; + if (ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) + ramdisk_image -= KERNBASE; + initrd_start = ramdisk_image + phys_base; initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > end_of_phys_memory) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -1300,6 +1303,10 @@ initrd_start, size); #endif /* Resert the initrd image area. */ +#ifdef CONFIG_DEBUG_BOOTMEM + prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n", + initrd_start, initrd_end); +#endif reserve_bootmem(initrd_start, size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -1353,7 +1360,7 @@ if ((real_end > ((unsigned long)KERNBASE + 0x400000))) bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD - if (sparc_ramdisk_image) + if (sparc_ramdisk_image || sparc_ramdisk_image64) real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size)); #endif diff -urN linux-2.4.27/arch/x86_64/boot/compressed/misc.c linux-2.4.28/arch/x86_64/boot/compressed/misc.c --- linux-2.4.27/arch/x86_64/boot/compressed/misc.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/arch/x86_64/boot/compressed/misc.c 2004-11-17 03:54:21.158379803 -0800 @@ -96,7 +96,7 @@ static void gzip_mark(void **); static void gzip_release(void **); -static void puts(const char *); +static void putstr(const char *); extern int end; static long free_mem_ptr = (long)&end; @@ -157,7 +157,7 @@ vidmem[i] = ' '; } -static void puts(const char *s) +static void putstr(const char *s) { int x,y,pos; char c; @@ -275,9 +275,9 @@ static void error(char *x) { - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); + putstr("\n\n"); + putstr(x); + putstr("\n\n -- System halted"); while(1); } @@ -351,9 +351,9 @@ else setup_output_buffer_if_we_run_high(mv); makecrc(); - puts(".\nDecompressing Linux..."); + putstr(".\nDecompressing Linux..."); gunzip(); - puts("done.\nBooting the kernel.\n"); + putstr("done.\nBooting the kernel.\n"); if (high_loaded) close_output_buffer_if_we_run_high(mv); return high_loaded; } diff -urN linux-2.4.27/arch/x86_64/config.in linux-2.4.28/arch/x86_64/config.in --- linux-2.4.27/arch/x86_64/config.in 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/arch/x86_64/config.in 2004-11-17 03:54:21.159379844 -0800 @@ -117,7 +117,7 @@ define_bool CONFIG_KCORE_ELF y fi #tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Power Management support' CONFIG_PM diff -urN linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.28/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/arch/x86_64/ia32/ia32_ioctl.c 2004-11-17 03:54:21.162379967 -0800 @@ -1171,6 +1171,7 @@ case FDDEFPRM32: case FDGETPRM32: { + u32 name; struct floppy_struct *f; f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); @@ -1187,7 +1188,8 @@ err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + err |= __get_user(name, &((struct floppy_struct32 *)arg)->name); + f->name = (void*)(u64)name; if (err) { err = -EFAULT; goto out; @@ -2726,13 +2728,15 @@ { struct blkpg_ioctl_arg a; struct blkpg_partition p; + u32 udata; int err; mm_segment_t old_fs = get_fs(); err = get_user(a.op, &arg->op); err |= __get_user(a.flags, &arg->flags); err |= __get_user(a.datalen, &arg->datalen); - err |= __get_user((long)a.data, &arg->data); + err |= __get_user(udata, &arg->data); + a.data = (void*)(u64)udata; if (err) return err; switch (a.op) { case BLKPG_ADD_PARTITION: diff -urN linux-2.4.27/arch/x86_64/ia32/socket32.c linux-2.4.28/arch/x86_64/ia32/socket32.c --- linux-2.4.27/arch/x86_64/ia32/socket32.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/arch/x86_64/ia32/socket32.c 2004-11-17 03:54:21.163380008 -0800 @@ -555,7 +555,7 @@ asmlinkage long sys32_setsockopt(int fd, int level, int optname, char *optval, int optlen) { - if (optname == SO_ATTACH_FILTER) + if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) diff -urN linux-2.4.27/arch/x86_64/ia32/sys_ia32.c linux-2.4.28/arch/x86_64/ia32/sys_ia32.c --- linux-2.4.27/arch/x86_64/ia32/sys_ia32.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/arch/x86_64/ia32/sys_ia32.c 2004-11-17 03:54:21.165380091 -0800 @@ -384,12 +384,16 @@ return -EINVAL; if (act) { + u32 handler, restorer; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer)|| + __get_user(restorer, &act->sa_restorer)|| __copy_from_user(&set32, &act->sa_mask, sizeof(sigset32_t))) return -EFAULT; + new_ka.sa.sa_handler = (void*)(u64)handler; + new_ka.sa.sa_restorer = (void*)(u64)restorer; /* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */ switch (_NSIG_WORDS) { @@ -441,13 +445,16 @@ if (act) { old_sigset32_t mask; + u32 handler, restorer; if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(restorer, &act->sa_restorer) || __get_user(mask, &act->sa_mask)) return -EFAULT; + new_ka.sa.sa_handler = (void*)(u64)handler; + new_ka.sa.sa_restorer = (void*)(u64)restorer; siginitset(&new_ka.sa.sa_mask, mask); } @@ -778,7 +785,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = ((void *)dirent) + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; diff -urN linux-2.4.27/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.28/arch/x86_64/kernel/x8664_ksyms.c --- linux-2.4.27/arch/x86_64/kernel/x8664_ksyms.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/arch/x86_64/kernel/x8664_ksyms.c 2004-11-17 03:54:21.165380091 -0800 @@ -157,7 +157,7 @@ extern __kernel_size_t strlen(const char *); extern int strcmp(const char *,const char *); extern char * strcpy(char *,const char *); -extern char * bcopy(const char * src, char * dest, int count); +extern void bcopy(const void * src, void * dest, size_t count); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(__memcpy); diff -urN linux-2.4.27/arch/x86_64/lib/usercopy.c linux-2.4.28/arch/x86_64/lib/usercopy.c --- linux-2.4.27/arch/x86_64/lib/usercopy.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/arch/x86_64/lib/usercopy.c 2004-11-17 03:54:21.166380132 -0800 @@ -88,7 +88,7 @@ " .quad 1b,2b\n" ".previous" : [size8] "=c"(size), [dst] "=&D" (__d0) - : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr), + : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr), [zero] "r" (0UL), [eight] "r" (8UL)); return size; } diff -urN linux-2.4.27/crypto/Config.in linux-2.4.28/crypto/Config.in --- linux-2.4.27/crypto/Config.in 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/Config.in 2004-11-17 03:54:21.166380132 -0800 @@ -58,6 +58,7 @@ fi tristate ' SHA256 digest algorithm' CONFIG_CRYPTO_SHA256 tristate ' SHA384 and SHA512 digest algorithms' CONFIG_CRYPTO_SHA512 + tristate ' Whirlpool digest algorithms' CONFIG_CRYPTO_WP512 if [ "$CONFIG_INET_ESP" = "y" -o \ "$CONFIG_INET_ESP" = "m" -o \ "$CONFIG_INET6_ESP" = "y" -o \ @@ -73,6 +74,8 @@ tristate ' CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5 tristate ' CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6 tristate ' TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA + tristate ' Khazad cipher algorithm' CONFIG_CRYPTO_KHAZAD + tristate ' Anubis cipher algorithm' CONFIG_CRYPTO_ANUBIS tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4 if [ "$CONFIG_INET_IPCOMP" = "y" -o \ "$CONFIG_INET_IPCOMP" = "m" -o \ diff -urN linux-2.4.27/crypto/Makefile linux-2.4.28/crypto/Makefile --- linux-2.4.27/crypto/Makefile 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/Makefile 2004-11-17 03:54:21.167380173 -0800 @@ -19,6 +19,7 @@ obj-$(CONFIG_CRYPTO_SHA1) += sha1.o obj-$(CONFIG_CRYPTO_SHA256) += sha256.o obj-$(CONFIG_CRYPTO_SHA512) += sha512.o +obj-$(CONFIG_CRYPTO_WP512) += wp512.o obj-$(CONFIG_CRYPTO_DES) += des.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o @@ -28,6 +29,8 @@ obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o +obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o +obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o diff -urN linux-2.4.27/crypto/aes.c linux-2.4.28/crypto/aes.c --- linux-2.4.27/crypto/aes.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/crypto/aes.c 2004-11-17 03:54:21.167380173 -0800 @@ -102,10 +102,10 @@ #define E_KEY ctx->E #define D_KEY ctx->D -static u8 pow_tab[256]; -static u8 log_tab[256]; -static u8 sbx_tab[256]; -static u8 isb_tab[256]; +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; static u32 rco_tab[10]; static u32 ft_tab[4][256]; static u32 it_tab[4][256]; @@ -113,7 +113,7 @@ static u32 fl_tab[4][256]; static u32 il_tab[4][256]; -static inline u8 +static inline u8 __init f_mult (u8 a, u8 b) { u8 aa = log_tab[a], cc = aa + log_tab[b]; @@ -153,14 +153,14 @@ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) -static void +static void __init gen_tabs (void) { u32 i, t; u8 p, q; /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest prmitive + 0x011b as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ for (i = 0, p = 1; i < 256; ++i) { diff -urN linux-2.4.27/crypto/anubis.c linux-2.4.28/crypto/anubis.c --- linux-2.4.27/crypto/anubis.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/crypto/anubis.c 2004-11-17 03:54:21.169380255 -0800 @@ -0,0 +1,719 @@ +/* + * Cryptographic API. + * + * Anubis Algorithm + * + * The Anubis algorithm was developed by Paulo S. L. M. Barreto and + * Vincent Rijmen. + * + * See + * + * P.S.L.M. Barreto, V. Rijmen, + * ``The Anubis block cipher,'' + * NESSIE submission, 2000. + * + * This software implements the "tweaked" version of Anubis. + * Only the S-box and (consequently) the rounds constants have been + * changed. + * + * The original authors have disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors + * have put this under the GNU General Public License. + * + * By Aaron Grothe ajgrothe@yahoo.com, October 28, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#define ANUBIS_MIN_KEY_SIZE 16 +#define ANUBIS_MAX_KEY_SIZE 40 +#define ANUBIS_BLOCK_SIZE 16 +#define ANUBIS_MAX_N 10 +#define ANUBIS_MAX_ROUNDS (8 + ANUBIS_MAX_N) + +struct anubis_ctx { + int key_len; // in bits + int R; + u32 E[ANUBIS_MAX_ROUNDS + 1][4]; + u32 D[ANUBIS_MAX_ROUNDS + 1][4]; +}; + +static const u32 T0[256] = { + 0xba69d2bbU, 0x54a84de5U, 0x2f5ebce2U, 0x74e8cd25U, + 0x53a651f7U, 0xd3bb6bd0U, 0xd2b96fd6U, 0x4d9a29b3U, + 0x50a05dfdU, 0xac458acfU, 0x8d070e09U, 0xbf63c6a5U, + 0x70e0dd3dU, 0x52a455f1U, 0x9a29527bU, 0x4c982db5U, + 0xeac98f46U, 0xd5b773c4U, 0x97336655U, 0xd1bf63dcU, + 0x3366ccaaU, 0x51a259fbU, 0x5bb671c7U, 0xa651a2f3U, + 0xdea15ffeU, 0x48903dadU, 0xa84d9ad7U, 0x992f5e71U, + 0xdbab4be0U, 0x3264c8acU, 0xb773e695U, 0xfce5d732U, + 0xe3dbab70U, 0x9e214263U, 0x913f7e41U, 0x9b2b567dU, + 0xe2d9af76U, 0xbb6bd6bdU, 0x4182199bU, 0x6edca579U, + 0xa557aef9U, 0xcb8b0b80U, 0x6bd6b167U, 0x95376e59U, + 0xa15fbee1U, 0xf3fbeb10U, 0xb17ffe81U, 0x0204080cU, + 0xcc851792U, 0xc49537a2U, 0x1d3a744eU, 0x14285078U, + 0xc39b2bb0U, 0x63c69157U, 0xdaa94fe6U, 0x5dba69d3U, + 0x5fbe61dfU, 0xdca557f2U, 0x7dfae913U, 0xcd871394U, + 0x7ffee11fU, 0x5ab475c1U, 0x6cd8ad75U, 0x5cb86dd5U, + 0xf7f3fb08U, 0x264c98d4U, 0xffe3db38U, 0xedc79354U, + 0xe8cd874aU, 0x9d274e69U, 0x6fdea17fU, 0x8e010203U, + 0x19326456U, 0xa05dbae7U, 0xf0fde71aU, 0x890f1e11U, + 0x0f1e3c22U, 0x070e1c12U, 0xaf4386c5U, 0xfbebcb20U, + 0x08102030U, 0x152a547eU, 0x0d1a342eU, 0x04081018U, + 0x01020406U, 0x64c88d45U, 0xdfa35bf8U, 0x76ecc529U, + 0x79f2f90bU, 0xdda753f4U, 0x3d7af48eU, 0x162c5874U, + 0x3f7efc82U, 0x376edcb2U, 0x6ddaa973U, 0x3870e090U, + 0xb96fdeb1U, 0x73e6d137U, 0xe9cf834cU, 0x356ad4beU, + 0x55aa49e3U, 0x71e2d93bU, 0x7bf6f107U, 0x8c050a0fU, + 0x72e4d531U, 0x880d1a17U, 0xf6f1ff0eU, 0x2a54a8fcU, + 0x3e7cf884U, 0x5ebc65d9U, 0x274e9cd2U, 0x468c0589U, + 0x0c183028U, 0x65ca8943U, 0x68d0bd6dU, 0x61c2995bU, + 0x03060c0aU, 0xc19f23bcU, 0x57ae41efU, 0xd6b17fceU, + 0xd9af43ecU, 0x58b07dcdU, 0xd8ad47eaU, 0x66cc8549U, + 0xd7b37bc8U, 0x3a74e89cU, 0xc88d078aU, 0x3c78f088U, + 0xfae9cf26U, 0x96316253U, 0xa753a6f5U, 0x982d5a77U, + 0xecc59752U, 0xb86ddab7U, 0xc7933ba8U, 0xae4182c3U, + 0x69d2b96bU, 0x4b9631a7U, 0xab4b96ddU, 0xa94f9ed1U, + 0x67ce814fU, 0x0a14283cU, 0x478e018fU, 0xf2f9ef16U, + 0xb577ee99U, 0x224488ccU, 0xe5d7b364U, 0xeec19f5eU, + 0xbe61c2a3U, 0x2b56acfaU, 0x811f3e21U, 0x1224486cU, + 0x831b362dU, 0x1b366c5aU, 0x0e1c3824U, 0x23468ccaU, + 0xf5f7f304U, 0x458a0983U, 0x214284c6U, 0xce811f9eU, + 0x499239abU, 0x2c58b0e8U, 0xf9efc32cU, 0xe6d1bf6eU, + 0xb671e293U, 0x2850a0f0U, 0x172e5c72U, 0x8219322bU, + 0x1a34685cU, 0x8b0b161dU, 0xfee1df3eU, 0x8a09121bU, + 0x09122436U, 0xc98f038cU, 0x87132635U, 0x4e9c25b9U, + 0xe1dfa37cU, 0x2e5cb8e4U, 0xe4d5b762U, 0xe0dda77aU, + 0xebcb8b40U, 0x903d7a47U, 0xa455aaffU, 0x1e3c7844U, + 0x85172e39U, 0x60c09d5dU, 0x00000000U, 0x254a94deU, + 0xf4f5f702U, 0xf1ffe31cU, 0x94356a5fU, 0x0b162c3aU, + 0xe7d3bb68U, 0x75eac923U, 0xefc39b58U, 0x3468d0b8U, + 0x3162c4a6U, 0xd4b577c2U, 0xd0bd67daU, 0x86112233U, + 0x7efce519U, 0xad478ec9U, 0xfde7d334U, 0x2952a4f6U, + 0x3060c0a0U, 0x3b76ec9aU, 0x9f234665U, 0xf8edc72aU, + 0xc6913faeU, 0x13264c6aU, 0x060c1814U, 0x050a141eU, + 0xc59733a4U, 0x11224466U, 0x77eec12fU, 0x7cf8ed15U, + 0x7af4f501U, 0x78f0fd0dU, 0x366cd8b4U, 0x1c387048U, + 0x3972e496U, 0x59b279cbU, 0x18306050U, 0x56ac45e9U, + 0xb37bf68dU, 0xb07dfa87U, 0x244890d8U, 0x204080c0U, + 0xb279f28bU, 0x9239724bU, 0xa35bb6edU, 0xc09d27baU, + 0x44880d85U, 0x62c49551U, 0x10204060U, 0xb475ea9fU, + 0x84152a3fU, 0x43861197U, 0x933b764dU, 0xc2992fb6U, + 0x4a9435a1U, 0xbd67cea9U, 0x8f030605U, 0x2d5ab4eeU, + 0xbc65caafU, 0x9c254a6fU, 0x6ad4b561U, 0x40801d9dU, + 0xcf831b98U, 0xa259b2ebU, 0x801d3a27U, 0x4f9e21bfU, + 0x1f3e7c42U, 0xca890f86U, 0xaa4992dbU, 0x42841591U, +}; + +static const u32 T1[256] = { + 0x69babbd2U, 0xa854e54dU, 0x5e2fe2bcU, 0xe87425cdU, + 0xa653f751U, 0xbbd3d06bU, 0xb9d2d66fU, 0x9a4db329U, + 0xa050fd5dU, 0x45accf8aU, 0x078d090eU, 0x63bfa5c6U, + 0xe0703dddU, 0xa452f155U, 0x299a7b52U, 0x984cb52dU, + 0xc9ea468fU, 0xb7d5c473U, 0x33975566U, 0xbfd1dc63U, + 0x6633aaccU, 0xa251fb59U, 0xb65bc771U, 0x51a6f3a2U, + 0xa1defe5fU, 0x9048ad3dU, 0x4da8d79aU, 0x2f99715eU, + 0xabdbe04bU, 0x6432acc8U, 0x73b795e6U, 0xe5fc32d7U, + 0xdbe370abU, 0x219e6342U, 0x3f91417eU, 0x2b9b7d56U, + 0xd9e276afU, 0x6bbbbdd6U, 0x82419b19U, 0xdc6e79a5U, + 0x57a5f9aeU, 0x8bcb800bU, 0xd66b67b1U, 0x3795596eU, + 0x5fa1e1beU, 0xfbf310ebU, 0x7fb181feU, 0x04020c08U, + 0x85cc9217U, 0x95c4a237U, 0x3a1d4e74U, 0x28147850U, + 0x9bc3b02bU, 0xc6635791U, 0xa9dae64fU, 0xba5dd369U, + 0xbe5fdf61U, 0xa5dcf257U, 0xfa7d13e9U, 0x87cd9413U, + 0xfe7f1fe1U, 0xb45ac175U, 0xd86c75adU, 0xb85cd56dU, + 0xf3f708fbU, 0x4c26d498U, 0xe3ff38dbU, 0xc7ed5493U, + 0xcde84a87U, 0x279d694eU, 0xde6f7fa1U, 0x018e0302U, + 0x32195664U, 0x5da0e7baU, 0xfdf01ae7U, 0x0f89111eU, + 0x1e0f223cU, 0x0e07121cU, 0x43afc586U, 0xebfb20cbU, + 0x10083020U, 0x2a157e54U, 0x1a0d2e34U, 0x08041810U, + 0x02010604U, 0xc864458dU, 0xa3dff85bU, 0xec7629c5U, + 0xf2790bf9U, 0xa7ddf453U, 0x7a3d8ef4U, 0x2c167458U, + 0x7e3f82fcU, 0x6e37b2dcU, 0xda6d73a9U, 0x703890e0U, + 0x6fb9b1deU, 0xe67337d1U, 0xcfe94c83U, 0x6a35bed4U, + 0xaa55e349U, 0xe2713bd9U, 0xf67b07f1U, 0x058c0f0aU, + 0xe47231d5U, 0x0d88171aU, 0xf1f60effU, 0x542afca8U, + 0x7c3e84f8U, 0xbc5ed965U, 0x4e27d29cU, 0x8c468905U, + 0x180c2830U, 0xca654389U, 0xd0686dbdU, 0xc2615b99U, + 0x06030a0cU, 0x9fc1bc23U, 0xae57ef41U, 0xb1d6ce7fU, + 0xafd9ec43U, 0xb058cd7dU, 0xadd8ea47U, 0xcc664985U, + 0xb3d7c87bU, 0x743a9ce8U, 0x8dc88a07U, 0x783c88f0U, + 0xe9fa26cfU, 0x31965362U, 0x53a7f5a6U, 0x2d98775aU, + 0xc5ec5297U, 0x6db8b7daU, 0x93c7a83bU, 0x41aec382U, + 0xd2696bb9U, 0x964ba731U, 0x4babdd96U, 0x4fa9d19eU, + 0xce674f81U, 0x140a3c28U, 0x8e478f01U, 0xf9f216efU, + 0x77b599eeU, 0x4422cc88U, 0xd7e564b3U, 0xc1ee5e9fU, + 0x61bea3c2U, 0x562bfaacU, 0x1f81213eU, 0x24126c48U, + 0x1b832d36U, 0x361b5a6cU, 0x1c0e2438U, 0x4623ca8cU, + 0xf7f504f3U, 0x8a458309U, 0x4221c684U, 0x81ce9e1fU, + 0x9249ab39U, 0x582ce8b0U, 0xeff92cc3U, 0xd1e66ebfU, + 0x71b693e2U, 0x5028f0a0U, 0x2e17725cU, 0x19822b32U, + 0x341a5c68U, 0x0b8b1d16U, 0xe1fe3edfU, 0x098a1b12U, + 0x12093624U, 0x8fc98c03U, 0x13873526U, 0x9c4eb925U, + 0xdfe17ca3U, 0x5c2ee4b8U, 0xd5e462b7U, 0xdde07aa7U, + 0xcbeb408bU, 0x3d90477aU, 0x55a4ffaaU, 0x3c1e4478U, + 0x1785392eU, 0xc0605d9dU, 0x00000000U, 0x4a25de94U, + 0xf5f402f7U, 0xfff11ce3U, 0x35945f6aU, 0x160b3a2cU, + 0xd3e768bbU, 0xea7523c9U, 0xc3ef589bU, 0x6834b8d0U, + 0x6231a6c4U, 0xb5d4c277U, 0xbdd0da67U, 0x11863322U, + 0xfc7e19e5U, 0x47adc98eU, 0xe7fd34d3U, 0x5229f6a4U, + 0x6030a0c0U, 0x763b9aecU, 0x239f6546U, 0xedf82ac7U, + 0x91c6ae3fU, 0x26136a4cU, 0x0c061418U, 0x0a051e14U, + 0x97c5a433U, 0x22116644U, 0xee772fc1U, 0xf87c15edU, + 0xf47a01f5U, 0xf0780dfdU, 0x6c36b4d8U, 0x381c4870U, + 0x723996e4U, 0xb259cb79U, 0x30185060U, 0xac56e945U, + 0x7bb38df6U, 0x7db087faU, 0x4824d890U, 0x4020c080U, + 0x79b28bf2U, 0x39924b72U, 0x5ba3edb6U, 0x9dc0ba27U, + 0x8844850dU, 0xc4625195U, 0x20106040U, 0x75b49feaU, + 0x15843f2aU, 0x86439711U, 0x3b934d76U, 0x99c2b62fU, + 0x944aa135U, 0x67bda9ceU, 0x038f0506U, 0x5a2deeb4U, + 0x65bcafcaU, 0x259c6f4aU, 0xd46a61b5U, 0x80409d1dU, + 0x83cf981bU, 0x59a2ebb2U, 0x1d80273aU, 0x9e4fbf21U, + 0x3e1f427cU, 0x89ca860fU, 0x49aadb92U, 0x84429115U, +}; + +static const u32 T2[256] = { + 0xd2bbba69U, 0x4de554a8U, 0xbce22f5eU, 0xcd2574e8U, + 0x51f753a6U, 0x6bd0d3bbU, 0x6fd6d2b9U, 0x29b34d9aU, + 0x5dfd50a0U, 0x8acfac45U, 0x0e098d07U, 0xc6a5bf63U, + 0xdd3d70e0U, 0x55f152a4U, 0x527b9a29U, 0x2db54c98U, + 0x8f46eac9U, 0x73c4d5b7U, 0x66559733U, 0x63dcd1bfU, + 0xccaa3366U, 0x59fb51a2U, 0x71c75bb6U, 0xa2f3a651U, + 0x5ffedea1U, 0x3dad4890U, 0x9ad7a84dU, 0x5e71992fU, + 0x4be0dbabU, 0xc8ac3264U, 0xe695b773U, 0xd732fce5U, + 0xab70e3dbU, 0x42639e21U, 0x7e41913fU, 0x567d9b2bU, + 0xaf76e2d9U, 0xd6bdbb6bU, 0x199b4182U, 0xa5796edcU, + 0xaef9a557U, 0x0b80cb8bU, 0xb1676bd6U, 0x6e599537U, + 0xbee1a15fU, 0xeb10f3fbU, 0xfe81b17fU, 0x080c0204U, + 0x1792cc85U, 0x37a2c495U, 0x744e1d3aU, 0x50781428U, + 0x2bb0c39bU, 0x915763c6U, 0x4fe6daa9U, 0x69d35dbaU, + 0x61df5fbeU, 0x57f2dca5U, 0xe9137dfaU, 0x1394cd87U, + 0xe11f7ffeU, 0x75c15ab4U, 0xad756cd8U, 0x6dd55cb8U, + 0xfb08f7f3U, 0x98d4264cU, 0xdb38ffe3U, 0x9354edc7U, + 0x874ae8cdU, 0x4e699d27U, 0xa17f6fdeU, 0x02038e01U, + 0x64561932U, 0xbae7a05dU, 0xe71af0fdU, 0x1e11890fU, + 0x3c220f1eU, 0x1c12070eU, 0x86c5af43U, 0xcb20fbebU, + 0x20300810U, 0x547e152aU, 0x342e0d1aU, 0x10180408U, + 0x04060102U, 0x8d4564c8U, 0x5bf8dfa3U, 0xc52976ecU, + 0xf90b79f2U, 0x53f4dda7U, 0xf48e3d7aU, 0x5874162cU, + 0xfc823f7eU, 0xdcb2376eU, 0xa9736ddaU, 0xe0903870U, + 0xdeb1b96fU, 0xd13773e6U, 0x834ce9cfU, 0xd4be356aU, + 0x49e355aaU, 0xd93b71e2U, 0xf1077bf6U, 0x0a0f8c05U, + 0xd53172e4U, 0x1a17880dU, 0xff0ef6f1U, 0xa8fc2a54U, + 0xf8843e7cU, 0x65d95ebcU, 0x9cd2274eU, 0x0589468cU, + 0x30280c18U, 0x894365caU, 0xbd6d68d0U, 0x995b61c2U, + 0x0c0a0306U, 0x23bcc19fU, 0x41ef57aeU, 0x7fced6b1U, + 0x43ecd9afU, 0x7dcd58b0U, 0x47ead8adU, 0x854966ccU, + 0x7bc8d7b3U, 0xe89c3a74U, 0x078ac88dU, 0xf0883c78U, + 0xcf26fae9U, 0x62539631U, 0xa6f5a753U, 0x5a77982dU, + 0x9752ecc5U, 0xdab7b86dU, 0x3ba8c793U, 0x82c3ae41U, + 0xb96b69d2U, 0x31a74b96U, 0x96ddab4bU, 0x9ed1a94fU, + 0x814f67ceU, 0x283c0a14U, 0x018f478eU, 0xef16f2f9U, + 0xee99b577U, 0x88cc2244U, 0xb364e5d7U, 0x9f5eeec1U, + 0xc2a3be61U, 0xacfa2b56U, 0x3e21811fU, 0x486c1224U, + 0x362d831bU, 0x6c5a1b36U, 0x38240e1cU, 0x8cca2346U, + 0xf304f5f7U, 0x0983458aU, 0x84c62142U, 0x1f9ece81U, + 0x39ab4992U, 0xb0e82c58U, 0xc32cf9efU, 0xbf6ee6d1U, + 0xe293b671U, 0xa0f02850U, 0x5c72172eU, 0x322b8219U, + 0x685c1a34U, 0x161d8b0bU, 0xdf3efee1U, 0x121b8a09U, + 0x24360912U, 0x038cc98fU, 0x26358713U, 0x25b94e9cU, + 0xa37ce1dfU, 0xb8e42e5cU, 0xb762e4d5U, 0xa77ae0ddU, + 0x8b40ebcbU, 0x7a47903dU, 0xaaffa455U, 0x78441e3cU, + 0x2e398517U, 0x9d5d60c0U, 0x00000000U, 0x94de254aU, + 0xf702f4f5U, 0xe31cf1ffU, 0x6a5f9435U, 0x2c3a0b16U, + 0xbb68e7d3U, 0xc92375eaU, 0x9b58efc3U, 0xd0b83468U, + 0xc4a63162U, 0x77c2d4b5U, 0x67dad0bdU, 0x22338611U, + 0xe5197efcU, 0x8ec9ad47U, 0xd334fde7U, 0xa4f62952U, + 0xc0a03060U, 0xec9a3b76U, 0x46659f23U, 0xc72af8edU, + 0x3faec691U, 0x4c6a1326U, 0x1814060cU, 0x141e050aU, + 0x33a4c597U, 0x44661122U, 0xc12f77eeU, 0xed157cf8U, + 0xf5017af4U, 0xfd0d78f0U, 0xd8b4366cU, 0x70481c38U, + 0xe4963972U, 0x79cb59b2U, 0x60501830U, 0x45e956acU, + 0xf68db37bU, 0xfa87b07dU, 0x90d82448U, 0x80c02040U, + 0xf28bb279U, 0x724b9239U, 0xb6eda35bU, 0x27bac09dU, + 0x0d854488U, 0x955162c4U, 0x40601020U, 0xea9fb475U, + 0x2a3f8415U, 0x11974386U, 0x764d933bU, 0x2fb6c299U, + 0x35a14a94U, 0xcea9bd67U, 0x06058f03U, 0xb4ee2d5aU, + 0xcaafbc65U, 0x4a6f9c25U, 0xb5616ad4U, 0x1d9d4080U, + 0x1b98cf83U, 0xb2eba259U, 0x3a27801dU, 0x21bf4f9eU, + 0x7c421f3eU, 0x0f86ca89U, 0x92dbaa49U, 0x15914284U, +}; + +static const u32 T3[256] = { + 0xbbd269baU, 0xe54da854U, 0xe2bc5e2fU, 0x25cde874U, + 0xf751a653U, 0xd06bbbd3U, 0xd66fb9d2U, 0xb3299a4dU, + 0xfd5da050U, 0xcf8a45acU, 0x090e078dU, 0xa5c663bfU, + 0x3ddde070U, 0xf155a452U, 0x7b52299aU, 0xb52d984cU, + 0x468fc9eaU, 0xc473b7d5U, 0x55663397U, 0xdc63bfd1U, + 0xaacc6633U, 0xfb59a251U, 0xc771b65bU, 0xf3a251a6U, + 0xfe5fa1deU, 0xad3d9048U, 0xd79a4da8U, 0x715e2f99U, + 0xe04babdbU, 0xacc86432U, 0x95e673b7U, 0x32d7e5fcU, + 0x70abdbe3U, 0x6342219eU, 0x417e3f91U, 0x7d562b9bU, + 0x76afd9e2U, 0xbdd66bbbU, 0x9b198241U, 0x79a5dc6eU, + 0xf9ae57a5U, 0x800b8bcbU, 0x67b1d66bU, 0x596e3795U, + 0xe1be5fa1U, 0x10ebfbf3U, 0x81fe7fb1U, 0x0c080402U, + 0x921785ccU, 0xa23795c4U, 0x4e743a1dU, 0x78502814U, + 0xb02b9bc3U, 0x5791c663U, 0xe64fa9daU, 0xd369ba5dU, + 0xdf61be5fU, 0xf257a5dcU, 0x13e9fa7dU, 0x941387cdU, + 0x1fe1fe7fU, 0xc175b45aU, 0x75add86cU, 0xd56db85cU, + 0x08fbf3f7U, 0xd4984c26U, 0x38dbe3ffU, 0x5493c7edU, + 0x4a87cde8U, 0x694e279dU, 0x7fa1de6fU, 0x0302018eU, + 0x56643219U, 0xe7ba5da0U, 0x1ae7fdf0U, 0x111e0f89U, + 0x223c1e0fU, 0x121c0e07U, 0xc58643afU, 0x20cbebfbU, + 0x30201008U, 0x7e542a15U, 0x2e341a0dU, 0x18100804U, + 0x06040201U, 0x458dc864U, 0xf85ba3dfU, 0x29c5ec76U, + 0x0bf9f279U, 0xf453a7ddU, 0x8ef47a3dU, 0x74582c16U, + 0x82fc7e3fU, 0xb2dc6e37U, 0x73a9da6dU, 0x90e07038U, + 0xb1de6fb9U, 0x37d1e673U, 0x4c83cfe9U, 0xbed46a35U, + 0xe349aa55U, 0x3bd9e271U, 0x07f1f67bU, 0x0f0a058cU, + 0x31d5e472U, 0x171a0d88U, 0x0efff1f6U, 0xfca8542aU, + 0x84f87c3eU, 0xd965bc5eU, 0xd29c4e27U, 0x89058c46U, + 0x2830180cU, 0x4389ca65U, 0x6dbdd068U, 0x5b99c261U, + 0x0a0c0603U, 0xbc239fc1U, 0xef41ae57U, 0xce7fb1d6U, + 0xec43afd9U, 0xcd7db058U, 0xea47add8U, 0x4985cc66U, + 0xc87bb3d7U, 0x9ce8743aU, 0x8a078dc8U, 0x88f0783cU, + 0x26cfe9faU, 0x53623196U, 0xf5a653a7U, 0x775a2d98U, + 0x5297c5ecU, 0xb7da6db8U, 0xa83b93c7U, 0xc38241aeU, + 0x6bb9d269U, 0xa731964bU, 0xdd964babU, 0xd19e4fa9U, + 0x4f81ce67U, 0x3c28140aU, 0x8f018e47U, 0x16eff9f2U, + 0x99ee77b5U, 0xcc884422U, 0x64b3d7e5U, 0x5e9fc1eeU, + 0xa3c261beU, 0xfaac562bU, 0x213e1f81U, 0x6c482412U, + 0x2d361b83U, 0x5a6c361bU, 0x24381c0eU, 0xca8c4623U, + 0x04f3f7f5U, 0x83098a45U, 0xc6844221U, 0x9e1f81ceU, + 0xab399249U, 0xe8b0582cU, 0x2cc3eff9U, 0x6ebfd1e6U, + 0x93e271b6U, 0xf0a05028U, 0x725c2e17U, 0x2b321982U, + 0x5c68341aU, 0x1d160b8bU, 0x3edfe1feU, 0x1b12098aU, + 0x36241209U, 0x8c038fc9U, 0x35261387U, 0xb9259c4eU, + 0x7ca3dfe1U, 0xe4b85c2eU, 0x62b7d5e4U, 0x7aa7dde0U, + 0x408bcbebU, 0x477a3d90U, 0xffaa55a4U, 0x44783c1eU, + 0x392e1785U, 0x5d9dc060U, 0x00000000U, 0xde944a25U, + 0x02f7f5f4U, 0x1ce3fff1U, 0x5f6a3594U, 0x3a2c160bU, + 0x68bbd3e7U, 0x23c9ea75U, 0x589bc3efU, 0xb8d06834U, + 0xa6c46231U, 0xc277b5d4U, 0xda67bdd0U, 0x33221186U, + 0x19e5fc7eU, 0xc98e47adU, 0x34d3e7fdU, 0xf6a45229U, + 0xa0c06030U, 0x9aec763bU, 0x6546239fU, 0x2ac7edf8U, + 0xae3f91c6U, 0x6a4c2613U, 0x14180c06U, 0x1e140a05U, + 0xa43397c5U, 0x66442211U, 0x2fc1ee77U, 0x15edf87cU, + 0x01f5f47aU, 0x0dfdf078U, 0xb4d86c36U, 0x4870381cU, + 0x96e47239U, 0xcb79b259U, 0x50603018U, 0xe945ac56U, + 0x8df67bb3U, 0x87fa7db0U, 0xd8904824U, 0xc0804020U, + 0x8bf279b2U, 0x4b723992U, 0xedb65ba3U, 0xba279dc0U, + 0x850d8844U, 0x5195c462U, 0x60402010U, 0x9fea75b4U, + 0x3f2a1584U, 0x97118643U, 0x4d763b93U, 0xb62f99c2U, + 0xa135944aU, 0xa9ce67bdU, 0x0506038fU, 0xeeb45a2dU, + 0xafca65bcU, 0x6f4a259cU, 0x61b5d46aU, 0x9d1d8040U, + 0x981b83cfU, 0xebb259a2U, 0x273a1d80U, 0xbf219e4fU, + 0x427c3e1fU, 0x860f89caU, 0xdb9249aaU, 0x91158442U, +}; + +static const u32 T4[256] = { + 0xbabababaU, 0x54545454U, 0x2f2f2f2fU, 0x74747474U, + 0x53535353U, 0xd3d3d3d3U, 0xd2d2d2d2U, 0x4d4d4d4dU, + 0x50505050U, 0xacacacacU, 0x8d8d8d8dU, 0xbfbfbfbfU, + 0x70707070U, 0x52525252U, 0x9a9a9a9aU, 0x4c4c4c4cU, + 0xeaeaeaeaU, 0xd5d5d5d5U, 0x97979797U, 0xd1d1d1d1U, + 0x33333333U, 0x51515151U, 0x5b5b5b5bU, 0xa6a6a6a6U, + 0xdedededeU, 0x48484848U, 0xa8a8a8a8U, 0x99999999U, + 0xdbdbdbdbU, 0x32323232U, 0xb7b7b7b7U, 0xfcfcfcfcU, + 0xe3e3e3e3U, 0x9e9e9e9eU, 0x91919191U, 0x9b9b9b9bU, + 0xe2e2e2e2U, 0xbbbbbbbbU, 0x41414141U, 0x6e6e6e6eU, + 0xa5a5a5a5U, 0xcbcbcbcbU, 0x6b6b6b6bU, 0x95959595U, + 0xa1a1a1a1U, 0xf3f3f3f3U, 0xb1b1b1b1U, 0x02020202U, + 0xccccccccU, 0xc4c4c4c4U, 0x1d1d1d1dU, 0x14141414U, + 0xc3c3c3c3U, 0x63636363U, 0xdadadadaU, 0x5d5d5d5dU, + 0x5f5f5f5fU, 0xdcdcdcdcU, 0x7d7d7d7dU, 0xcdcdcdcdU, + 0x7f7f7f7fU, 0x5a5a5a5aU, 0x6c6c6c6cU, 0x5c5c5c5cU, + 0xf7f7f7f7U, 0x26262626U, 0xffffffffU, 0xededededU, + 0xe8e8e8e8U, 0x9d9d9d9dU, 0x6f6f6f6fU, 0x8e8e8e8eU, + 0x19191919U, 0xa0a0a0a0U, 0xf0f0f0f0U, 0x89898989U, + 0x0f0f0f0fU, 0x07070707U, 0xafafafafU, 0xfbfbfbfbU, + 0x08080808U, 0x15151515U, 0x0d0d0d0dU, 0x04040404U, + 0x01010101U, 0x64646464U, 0xdfdfdfdfU, 0x76767676U, + 0x79797979U, 0xddddddddU, 0x3d3d3d3dU, 0x16161616U, + 0x3f3f3f3fU, 0x37373737U, 0x6d6d6d6dU, 0x38383838U, + 0xb9b9b9b9U, 0x73737373U, 0xe9e9e9e9U, 0x35353535U, + 0x55555555U, 0x71717171U, 0x7b7b7b7bU, 0x8c8c8c8cU, + 0x72727272U, 0x88888888U, 0xf6f6f6f6U, 0x2a2a2a2aU, + 0x3e3e3e3eU, 0x5e5e5e5eU, 0x27272727U, 0x46464646U, + 0x0c0c0c0cU, 0x65656565U, 0x68686868U, 0x61616161U, + 0x03030303U, 0xc1c1c1c1U, 0x57575757U, 0xd6d6d6d6U, + 0xd9d9d9d9U, 0x58585858U, 0xd8d8d8d8U, 0x66666666U, + 0xd7d7d7d7U, 0x3a3a3a3aU, 0xc8c8c8c8U, 0x3c3c3c3cU, + 0xfafafafaU, 0x96969696U, 0xa7a7a7a7U, 0x98989898U, + 0xececececU, 0xb8b8b8b8U, 0xc7c7c7c7U, 0xaeaeaeaeU, + 0x69696969U, 0x4b4b4b4bU, 0xababababU, 0xa9a9a9a9U, + 0x67676767U, 0x0a0a0a0aU, 0x47474747U, 0xf2f2f2f2U, + 0xb5b5b5b5U, 0x22222222U, 0xe5e5e5e5U, 0xeeeeeeeeU, + 0xbebebebeU, 0x2b2b2b2bU, 0x81818181U, 0x12121212U, + 0x83838383U, 0x1b1b1b1bU, 0x0e0e0e0eU, 0x23232323U, + 0xf5f5f5f5U, 0x45454545U, 0x21212121U, 0xcecececeU, + 0x49494949U, 0x2c2c2c2cU, 0xf9f9f9f9U, 0xe6e6e6e6U, + 0xb6b6b6b6U, 0x28282828U, 0x17171717U, 0x82828282U, + 0x1a1a1a1aU, 0x8b8b8b8bU, 0xfefefefeU, 0x8a8a8a8aU, + 0x09090909U, 0xc9c9c9c9U, 0x87878787U, 0x4e4e4e4eU, + 0xe1e1e1e1U, 0x2e2e2e2eU, 0xe4e4e4e4U, 0xe0e0e0e0U, + 0xebebebebU, 0x90909090U, 0xa4a4a4a4U, 0x1e1e1e1eU, + 0x85858585U, 0x60606060U, 0x00000000U, 0x25252525U, + 0xf4f4f4f4U, 0xf1f1f1f1U, 0x94949494U, 0x0b0b0b0bU, + 0xe7e7e7e7U, 0x75757575U, 0xefefefefU, 0x34343434U, + 0x31313131U, 0xd4d4d4d4U, 0xd0d0d0d0U, 0x86868686U, + 0x7e7e7e7eU, 0xadadadadU, 0xfdfdfdfdU, 0x29292929U, + 0x30303030U, 0x3b3b3b3bU, 0x9f9f9f9fU, 0xf8f8f8f8U, + 0xc6c6c6c6U, 0x13131313U, 0x06060606U, 0x05050505U, + 0xc5c5c5c5U, 0x11111111U, 0x77777777U, 0x7c7c7c7cU, + 0x7a7a7a7aU, 0x78787878U, 0x36363636U, 0x1c1c1c1cU, + 0x39393939U, 0x59595959U, 0x18181818U, 0x56565656U, + 0xb3b3b3b3U, 0xb0b0b0b0U, 0x24242424U, 0x20202020U, + 0xb2b2b2b2U, 0x92929292U, 0xa3a3a3a3U, 0xc0c0c0c0U, + 0x44444444U, 0x62626262U, 0x10101010U, 0xb4b4b4b4U, + 0x84848484U, 0x43434343U, 0x93939393U, 0xc2c2c2c2U, + 0x4a4a4a4aU, 0xbdbdbdbdU, 0x8f8f8f8fU, 0x2d2d2d2dU, + 0xbcbcbcbcU, 0x9c9c9c9cU, 0x6a6a6a6aU, 0x40404040U, + 0xcfcfcfcfU, 0xa2a2a2a2U, 0x80808080U, 0x4f4f4f4fU, + 0x1f1f1f1fU, 0xcacacacaU, 0xaaaaaaaaU, 0x42424242U, +}; + +static const u32 T5[256] = { + 0x00000000U, 0x01020608U, 0x02040c10U, 0x03060a18U, + 0x04081820U, 0x050a1e28U, 0x060c1430U, 0x070e1238U, + 0x08103040U, 0x09123648U, 0x0a143c50U, 0x0b163a58U, + 0x0c182860U, 0x0d1a2e68U, 0x0e1c2470U, 0x0f1e2278U, + 0x10206080U, 0x11226688U, 0x12246c90U, 0x13266a98U, + 0x142878a0U, 0x152a7ea8U, 0x162c74b0U, 0x172e72b8U, + 0x183050c0U, 0x193256c8U, 0x1a345cd0U, 0x1b365ad8U, + 0x1c3848e0U, 0x1d3a4ee8U, 0x1e3c44f0U, 0x1f3e42f8U, + 0x2040c01dU, 0x2142c615U, 0x2244cc0dU, 0x2346ca05U, + 0x2448d83dU, 0x254ade35U, 0x264cd42dU, 0x274ed225U, + 0x2850f05dU, 0x2952f655U, 0x2a54fc4dU, 0x2b56fa45U, + 0x2c58e87dU, 0x2d5aee75U, 0x2e5ce46dU, 0x2f5ee265U, + 0x3060a09dU, 0x3162a695U, 0x3264ac8dU, 0x3366aa85U, + 0x3468b8bdU, 0x356abeb5U, 0x366cb4adU, 0x376eb2a5U, + 0x387090ddU, 0x397296d5U, 0x3a749ccdU, 0x3b769ac5U, + 0x3c7888fdU, 0x3d7a8ef5U, 0x3e7c84edU, 0x3f7e82e5U, + 0x40809d3aU, 0x41829b32U, 0x4284912aU, 0x43869722U, + 0x4488851aU, 0x458a8312U, 0x468c890aU, 0x478e8f02U, + 0x4890ad7aU, 0x4992ab72U, 0x4a94a16aU, 0x4b96a762U, + 0x4c98b55aU, 0x4d9ab352U, 0x4e9cb94aU, 0x4f9ebf42U, + 0x50a0fdbaU, 0x51a2fbb2U, 0x52a4f1aaU, 0x53a6f7a2U, + 0x54a8e59aU, 0x55aae392U, 0x56ace98aU, 0x57aeef82U, + 0x58b0cdfaU, 0x59b2cbf2U, 0x5ab4c1eaU, 0x5bb6c7e2U, + 0x5cb8d5daU, 0x5dbad3d2U, 0x5ebcd9caU, 0x5fbedfc2U, + 0x60c05d27U, 0x61c25b2fU, 0x62c45137U, 0x63c6573fU, + 0x64c84507U, 0x65ca430fU, 0x66cc4917U, 0x67ce4f1fU, + 0x68d06d67U, 0x69d26b6fU, 0x6ad46177U, 0x6bd6677fU, + 0x6cd87547U, 0x6dda734fU, 0x6edc7957U, 0x6fde7f5fU, + 0x70e03da7U, 0x71e23bafU, 0x72e431b7U, 0x73e637bfU, + 0x74e82587U, 0x75ea238fU, 0x76ec2997U, 0x77ee2f9fU, + 0x78f00de7U, 0x79f20befU, 0x7af401f7U, 0x7bf607ffU, + 0x7cf815c7U, 0x7dfa13cfU, 0x7efc19d7U, 0x7ffe1fdfU, + 0x801d2774U, 0x811f217cU, 0x82192b64U, 0x831b2d6cU, + 0x84153f54U, 0x8517395cU, 0x86113344U, 0x8713354cU, + 0x880d1734U, 0x890f113cU, 0x8a091b24U, 0x8b0b1d2cU, + 0x8c050f14U, 0x8d07091cU, 0x8e010304U, 0x8f03050cU, + 0x903d47f4U, 0x913f41fcU, 0x92394be4U, 0x933b4decU, + 0x94355fd4U, 0x953759dcU, 0x963153c4U, 0x973355ccU, + 0x982d77b4U, 0x992f71bcU, 0x9a297ba4U, 0x9b2b7dacU, + 0x9c256f94U, 0x9d27699cU, 0x9e216384U, 0x9f23658cU, + 0xa05de769U, 0xa15fe161U, 0xa259eb79U, 0xa35bed71U, + 0xa455ff49U, 0xa557f941U, 0xa651f359U, 0xa753f551U, + 0xa84dd729U, 0xa94fd121U, 0xaa49db39U, 0xab4bdd31U, + 0xac45cf09U, 0xad47c901U, 0xae41c319U, 0xaf43c511U, + 0xb07d87e9U, 0xb17f81e1U, 0xb2798bf9U, 0xb37b8df1U, + 0xb4759fc9U, 0xb57799c1U, 0xb67193d9U, 0xb77395d1U, + 0xb86db7a9U, 0xb96fb1a1U, 0xba69bbb9U, 0xbb6bbdb1U, + 0xbc65af89U, 0xbd67a981U, 0xbe61a399U, 0xbf63a591U, + 0xc09dba4eU, 0xc19fbc46U, 0xc299b65eU, 0xc39bb056U, + 0xc495a26eU, 0xc597a466U, 0xc691ae7eU, 0xc793a876U, + 0xc88d8a0eU, 0xc98f8c06U, 0xca89861eU, 0xcb8b8016U, + 0xcc85922eU, 0xcd879426U, 0xce819e3eU, 0xcf839836U, + 0xd0bddaceU, 0xd1bfdcc6U, 0xd2b9d6deU, 0xd3bbd0d6U, + 0xd4b5c2eeU, 0xd5b7c4e6U, 0xd6b1cefeU, 0xd7b3c8f6U, + 0xd8adea8eU, 0xd9afec86U, 0xdaa9e69eU, 0xdbabe096U, + 0xdca5f2aeU, 0xdda7f4a6U, 0xdea1febeU, 0xdfa3f8b6U, + 0xe0dd7a53U, 0xe1df7c5bU, 0xe2d97643U, 0xe3db704bU, + 0xe4d56273U, 0xe5d7647bU, 0xe6d16e63U, 0xe7d3686bU, + 0xe8cd4a13U, 0xe9cf4c1bU, 0xeac94603U, 0xebcb400bU, + 0xecc55233U, 0xedc7543bU, 0xeec15e23U, 0xefc3582bU, + 0xf0fd1ad3U, 0xf1ff1cdbU, 0xf2f916c3U, 0xf3fb10cbU, + 0xf4f502f3U, 0xf5f704fbU, 0xf6f10ee3U, 0xf7f308ebU, + 0xf8ed2a93U, 0xf9ef2c9bU, 0xfae92683U, 0xfbeb208bU, + 0xfce532b3U, 0xfde734bbU, 0xfee13ea3U, 0xffe338abU, +}; + +static const u32 rc[] = { + 0xba542f74U, 0x53d3d24dU, 0x50ac8dbfU, 0x70529a4cU, + 0xead597d1U, 0x33515ba6U, 0xde48a899U, 0xdb32b7fcU, + 0xe39e919bU, 0xe2bb416eU, 0xa5cb6b95U, 0xa1f3b102U, + 0xccc41d14U, 0xc363da5dU, 0x5fdc7dcdU, 0x7f5a6c5cU, + 0xf726ffedU, 0xe89d6f8eU, 0x19a0f089U, +}; + +static int anubis_setkey(void *ctx_arg, const u8 *in_key, + unsigned int key_len, u32 *flags) +{ + + int N, R, i, pos, r; + u32 kappa[ANUBIS_MAX_N]; + u32 inter[ANUBIS_MAX_N]; + + struct anubis_ctx *ctx = ctx_arg; + + switch (key_len) + { + case 16: case 20: case 24: case 28: + case 32: case 36: case 40: + break; + default: + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return - EINVAL; + } + + ctx->key_len = key_len * 8; + N = ctx->key_len >> 5; + ctx->R = R = 8 + N; + + /* * map cipher key to initial key state (mu): */ + for (i = 0, pos = 0; i < N; i++, pos += 4) { + kappa[i] = + (in_key[pos ] << 24) ^ + (in_key[pos + 1] << 16) ^ + (in_key[pos + 2] << 8) ^ + (in_key[pos + 3] ); + } + + /* + * generate R + 1 round keys: + */ + for (r = 0; r <= R; r++) { + u32 K0, K1, K2, K3; + /* + * generate r-th round key K^r: + */ + K0 = T4[(kappa[N - 1] >> 24) ]; + K1 = T4[(kappa[N - 1] >> 16) & 0xff]; + K2 = T4[(kappa[N - 1] >> 8) & 0xff]; + K3 = T4[(kappa[N - 1] ) & 0xff]; + for (i = N - 2; i >= 0; i--) { + K0 = T4[(kappa[i] >> 24) ] ^ + (T5[(K0 >> 24) ] & 0xff000000U) ^ + (T5[(K0 >> 16) & 0xff] & 0x00ff0000U) ^ + (T5[(K0 >> 8) & 0xff] & 0x0000ff00U) ^ + (T5[(K0 ) & 0xff] & 0x000000ffU); + K1 = T4[(kappa[i] >> 16) & 0xff] ^ + (T5[(K1 >> 24) ] & 0xff000000U) ^ + (T5[(K1 >> 16) & 0xff] & 0x00ff0000U) ^ + (T5[(K1 >> 8) & 0xff] & 0x0000ff00U) ^ + (T5[(K1 ) & 0xff] & 0x000000ffU); + K2 = T4[(kappa[i] >> 8) & 0xff] ^ + (T5[(K2 >> 24) ] & 0xff000000U) ^ + (T5[(K2 >> 16) & 0xff] & 0x00ff0000U) ^ + (T5[(K2 >> 8) & 0xff] & 0x0000ff00U) ^ + (T5[(K2 ) & 0xff] & 0x000000ffU); + K3 = T4[(kappa[i] ) & 0xff] ^ + (T5[(K3 >> 24) ] & 0xff000000U) ^ + (T5[(K3 >> 16) & 0xff] & 0x00ff0000U) ^ + (T5[(K3 >> 8) & 0xff] & 0x0000ff00U) ^ + (T5[(K3 ) & 0xff] & 0x000000ffU); + } + + ctx->E[r][0] = K0; + ctx->E[r][1] = K1; + ctx->E[r][2] = K2; + ctx->E[r][3] = K3; + + /* + * compute kappa^{r+1} from kappa^r: + */ + if (r == R) { + break; + } + for (i = 0; i < N; i++) { + int j = i; + inter[i] = T0[(kappa[j--] >> 24) ]; + if (j < 0) j = N - 1; + inter[i] ^= T1[(kappa[j--] >> 16) & 0xff]; + if (j < 0) j = N - 1; + inter[i] ^= T2[(kappa[j--] >> 8) & 0xff]; + if (j < 0) j = N - 1; + inter[i] ^= T3[(kappa[j ] ) & 0xff]; + } + kappa[0] = inter[0] ^ rc[r]; + for (i = 1; i < N; i++) { + kappa[i] = inter[i]; + } + } + + /* + * generate inverse key schedule: K'^0 = K^R, K'^R = + * K^0, K'^r = theta(K^{R-r}): + */ + for (i = 0; i < 4; i++) { + ctx->D[0][i] = ctx->E[R][i]; + ctx->D[R][i] = ctx->E[0][i]; + } + for (r = 1; r < R; r++) { + for (i = 0; i < 4; i++) { + u32 v = ctx->E[R - r][i]; + ctx->D[r][i] = + T0[T4[(v >> 24) ] & 0xff] ^ + T1[T4[(v >> 16) & 0xff] & 0xff] ^ + T2[T4[(v >> 8) & 0xff] & 0xff] ^ + T3[T4[(v ) & 0xff] & 0xff]; + } + } + + return 0; +} + +static void anubis_crypt(u32 roundKey[ANUBIS_MAX_ROUNDS + 1][4], + u8 *ciphertext, const u8 *plaintext, const int R) +{ + int i, pos, r; + u32 state[4]; + u32 inter[4]; + + /* + * map plaintext block to cipher state (mu) + * and add initial round key (sigma[K^0]): + */ + for (i = 0, pos = 0; i < 4; i++, pos += 4) { + state[i] = + (plaintext[pos ] << 24) ^ + (plaintext[pos + 1] << 16) ^ + (plaintext[pos + 2] << 8) ^ + (plaintext[pos + 3] ) ^ + roundKey[0][i]; + } + + /* + * R - 1 full rounds: + */ + + for (r = 1; r < R; r++) { + inter[0] = + T0[(state[0] >> 24) ] ^ + T1[(state[1] >> 24) ] ^ + T2[(state[2] >> 24) ] ^ + T3[(state[3] >> 24) ] ^ + roundKey[r][0]; + inter[1] = + T0[(state[0] >> 16) & 0xff] ^ + T1[(state[1] >> 16) & 0xff] ^ + T2[(state[2] >> 16) & 0xff] ^ + T3[(state[3] >> 16) & 0xff] ^ + roundKey[r][1]; + inter[2] = + T0[(state[0] >> 8) & 0xff] ^ + T1[(state[1] >> 8) & 0xff] ^ + T2[(state[2] >> 8) & 0xff] ^ + T3[(state[3] >> 8) & 0xff] ^ + roundKey[r][2]; + inter[3] = + T0[(state[0] ) & 0xff] ^ + T1[(state[1] ) & 0xff] ^ + T2[(state[2] ) & 0xff] ^ + T3[(state[3] ) & 0xff] ^ + roundKey[r][3]; + state[0] = inter[0]; + state[1] = inter[1]; + state[2] = inter[2]; + state[3] = inter[3]; + } + + /* + * last round: + */ + + inter[0] = + (T0[(state[0] >> 24) ] & 0xff000000U) ^ + (T1[(state[1] >> 24) ] & 0x00ff0000U) ^ + (T2[(state[2] >> 24) ] & 0x0000ff00U) ^ + (T3[(state[3] >> 24) ] & 0x000000ffU) ^ + roundKey[R][0]; + inter[1] = + (T0[(state[0] >> 16) & 0xff] & 0xff000000U) ^ + (T1[(state[1] >> 16) & 0xff] & 0x00ff0000U) ^ + (T2[(state[2] >> 16) & 0xff] & 0x0000ff00U) ^ + (T3[(state[3] >> 16) & 0xff] & 0x000000ffU) ^ + roundKey[R][1]; + inter[2] = + (T0[(state[0] >> 8) & 0xff] & 0xff000000U) ^ + (T1[(state[1] >> 8) & 0xff] & 0x00ff0000U) ^ + (T2[(state[2] >> 8) & 0xff] & 0x0000ff00U) ^ + (T3[(state[3] >> 8) & 0xff] & 0x000000ffU) ^ + roundKey[R][2]; + inter[3] = + (T0[(state[0] ) & 0xff] & 0xff000000U) ^ + (T1[(state[1] ) & 0xff] & 0x00ff0000U) ^ + (T2[(state[2] ) & 0xff] & 0x0000ff00U) ^ + (T3[(state[3] ) & 0xff] & 0x000000ffU) ^ + roundKey[R][3]; + + /* + * map cipher state to ciphertext block (mu^{-1}): + */ + + for (i = 0, pos = 0; i < 4; i++, pos += 4) { + u32 w = inter[i]; + ciphertext[pos ] = (u8)(w >> 24); + ciphertext[pos + 1] = (u8)(w >> 16); + ciphertext[pos + 2] = (u8)(w >> 8); + ciphertext[pos + 3] = (u8)(w ); + } +} + +static void anubis_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct anubis_ctx *ctx = ctx_arg; + anubis_crypt(ctx->E, dst, src, ctx->R); +} + +static void anubis_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct anubis_ctx *ctx = ctx_arg; + anubis_crypt(ctx->D, dst, src, ctx->R); +} + +static struct crypto_alg anubis_alg = { + .cra_name = "anubis", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ANUBIS_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct anubis_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(anubis_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = ANUBIS_MIN_KEY_SIZE, + .cia_max_keysize = ANUBIS_MAX_KEY_SIZE, + .cia_setkey = anubis_setkey, + .cia_encrypt = anubis_encrypt, + .cia_decrypt = anubis_decrypt } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&anubis_alg); + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&anubis_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Anubis Cryptographic Algorithm"); diff -urN linux-2.4.27/crypto/api.c linux-2.4.28/crypto/api.c --- linux-2.4.27/crypto/api.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/crypto/api.c 2004-11-17 03:54:21.170380296 -0800 @@ -156,8 +156,12 @@ void crypto_free_tfm(struct crypto_tfm *tfm) { + struct crypto_alg *alg = tfm->__crt_alg; + int size = sizeof(*tfm) + alg->cra_ctxsize; + crypto_exit_ops(tfm); - crypto_alg_put(tfm->__crt_alg); + crypto_alg_put(alg); + memset(tfm, 0, size); kfree(tfm); } diff -urN linux-2.4.27/crypto/arc4.c linux-2.4.28/crypto/arc4.c --- linux-2.4.27/crypto/arc4.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/crypto/arc4.c 2004-11-17 03:54:21.170380296 -0800 @@ -3,7 +3,7 @@ * * ARC4 Cipher Algorithm * - * Jon Oberheide + * Jon Oberheide * * 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 @@ -100,4 +100,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); -MODULE_AUTHOR("Jon Oberheide "); +MODULE_AUTHOR("Jon Oberheide "); diff -urN linux-2.4.27/crypto/blowfish.c linux-2.4.28/crypto/blowfish.c --- linux-2.4.27/crypto/blowfish.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/crypto/blowfish.c 2004-11-17 03:54:21.171380337 -0800 @@ -3,9 +3,9 @@ * * Blowfish Cipher Algorithm, by Bruce Schneier. * http://www.counterpane.com/blowfish.html - * - * Adapated from Kerneli implementation. - * + * + * Adapted from Kerneli implementation. + * * Copyright (c) Herbert Valerio Riedel * Copyright (c) Kyle McMartin * Copyright (c) 2002 James Morris diff -urN linux-2.4.27/crypto/khazad.c linux-2.4.28/crypto/khazad.c --- linux-2.4.27/crypto/khazad.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/crypto/khazad.c 2004-11-17 03:54:21.174380461 -0800 @@ -0,0 +1,915 @@ +/* + * Cryptographic API. + * + * Khazad Algorithm + * + * The Khazad algorithm was developed by Paulo S. L. M. Barreto and + * Vincent Rijmen. It was a finalist in the NESSIE encryption contest. + * + * The original authors have disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors + * have put this under the GNU General Public License. + * + * By Aaron Grothe ajgrothe@yahoo.com, August 1, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#define KHAZAD_KEY_SIZE 16 +#define KHAZAD_BLOCK_SIZE 8 +#define KHAZAD_ROUNDS 8 + +struct khazad_ctx { + u64 E[KHAZAD_ROUNDS + 1]; + u64 D[KHAZAD_ROUNDS + 1]; +}; + +static const u64 T0[256] = { + 0xbad3d268bbb96a01ULL, 0x54fc4d19e59a66b1ULL, 0x2f71bc93e26514cdULL, + 0x749ccdb925871b51ULL, 0x53f55102f7a257a4ULL, 0xd3686bb8d0d6be03ULL, + 0xd26b6fbdd6deb504ULL, 0x4dd72964b35285feULL, 0x50f05d0dfdba4aadULL, + 0xace98a26cf09e063ULL, 0x8d8a0e83091c9684ULL, 0xbfdcc679a5914d1aULL, + 0x7090ddad3da7374dULL, 0x52f65507f1aa5ca3ULL, 0x9ab352c87ba417e1ULL, + 0x4cd42d61b55a8ef9ULL, 0xea238f65460320acULL, 0xd56273a6c4e68411ULL, + 0x97a466f155cc68c2ULL, 0xd16e63b2dcc6a80dULL, 0x3355ccffaa85d099ULL, + 0x51f35908fbb241aaULL, 0x5bed712ac7e20f9cULL, 0xa6f7a204f359ae55ULL, + 0xde7f5f81febec120ULL, 0x48d83d75ad7aa2e5ULL, 0xa8e59a32d729cc7fULL, + 0x99b65ec771bc0ae8ULL, 0xdb704b90e096e63bULL, 0x3256c8faac8ddb9eULL, + 0xb7c4e65195d11522ULL, 0xfc19d72b32b3aaceULL, 0xe338ab48704b7393ULL, + 0x9ebf42dc63843bfdULL, 0x91ae7eef41fc52d0ULL, 0x9bb056cd7dac1ce6ULL, + 0xe23baf4d76437894ULL, 0xbbd0d66dbdb16106ULL, 0x41c319589b32f1daULL, + 0x6eb2a5cb7957e517ULL, 0xa5f2ae0bf941b35cULL, 0xcb400bc08016564bULL, + 0x6bbdb1da677fc20cULL, 0x95a26efb59dc7eccULL, 0xa1febe1fe1619f40ULL, + 0xf308eb1810cbc3e3ULL, 0xb1cefe4f81e12f30ULL, 0x0206080a0c10160eULL, + 0xcc4917db922e675eULL, 0xc45137f3a26e3f66ULL, 0x1d2774694ee8cf53ULL, + 0x143c504478a09c6cULL, 0xc3582be8b0560e73ULL, 0x63a591f2573f9a34ULL, + 0xda734f95e69eed3cULL, 0x5de76934d3d2358eULL, 0x5fe1613edfc22380ULL, + 0xdc79578bf2aed72eULL, 0x7d87e99413cf486eULL, 0xcd4a13de94266c59ULL, + 0x7f81e19e1fdf5e60ULL, 0x5aee752fc1ea049bULL, 0x6cb4adc17547f319ULL, + 0x5ce46d31d5da3e89ULL, 0xf704fb0c08ebefffULL, 0x266a98bed42d47f2ULL, + 0xff1cdb2438abb7c7ULL, 0xed2a937e543b11b9ULL, 0xe825876f4a1336a2ULL, + 0x9dba4ed3699c26f4ULL, 0x6fb1a1ce7f5fee10ULL, 0x8e8f028c03048b8dULL, + 0x192b647d56c8e34fULL, 0xa0fdba1ae7699447ULL, 0xf00de7171ad3deeaULL, + 0x89861e97113cba98ULL, 0x0f113c332278692dULL, 0x07091c1b12383115ULL, + 0xafec8629c511fd6aULL, 0xfb10cb30208b9bdbULL, 0x0818202830405838ULL, + 0x153f54417ea8976bULL, 0x0d1734392e687f23ULL, 0x040c101418202c1cULL, + 0x0103040506080b07ULL, 0x64ac8de94507ab21ULL, 0xdf7c5b84f8b6ca27ULL, + 0x769ac5b329970d5fULL, 0x798bf9800bef6472ULL, 0xdd7a538ef4a6dc29ULL, + 0x3d47f4c98ef5b2b3ULL, 0x163a584e74b08a62ULL, 0x3f41fcc382e5a4bdULL, + 0x3759dcebb2a5fc85ULL, 0x6db7a9c4734ff81eULL, 0x3848e0d890dd95a8ULL, + 0xb9d6de67b1a17708ULL, 0x7395d1a237bf2a44ULL, 0xe926836a4c1b3da5ULL, + 0x355fd4e1beb5ea8bULL, 0x55ff491ce3926db6ULL, 0x7193d9a83baf3c4aULL, + 0x7b8df18a07ff727cULL, 0x8c890a860f149d83ULL, 0x7296d5a731b72143ULL, + 0x88851a921734b19fULL, 0xf607ff090ee3e4f8ULL, 0x2a7ea882fc4d33d6ULL, + 0x3e42f8c684edafbaULL, 0x5ee2653bd9ca2887ULL, 0x27699cbbd2254cf5ULL, + 0x46ca0543890ac0cfULL, 0x0c14303c28607424ULL, 0x65af89ec430fa026ULL, + 0x68b8bdd56d67df05ULL, 0x61a399f85b2f8c3aULL, 0x03050c0f0a181d09ULL, + 0xc15e23e2bc46187dULL, 0x57f94116ef827bb8ULL, 0xd6677fa9cefe9918ULL, + 0xd976439aec86f035ULL, 0x58e87d25cdfa1295ULL, 0xd875479fea8efb32ULL, + 0x66aa85e34917bd2fULL, 0xd7647bacc8f6921fULL, 0x3a4ee8d29ccd83a6ULL, + 0xc84507cf8a0e4b42ULL, 0x3c44f0cc88fdb9b4ULL, 0xfa13cf35268390dcULL, + 0x96a762f453c463c5ULL, 0xa7f4a601f551a552ULL, 0x98b55ac277b401efULL, + 0xec29977b52331abeULL, 0xb8d5da62b7a97c0fULL, 0xc7543bfca876226fULL, + 0xaeef822cc319f66dULL, 0x69bbb9d06b6fd402ULL, 0x4bdd317aa762bfecULL, + 0xabe0963ddd31d176ULL, 0xa9e69e37d121c778ULL, 0x67a981e64f1fb628ULL, + 0x0a1e28223c504e36ULL, 0x47c901468f02cbc8ULL, 0xf20bef1d16c3c8e4ULL, + 0xb5c2ee5b99c1032cULL, 0x226688aacc0d6beeULL, 0xe532b356647b4981ULL, + 0xee2f9f715e230cb0ULL, 0xbedfc27ca399461dULL, 0x2b7dac87fa4538d1ULL, + 0x819e3ebf217ce2a0ULL, 0x1236485a6c90a67eULL, 0x839836b52d6cf4aeULL, + 0x1b2d6c775ad8f541ULL, 0x0e1238362470622aULL, 0x23658cafca0560e9ULL, + 0xf502f30604fbf9f1ULL, 0x45cf094c8312ddc6ULL, 0x216384a5c61576e7ULL, + 0xce4f1fd19e3e7150ULL, 0x49db3970ab72a9e2ULL, 0x2c74b09ce87d09c4ULL, + 0xf916c33a2c9b8dd5ULL, 0xe637bf596e635488ULL, 0xb6c7e25493d91e25ULL, + 0x2878a088f05d25d8ULL, 0x17395c4b72b88165ULL, 0x829b32b02b64ffa9ULL, + 0x1a2e68725cd0fe46ULL, 0x8b80169d1d2cac96ULL, 0xfe1fdf213ea3bcc0ULL, + 0x8a8312981b24a791ULL, 0x091b242d3648533fULL, 0xc94603ca8c064045ULL, + 0x879426a1354cd8b2ULL, 0x4ed2256bb94a98f7ULL, 0xe13ea3427c5b659dULL, + 0x2e72b896e46d1fcaULL, 0xe431b75362734286ULL, 0xe03da7477a536e9aULL, + 0xeb208b60400b2babULL, 0x90ad7aea47f459d7ULL, 0xa4f1aa0eff49b85bULL, + 0x1e22786644f0d25aULL, 0x85922eab395ccebcULL, 0x60a09dfd5d27873dULL, + 0x0000000000000000ULL, 0x256f94b1de355afbULL, 0xf401f70302f3f2f6ULL, + 0xf10ee3121cdbd5edULL, 0x94a16afe5fd475cbULL, 0x0b1d2c273a584531ULL, + 0xe734bb5c686b5f8fULL, 0x759fc9bc238f1056ULL, 0xef2c9b74582b07b7ULL, + 0x345cd0e4b8bde18cULL, 0x3153c4f5a695c697ULL, 0xd46177a3c2ee8f16ULL, + 0xd06d67b7dacea30aULL, 0x869722a43344d3b5ULL, 0x7e82e59b19d75567ULL, + 0xadea8e23c901eb64ULL, 0xfd1ad32e34bba1c9ULL, 0x297ba48df6552edfULL, + 0x3050c0f0a09dcd90ULL, 0x3b4decd79ac588a1ULL, 0x9fbc46d9658c30faULL, + 0xf815c73f2a9386d2ULL, 0xc6573ff9ae7e2968ULL, 0x13354c5f6a98ad79ULL, + 0x060a181e14303a12ULL, 0x050f14111e28271bULL, 0xc55233f6a4663461ULL, + 0x113344556688bb77ULL, 0x7799c1b62f9f0658ULL, 0x7c84ed9115c74369ULL, + 0x7a8ef58f01f7797bULL, 0x7888fd850de76f75ULL, 0x365ad8eeb4adf782ULL, + 0x1c24706c48e0c454ULL, 0x394be4dd96d59eafULL, 0x59eb7920cbf21992ULL, + 0x1828607850c0e848ULL, 0x56fa4513e98a70bfULL, 0xb3c8f6458df1393eULL, + 0xb0cdfa4a87e92437ULL, 0x246c90b4d83d51fcULL, 0x206080a0c01d7de0ULL, + 0xb2cbf2408bf93239ULL, 0x92ab72e04be44fd9ULL, 0xa3f8b615ed71894eULL, + 0xc05d27e7ba4e137aULL, 0x44cc0d49851ad6c1ULL, 0x62a695f751379133ULL, + 0x103040506080b070ULL, 0xb4c1ea5e9fc9082bULL, 0x84912aae3f54c5bbULL, + 0x43c511529722e7d4ULL, 0x93a876e54dec44deULL, 0xc25b2fedb65e0574ULL, + 0x4ade357fa16ab4ebULL, 0xbddace73a9815b14ULL, 0x8f8c0689050c808aULL, + 0x2d77b499ee7502c3ULL, 0xbcd9ca76af895013ULL, 0x9cb94ad66f942df3ULL, + 0x6abeb5df6177c90bULL, 0x40c01d5d9d3afaddULL, 0xcf4c1bd498367a57ULL, + 0xa2fbb210eb798249ULL, 0x809d3aba2774e9a7ULL, 0x4fd1216ebf4293f0ULL, + 0x1f217c6342f8d95dULL, 0xca430fc5861e5d4cULL, 0xaae39238db39da71ULL, + 0x42c61557912aecd3ULL +}; + +static const u64 T1[256] = { + 0xd3ba68d2b9bb016aULL, 0xfc54194d9ae5b166ULL, 0x712f93bc65e2cd14ULL, + 0x9c74b9cd8725511bULL, 0xf5530251a2f7a457ULL, 0x68d3b86bd6d003beULL, + 0x6bd2bd6fded604b5ULL, 0xd74d642952b3fe85ULL, 0xf0500d5dbafdad4aULL, + 0xe9ac268a09cf63e0ULL, 0x8a8d830e1c098496ULL, 0xdcbf79c691a51a4dULL, + 0x9070addda73d4d37ULL, 0xf6520755aaf1a35cULL, 0xb39ac852a47be117ULL, + 0xd44c612d5ab5f98eULL, 0x23ea658f0346ac20ULL, 0x62d5a673e6c41184ULL, + 0xa497f166cc55c268ULL, 0x6ed1b263c6dc0da8ULL, 0x5533ffcc85aa99d0ULL, + 0xf3510859b2fbaa41ULL, 0xed5b2a71e2c79c0fULL, 0xf7a604a259f355aeULL, + 0x7fde815fbefe20c1ULL, 0xd848753d7aade5a2ULL, 0xe5a8329a29d77fccULL, + 0xb699c75ebc71e80aULL, 0x70db904b96e03be6ULL, 0x5632fac88dac9edbULL, + 0xc4b751e6d1952215ULL, 0x19fc2bd7b332ceaaULL, 0x38e348ab4b709373ULL, + 0xbf9edc428463fd3bULL, 0xae91ef7efc41d052ULL, 0xb09bcd56ac7de61cULL, + 0x3be24daf43769478ULL, 0xd0bb6dd6b1bd0661ULL, 0xc3415819329bdaf1ULL, + 0xb26ecba5577917e5ULL, 0xf2a50bae41f95cb3ULL, 0x40cbc00b16804b56ULL, + 0xbd6bdab17f670cc2ULL, 0xa295fb6edc59cc7eULL, 0xfea11fbe61e1409fULL, + 0x08f318ebcb10e3c3ULL, 0xceb14ffee181302fULL, 0x06020a08100c0e16ULL, + 0x49ccdb172e925e67ULL, 0x51c4f3376ea2663fULL, 0x271d6974e84e53cfULL, + 0x3c144450a0786c9cULL, 0x58c3e82b56b0730eULL, 0xa563f2913f57349aULL, + 0x73da954f9ee63cedULL, 0xe75d3469d2d38e35ULL, 0xe15f3e61c2df8023ULL, + 0x79dc8b57aef22ed7ULL, 0x877d94e9cf136e48ULL, 0x4acdde132694596cULL, + 0x817f9ee1df1f605eULL, 0xee5a2f75eac19b04ULL, 0xb46cc1ad477519f3ULL, + 0xe45c316ddad5893eULL, 0x04f70cfbeb08ffefULL, 0x6a26be982dd4f247ULL, + 0x1cff24dbab38c7b7ULL, 0x2aed7e933b54b911ULL, 0x25e86f87134aa236ULL, + 0xba9dd34e9c69f426ULL, 0xb16fcea15f7f10eeULL, 0x8f8e8c0204038d8bULL, + 0x2b197d64c8564fe3ULL, 0xfda01aba69e74794ULL, 0x0df017e7d31aeadeULL, + 0x8689971e3c1198baULL, 0x110f333c78222d69ULL, 0x09071b1c38121531ULL, + 0xecaf298611c56afdULL, 0x10fb30cb8b20db9bULL, 0x1808282040303858ULL, + 0x3f154154a87e6b97ULL, 0x170d3934682e237fULL, 0x0c04141020181c2cULL, + 0x030105040806070bULL, 0xac64e98d074521abULL, 0x7cdf845bb6f827caULL, + 0x9a76b3c597295f0dULL, 0x8b7980f9ef0b7264ULL, 0x7add8e53a6f429dcULL, + 0x473dc9f4f58eb3b2ULL, 0x3a164e58b074628aULL, 0x413fc3fce582bda4ULL, + 0x5937ebdca5b285fcULL, 0xb76dc4a94f731ef8ULL, 0x4838d8e0dd90a895ULL, + 0xd6b967dea1b10877ULL, 0x9573a2d1bf37442aULL, 0x26e96a831b4ca53dULL, + 0x5f35e1d4b5be8beaULL, 0xff551c4992e3b66dULL, 0x9371a8d9af3b4a3cULL, + 0x8d7b8af1ff077c72ULL, 0x898c860a140f839dULL, 0x9672a7d5b7314321ULL, + 0x8588921a34179fb1ULL, 0x07f609ffe30ef8e4ULL, 0x7e2a82a84dfcd633ULL, + 0x423ec6f8ed84baafULL, 0xe25e3b65cad98728ULL, 0x6927bb9c25d2f54cULL, + 0xca4643050a89cfc0ULL, 0x140c3c3060282474ULL, 0xaf65ec890f4326a0ULL, + 0xb868d5bd676d05dfULL, 0xa361f8992f5b3a8cULL, 0x05030f0c180a091dULL, + 0x5ec1e22346bc7d18ULL, 0xf957164182efb87bULL, 0x67d6a97ffece1899ULL, + 0x76d99a4386ec35f0ULL, 0xe858257dfacd9512ULL, 0x75d89f478eea32fbULL, + 0xaa66e38517492fbdULL, 0x64d7ac7bf6c81f92ULL, 0x4e3ad2e8cd9ca683ULL, + 0x45c8cf070e8a424bULL, 0x443cccf0fd88b4b9ULL, 0x13fa35cf8326dc90ULL, + 0xa796f462c453c563ULL, 0xf4a701a651f552a5ULL, 0xb598c25ab477ef01ULL, + 0x29ec7b973352be1aULL, 0xd5b862daa9b70f7cULL, 0x54c7fc3b76a86f22ULL, + 0xefae2c8219c36df6ULL, 0xbb69d0b96f6b02d4ULL, 0xdd4b7a3162a7ecbfULL, + 0xe0ab3d9631dd76d1ULL, 0xe6a9379e21d178c7ULL, 0xa967e6811f4f28b6ULL, + 0x1e0a2228503c364eULL, 0xc9474601028fc8cbULL, 0x0bf21defc316e4c8ULL, + 0xc2b55beec1992c03ULL, 0x6622aa880dccee6bULL, 0x32e556b37b648149ULL, + 0x2fee719f235eb00cULL, 0xdfbe7cc299a31d46ULL, 0x7d2b87ac45fad138ULL, + 0x9e81bf3e7c21a0e2ULL, 0x36125a48906c7ea6ULL, 0x9883b5366c2daef4ULL, + 0x2d1b776cd85a41f5ULL, 0x120e363870242a62ULL, 0x6523af8c05cae960ULL, + 0x02f506f3fb04f1f9ULL, 0xcf454c091283c6ddULL, 0x6321a58415c6e776ULL, + 0x4fced11f3e9e5071ULL, 0xdb49703972abe2a9ULL, 0x742c9cb07de8c409ULL, + 0x16f93ac39b2cd58dULL, 0x37e659bf636e8854ULL, 0xc7b654e2d993251eULL, + 0x782888a05df0d825ULL, 0x39174b5cb8726581ULL, 0x9b82b032642ba9ffULL, + 0x2e1a7268d05c46feULL, 0x808b9d162c1d96acULL, 0x1ffe21dfa33ec0bcULL, + 0x838a9812241b91a7ULL, 0x1b092d2448363f53ULL, 0x46c9ca03068c4540ULL, + 0x9487a1264c35b2d8ULL, 0xd24e6b254ab9f798ULL, 0x3ee142a35b7c9d65ULL, + 0x722e96b86de4ca1fULL, 0x31e453b773628642ULL, 0x3de047a7537a9a6eULL, + 0x20eb608b0b40ab2bULL, 0xad90ea7af447d759ULL, 0xf1a40eaa49ff5bb8ULL, + 0x221e6678f0445ad2ULL, 0x9285ab2e5c39bcceULL, 0xa060fd9d275d3d87ULL, + 0x0000000000000000ULL, 0x6f25b19435defb5aULL, 0x01f403f7f302f6f2ULL, + 0x0ef112e3db1cedd5ULL, 0xa194fe6ad45fcb75ULL, 0x1d0b272c583a3145ULL, + 0x34e75cbb6b688f5fULL, 0x9f75bcc98f235610ULL, 0x2cef749b2b58b707ULL, + 0x5c34e4d0bdb88ce1ULL, 0x5331f5c495a697c6ULL, 0x61d4a377eec2168fULL, + 0x6dd0b767ceda0aa3ULL, 0x9786a4224433b5d3ULL, 0x827e9be5d7196755ULL, + 0xeaad238e01c964ebULL, 0x1afd2ed3bb34c9a1ULL, 0x7b298da455f6df2eULL, + 0x5030f0c09da090cdULL, 0x4d3bd7ecc59aa188ULL, 0xbc9fd9468c65fa30ULL, + 0x15f83fc7932ad286ULL, 0x57c6f93f7eae6829ULL, 0x35135f4c986a79adULL, + 0x0a061e183014123aULL, 0x0f051114281e1b27ULL, 0x52c5f63366a46134ULL, + 0x33115544886677bbULL, 0x9977b6c19f2f5806ULL, 0x847c91edc7156943ULL, + 0x8e7a8ff5f7017b79ULL, 0x887885fde70d756fULL, 0x5a36eed8adb482f7ULL, + 0x241c6c70e04854c4ULL, 0x4b39dde4d596af9eULL, 0xeb592079f2cb9219ULL, + 0x28187860c05048e8ULL, 0xfa5613458ae9bf70ULL, 0xc8b345f6f18d3e39ULL, + 0xcdb04afae9873724ULL, 0x6c24b4903dd8fc51ULL, 0x6020a0801dc0e07dULL, + 0xcbb240f2f98b3932ULL, 0xab92e072e44bd94fULL, 0xf8a315b671ed4e89ULL, + 0x5dc0e7274eba7a13ULL, 0xcc44490d1a85c1d6ULL, 0xa662f79537513391ULL, + 0x30105040806070b0ULL, 0xc1b45eeac99f2b08ULL, 0x9184ae2a543fbbc5ULL, + 0xc54352112297d4e7ULL, 0xa893e576ec4dde44ULL, 0x5bc2ed2f5eb67405ULL, + 0xde4a7f356aa1ebb4ULL, 0xdabd73ce81a9145bULL, 0x8c8f89060c058a80ULL, + 0x772d99b475eec302ULL, 0xd9bc76ca89af1350ULL, 0xb99cd64a946ff32dULL, + 0xbe6adfb577610bc9ULL, 0xc0405d1d3a9dddfaULL, 0x4ccfd41b3698577aULL, + 0xfba210b279eb4982ULL, 0x9d80ba3a7427a7e9ULL, 0xd14f6e2142bff093ULL, + 0x211f637cf8425dd9ULL, 0x43cac50f1e864c5dULL, 0xe3aa389239db71daULL, + 0xc64257152a91d3ecULL +}; + +static const u64 T2[256] = { + 0xd268bad36a01bbb9ULL, 0x4d1954fc66b1e59aULL, 0xbc932f7114cde265ULL, + 0xcdb9749c1b512587ULL, 0x510253f557a4f7a2ULL, 0x6bb8d368be03d0d6ULL, + 0x6fbdd26bb504d6deULL, 0x29644dd785feb352ULL, 0x5d0d50f04aadfdbaULL, + 0x8a26ace9e063cf09ULL, 0x0e838d8a9684091cULL, 0xc679bfdc4d1aa591ULL, + 0xddad7090374d3da7ULL, 0x550752f65ca3f1aaULL, 0x52c89ab317e17ba4ULL, + 0x2d614cd48ef9b55aULL, 0x8f65ea2320ac4603ULL, 0x73a6d5628411c4e6ULL, + 0x66f197a468c255ccULL, 0x63b2d16ea80ddcc6ULL, 0xccff3355d099aa85ULL, + 0x590851f341aafbb2ULL, 0x712a5bed0f9cc7e2ULL, 0xa204a6f7ae55f359ULL, + 0x5f81de7fc120febeULL, 0x3d7548d8a2e5ad7aULL, 0x9a32a8e5cc7fd729ULL, + 0x5ec799b60ae871bcULL, 0x4b90db70e63be096ULL, 0xc8fa3256db9eac8dULL, + 0xe651b7c4152295d1ULL, 0xd72bfc19aace32b3ULL, 0xab48e3387393704bULL, + 0x42dc9ebf3bfd6384ULL, 0x7eef91ae52d041fcULL, 0x56cd9bb01ce67dacULL, + 0xaf4de23b78947643ULL, 0xd66dbbd06106bdb1ULL, 0x195841c3f1da9b32ULL, + 0xa5cb6eb2e5177957ULL, 0xae0ba5f2b35cf941ULL, 0x0bc0cb40564b8016ULL, + 0xb1da6bbdc20c677fULL, 0x6efb95a27ecc59dcULL, 0xbe1fa1fe9f40e161ULL, + 0xeb18f308c3e310cbULL, 0xfe4fb1ce2f3081e1ULL, 0x080a0206160e0c10ULL, + 0x17dbcc49675e922eULL, 0x37f3c4513f66a26eULL, 0x74691d27cf534ee8ULL, + 0x5044143c9c6c78a0ULL, 0x2be8c3580e73b056ULL, 0x91f263a59a34573fULL, + 0x4f95da73ed3ce69eULL, 0x69345de7358ed3d2ULL, 0x613e5fe12380dfc2ULL, + 0x578bdc79d72ef2aeULL, 0xe9947d87486e13cfULL, 0x13decd4a6c599426ULL, + 0xe19e7f815e601fdfULL, 0x752f5aee049bc1eaULL, 0xadc16cb4f3197547ULL, + 0x6d315ce43e89d5daULL, 0xfb0cf704efff08ebULL, 0x98be266a47f2d42dULL, + 0xdb24ff1cb7c738abULL, 0x937eed2a11b9543bULL, 0x876fe82536a24a13ULL, + 0x4ed39dba26f4699cULL, 0xa1ce6fb1ee107f5fULL, 0x028c8e8f8b8d0304ULL, + 0x647d192be34f56c8ULL, 0xba1aa0fd9447e769ULL, 0xe717f00ddeea1ad3ULL, + 0x1e978986ba98113cULL, 0x3c330f11692d2278ULL, 0x1c1b070931151238ULL, + 0x8629afecfd6ac511ULL, 0xcb30fb109bdb208bULL, 0x2028081858383040ULL, + 0x5441153f976b7ea8ULL, 0x34390d177f232e68ULL, 0x1014040c2c1c1820ULL, + 0x040501030b070608ULL, 0x8de964acab214507ULL, 0x5b84df7cca27f8b6ULL, + 0xc5b3769a0d5f2997ULL, 0xf980798b64720befULL, 0x538edd7adc29f4a6ULL, + 0xf4c93d47b2b38ef5ULL, 0x584e163a8a6274b0ULL, 0xfcc33f41a4bd82e5ULL, + 0xdceb3759fc85b2a5ULL, 0xa9c46db7f81e734fULL, 0xe0d8384895a890ddULL, + 0xde67b9d67708b1a1ULL, 0xd1a273952a4437bfULL, 0x836ae9263da54c1bULL, + 0xd4e1355fea8bbeb5ULL, 0x491c55ff6db6e392ULL, 0xd9a871933c4a3bafULL, + 0xf18a7b8d727c07ffULL, 0x0a868c899d830f14ULL, 0xd5a77296214331b7ULL, + 0x1a928885b19f1734ULL, 0xff09f607e4f80ee3ULL, 0xa8822a7e33d6fc4dULL, + 0xf8c63e42afba84edULL, 0x653b5ee22887d9caULL, 0x9cbb27694cf5d225ULL, + 0x054346cac0cf890aULL, 0x303c0c1474242860ULL, 0x89ec65afa026430fULL, + 0xbdd568b8df056d67ULL, 0x99f861a38c3a5b2fULL, 0x0c0f03051d090a18ULL, + 0x23e2c15e187dbc46ULL, 0x411657f97bb8ef82ULL, 0x7fa9d6679918cefeULL, + 0x439ad976f035ec86ULL, 0x7d2558e81295cdfaULL, 0x479fd875fb32ea8eULL, + 0x85e366aabd2f4917ULL, 0x7bacd764921fc8f6ULL, 0xe8d23a4e83a69ccdULL, + 0x07cfc8454b428a0eULL, 0xf0cc3c44b9b488fdULL, 0xcf35fa1390dc2683ULL, + 0x62f496a763c553c4ULL, 0xa601a7f4a552f551ULL, 0x5ac298b501ef77b4ULL, + 0x977bec291abe5233ULL, 0xda62b8d57c0fb7a9ULL, 0x3bfcc754226fa876ULL, + 0x822caeeff66dc319ULL, 0xb9d069bbd4026b6fULL, 0x317a4bddbfeca762ULL, + 0x963dabe0d176dd31ULL, 0x9e37a9e6c778d121ULL, 0x81e667a9b6284f1fULL, + 0x28220a1e4e363c50ULL, 0x014647c9cbc88f02ULL, 0xef1df20bc8e416c3ULL, + 0xee5bb5c2032c99c1ULL, 0x88aa22666beecc0dULL, 0xb356e5324981647bULL, + 0x9f71ee2f0cb05e23ULL, 0xc27cbedf461da399ULL, 0xac872b7d38d1fa45ULL, + 0x3ebf819ee2a0217cULL, 0x485a1236a67e6c90ULL, 0x36b58398f4ae2d6cULL, + 0x6c771b2df5415ad8ULL, 0x38360e12622a2470ULL, 0x8caf236560e9ca05ULL, + 0xf306f502f9f104fbULL, 0x094c45cfddc68312ULL, 0x84a5216376e7c615ULL, + 0x1fd1ce4f71509e3eULL, 0x397049dba9e2ab72ULL, 0xb09c2c7409c4e87dULL, + 0xc33af9168dd52c9bULL, 0xbf59e63754886e63ULL, 0xe254b6c71e2593d9ULL, + 0xa088287825d8f05dULL, 0x5c4b1739816572b8ULL, 0x32b0829bffa92b64ULL, + 0x68721a2efe465cd0ULL, 0x169d8b80ac961d2cULL, 0xdf21fe1fbcc03ea3ULL, + 0x12988a83a7911b24ULL, 0x242d091b533f3648ULL, 0x03cac94640458c06ULL, + 0x26a18794d8b2354cULL, 0x256b4ed298f7b94aULL, 0xa342e13e659d7c5bULL, + 0xb8962e721fcae46dULL, 0xb753e43142866273ULL, 0xa747e03d6e9a7a53ULL, + 0x8b60eb202bab400bULL, 0x7aea90ad59d747f4ULL, 0xaa0ea4f1b85bff49ULL, + 0x78661e22d25a44f0ULL, 0x2eab8592cebc395cULL, 0x9dfd60a0873d5d27ULL, + 0x0000000000000000ULL, 0x94b1256f5afbde35ULL, 0xf703f401f2f602f3ULL, + 0xe312f10ed5ed1cdbULL, 0x6afe94a175cb5fd4ULL, 0x2c270b1d45313a58ULL, + 0xbb5ce7345f8f686bULL, 0xc9bc759f1056238fULL, 0x9b74ef2c07b7582bULL, + 0xd0e4345ce18cb8bdULL, 0xc4f53153c697a695ULL, 0x77a3d4618f16c2eeULL, + 0x67b7d06da30adaceULL, 0x22a48697d3b53344ULL, 0xe59b7e82556719d7ULL, + 0x8e23adeaeb64c901ULL, 0xd32efd1aa1c934bbULL, 0xa48d297b2edff655ULL, + 0xc0f03050cd90a09dULL, 0xecd73b4d88a19ac5ULL, 0x46d99fbc30fa658cULL, + 0xc73ff81586d22a93ULL, 0x3ff9c6572968ae7eULL, 0x4c5f1335ad796a98ULL, + 0x181e060a3a121430ULL, 0x1411050f271b1e28ULL, 0x33f6c5523461a466ULL, + 0x44551133bb776688ULL, 0xc1b6779906582f9fULL, 0xed917c84436915c7ULL, + 0xf58f7a8e797b01f7ULL, 0xfd8578886f750de7ULL, 0xd8ee365af782b4adULL, + 0x706c1c24c45448e0ULL, 0xe4dd394b9eaf96d5ULL, 0x792059eb1992cbf2ULL, + 0x60781828e84850c0ULL, 0x451356fa70bfe98aULL, 0xf645b3c8393e8df1ULL, + 0xfa4ab0cd243787e9ULL, 0x90b4246c51fcd83dULL, 0x80a020607de0c01dULL, + 0xf240b2cb32398bf9ULL, 0x72e092ab4fd94be4ULL, 0xb615a3f8894eed71ULL, + 0x27e7c05d137aba4eULL, 0x0d4944ccd6c1851aULL, 0x95f762a691335137ULL, + 0x40501030b0706080ULL, 0xea5eb4c1082b9fc9ULL, 0x2aae8491c5bb3f54ULL, + 0x115243c5e7d49722ULL, 0x76e593a844de4decULL, 0x2fedc25b0574b65eULL, + 0x357f4adeb4eba16aULL, 0xce73bdda5b14a981ULL, 0x06898f8c808a050cULL, + 0xb4992d7702c3ee75ULL, 0xca76bcd95013af89ULL, 0x4ad69cb92df36f94ULL, + 0xb5df6abec90b6177ULL, 0x1d5d40c0fadd9d3aULL, 0x1bd4cf4c7a579836ULL, + 0xb210a2fb8249eb79ULL, 0x3aba809de9a72774ULL, 0x216e4fd193f0bf42ULL, + 0x7c631f21d95d42f8ULL, 0x0fc5ca435d4c861eULL, 0x9238aae3da71db39ULL, + 0x155742c6ecd3912aULL +}; + +static const u64 T3[256] = { + 0x68d2d3ba016ab9bbULL, 0x194dfc54b1669ae5ULL, 0x93bc712fcd1465e2ULL, + 0xb9cd9c74511b8725ULL, 0x0251f553a457a2f7ULL, 0xb86b68d303bed6d0ULL, + 0xbd6f6bd204b5ded6ULL, 0x6429d74dfe8552b3ULL, 0x0d5df050ad4abafdULL, + 0x268ae9ac63e009cfULL, 0x830e8a8d84961c09ULL, 0x79c6dcbf1a4d91a5ULL, + 0xaddd90704d37a73dULL, 0x0755f652a35caaf1ULL, 0xc852b39ae117a47bULL, + 0x612dd44cf98e5ab5ULL, 0x658f23eaac200346ULL, 0xa67362d51184e6c4ULL, + 0xf166a497c268cc55ULL, 0xb2636ed10da8c6dcULL, 0xffcc553399d085aaULL, + 0x0859f351aa41b2fbULL, 0x2a71ed5b9c0fe2c7ULL, 0x04a2f7a655ae59f3ULL, + 0x815f7fde20c1befeULL, 0x753dd848e5a27aadULL, 0x329ae5a87fcc29d7ULL, + 0xc75eb699e80abc71ULL, 0x904b70db3be696e0ULL, 0xfac856329edb8dacULL, + 0x51e6c4b72215d195ULL, 0x2bd719fcceaab332ULL, 0x48ab38e393734b70ULL, + 0xdc42bf9efd3b8463ULL, 0xef7eae91d052fc41ULL, 0xcd56b09be61cac7dULL, + 0x4daf3be294784376ULL, 0x6dd6d0bb0661b1bdULL, 0x5819c341daf1329bULL, + 0xcba5b26e17e55779ULL, 0x0baef2a55cb341f9ULL, 0xc00b40cb4b561680ULL, + 0xdab1bd6b0cc27f67ULL, 0xfb6ea295cc7edc59ULL, 0x1fbefea1409f61e1ULL, + 0x18eb08f3e3c3cb10ULL, 0x4ffeceb1302fe181ULL, 0x0a0806020e16100cULL, + 0xdb1749cc5e672e92ULL, 0xf33751c4663f6ea2ULL, 0x6974271d53cfe84eULL, + 0x44503c146c9ca078ULL, 0xe82b58c3730e56b0ULL, 0xf291a563349a3f57ULL, + 0x954f73da3ced9ee6ULL, 0x3469e75d8e35d2d3ULL, 0x3e61e15f8023c2dfULL, + 0x8b5779dc2ed7aef2ULL, 0x94e9877d6e48cf13ULL, 0xde134acd596c2694ULL, + 0x9ee1817f605edf1fULL, 0x2f75ee5a9b04eac1ULL, 0xc1adb46c19f34775ULL, + 0x316de45c893edad5ULL, 0x0cfb04f7ffefeb08ULL, 0xbe986a26f2472dd4ULL, + 0x24db1cffc7b7ab38ULL, 0x7e932aedb9113b54ULL, 0x6f8725e8a236134aULL, + 0xd34eba9df4269c69ULL, 0xcea1b16f10ee5f7fULL, 0x8c028f8e8d8b0403ULL, + 0x7d642b194fe3c856ULL, 0x1abafda0479469e7ULL, 0x17e70df0eaded31aULL, + 0x971e868998ba3c11ULL, 0x333c110f2d697822ULL, 0x1b1c090715313812ULL, + 0x2986ecaf6afd11c5ULL, 0x30cb10fbdb9b8b20ULL, 0x2820180838584030ULL, + 0x41543f156b97a87eULL, 0x3934170d237f682eULL, 0x14100c041c2c2018ULL, + 0x05040301070b0806ULL, 0xe98dac6421ab0745ULL, 0x845b7cdf27cab6f8ULL, + 0xb3c59a765f0d9729ULL, 0x80f98b797264ef0bULL, 0x8e537add29dca6f4ULL, + 0xc9f4473db3b2f58eULL, 0x4e583a16628ab074ULL, 0xc3fc413fbda4e582ULL, + 0xebdc593785fca5b2ULL, 0xc4a9b76d1ef84f73ULL, 0xd8e04838a895dd90ULL, + 0x67ded6b90877a1b1ULL, 0xa2d19573442abf37ULL, 0x6a8326e9a53d1b4cULL, + 0xe1d45f358beab5beULL, 0x1c49ff55b66d92e3ULL, 0xa8d993714a3caf3bULL, + 0x8af18d7b7c72ff07ULL, 0x860a898c839d140fULL, 0xa7d596724321b731ULL, + 0x921a85889fb13417ULL, 0x09ff07f6f8e4e30eULL, 0x82a87e2ad6334dfcULL, + 0xc6f8423ebaafed84ULL, 0x3b65e25e8728cad9ULL, 0xbb9c6927f54c25d2ULL, + 0x4305ca46cfc00a89ULL, 0x3c30140c24746028ULL, 0xec89af6526a00f43ULL, + 0xd5bdb86805df676dULL, 0xf899a3613a8c2f5bULL, 0x0f0c0503091d180aULL, + 0xe2235ec17d1846bcULL, 0x1641f957b87b82efULL, 0xa97f67d61899feceULL, + 0x9a4376d935f086ecULL, 0x257de8589512facdULL, 0x9f4775d832fb8eeaULL, + 0xe385aa662fbd1749ULL, 0xac7b64d71f92f6c8ULL, 0xd2e84e3aa683cd9cULL, + 0xcf0745c8424b0e8aULL, 0xccf0443cb4b9fd88ULL, 0x35cf13fadc908326ULL, + 0xf462a796c563c453ULL, 0x01a6f4a752a551f5ULL, 0xc25ab598ef01b477ULL, + 0x7b9729ecbe1a3352ULL, 0x62dad5b80f7ca9b7ULL, 0xfc3b54c76f2276a8ULL, + 0x2c82efae6df619c3ULL, 0xd0b9bb6902d46f6bULL, 0x7a31dd4becbf62a7ULL, + 0x3d96e0ab76d131ddULL, 0x379ee6a978c721d1ULL, 0xe681a96728b61f4fULL, + 0x22281e0a364e503cULL, 0x4601c947c8cb028fULL, 0x1def0bf2e4c8c316ULL, + 0x5beec2b52c03c199ULL, 0xaa886622ee6b0dccULL, 0x56b332e581497b64ULL, + 0x719f2feeb00c235eULL, 0x7cc2dfbe1d4699a3ULL, 0x87ac7d2bd13845faULL, + 0xbf3e9e81a0e27c21ULL, 0x5a4836127ea6906cULL, 0xb5369883aef46c2dULL, + 0x776c2d1b41f5d85aULL, 0x3638120e2a627024ULL, 0xaf8c6523e96005caULL, + 0x06f302f5f1f9fb04ULL, 0x4c09cf45c6dd1283ULL, 0xa5846321e77615c6ULL, + 0xd11f4fce50713e9eULL, 0x7039db49e2a972abULL, 0x9cb0742cc4097de8ULL, + 0x3ac316f9d58d9b2cULL, 0x59bf37e68854636eULL, 0x54e2c7b6251ed993ULL, + 0x88a07828d8255df0ULL, 0x4b5c39176581b872ULL, 0xb0329b82a9ff642bULL, + 0x72682e1a46fed05cULL, 0x9d16808b96ac2c1dULL, 0x21df1ffec0bca33eULL, + 0x9812838a91a7241bULL, 0x2d241b093f534836ULL, 0xca0346c94540068cULL, + 0xa1269487b2d84c35ULL, 0x6b25d24ef7984ab9ULL, 0x42a33ee19d655b7cULL, + 0x96b8722eca1f6de4ULL, 0x53b731e486427362ULL, 0x47a73de09a6e537aULL, + 0x608b20ebab2b0b40ULL, 0xea7aad90d759f447ULL, 0x0eaaf1a45bb849ffULL, + 0x6678221e5ad2f044ULL, 0xab2e9285bcce5c39ULL, 0xfd9da0603d87275dULL, + 0x0000000000000000ULL, 0xb1946f25fb5a35deULL, 0x03f701f4f6f2f302ULL, + 0x12e30ef1edd5db1cULL, 0xfe6aa194cb75d45fULL, 0x272c1d0b3145583aULL, + 0x5cbb34e78f5f6b68ULL, 0xbcc99f7556108f23ULL, 0x749b2cefb7072b58ULL, + 0xe4d05c348ce1bdb8ULL, 0xf5c4533197c695a6ULL, 0xa37761d4168feec2ULL, + 0xb7676dd00aa3cedaULL, 0xa4229786b5d34433ULL, 0x9be5827e6755d719ULL, + 0x238eeaad64eb01c9ULL, 0x2ed31afdc9a1bb34ULL, 0x8da47b29df2e55f6ULL, + 0xf0c0503090cd9da0ULL, 0xd7ec4d3ba188c59aULL, 0xd946bc9ffa308c65ULL, + 0x3fc715f8d286932aULL, 0xf93f57c668297eaeULL, 0x5f4c351379ad986aULL, + 0x1e180a06123a3014ULL, 0x11140f051b27281eULL, 0xf63352c5613466a4ULL, + 0x5544331177bb8866ULL, 0xb6c1997758069f2fULL, 0x91ed847c6943c715ULL, + 0x8ff58e7a7b79f701ULL, 0x85fd8878756fe70dULL, 0xeed85a3682f7adb4ULL, + 0x6c70241c54c4e048ULL, 0xdde44b39af9ed596ULL, 0x2079eb599219f2cbULL, + 0x7860281848e8c050ULL, 0x1345fa56bf708ae9ULL, 0x45f6c8b33e39f18dULL, + 0x4afacdb03724e987ULL, 0xb4906c24fc513dd8ULL, 0xa0806020e07d1dc0ULL, + 0x40f2cbb23932f98bULL, 0xe072ab92d94fe44bULL, 0x15b6f8a34e8971edULL, + 0xe7275dc07a134ebaULL, 0x490dcc44c1d61a85ULL, 0xf795a66233913751ULL, + 0x5040301070b08060ULL, 0x5eeac1b42b08c99fULL, 0xae2a9184bbc5543fULL, + 0x5211c543d4e72297ULL, 0xe576a893de44ec4dULL, 0xed2f5bc274055eb6ULL, + 0x7f35de4aebb46aa1ULL, 0x73cedabd145b81a9ULL, 0x89068c8f8a800c05ULL, + 0x99b4772dc30275eeULL, 0x76cad9bc135089afULL, 0xd64ab99cf32d946fULL, + 0xdfb5be6a0bc97761ULL, 0x5d1dc040ddfa3a9dULL, 0xd41b4ccf577a3698ULL, + 0x10b2fba2498279ebULL, 0xba3a9d80a7e97427ULL, 0x6e21d14ff09342bfULL, + 0x637c211f5dd9f842ULL, 0xc50f43ca4c5d1e86ULL, 0x3892e3aa71da39dbULL, + 0x5715c642d3ec2a91ULL +}; + +static const u64 T4[256] = { + 0xbbb96a01bad3d268ULL, 0xe59a66b154fc4d19ULL, 0xe26514cd2f71bc93ULL, + 0x25871b51749ccdb9ULL, 0xf7a257a453f55102ULL, 0xd0d6be03d3686bb8ULL, + 0xd6deb504d26b6fbdULL, 0xb35285fe4dd72964ULL, 0xfdba4aad50f05d0dULL, + 0xcf09e063ace98a26ULL, 0x091c96848d8a0e83ULL, 0xa5914d1abfdcc679ULL, + 0x3da7374d7090ddadULL, 0xf1aa5ca352f65507ULL, 0x7ba417e19ab352c8ULL, + 0xb55a8ef94cd42d61ULL, 0x460320acea238f65ULL, 0xc4e68411d56273a6ULL, + 0x55cc68c297a466f1ULL, 0xdcc6a80dd16e63b2ULL, 0xaa85d0993355ccffULL, + 0xfbb241aa51f35908ULL, 0xc7e20f9c5bed712aULL, 0xf359ae55a6f7a204ULL, + 0xfebec120de7f5f81ULL, 0xad7aa2e548d83d75ULL, 0xd729cc7fa8e59a32ULL, + 0x71bc0ae899b65ec7ULL, 0xe096e63bdb704b90ULL, 0xac8ddb9e3256c8faULL, + 0x95d11522b7c4e651ULL, 0x32b3aacefc19d72bULL, 0x704b7393e338ab48ULL, + 0x63843bfd9ebf42dcULL, 0x41fc52d091ae7eefULL, 0x7dac1ce69bb056cdULL, + 0x76437894e23baf4dULL, 0xbdb16106bbd0d66dULL, 0x9b32f1da41c31958ULL, + 0x7957e5176eb2a5cbULL, 0xf941b35ca5f2ae0bULL, 0x8016564bcb400bc0ULL, + 0x677fc20c6bbdb1daULL, 0x59dc7ecc95a26efbULL, 0xe1619f40a1febe1fULL, + 0x10cbc3e3f308eb18ULL, 0x81e12f30b1cefe4fULL, 0x0c10160e0206080aULL, + 0x922e675ecc4917dbULL, 0xa26e3f66c45137f3ULL, 0x4ee8cf531d277469ULL, + 0x78a09c6c143c5044ULL, 0xb0560e73c3582be8ULL, 0x573f9a3463a591f2ULL, + 0xe69eed3cda734f95ULL, 0xd3d2358e5de76934ULL, 0xdfc223805fe1613eULL, + 0xf2aed72edc79578bULL, 0x13cf486e7d87e994ULL, 0x94266c59cd4a13deULL, + 0x1fdf5e607f81e19eULL, 0xc1ea049b5aee752fULL, 0x7547f3196cb4adc1ULL, + 0xd5da3e895ce46d31ULL, 0x08ebeffff704fb0cULL, 0xd42d47f2266a98beULL, + 0x38abb7c7ff1cdb24ULL, 0x543b11b9ed2a937eULL, 0x4a1336a2e825876fULL, + 0x699c26f49dba4ed3ULL, 0x7f5fee106fb1a1ceULL, 0x03048b8d8e8f028cULL, + 0x56c8e34f192b647dULL, 0xe7699447a0fdba1aULL, 0x1ad3deeaf00de717ULL, + 0x113cba9889861e97ULL, 0x2278692d0f113c33ULL, 0x1238311507091c1bULL, + 0xc511fd6aafec8629ULL, 0x208b9bdbfb10cb30ULL, 0x3040583808182028ULL, + 0x7ea8976b153f5441ULL, 0x2e687f230d173439ULL, 0x18202c1c040c1014ULL, + 0x06080b0701030405ULL, 0x4507ab2164ac8de9ULL, 0xf8b6ca27df7c5b84ULL, + 0x29970d5f769ac5b3ULL, 0x0bef6472798bf980ULL, 0xf4a6dc29dd7a538eULL, + 0x8ef5b2b33d47f4c9ULL, 0x74b08a62163a584eULL, 0x82e5a4bd3f41fcc3ULL, + 0xb2a5fc853759dcebULL, 0x734ff81e6db7a9c4ULL, 0x90dd95a83848e0d8ULL, + 0xb1a17708b9d6de67ULL, 0x37bf2a447395d1a2ULL, 0x4c1b3da5e926836aULL, + 0xbeb5ea8b355fd4e1ULL, 0xe3926db655ff491cULL, 0x3baf3c4a7193d9a8ULL, + 0x07ff727c7b8df18aULL, 0x0f149d838c890a86ULL, 0x31b721437296d5a7ULL, + 0x1734b19f88851a92ULL, 0x0ee3e4f8f607ff09ULL, 0xfc4d33d62a7ea882ULL, + 0x84edafba3e42f8c6ULL, 0xd9ca28875ee2653bULL, 0xd2254cf527699cbbULL, + 0x890ac0cf46ca0543ULL, 0x286074240c14303cULL, 0x430fa02665af89ecULL, + 0x6d67df0568b8bdd5ULL, 0x5b2f8c3a61a399f8ULL, 0x0a181d0903050c0fULL, + 0xbc46187dc15e23e2ULL, 0xef827bb857f94116ULL, 0xcefe9918d6677fa9ULL, + 0xec86f035d976439aULL, 0xcdfa129558e87d25ULL, 0xea8efb32d875479fULL, + 0x4917bd2f66aa85e3ULL, 0xc8f6921fd7647bacULL, 0x9ccd83a63a4ee8d2ULL, + 0x8a0e4b42c84507cfULL, 0x88fdb9b43c44f0ccULL, 0x268390dcfa13cf35ULL, + 0x53c463c596a762f4ULL, 0xf551a552a7f4a601ULL, 0x77b401ef98b55ac2ULL, + 0x52331abeec29977bULL, 0xb7a97c0fb8d5da62ULL, 0xa876226fc7543bfcULL, + 0xc319f66daeef822cULL, 0x6b6fd40269bbb9d0ULL, 0xa762bfec4bdd317aULL, + 0xdd31d176abe0963dULL, 0xd121c778a9e69e37ULL, 0x4f1fb62867a981e6ULL, + 0x3c504e360a1e2822ULL, 0x8f02cbc847c90146ULL, 0x16c3c8e4f20bef1dULL, + 0x99c1032cb5c2ee5bULL, 0xcc0d6bee226688aaULL, 0x647b4981e532b356ULL, + 0x5e230cb0ee2f9f71ULL, 0xa399461dbedfc27cULL, 0xfa4538d12b7dac87ULL, + 0x217ce2a0819e3ebfULL, 0x6c90a67e1236485aULL, 0x2d6cf4ae839836b5ULL, + 0x5ad8f5411b2d6c77ULL, 0x2470622a0e123836ULL, 0xca0560e923658cafULL, + 0x04fbf9f1f502f306ULL, 0x8312ddc645cf094cULL, 0xc61576e7216384a5ULL, + 0x9e3e7150ce4f1fd1ULL, 0xab72a9e249db3970ULL, 0xe87d09c42c74b09cULL, + 0x2c9b8dd5f916c33aULL, 0x6e635488e637bf59ULL, 0x93d91e25b6c7e254ULL, + 0xf05d25d82878a088ULL, 0x72b8816517395c4bULL, 0x2b64ffa9829b32b0ULL, + 0x5cd0fe461a2e6872ULL, 0x1d2cac968b80169dULL, 0x3ea3bcc0fe1fdf21ULL, + 0x1b24a7918a831298ULL, 0x3648533f091b242dULL, 0x8c064045c94603caULL, + 0x354cd8b2879426a1ULL, 0xb94a98f74ed2256bULL, 0x7c5b659de13ea342ULL, + 0xe46d1fca2e72b896ULL, 0x62734286e431b753ULL, 0x7a536e9ae03da747ULL, + 0x400b2babeb208b60ULL, 0x47f459d790ad7aeaULL, 0xff49b85ba4f1aa0eULL, + 0x44f0d25a1e227866ULL, 0x395ccebc85922eabULL, 0x5d27873d60a09dfdULL, + 0x0000000000000000ULL, 0xde355afb256f94b1ULL, 0x02f3f2f6f401f703ULL, + 0x1cdbd5edf10ee312ULL, 0x5fd475cb94a16afeULL, 0x3a5845310b1d2c27ULL, + 0x686b5f8fe734bb5cULL, 0x238f1056759fc9bcULL, 0x582b07b7ef2c9b74ULL, + 0xb8bde18c345cd0e4ULL, 0xa695c6973153c4f5ULL, 0xc2ee8f16d46177a3ULL, + 0xdacea30ad06d67b7ULL, 0x3344d3b5869722a4ULL, 0x19d755677e82e59bULL, + 0xc901eb64adea8e23ULL, 0x34bba1c9fd1ad32eULL, 0xf6552edf297ba48dULL, + 0xa09dcd903050c0f0ULL, 0x9ac588a13b4decd7ULL, 0x658c30fa9fbc46d9ULL, + 0x2a9386d2f815c73fULL, 0xae7e2968c6573ff9ULL, 0x6a98ad7913354c5fULL, + 0x14303a12060a181eULL, 0x1e28271b050f1411ULL, 0xa4663461c55233f6ULL, + 0x6688bb7711334455ULL, 0x2f9f06587799c1b6ULL, 0x15c743697c84ed91ULL, + 0x01f7797b7a8ef58fULL, 0x0de76f757888fd85ULL, 0xb4adf782365ad8eeULL, + 0x48e0c4541c24706cULL, 0x96d59eaf394be4ddULL, 0xcbf2199259eb7920ULL, + 0x50c0e84818286078ULL, 0xe98a70bf56fa4513ULL, 0x8df1393eb3c8f645ULL, + 0x87e92437b0cdfa4aULL, 0xd83d51fc246c90b4ULL, 0xc01d7de0206080a0ULL, + 0x8bf93239b2cbf240ULL, 0x4be44fd992ab72e0ULL, 0xed71894ea3f8b615ULL, + 0xba4e137ac05d27e7ULL, 0x851ad6c144cc0d49ULL, 0x5137913362a695f7ULL, + 0x6080b07010304050ULL, 0x9fc9082bb4c1ea5eULL, 0x3f54c5bb84912aaeULL, + 0x9722e7d443c51152ULL, 0x4dec44de93a876e5ULL, 0xb65e0574c25b2fedULL, + 0xa16ab4eb4ade357fULL, 0xa9815b14bddace73ULL, 0x050c808a8f8c0689ULL, + 0xee7502c32d77b499ULL, 0xaf895013bcd9ca76ULL, 0x6f942df39cb94ad6ULL, + 0x6177c90b6abeb5dfULL, 0x9d3afadd40c01d5dULL, 0x98367a57cf4c1bd4ULL, + 0xeb798249a2fbb210ULL, 0x2774e9a7809d3abaULL, 0xbf4293f04fd1216eULL, + 0x42f8d95d1f217c63ULL, 0x861e5d4cca430fc5ULL, 0xdb39da71aae39238ULL, + 0x912aecd342c61557ULL +}; + +static const u64 T5[256] = { + 0xb9bb016ad3ba68d2ULL, 0x9ae5b166fc54194dULL, 0x65e2cd14712f93bcULL, + 0x8725511b9c74b9cdULL, 0xa2f7a457f5530251ULL, 0xd6d003be68d3b86bULL, + 0xded604b56bd2bd6fULL, 0x52b3fe85d74d6429ULL, 0xbafdad4af0500d5dULL, + 0x09cf63e0e9ac268aULL, 0x1c0984968a8d830eULL, 0x91a51a4ddcbf79c6ULL, + 0xa73d4d379070adddULL, 0xaaf1a35cf6520755ULL, 0xa47be117b39ac852ULL, + 0x5ab5f98ed44c612dULL, 0x0346ac2023ea658fULL, 0xe6c4118462d5a673ULL, + 0xcc55c268a497f166ULL, 0xc6dc0da86ed1b263ULL, 0x85aa99d05533ffccULL, + 0xb2fbaa41f3510859ULL, 0xe2c79c0fed5b2a71ULL, 0x59f355aef7a604a2ULL, + 0xbefe20c17fde815fULL, 0x7aade5a2d848753dULL, 0x29d77fcce5a8329aULL, + 0xbc71e80ab699c75eULL, 0x96e03be670db904bULL, 0x8dac9edb5632fac8ULL, + 0xd1952215c4b751e6ULL, 0xb332ceaa19fc2bd7ULL, 0x4b70937338e348abULL, + 0x8463fd3bbf9edc42ULL, 0xfc41d052ae91ef7eULL, 0xac7de61cb09bcd56ULL, + 0x437694783be24dafULL, 0xb1bd0661d0bb6dd6ULL, 0x329bdaf1c3415819ULL, + 0x577917e5b26ecba5ULL, 0x41f95cb3f2a50baeULL, 0x16804b5640cbc00bULL, + 0x7f670cc2bd6bdab1ULL, 0xdc59cc7ea295fb6eULL, 0x61e1409ffea11fbeULL, + 0xcb10e3c308f318ebULL, 0xe181302fceb14ffeULL, 0x100c0e1606020a08ULL, + 0x2e925e6749ccdb17ULL, 0x6ea2663f51c4f337ULL, 0xe84e53cf271d6974ULL, + 0xa0786c9c3c144450ULL, 0x56b0730e58c3e82bULL, 0x3f57349aa563f291ULL, + 0x9ee63ced73da954fULL, 0xd2d38e35e75d3469ULL, 0xc2df8023e15f3e61ULL, + 0xaef22ed779dc8b57ULL, 0xcf136e48877d94e9ULL, 0x2694596c4acdde13ULL, + 0xdf1f605e817f9ee1ULL, 0xeac19b04ee5a2f75ULL, 0x477519f3b46cc1adULL, + 0xdad5893ee45c316dULL, 0xeb08ffef04f70cfbULL, 0x2dd4f2476a26be98ULL, + 0xab38c7b71cff24dbULL, 0x3b54b9112aed7e93ULL, 0x134aa23625e86f87ULL, + 0x9c69f426ba9dd34eULL, 0x5f7f10eeb16fcea1ULL, 0x04038d8b8f8e8c02ULL, + 0xc8564fe32b197d64ULL, 0x69e74794fda01abaULL, 0xd31aeade0df017e7ULL, + 0x3c1198ba8689971eULL, 0x78222d69110f333cULL, 0x3812153109071b1cULL, + 0x11c56afdecaf2986ULL, 0x8b20db9b10fb30cbULL, 0x4030385818082820ULL, + 0xa87e6b973f154154ULL, 0x682e237f170d3934ULL, 0x20181c2c0c041410ULL, + 0x0806070b03010504ULL, 0x074521abac64e98dULL, 0xb6f827ca7cdf845bULL, + 0x97295f0d9a76b3c5ULL, 0xef0b72648b7980f9ULL, 0xa6f429dc7add8e53ULL, + 0xf58eb3b2473dc9f4ULL, 0xb074628a3a164e58ULL, 0xe582bda4413fc3fcULL, + 0xa5b285fc5937ebdcULL, 0x4f731ef8b76dc4a9ULL, 0xdd90a8954838d8e0ULL, + 0xa1b10877d6b967deULL, 0xbf37442a9573a2d1ULL, 0x1b4ca53d26e96a83ULL, + 0xb5be8bea5f35e1d4ULL, 0x92e3b66dff551c49ULL, 0xaf3b4a3c9371a8d9ULL, + 0xff077c728d7b8af1ULL, 0x140f839d898c860aULL, 0xb73143219672a7d5ULL, + 0x34179fb18588921aULL, 0xe30ef8e407f609ffULL, 0x4dfcd6337e2a82a8ULL, + 0xed84baaf423ec6f8ULL, 0xcad98728e25e3b65ULL, 0x25d2f54c6927bb9cULL, + 0x0a89cfc0ca464305ULL, 0x60282474140c3c30ULL, 0x0f4326a0af65ec89ULL, + 0x676d05dfb868d5bdULL, 0x2f5b3a8ca361f899ULL, 0x180a091d05030f0cULL, + 0x46bc7d185ec1e223ULL, 0x82efb87bf9571641ULL, 0xfece189967d6a97fULL, + 0x86ec35f076d99a43ULL, 0xfacd9512e858257dULL, 0x8eea32fb75d89f47ULL, + 0x17492fbdaa66e385ULL, 0xf6c81f9264d7ac7bULL, 0xcd9ca6834e3ad2e8ULL, + 0x0e8a424b45c8cf07ULL, 0xfd88b4b9443cccf0ULL, 0x8326dc9013fa35cfULL, + 0xc453c563a796f462ULL, 0x51f552a5f4a701a6ULL, 0xb477ef01b598c25aULL, + 0x3352be1a29ec7b97ULL, 0xa9b70f7cd5b862daULL, 0x76a86f2254c7fc3bULL, + 0x19c36df6efae2c82ULL, 0x6f6b02d4bb69d0b9ULL, 0x62a7ecbfdd4b7a31ULL, + 0x31dd76d1e0ab3d96ULL, 0x21d178c7e6a9379eULL, 0x1f4f28b6a967e681ULL, + 0x503c364e1e0a2228ULL, 0x028fc8cbc9474601ULL, 0xc316e4c80bf21defULL, + 0xc1992c03c2b55beeULL, 0x0dccee6b6622aa88ULL, 0x7b64814932e556b3ULL, + 0x235eb00c2fee719fULL, 0x99a31d46dfbe7cc2ULL, 0x45fad1387d2b87acULL, + 0x7c21a0e29e81bf3eULL, 0x906c7ea636125a48ULL, 0x6c2daef49883b536ULL, + 0xd85a41f52d1b776cULL, 0x70242a62120e3638ULL, 0x05cae9606523af8cULL, + 0xfb04f1f902f506f3ULL, 0x1283c6ddcf454c09ULL, 0x15c6e7766321a584ULL, + 0x3e9e50714fced11fULL, 0x72abe2a9db497039ULL, 0x7de8c409742c9cb0ULL, + 0x9b2cd58d16f93ac3ULL, 0x636e885437e659bfULL, 0xd993251ec7b654e2ULL, + 0x5df0d825782888a0ULL, 0xb872658139174b5cULL, 0x642ba9ff9b82b032ULL, + 0xd05c46fe2e1a7268ULL, 0x2c1d96ac808b9d16ULL, 0xa33ec0bc1ffe21dfULL, + 0x241b91a7838a9812ULL, 0x48363f531b092d24ULL, 0x068c454046c9ca03ULL, + 0x4c35b2d89487a126ULL, 0x4ab9f798d24e6b25ULL, 0x5b7c9d653ee142a3ULL, + 0x6de4ca1f722e96b8ULL, 0x7362864231e453b7ULL, 0x537a9a6e3de047a7ULL, + 0x0b40ab2b20eb608bULL, 0xf447d759ad90ea7aULL, 0x49ff5bb8f1a40eaaULL, + 0xf0445ad2221e6678ULL, 0x5c39bcce9285ab2eULL, 0x275d3d87a060fd9dULL, + 0x0000000000000000ULL, 0x35defb5a6f25b194ULL, 0xf302f6f201f403f7ULL, + 0xdb1cedd50ef112e3ULL, 0xd45fcb75a194fe6aULL, 0x583a31451d0b272cULL, + 0x6b688f5f34e75cbbULL, 0x8f2356109f75bcc9ULL, 0x2b58b7072cef749bULL, + 0xbdb88ce15c34e4d0ULL, 0x95a697c65331f5c4ULL, 0xeec2168f61d4a377ULL, + 0xceda0aa36dd0b767ULL, 0x4433b5d39786a422ULL, 0xd7196755827e9be5ULL, + 0x01c964ebeaad238eULL, 0xbb34c9a11afd2ed3ULL, 0x55f6df2e7b298da4ULL, + 0x9da090cd5030f0c0ULL, 0xc59aa1884d3bd7ecULL, 0x8c65fa30bc9fd946ULL, + 0x932ad28615f83fc7ULL, 0x7eae682957c6f93fULL, 0x986a79ad35135f4cULL, + 0x3014123a0a061e18ULL, 0x281e1b270f051114ULL, 0x66a4613452c5f633ULL, + 0x886677bb33115544ULL, 0x9f2f58069977b6c1ULL, 0xc7156943847c91edULL, + 0xf7017b798e7a8ff5ULL, 0xe70d756f887885fdULL, 0xadb482f75a36eed8ULL, + 0xe04854c4241c6c70ULL, 0xd596af9e4b39dde4ULL, 0xf2cb9219eb592079ULL, + 0xc05048e828187860ULL, 0x8ae9bf70fa561345ULL, 0xf18d3e39c8b345f6ULL, + 0xe9873724cdb04afaULL, 0x3dd8fc516c24b490ULL, 0x1dc0e07d6020a080ULL, + 0xf98b3932cbb240f2ULL, 0xe44bd94fab92e072ULL, 0x71ed4e89f8a315b6ULL, + 0x4eba7a135dc0e727ULL, 0x1a85c1d6cc44490dULL, 0x37513391a662f795ULL, + 0x806070b030105040ULL, 0xc99f2b08c1b45eeaULL, 0x543fbbc59184ae2aULL, + 0x2297d4e7c5435211ULL, 0xec4dde44a893e576ULL, 0x5eb674055bc2ed2fULL, + 0x6aa1ebb4de4a7f35ULL, 0x81a9145bdabd73ceULL, 0x0c058a808c8f8906ULL, + 0x75eec302772d99b4ULL, 0x89af1350d9bc76caULL, 0x946ff32db99cd64aULL, + 0x77610bc9be6adfb5ULL, 0x3a9dddfac0405d1dULL, 0x3698577a4ccfd41bULL, + 0x79eb4982fba210b2ULL, 0x7427a7e99d80ba3aULL, 0x42bff093d14f6e21ULL, + 0xf8425dd9211f637cULL, 0x1e864c5d43cac50fULL, 0x39db71dae3aa3892ULL, + 0x2a91d3ecc6425715ULL +}; + +static const u64 T6[256] = { + 0x6a01bbb9d268bad3ULL, 0x66b1e59a4d1954fcULL, 0x14cde265bc932f71ULL, + 0x1b512587cdb9749cULL, 0x57a4f7a2510253f5ULL, 0xbe03d0d66bb8d368ULL, + 0xb504d6de6fbdd26bULL, 0x85feb35229644dd7ULL, 0x4aadfdba5d0d50f0ULL, + 0xe063cf098a26ace9ULL, 0x9684091c0e838d8aULL, 0x4d1aa591c679bfdcULL, + 0x374d3da7ddad7090ULL, 0x5ca3f1aa550752f6ULL, 0x17e17ba452c89ab3ULL, + 0x8ef9b55a2d614cd4ULL, 0x20ac46038f65ea23ULL, 0x8411c4e673a6d562ULL, + 0x68c255cc66f197a4ULL, 0xa80ddcc663b2d16eULL, 0xd099aa85ccff3355ULL, + 0x41aafbb2590851f3ULL, 0x0f9cc7e2712a5bedULL, 0xae55f359a204a6f7ULL, + 0xc120febe5f81de7fULL, 0xa2e5ad7a3d7548d8ULL, 0xcc7fd7299a32a8e5ULL, + 0x0ae871bc5ec799b6ULL, 0xe63be0964b90db70ULL, 0xdb9eac8dc8fa3256ULL, + 0x152295d1e651b7c4ULL, 0xaace32b3d72bfc19ULL, 0x7393704bab48e338ULL, + 0x3bfd638442dc9ebfULL, 0x52d041fc7eef91aeULL, 0x1ce67dac56cd9bb0ULL, + 0x78947643af4de23bULL, 0x6106bdb1d66dbbd0ULL, 0xf1da9b32195841c3ULL, + 0xe5177957a5cb6eb2ULL, 0xb35cf941ae0ba5f2ULL, 0x564b80160bc0cb40ULL, + 0xc20c677fb1da6bbdULL, 0x7ecc59dc6efb95a2ULL, 0x9f40e161be1fa1feULL, + 0xc3e310cbeb18f308ULL, 0x2f3081e1fe4fb1ceULL, 0x160e0c10080a0206ULL, + 0x675e922e17dbcc49ULL, 0x3f66a26e37f3c451ULL, 0xcf534ee874691d27ULL, + 0x9c6c78a05044143cULL, 0x0e73b0562be8c358ULL, 0x9a34573f91f263a5ULL, + 0xed3ce69e4f95da73ULL, 0x358ed3d269345de7ULL, 0x2380dfc2613e5fe1ULL, + 0xd72ef2ae578bdc79ULL, 0x486e13cfe9947d87ULL, 0x6c59942613decd4aULL, + 0x5e601fdfe19e7f81ULL, 0x049bc1ea752f5aeeULL, 0xf3197547adc16cb4ULL, + 0x3e89d5da6d315ce4ULL, 0xefff08ebfb0cf704ULL, 0x47f2d42d98be266aULL, + 0xb7c738abdb24ff1cULL, 0x11b9543b937eed2aULL, 0x36a24a13876fe825ULL, + 0x26f4699c4ed39dbaULL, 0xee107f5fa1ce6fb1ULL, 0x8b8d0304028c8e8fULL, + 0xe34f56c8647d192bULL, 0x9447e769ba1aa0fdULL, 0xdeea1ad3e717f00dULL, + 0xba98113c1e978986ULL, 0x692d22783c330f11ULL, 0x311512381c1b0709ULL, + 0xfd6ac5118629afecULL, 0x9bdb208bcb30fb10ULL, 0x5838304020280818ULL, + 0x976b7ea85441153fULL, 0x7f232e6834390d17ULL, 0x2c1c18201014040cULL, + 0x0b07060804050103ULL, 0xab2145078de964acULL, 0xca27f8b65b84df7cULL, + 0x0d5f2997c5b3769aULL, 0x64720beff980798bULL, 0xdc29f4a6538edd7aULL, + 0xb2b38ef5f4c93d47ULL, 0x8a6274b0584e163aULL, 0xa4bd82e5fcc33f41ULL, + 0xfc85b2a5dceb3759ULL, 0xf81e734fa9c46db7ULL, 0x95a890dde0d83848ULL, + 0x7708b1a1de67b9d6ULL, 0x2a4437bfd1a27395ULL, 0x3da54c1b836ae926ULL, + 0xea8bbeb5d4e1355fULL, 0x6db6e392491c55ffULL, 0x3c4a3bafd9a87193ULL, + 0x727c07fff18a7b8dULL, 0x9d830f140a868c89ULL, 0x214331b7d5a77296ULL, + 0xb19f17341a928885ULL, 0xe4f80ee3ff09f607ULL, 0x33d6fc4da8822a7eULL, + 0xafba84edf8c63e42ULL, 0x2887d9ca653b5ee2ULL, 0x4cf5d2259cbb2769ULL, + 0xc0cf890a054346caULL, 0x74242860303c0c14ULL, 0xa026430f89ec65afULL, + 0xdf056d67bdd568b8ULL, 0x8c3a5b2f99f861a3ULL, 0x1d090a180c0f0305ULL, + 0x187dbc4623e2c15eULL, 0x7bb8ef82411657f9ULL, 0x9918cefe7fa9d667ULL, + 0xf035ec86439ad976ULL, 0x1295cdfa7d2558e8ULL, 0xfb32ea8e479fd875ULL, + 0xbd2f491785e366aaULL, 0x921fc8f67bacd764ULL, 0x83a69ccde8d23a4eULL, + 0x4b428a0e07cfc845ULL, 0xb9b488fdf0cc3c44ULL, 0x90dc2683cf35fa13ULL, + 0x63c553c462f496a7ULL, 0xa552f551a601a7f4ULL, 0x01ef77b45ac298b5ULL, + 0x1abe5233977bec29ULL, 0x7c0fb7a9da62b8d5ULL, 0x226fa8763bfcc754ULL, + 0xf66dc319822caeefULL, 0xd4026b6fb9d069bbULL, 0xbfeca762317a4bddULL, + 0xd176dd31963dabe0ULL, 0xc778d1219e37a9e6ULL, 0xb6284f1f81e667a9ULL, + 0x4e363c5028220a1eULL, 0xcbc88f02014647c9ULL, 0xc8e416c3ef1df20bULL, + 0x032c99c1ee5bb5c2ULL, 0x6beecc0d88aa2266ULL, 0x4981647bb356e532ULL, + 0x0cb05e239f71ee2fULL, 0x461da399c27cbedfULL, 0x38d1fa45ac872b7dULL, + 0xe2a0217c3ebf819eULL, 0xa67e6c90485a1236ULL, 0xf4ae2d6c36b58398ULL, + 0xf5415ad86c771b2dULL, 0x622a247038360e12ULL, 0x60e9ca058caf2365ULL, + 0xf9f104fbf306f502ULL, 0xddc68312094c45cfULL, 0x76e7c61584a52163ULL, + 0x71509e3e1fd1ce4fULL, 0xa9e2ab72397049dbULL, 0x09c4e87db09c2c74ULL, + 0x8dd52c9bc33af916ULL, 0x54886e63bf59e637ULL, 0x1e2593d9e254b6c7ULL, + 0x25d8f05da0882878ULL, 0x816572b85c4b1739ULL, 0xffa92b6432b0829bULL, + 0xfe465cd068721a2eULL, 0xac961d2c169d8b80ULL, 0xbcc03ea3df21fe1fULL, + 0xa7911b2412988a83ULL, 0x533f3648242d091bULL, 0x40458c0603cac946ULL, + 0xd8b2354c26a18794ULL, 0x98f7b94a256b4ed2ULL, 0x659d7c5ba342e13eULL, + 0x1fcae46db8962e72ULL, 0x42866273b753e431ULL, 0x6e9a7a53a747e03dULL, + 0x2bab400b8b60eb20ULL, 0x59d747f47aea90adULL, 0xb85bff49aa0ea4f1ULL, + 0xd25a44f078661e22ULL, 0xcebc395c2eab8592ULL, 0x873d5d279dfd60a0ULL, + 0x0000000000000000ULL, 0x5afbde3594b1256fULL, 0xf2f602f3f703f401ULL, + 0xd5ed1cdbe312f10eULL, 0x75cb5fd46afe94a1ULL, 0x45313a582c270b1dULL, + 0x5f8f686bbb5ce734ULL, 0x1056238fc9bc759fULL, 0x07b7582b9b74ef2cULL, + 0xe18cb8bdd0e4345cULL, 0xc697a695c4f53153ULL, 0x8f16c2ee77a3d461ULL, + 0xa30adace67b7d06dULL, 0xd3b5334422a48697ULL, 0x556719d7e59b7e82ULL, + 0xeb64c9018e23adeaULL, 0xa1c934bbd32efd1aULL, 0x2edff655a48d297bULL, + 0xcd90a09dc0f03050ULL, 0x88a19ac5ecd73b4dULL, 0x30fa658c46d99fbcULL, + 0x86d22a93c73ff815ULL, 0x2968ae7e3ff9c657ULL, 0xad796a984c5f1335ULL, + 0x3a121430181e060aULL, 0x271b1e281411050fULL, 0x3461a46633f6c552ULL, + 0xbb77668844551133ULL, 0x06582f9fc1b67799ULL, 0x436915c7ed917c84ULL, + 0x797b01f7f58f7a8eULL, 0x6f750de7fd857888ULL, 0xf782b4add8ee365aULL, + 0xc45448e0706c1c24ULL, 0x9eaf96d5e4dd394bULL, 0x1992cbf2792059ebULL, + 0xe84850c060781828ULL, 0x70bfe98a451356faULL, 0x393e8df1f645b3c8ULL, + 0x243787e9fa4ab0cdULL, 0x51fcd83d90b4246cULL, 0x7de0c01d80a02060ULL, + 0x32398bf9f240b2cbULL, 0x4fd94be472e092abULL, 0x894eed71b615a3f8ULL, + 0x137aba4e27e7c05dULL, 0xd6c1851a0d4944ccULL, 0x9133513795f762a6ULL, + 0xb070608040501030ULL, 0x082b9fc9ea5eb4c1ULL, 0xc5bb3f542aae8491ULL, + 0xe7d49722115243c5ULL, 0x44de4dec76e593a8ULL, 0x0574b65e2fedc25bULL, + 0xb4eba16a357f4adeULL, 0x5b14a981ce73bddaULL, 0x808a050c06898f8cULL, + 0x02c3ee75b4992d77ULL, 0x5013af89ca76bcd9ULL, 0x2df36f944ad69cb9ULL, + 0xc90b6177b5df6abeULL, 0xfadd9d3a1d5d40c0ULL, 0x7a5798361bd4cf4cULL, + 0x8249eb79b210a2fbULL, 0xe9a727743aba809dULL, 0x93f0bf42216e4fd1ULL, + 0xd95d42f87c631f21ULL, 0x5d4c861e0fc5ca43ULL, 0xda71db399238aae3ULL, + 0xecd3912a155742c6ULL +}; + +static const u64 T7[256] = { + 0x016ab9bb68d2d3baULL, 0xb1669ae5194dfc54ULL, 0xcd1465e293bc712fULL, + 0x511b8725b9cd9c74ULL, 0xa457a2f70251f553ULL, 0x03bed6d0b86b68d3ULL, + 0x04b5ded6bd6f6bd2ULL, 0xfe8552b36429d74dULL, 0xad4abafd0d5df050ULL, + 0x63e009cf268ae9acULL, 0x84961c09830e8a8dULL, 0x1a4d91a579c6dcbfULL, + 0x4d37a73daddd9070ULL, 0xa35caaf10755f652ULL, 0xe117a47bc852b39aULL, + 0xf98e5ab5612dd44cULL, 0xac200346658f23eaULL, 0x1184e6c4a67362d5ULL, + 0xc268cc55f166a497ULL, 0x0da8c6dcb2636ed1ULL, 0x99d085aaffcc5533ULL, + 0xaa41b2fb0859f351ULL, 0x9c0fe2c72a71ed5bULL, 0x55ae59f304a2f7a6ULL, + 0x20c1befe815f7fdeULL, 0xe5a27aad753dd848ULL, 0x7fcc29d7329ae5a8ULL, + 0xe80abc71c75eb699ULL, 0x3be696e0904b70dbULL, 0x9edb8dacfac85632ULL, + 0x2215d19551e6c4b7ULL, 0xceaab3322bd719fcULL, 0x93734b7048ab38e3ULL, + 0xfd3b8463dc42bf9eULL, 0xd052fc41ef7eae91ULL, 0xe61cac7dcd56b09bULL, + 0x947843764daf3be2ULL, 0x0661b1bd6dd6d0bbULL, 0xdaf1329b5819c341ULL, + 0x17e55779cba5b26eULL, 0x5cb341f90baef2a5ULL, 0x4b561680c00b40cbULL, + 0x0cc27f67dab1bd6bULL, 0xcc7edc59fb6ea295ULL, 0x409f61e11fbefea1ULL, + 0xe3c3cb1018eb08f3ULL, 0x302fe1814ffeceb1ULL, 0x0e16100c0a080602ULL, + 0x5e672e92db1749ccULL, 0x663f6ea2f33751c4ULL, 0x53cfe84e6974271dULL, + 0x6c9ca07844503c14ULL, 0x730e56b0e82b58c3ULL, 0x349a3f57f291a563ULL, + 0x3ced9ee6954f73daULL, 0x8e35d2d33469e75dULL, 0x8023c2df3e61e15fULL, + 0x2ed7aef28b5779dcULL, 0x6e48cf1394e9877dULL, 0x596c2694de134acdULL, + 0x605edf1f9ee1817fULL, 0x9b04eac12f75ee5aULL, 0x19f34775c1adb46cULL, + 0x893edad5316de45cULL, 0xffefeb080cfb04f7ULL, 0xf2472dd4be986a26ULL, + 0xc7b7ab3824db1cffULL, 0xb9113b547e932aedULL, 0xa236134a6f8725e8ULL, + 0xf4269c69d34eba9dULL, 0x10ee5f7fcea1b16fULL, 0x8d8b04038c028f8eULL, + 0x4fe3c8567d642b19ULL, 0x479469e71abafda0ULL, 0xeaded31a17e70df0ULL, + 0x98ba3c11971e8689ULL, 0x2d697822333c110fULL, 0x153138121b1c0907ULL, + 0x6afd11c52986ecafULL, 0xdb9b8b2030cb10fbULL, 0x3858403028201808ULL, + 0x6b97a87e41543f15ULL, 0x237f682e3934170dULL, 0x1c2c201814100c04ULL, + 0x070b080605040301ULL, 0x21ab0745e98dac64ULL, 0x27cab6f8845b7cdfULL, + 0x5f0d9729b3c59a76ULL, 0x7264ef0b80f98b79ULL, 0x29dca6f48e537addULL, + 0xb3b2f58ec9f4473dULL, 0x628ab0744e583a16ULL, 0xbda4e582c3fc413fULL, + 0x85fca5b2ebdc5937ULL, 0x1ef84f73c4a9b76dULL, 0xa895dd90d8e04838ULL, + 0x0877a1b167ded6b9ULL, 0x442abf37a2d19573ULL, 0xa53d1b4c6a8326e9ULL, + 0x8beab5bee1d45f35ULL, 0xb66d92e31c49ff55ULL, 0x4a3caf3ba8d99371ULL, + 0x7c72ff078af18d7bULL, 0x839d140f860a898cULL, 0x4321b731a7d59672ULL, + 0x9fb13417921a8588ULL, 0xf8e4e30e09ff07f6ULL, 0xd6334dfc82a87e2aULL, + 0xbaafed84c6f8423eULL, 0x8728cad93b65e25eULL, 0xf54c25d2bb9c6927ULL, + 0xcfc00a894305ca46ULL, 0x247460283c30140cULL, 0x26a00f43ec89af65ULL, + 0x05df676dd5bdb868ULL, 0x3a8c2f5bf899a361ULL, 0x091d180a0f0c0503ULL, + 0x7d1846bce2235ec1ULL, 0xb87b82ef1641f957ULL, 0x1899fecea97f67d6ULL, + 0x35f086ec9a4376d9ULL, 0x9512facd257de858ULL, 0x32fb8eea9f4775d8ULL, + 0x2fbd1749e385aa66ULL, 0x1f92f6c8ac7b64d7ULL, 0xa683cd9cd2e84e3aULL, + 0x424b0e8acf0745c8ULL, 0xb4b9fd88ccf0443cULL, 0xdc90832635cf13faULL, + 0xc563c453f462a796ULL, 0x52a551f501a6f4a7ULL, 0xef01b477c25ab598ULL, + 0xbe1a33527b9729ecULL, 0x0f7ca9b762dad5b8ULL, 0x6f2276a8fc3b54c7ULL, + 0x6df619c32c82efaeULL, 0x02d46f6bd0b9bb69ULL, 0xecbf62a77a31dd4bULL, + 0x76d131dd3d96e0abULL, 0x78c721d1379ee6a9ULL, 0x28b61f4fe681a967ULL, + 0x364e503c22281e0aULL, 0xc8cb028f4601c947ULL, 0xe4c8c3161def0bf2ULL, + 0x2c03c1995beec2b5ULL, 0xee6b0dccaa886622ULL, 0x81497b6456b332e5ULL, + 0xb00c235e719f2feeULL, 0x1d4699a37cc2dfbeULL, 0xd13845fa87ac7d2bULL, + 0xa0e27c21bf3e9e81ULL, 0x7ea6906c5a483612ULL, 0xaef46c2db5369883ULL, + 0x41f5d85a776c2d1bULL, 0x2a6270243638120eULL, 0xe96005caaf8c6523ULL, + 0xf1f9fb0406f302f5ULL, 0xc6dd12834c09cf45ULL, 0xe77615c6a5846321ULL, + 0x50713e9ed11f4fceULL, 0xe2a972ab7039db49ULL, 0xc4097de89cb0742cULL, + 0xd58d9b2c3ac316f9ULL, 0x8854636e59bf37e6ULL, 0x251ed99354e2c7b6ULL, + 0xd8255df088a07828ULL, 0x6581b8724b5c3917ULL, 0xa9ff642bb0329b82ULL, + 0x46fed05c72682e1aULL, 0x96ac2c1d9d16808bULL, 0xc0bca33e21df1ffeULL, + 0x91a7241b9812838aULL, 0x3f5348362d241b09ULL, 0x4540068cca0346c9ULL, + 0xb2d84c35a1269487ULL, 0xf7984ab96b25d24eULL, 0x9d655b7c42a33ee1ULL, + 0xca1f6de496b8722eULL, 0x8642736253b731e4ULL, 0x9a6e537a47a73de0ULL, + 0xab2b0b40608b20ebULL, 0xd759f447ea7aad90ULL, 0x5bb849ff0eaaf1a4ULL, + 0x5ad2f0446678221eULL, 0xbcce5c39ab2e9285ULL, 0x3d87275dfd9da060ULL, + 0x0000000000000000ULL, 0xfb5a35deb1946f25ULL, 0xf6f2f30203f701f4ULL, + 0xedd5db1c12e30ef1ULL, 0xcb75d45ffe6aa194ULL, 0x3145583a272c1d0bULL, + 0x8f5f6b685cbb34e7ULL, 0x56108f23bcc99f75ULL, 0xb7072b58749b2cefULL, + 0x8ce1bdb8e4d05c34ULL, 0x97c695a6f5c45331ULL, 0x168feec2a37761d4ULL, + 0x0aa3cedab7676dd0ULL, 0xb5d34433a4229786ULL, 0x6755d7199be5827eULL, + 0x64eb01c9238eeaadULL, 0xc9a1bb342ed31afdULL, 0xdf2e55f68da47b29ULL, + 0x90cd9da0f0c05030ULL, 0xa188c59ad7ec4d3bULL, 0xfa308c65d946bc9fULL, + 0xd286932a3fc715f8ULL, 0x68297eaef93f57c6ULL, 0x79ad986a5f4c3513ULL, + 0x123a30141e180a06ULL, 0x1b27281e11140f05ULL, 0x613466a4f63352c5ULL, + 0x77bb886655443311ULL, 0x58069f2fb6c19977ULL, 0x6943c71591ed847cULL, + 0x7b79f7018ff58e7aULL, 0x756fe70d85fd8878ULL, 0x82f7adb4eed85a36ULL, + 0x54c4e0486c70241cULL, 0xaf9ed596dde44b39ULL, 0x9219f2cb2079eb59ULL, + 0x48e8c05078602818ULL, 0xbf708ae91345fa56ULL, 0x3e39f18d45f6c8b3ULL, + 0x3724e9874afacdb0ULL, 0xfc513dd8b4906c24ULL, 0xe07d1dc0a0806020ULL, + 0x3932f98b40f2cbb2ULL, 0xd94fe44be072ab92ULL, 0x4e8971ed15b6f8a3ULL, + 0x7a134ebae7275dc0ULL, 0xc1d61a85490dcc44ULL, 0x33913751f795a662ULL, + 0x70b0806050403010ULL, 0x2b08c99f5eeac1b4ULL, 0xbbc5543fae2a9184ULL, + 0xd4e722975211c543ULL, 0xde44ec4de576a893ULL, 0x74055eb6ed2f5bc2ULL, + 0xebb46aa17f35de4aULL, 0x145b81a973cedabdULL, 0x8a800c0589068c8fULL, + 0xc30275ee99b4772dULL, 0x135089af76cad9bcULL, 0xf32d946fd64ab99cULL, + 0x0bc97761dfb5be6aULL, 0xddfa3a9d5d1dc040ULL, 0x577a3698d41b4ccfULL, + 0x498279eb10b2fba2ULL, 0xa7e97427ba3a9d80ULL, 0xf09342bf6e21d14fULL, + 0x5dd9f842637c211fULL, 0x4c5d1e86c50f43caULL, 0x71da39db3892e3aaULL, + 0xd3ec2a915715c642ULL +}; + +static const u64 c[KHAZAD_ROUNDS + 1] = { + 0xba542f7453d3d24dULL, 0x50ac8dbf70529a4cULL, 0xead597d133515ba6ULL, + 0xde48a899db32b7fcULL, 0xe39e919be2bb416eULL, 0xa5cb6b95a1f3b102ULL, + 0xccc41d14c363da5dULL, 0x5fdc7dcd7f5a6c5cULL, 0xf726ffede89d6f8eULL +}; + +static int khazad_setkey(void *ctx_arg, const u8 *in_key, + unsigned int key_len, u32 *flags) +{ + + struct khazad_ctx *ctx = ctx_arg; + int r; + const u64 *S = T7; + u64 K2, K1; + + if (key_len != 16) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + K2 = ((u64)in_key[ 0] << 56) ^ + ((u64)in_key[ 1] << 48) ^ + ((u64)in_key[ 2] << 40) ^ + ((u64)in_key[ 3] << 32) ^ + ((u64)in_key[ 4] << 24) ^ + ((u64)in_key[ 5] << 16) ^ + ((u64)in_key[ 6] << 8) ^ + ((u64)in_key[ 7] ); + K1 = ((u64)in_key[ 8] << 56) ^ + ((u64)in_key[ 9] << 48) ^ + ((u64)in_key[10] << 40) ^ + ((u64)in_key[11] << 32) ^ + ((u64)in_key[12] << 24) ^ + ((u64)in_key[13] << 16) ^ + ((u64)in_key[14] << 8) ^ + ((u64)in_key[15] ); + + /* setup the encrypt key */ + for (r = 0; r <= KHAZAD_ROUNDS; r++) { + ctx->E[r] = T0[(int)(K1 >> 56) ] ^ + T1[(int)(K1 >> 48) & 0xff] ^ + T2[(int)(K1 >> 40) & 0xff] ^ + T3[(int)(K1 >> 32) & 0xff] ^ + T4[(int)(K1 >> 24) & 0xff] ^ + T5[(int)(K1 >> 16) & 0xff] ^ + T6[(int)(K1 >> 8) & 0xff] ^ + T7[(int)(K1 ) & 0xff] ^ + c[r] ^ K2; + K2 = K1; + K1 = ctx->E[r]; + } + /* Setup the decrypt key */ + ctx->D[0] = ctx->E[KHAZAD_ROUNDS]; + for (r = 1; r < KHAZAD_ROUNDS; r++) { + K1 = ctx->E[KHAZAD_ROUNDS - r]; + ctx->D[r] = T0[(int)S[(int)(K1 >> 56) ] & 0xff] ^ + T1[(int)S[(int)(K1 >> 48) & 0xff] & 0xff] ^ + T2[(int)S[(int)(K1 >> 40) & 0xff] & 0xff] ^ + T3[(int)S[(int)(K1 >> 32) & 0xff] & 0xff] ^ + T4[(int)S[(int)(K1 >> 24) & 0xff] & 0xff] ^ + T5[(int)S[(int)(K1 >> 16) & 0xff] & 0xff] ^ + T6[(int)S[(int)(K1 >> 8) & 0xff] & 0xff] ^ + T7[(int)S[(int)(K1 ) & 0xff] & 0xff]; + } + ctx->D[KHAZAD_ROUNDS] = ctx->E[0]; + + return 0; + +} + +static void khazad_crypt(const u64 roundKey[KHAZAD_ROUNDS + 1], + u8 *ciphertext, const u8 *plaintext) +{ + + int r; + u64 state; + + state = ((u64)plaintext[0] << 56) ^ + ((u64)plaintext[1] << 48) ^ + ((u64)plaintext[2] << 40) ^ + ((u64)plaintext[3] << 32) ^ + ((u64)plaintext[4] << 24) ^ + ((u64)plaintext[5] << 16) ^ + ((u64)plaintext[6] << 8) ^ + ((u64)plaintext[7] ) ^ + roundKey[0]; + + for (r = 1; r < KHAZAD_ROUNDS; r++) { + state = T0[(int)(state >> 56) ] ^ + T1[(int)(state >> 48) & 0xff] ^ + T2[(int)(state >> 40) & 0xff] ^ + T3[(int)(state >> 32) & 0xff] ^ + T4[(int)(state >> 24) & 0xff] ^ + T5[(int)(state >> 16) & 0xff] ^ + T6[(int)(state >> 8) & 0xff] ^ + T7[(int)(state ) & 0xff] ^ + roundKey[r]; + } + + state = (T0[(int)(state >> 56) ] & 0xff00000000000000ULL) ^ + (T1[(int)(state >> 48) & 0xff] & 0x00ff000000000000ULL) ^ + (T2[(int)(state >> 40) & 0xff] & 0x0000ff0000000000ULL) ^ + (T3[(int)(state >> 32) & 0xff] & 0x000000ff00000000ULL) ^ + (T4[(int)(state >> 24) & 0xff] & 0x00000000ff000000ULL) ^ + (T5[(int)(state >> 16) & 0xff] & 0x0000000000ff0000ULL) ^ + (T6[(int)(state >> 8) & 0xff] & 0x000000000000ff00ULL) ^ + (T7[(int)(state ) & 0xff] & 0x00000000000000ffULL) ^ + roundKey[KHAZAD_ROUNDS]; + + ciphertext[0] = (u8)(state >> 56); + ciphertext[1] = (u8)(state >> 48); + ciphertext[2] = (u8)(state >> 40); + ciphertext[3] = (u8)(state >> 32); + ciphertext[4] = (u8)(state >> 24); + ciphertext[5] = (u8)(state >> 16); + ciphertext[6] = (u8)(state >> 8); + ciphertext[7] = (u8)(state ); + +} + +static void khazad_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct khazad_ctx *ctx = ctx_arg; + khazad_crypt(ctx->E, dst, src); +} + +static void khazad_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct khazad_ctx *ctx = ctx_arg; + khazad_crypt(ctx->D, dst, src); +} + +static struct crypto_alg khazad_alg = { + .cra_name = "khazad", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = KHAZAD_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct khazad_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(khazad_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = KHAZAD_KEY_SIZE, + .cia_max_keysize = KHAZAD_KEY_SIZE, + .cia_setkey = khazad_setkey, + .cia_encrypt = khazad_encrypt, + .cia_decrypt = khazad_decrypt } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&khazad_alg); + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&khazad_alg); +} + + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Khazad Cryptographic Algorithm"); diff -urN linux-2.4.27/crypto/scatterwalk.c linux-2.4.28/crypto/scatterwalk.c --- linux-2.4.27/crypto/scatterwalk.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/crypto/scatterwalk.c 2004-11-17 03:54:21.174380461 -0800 @@ -70,7 +70,7 @@ { /* walk->data may be pointing the first byte of the next page; however, we know we transfered at least one byte. So, - walk->data - 1 will be a virutual address in the mapped page. */ + walk->data - 1 will be a virtual address in the mapped page. */ if (out) flush_dcache_page(walk->page); diff -urN linux-2.4.27/crypto/serpent.c linux-2.4.28/crypto/serpent.c --- linux-2.4.27/crypto/serpent.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/crypto/serpent.c 2004-11-17 03:54:21.175380502 -0800 @@ -4,6 +4,10 @@ * Serpent Cipher Algorithm. * * Copyright (C) 2002 Dag Arne Osvik + * 2003 Herbert Valerio Riedel + * + * Added tnepres support: Ruben Jesus Garcia Hernandez , 18.10.2004 + * Based on code by hvr * * 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 @@ -212,7 +216,8 @@ u32 expkey[SERPENT_EXPKEY_WORDS]; }; -static int setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) + +static int serpent_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) { u32 *k = ((struct serpent_ctx *)ctx)->expkey; u8 *k8 = (u8 *)k; @@ -362,7 +367,7 @@ return 0; } -static void encrypt(void *ctx, u8 *dst, const u8 *src) +static void serpent_encrypt(void *ctx, u8 *dst, const u8 *src) { const u32 *k = ((struct serpent_ctx *)ctx)->expkey, @@ -420,7 +425,7 @@ d[3] = cpu_to_le32(r3); } -static void decrypt(void *ctx, u8 *dst, const u8 *src) +static void serpent_decrypt(void *ctx, u8 *dst, const u8 *src) { const u32 *k = ((struct serpent_ctx *)ctx)->expkey, @@ -483,18 +488,101 @@ .cra_u = { .cipher = { .cia_min_keysize = SERPENT_MIN_KEY_SIZE, .cia_max_keysize = SERPENT_MAX_KEY_SIZE, - .cia_setkey = setkey, - .cia_encrypt = encrypt, - .cia_decrypt = decrypt } } + .cia_setkey = serpent_setkey, + .cia_encrypt = serpent_encrypt, + .cia_decrypt = serpent_decrypt } } +}; + +static int tnepres_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + u8 rev_key[SERPENT_MAX_KEY_SIZE]; + int i; + + if ((keylen < SERPENT_MIN_KEY_SIZE) + || (keylen > SERPENT_MAX_KEY_SIZE)) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + for (i = 0; i < keylen; ++i) + rev_key[keylen - i - 1] = key[i]; + + return serpent_setkey(ctx, rev_key, keylen, flags); +} + +static void tnepres_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 * const s = (const u32 * const)src; + u32 * const d = (u32 * const)dst; + + u32 rs[4], rd[4]; + + rs[0] = swab32(s[3]); + rs[1] = swab32(s[2]); + rs[2] = swab32(s[1]); + rs[3] = swab32(s[0]); + + serpent_encrypt(ctx, (u8 *)rd, (u8 *)rs); + + d[0] = swab32(rd[3]); + d[1] = swab32(rd[2]); + d[2] = swab32(rd[1]); + d[3] = swab32(rd[0]); +} + +static void tnepres_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 * const s = (const u32 * const)src; + u32 * const d = (u32 * const)dst; + + u32 rs[4], rd[4]; + + rs[0] = swab32(s[3]); + rs[1] = swab32(s[2]); + rs[2] = swab32(s[1]); + rs[3] = swab32(s[0]); + + serpent_decrypt(ctx, (u8 *)rd, (u8 *)rs); + + d[0] = swab32(rd[3]); + d[1] = swab32(rd[2]); + d[2] = swab32(rd[1]); + d[3] = swab32(rd[0]); +} + +static struct crypto_alg tnepres_alg = { + .cra_name = "tnepres", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = SERPENT_MIN_KEY_SIZE, + .cia_max_keysize = SERPENT_MAX_KEY_SIZE, + .cia_setkey = tnepres_setkey, + .cia_encrypt = tnepres_encrypt, + .cia_decrypt = tnepres_decrypt } } }; static int __init init(void) { - return crypto_register_alg(&serpent_alg); + int ret = crypto_register_alg(&serpent_alg); + + if (ret) + return ret; + + ret = crypto_register_alg(&tnepres_alg); + + if (ret) + crypto_unregister_alg(&serpent_alg); + + return ret; } static void __exit fini(void) { + crypto_unregister_alg(&tnepres_alg); crypto_unregister_alg(&serpent_alg); } @@ -502,5 +590,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Serpent Cipher Algorithm"); +MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm"); MODULE_AUTHOR("Dag Arne Osvik "); diff -urN linux-2.4.27/crypto/tcrypt.c linux-2.4.28/crypto/tcrypt.c --- linux-2.4.27/crypto/tcrypt.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/tcrypt.c 2004-11-17 03:54:21.176380543 -0800 @@ -63,7 +63,8 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "arc4", "michael_mic", "deflate", "tea", "xtea", NULL + "arc4", "michael_mic", "deflate", "tea", "xtea", "khazad", + "wp512", "wp384", "wp256", "tnepres", "anubis", NULL }; static void @@ -550,6 +551,10 @@ test_cipher ("serpent", MODE_ECB, ENCRYPT, serpent_enc_tv_template, SERPENT_ENC_TEST_VECTORS); test_cipher ("serpent", MODE_ECB, DECRYPT, serpent_dec_tv_template, SERPENT_DEC_TEST_VECTORS); + //TNEPRES + test_cipher ("tnepres", MODE_ECB, ENCRYPT, tnepres_enc_tv_template, TNEPRES_ENC_TEST_VECTORS); + test_cipher ("tnepres", MODE_ECB, DECRYPT, tnepres_dec_tv_template, TNEPRES_DEC_TEST_VECTORS); + //AES test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS); test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS); @@ -575,8 +580,21 @@ test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS); test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); + //KHAZAD + test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS); + test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); + + //ANUBIS + test_cipher ("anubis", MODE_ECB, ENCRYPT, anubis_enc_tv_template, ANUBIS_ENC_TEST_VECTORS); + test_cipher ("anubis", MODE_ECB, DECRYPT, anubis_dec_tv_template, ANUBIS_DEC_TEST_VECTORS); + test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); + test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); test_deflate(); #ifdef CONFIG_CRYPTO_HMAC test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); @@ -630,6 +648,8 @@ break; case 9: + test_cipher ("serpent", MODE_ECB, ENCRYPT, serpent_enc_tv_template, SERPENT_ENC_TEST_VECTORS); + test_cipher ("serpent", MODE_ECB, DECRYPT, serpent_dec_tv_template, SERPENT_DEC_TEST_VECTORS); break; case 10: @@ -678,6 +698,33 @@ test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); break; + case 21: + test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS); + test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); + case 22: + test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); + break; + + case 23: + test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS); + break; + + case 24: + test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS); + break; + + case 25: + test_cipher ("tnepres", MODE_ECB, ENCRYPT, tnepres_enc_tv_template, TNEPRES_ENC_TEST_VECTORS); + test_cipher ("tnepres", MODE_ECB, DECRYPT, tnepres_dec_tv_template, TNEPRES_DEC_TEST_VECTORS); + break; + + case 26: + test_cipher ("anubis", MODE_ECB, ENCRYPT, anubis_enc_tv_template, ANUBIS_ENC_TEST_VECTORS); + test_cipher ("anubis", MODE_ECB, DECRYPT, anubis_dec_tv_template, ANUBIS_DEC_TEST_VECTORS); + test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); + test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); + break; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); diff -urN linux-2.4.27/crypto/tcrypt.h linux-2.4.28/crypto/tcrypt.h --- linux-2.4.27/crypto/tcrypt.h 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/tcrypt.h 2004-11-17 03:54:21.179380666 -0800 @@ -551,6 +551,257 @@ #endif /* CONFIG_CRYPTO_HMAC */ /* + * WHIRLPOOL test vectors from Whirlpool package + * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE + * submission + */ +#define WP512_TEST_VECTORS 8 + +struct hash_testvec wp512_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, + 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57, + 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, + 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42, + 0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6, + 0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59, + 0x1A, 0x92, 0x20, 0x0D, 0x56, 0x01, 0x95, 0xE5, + 0x3B, 0x47, 0x85, 0x84, 0xFD, 0xAE, 0x23, 0x1A }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C, + 0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27, + 0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6, + 0xC7, 0x97, 0xFC, 0x9D, 0x95, 0xD8, 0xB5, 0x82, + 0xD2, 0x25, 0x29, 0x20, 0x76, 0xD4, 0xEE, 0xF5 }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B, + 0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1, + 0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6, + 0x92, 0xED, 0x92, 0x00, 0x52, 0x83, 0x8F, 0x33, + 0x62, 0xE8, 0x6D, 0xBD, 0x37, 0xA8, 0x90, 0x3E }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B, + 0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A, + 0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6, + 0xF6, 0x8F, 0x67, 0x3E, 0x72, 0x07, 0x86, 0x5D, + 0x5D, 0x98, 0x19, 0xA3, 0xDB, 0xA4, 0xEB, 0x3B }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E, + 0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F, + 0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6, + 0x55, 0x17, 0xCC, 0x87, 0x9D, 0x7B, 0x96, 0x21, + 0x42, 0xC6, 0x5F, 0x5A, 0x7A, 0xF0, 0x14, 0x67 }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29, + 0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5, + 0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A, + 0x2C, 0x60, 0x48, 0x1E, 0x88, 0xC5, 0xA2, 0x0B, + 0x2C, 0x2A, 0x80, 0xCF, 0x3A, 0x9A, 0x08, 0x3B }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69, + 0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B, + 0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56, + 0x93, 0x9B, 0xAA, 0xA0, 0xAD, 0xFF, 0x9A, 0xE6, + 0x74, 0x5B, 0x7B, 0x18, 0x1C, 0x3B, 0xE3, 0xFD }, + }, +}; + +#define WP384_TEST_VECTORS 8 + +struct hash_testvec wp384_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, + 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42, + 0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6, + 0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59 }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C, + 0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27, + 0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6 }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B, + 0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1, + 0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6 }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B, + 0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A, + 0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6 }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E, + 0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F, + 0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6 }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29, + 0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5, + 0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69, + 0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B, + 0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56 }, + }, +}; + +#define WP256_TEST_VECTORS 8 + +struct hash_testvec wp256_tv_template[] = { + { + .plaintext = "", + .psize = 0, + .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, + 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, + 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7 }, + + + }, { + .plaintext = "a", + .psize = 1, + .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F, + 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7, + 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69, + 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42 }, + }, { + .plaintext = "abc", + .psize = 3, + .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB, + 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B, + 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72, + 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C }, + }, { + .plaintext = "message digest", + .psize = 14, + .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, + 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, + 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, + 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B }, + }, { + .plaintext = "abcdefghijklmnopqrstuvwxyz", + .psize = 26, + .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9, + 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A, + 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5, + 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789", + .psize = 62, + .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B, + 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90, + 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC, + 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E }, + }, { + .plaintext = "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + .psize = 80, + .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D, + 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0, + 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6, + 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29 }, + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijk", + .psize = 32, + .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, + 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48, + 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62, + 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69 }, + }, +}; + +/* * DES test vectors. */ #define DES_ENC_TEST_VECTORS 10 @@ -1186,11 +1437,14 @@ /* * Serpent test vectors. These are backwards because Serpent writes - * octect sequences in right-to-left mode. + * octet sequences in right-to-left mode. */ #define SERPENT_ENC_TEST_VECTORS 4 #define SERPENT_DEC_TEST_VECTORS 4 +#define TNEPRES_ENC_TEST_VECTORS 4 +#define TNEPRES_DEC_TEST_VECTORS 4 + struct cipher_testvec serpent_enc_tv_template[] = { { @@ -1233,6 +1487,57 @@ }, }; +struct cipher_testvec tnepres_enc_tv_template[] = +{ + { /* KeySize=128, PT=0, I=1 */ + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .ilen = 16, + .result = { 0x49, 0xaf, 0xbf, 0xad, 0x9d, 0x5a, 0x34, 0x05, + 0x2c, 0xd8, 0xff, 0xa5, 0x98, 0x6b, 0xd2, 0xdd }, + .rlen = 16, + }, { /* KeySize=192, PT=0, I=1 */ + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 24, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 16, + .result = { 0xe7, 0x8e, 0x54, 0x02, 0xc7, 0x19, 0x55, 0x68, + 0xac, 0x36, 0x78, 0xf7, 0xa3, 0xf6, 0x0c, 0x66 }, + .rlen = 16, + }, { /* KeySize=256, PT=0, I=1 */ + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 32, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 16, + .result = { 0xab, 0xed, 0x96, 0xe7, 0x66, 0xbf, 0x28, 0xcb, + 0xc0, 0xeb, 0xd2, 0x1a, 0x82, 0xef, 0x08, 0x19 }, + .rlen = 16, + }, { /* KeySize=256, I=257 */ + .key = { 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }, + .klen = 32, + .input = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }, + .ilen = 16, + .result = { 0x5c, 0xe7, 0x1c, 0x70, 0xd2, 0x88, 0x2e, 0x5b, + 0xb8, 0x32, 0xe4, 0x33, 0xf8, 0x9f, 0x26, 0xde }, + .rlen = 16, + }, +}; + + struct cipher_testvec serpent_dec_tv_template[] = { { @@ -1275,6 +1580,49 @@ }, }; +struct cipher_testvec tnepres_dec_tv_template[] = +{ + { + .input = { 0x41, 0xcc, 0x6b, 0x31, 0x59, 0x31, 0x45, 0x97, + 0x6d, 0x6f, 0xbb, 0x38, 0x4b, 0x37, 0x21, 0x28 }, + .ilen = 16, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .rlen = 16, + }, { + .key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .klen = 16, + .input = { 0xea, 0xf4, 0xd7, 0xfc, 0xd8, 0x01, 0x34, 0x47, + 0x81, 0x45, 0x0b, 0xfa, 0x0c, 0xd6, 0xad, 0x6e }, + .ilen = 16, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .rlen = 16, + }, { + .key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .klen = 32, + .input = { 0x64, 0xa9, 0x1a, 0x37, 0xed, 0x9f, 0xe7, 0x49, + 0xa8, 0x4e, 0x76, 0xd6, 0xf5, 0x0d, 0x78, 0xee }, + .ilen = 16, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .rlen = 16, + }, { /* KeySize=128, I=121 */ + .key = { [15] = 0x80 }, + .klen = 16, + .input = { 0x3d, 0xda, 0xbf, 0xc0, 0x06, 0xda, 0xab, 0x06, + 0x46, 0x2a, 0xf4, 0xef, 0x81, 0x54, 0x4e, 0x26 }, + .ilen = 16, + .result = { [0 ... 15] = 0x00 }, + .rlen = 16, + }, +}; + + /* Cast6 test vectors from RFC 2612 */ #define CAST6_ENC_TEST_VECTORS 3 #define CAST6_DEC_TEST_VECTORS 3 @@ -1818,7 +2166,308 @@ } }; +/* + * KHAZAD test vectors. + */ +#define KHAZAD_ENC_TEST_VECTORS 5 +#define KHAZAD_DEC_TEST_VECTORS 5 + +struct cipher_testvec khazad_enc_tv_template[] = { + { + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x49, 0xa4, 0xce, 0x32, 0xac, 0x19, 0x0e, 0x3f }, + .rlen = 8, + }, { + .key = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .klen = 16, + .input = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .ilen = 8, + .result = { 0x7e, 0x82, 0x12, 0xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 }, + .rlen = 8, + }, { + .key = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, + 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .klen = 16, + .input = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .ilen = 8, + .result = { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .ilen = 8, + .result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f , + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .ilen = 16, + .result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 , + 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .rlen = 16, + }, +}; + +struct cipher_testvec khazad_dec_tv_template[] = { + { + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0X49, 0Xa4, 0Xce, 0X32, 0Xac, 0X19, 0X0e, 0X3f }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .klen = 16, + .input = { 0X7e, 0X82, 0X12, 0Xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 }, + .ilen = 8, + .result = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .rlen = 8, + }, { + .key = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, + 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .klen = 16, + .input = { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c }, + .ilen = 8, + .result = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .rlen = 8, + }, { + .key = { 0x2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .ilen = 8, + .result = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 , + 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .ilen = 16, + .result = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f , + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .rlen = 16, + }, +}; + +/* + * Anubis test vectors. + */ + +#define ANUBIS_ENC_TEST_VECTORS 5 +#define ANUBIS_DEC_TEST_VECTORS 5 +#define ANUBIS_CBC_ENC_TEST_VECTORS 2 +#define ANUBIS_CBC_DEC_TEST_VECTORS 2 + +struct cipher_testvec anubis_enc_tv_template[] = { + { + .key = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .klen = 16, + .input = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .ilen = 16, + .result = { 0x6d, 0xc5, 0xda, 0xa2, 0x26, 0x7d, 0x62, 0x6f, + 0x08, 0xb7, 0x52, 0x8e, 0x6e, 0x6e, 0x86, 0x90 }, + .rlen = 16, + }, { + + .key = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03 }, + .klen = 20, + .input = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }, + .ilen = 16, + .result = { 0xdb, 0xf1, 0x42, 0xf4, 0xd1, 0x8a, 0xc7, 0x49, + 0x87, 0x41, 0x6f, 0x82, 0x0a, 0x98, 0x64, 0xae }, + .rlen = 16, + }, { + .key = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24 }, + .klen = 28, + .input = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 }, + .ilen = 16, + .result = { 0xfd, 0x1b, 0x4a, 0xe3, 0xbf, 0xf0, 0xad, 0x3d, + 0x06, 0xd3, 0x61, 0x27, 0xfd, 0x13, 0x9e, 0xde }, + .rlen = 16, + }, { + .key = { 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25 }, + .klen = 32, + .input = { 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25 }, + .ilen = 16, + .result = { 0x1a, 0x91, 0xfb, 0x2b, 0xb7, 0x78, 0x6b, 0xc4, + 0x17, 0xd9, 0xff, 0x40, 0x3b, 0x0e, 0xe5, 0xfe }, + .rlen = 16, + }, { + .key = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .klen = 40, + .input = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .ilen = 16, + .result = { 0xa5, 0x2c, 0x85, 0x6f, 0x9c, 0xba, 0xa0, 0x97, + 0x9e, 0xc6, 0x84, 0x0f, 0x17, 0x21, 0x07, 0xee }, + .rlen = 16, + }, +}; + +struct cipher_testvec anubis_dec_tv_template[] = { + { + .key = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .klen = 16, + .input = { 0x6d, 0xc5, 0xda, 0xa2, 0x26, 0x7d, 0x62, 0x6f, + 0x08, 0xb7, 0x52, 0x8e, 0x6e, 0x6e, 0x86, 0x90 }, + .ilen = 16, + .result = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .rlen = 16, + }, { + + .key = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03 }, + .klen = 20, + .input = { 0xdb, 0xf1, 0x42, 0xf4, 0xd1, 0x8a, 0xc7, 0x49, + 0x87, 0x41, 0x6f, 0x82, 0x0a, 0x98, 0x64, 0xae }, + .ilen = 16, + .result = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }, + .rlen = 16, + }, { + .key = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24 }, + .klen = 28, + .input = { 0xfd, 0x1b, 0x4a, 0xe3, 0xbf, 0xf0, 0xad, 0x3d, + 0x06, 0xd3, 0x61, 0x27, 0xfd, 0x13, 0x9e, 0xde }, + .ilen = 16, + .result = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 }, + .rlen = 16, + }, { + .key = { 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25 }, + .klen = 32, + .input = { 0x1a, 0x91, 0xfb, 0x2b, 0xb7, 0x78, 0x6b, 0xc4, + 0x17, 0xd9, 0xff, 0x40, 0x3b, 0x0e, 0xe5, 0xfe }, + .ilen = 16, + .result = { 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25 }, + .rlen = 16, + }, { + .key = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .input = { 0xa5, 0x2c, 0x85, 0x6f, 0x9c, 0xba, 0xa0, 0x97, + 0x9e, 0xc6, 0x84, 0x0f, 0x17, 0x21, 0x07, 0xee }, + .klen = 40, + .ilen = 16, + .result = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .rlen = 16, + }, +}; + +struct cipher_testvec anubis_cbc_enc_tv_template[] = { + { + .key = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .klen = 16, + .input = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .ilen = 32, + .result = { 0x6d, 0xc5, 0xda, 0xa2, 0x26, 0x7d, 0x62, 0x6f, + 0x08, 0xb7, 0x52, 0x8e, 0x6e, 0x6e, 0x86, 0x90, + 0x86, 0xd8, 0xb5, 0x6f, 0x98, 0x5e, 0x8a, 0x66, + 0x4f, 0x1f, 0x78, 0xa1, 0xbb, 0x37, 0xf1, 0xbe }, + .rlen = 32, + }, { + .key = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .klen = 40, + .input = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .ilen = 32, + .result = { 0xa5, 0x2c, 0x85, 0x6f, 0x9c, 0xba, 0xa0, 0x97, + 0x9e, 0xc6, 0x84, 0x0f, 0x17, 0x21, 0x07, 0xee, + 0xa2, 0xbc, 0x06, 0x98, 0xc6, 0x4b, 0xda, 0x75, + 0x2e, 0xaa, 0xbe, 0x58, 0xce, 0x01, 0x5b, 0xc7 }, + .rlen = 32, + }, +}; +struct cipher_testvec anubis_cbc_dec_tv_template[] = { + { + .key = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .klen = 16, + .input = { 0x6d, 0xc5, 0xda, 0xa2, 0x26, 0x7d, 0x62, 0x6f, + 0x08, 0xb7, 0x52, 0x8e, 0x6e, 0x6e, 0x86, 0x90, + 0x86, 0xd8, 0xb5, 0x6f, 0x98, 0x5e, 0x8a, 0x66, + 0x4f, 0x1f, 0x78, 0xa1, 0xbb, 0x37, 0xf1, 0xbe }, + .ilen = 32, + .result = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, + .rlen = 32, + }, { + .key = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .klen = 40, + .input = { 0xa5, 0x2c, 0x85, 0x6f, 0x9c, 0xba, 0xa0, 0x97, + 0x9e, 0xc6, 0x84, 0x0f, 0x17, 0x21, 0x07, 0xee, + 0xa2, 0xbc, 0x06, 0x98, 0xc6, 0x4b, 0xda, 0x75, + 0x2e, 0xaa, 0xbe, 0x58, 0xce, 0x01, 0x5b, 0xc7 }, + .ilen = 32, + .result = { 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35 }, + .rlen = 32, + }, +}; /* * Compression stuff. diff -urN linux-2.4.27/crypto/tea.c linux-2.4.28/crypto/tea.c --- linux-2.4.27/crypto/tea.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/tea.c 2004-11-17 03:54:21.180380707 -0800 @@ -154,7 +154,7 @@ while (sum != limit) { y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; - sum += TEA_DELTA; + sum += XTEA_DELTA; z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; } diff -urN linux-2.4.27/crypto/twofish.c linux-2.4.28/crypto/twofish.c --- linux-2.4.27/crypto/twofish.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/crypto/twofish.c 2004-11-17 03:54:21.181380749 -0800 @@ -1,7 +1,7 @@ /* * Twofish for CryptoAPI * - * Originaly Twofish for GPG + * Originally Twofish for GPG * By Matthew Skala , July 26, 1998 * 256-bit key length added March 20, 1999 * Some modifications to reduce the text size by Werner Koch, April, 1998 @@ -514,7 +514,7 @@ * preprocessed through q0 and q1 respectively; for longer keys they are the * output of previous stages. j is the index of the first key byte to use. * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 - * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * twice, doing the Pseudo-Hadamard Transform, and doing the necessary * rotations. Its parameters are: a, the array to write the results into, * j, the index of the first output entry, k and l, the preprocessed indices * for index 2i, and m and n, the preprocessed indices for index 2i+1. diff -urN linux-2.4.27/crypto/wp512.c linux-2.4.28/crypto/wp512.c --- linux-2.4.27/crypto/wp512.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/crypto/wp512.c 2004-11-17 03:54:21.184380872 -0800 @@ -0,0 +1,1205 @@ +/* + * Cryptographic API. + * + * Whirlpool hashing Algorithm + * + * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and + * Vincent Rijmen. It has been selected as one of cryptographic + * primitives by the NESSIE project http://www.cryptonessie.org/ + * + * The original authors have disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors + * have put this under the GNU General Public License. + * + * By Aaron Grothe ajgrothe@yahoo.com, August 23, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include + +#define WP512_DIGEST_SIZE 64 +#define WP384_DIGEST_SIZE 48 +#define WP256_DIGEST_SIZE 32 + +#define WP512_BLOCK_SIZE 64 +#define WP512_LENGTHBYTES 32 + +#define WHIRLPOOL_ROUNDS 10 + +struct wp512_ctx { + u8 bitLength[WP512_LENGTHBYTES]; + u8 buffer[WP512_BLOCK_SIZE]; + int bufferBits; + int bufferPos; + u64 hash[WP512_DIGEST_SIZE/8]; +}; + +/* + * Though Whirlpool is endianness-neutral, the encryption tables are listed + * in BIG-ENDIAN format, which is adopted throughout this implementation + * (but little-endian notation would be equally suitable if consistently + * employed). + */ + +static const u64 C0[256] = { + 0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL, + 0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL, + 0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL, + 0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL, + 0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL, + 0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL, + 0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL, + 0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL, + 0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL, + 0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL, + 0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL, + 0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL, + 0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL, + 0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL, + 0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL, + 0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL, + 0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL, + 0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL, + 0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL, + 0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL, + 0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL, + 0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL, + 0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL, + 0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL, + 0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL, + 0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL, + 0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL, + 0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL, + 0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL, + 0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL, + 0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL, + 0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL, + 0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL, + 0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL, + 0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL, + 0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL, + 0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL, + 0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL, + 0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL, + 0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL, + 0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL, + 0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL, + 0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL, + 0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL, + 0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL, + 0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL, + 0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL, + 0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL, + 0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL, + 0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL, + 0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL, + 0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL, + 0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL, + 0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL, + 0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL, + 0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL, + 0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL, + 0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL, + 0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL, + 0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL, + 0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL, + 0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL, + 0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL, + 0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL, + 0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL, + 0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL, + 0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL, + 0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL, + 0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL, + 0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL, + 0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL, + 0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL, + 0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL, + 0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL, + 0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL, + 0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL, + 0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL, + 0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL, + 0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL, + 0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL, + 0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL, + 0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL, + 0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL, + 0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL, + 0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL, + 0x8686228644a411c2ULL, +}; + +static const u64 C1[256] = { + 0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL, + 0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL, + 0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL, + 0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL, + 0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL, + 0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL, + 0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL, + 0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL, + 0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL, + 0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL, + 0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL, + 0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL, + 0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL, + 0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL, + 0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL, + 0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL, + 0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL, + 0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL, + 0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL, + 0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL, + 0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL, + 0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL, + 0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL, + 0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL, + 0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL, + 0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL, + 0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL, + 0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL, + 0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL, + 0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL, + 0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL, + 0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL, + 0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL, + 0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL, + 0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL, + 0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL, + 0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL, + 0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL, + 0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL, + 0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL, + 0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL, + 0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL, + 0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL, + 0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL, + 0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL, + 0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL, + 0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL, + 0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL, + 0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL, + 0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL, + 0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL, + 0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL, + 0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL, + 0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL, + 0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL, + 0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL, + 0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL, + 0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL, + 0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL, + 0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL, + 0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL, + 0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL, + 0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL, + 0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL, + 0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL, + 0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL, + 0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL, + 0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL, + 0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL, + 0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL, + 0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL, + 0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL, + 0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL, + 0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL, + 0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL, + 0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL, + 0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL, + 0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL, + 0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL, + 0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL, + 0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL, + 0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL, + 0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL, + 0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL, + 0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL, + 0xc28686228644a411ULL, +}; + +static const u64 C2[256] = { + 0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL, + 0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL, + 0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL, + 0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL, + 0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL, + 0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL, + 0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL, + 0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL, + 0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL, + 0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL, + 0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL, + 0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL, + 0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL, + 0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL, + 0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL, + 0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL, + 0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL, + 0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL, + 0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL, + 0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL, + 0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL, + 0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL, + 0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL, + 0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL, + 0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL, + 0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL, + 0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL, + 0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL, + 0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL, + 0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL, + 0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL, + 0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL, + 0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL, + 0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL, + 0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL, + 0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL, + 0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL, + 0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL, + 0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL, + 0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL, + 0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL, + 0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL, + 0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL, + 0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL, + 0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL, + 0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL, + 0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL, + 0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL, + 0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL, + 0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL, + 0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL, + 0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL, + 0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL, + 0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL, + 0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL, + 0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL, + 0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL, + 0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL, + 0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL, + 0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL, + 0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL, + 0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL, + 0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL, + 0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL, + 0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL, + 0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL, + 0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL, + 0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL, + 0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL, + 0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL, + 0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL, + 0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL, + 0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL, + 0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL, + 0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL, + 0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL, + 0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL, + 0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL, + 0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL, + 0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL, + 0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL, + 0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL, + 0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL, + 0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL, + 0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL, + 0x11c28686228644a4ULL, +}; + +static const u64 C3[256] = { + 0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL, + 0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL, + 0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL, + 0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL, + 0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL, + 0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL, + 0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL, + 0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL, + 0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL, + 0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL, + 0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL, + 0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL, + 0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL, + 0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL, + 0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL, + 0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL, + 0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL, + 0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL, + 0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL, + 0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL, + 0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL, + 0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL, + 0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL, + 0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL, + 0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL, + 0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL, + 0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL, + 0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL, + 0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL, + 0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL, + 0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL, + 0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL, + 0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL, + 0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL, + 0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL, + 0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL, + 0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL, + 0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL, + 0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL, + 0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL, + 0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL, + 0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL, + 0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL, + 0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL, + 0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL, + 0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL, + 0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL, + 0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL, + 0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL, + 0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL, + 0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL, + 0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL, + 0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL, + 0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL, + 0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL, + 0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL, + 0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL, + 0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL, + 0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL, + 0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL, + 0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL, + 0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL, + 0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL, + 0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL, + 0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL, + 0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL, + 0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL, + 0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL, + 0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL, + 0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL, + 0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL, + 0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL, + 0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL, + 0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL, + 0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL, + 0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL, + 0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL, + 0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL, + 0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL, + 0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL, + 0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL, + 0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL, + 0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL, + 0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL, + 0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL, + 0xa411c28686228644ULL, +}; + +static const u64 C4[256] = { + 0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL, + 0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL, + 0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL, + 0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL, + 0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL, + 0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL, + 0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL, + 0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL, + 0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL, + 0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL, + 0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL, + 0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL, + 0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL, + 0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL, + 0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL, + 0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL, + 0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL, + 0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL, + 0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL, + 0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL, + 0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL, + 0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL, + 0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL, + 0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL, + 0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL, + 0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL, + 0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL, + 0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL, + 0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL, + 0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL, + 0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL, + 0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL, + 0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL, + 0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL, + 0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL, + 0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL, + 0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL, + 0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL, + 0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL, + 0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL, + 0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL, + 0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL, + 0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL, + 0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL, + 0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL, + 0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL, + 0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL, + 0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL, + 0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL, + 0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL, + 0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL, + 0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL, + 0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL, + 0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL, + 0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL, + 0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL, + 0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL, + 0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL, + 0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL, + 0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL, + 0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL, + 0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL, + 0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL, + 0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL, + 0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL, + 0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL, + 0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL, + 0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL, + 0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL, + 0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL, + 0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL, + 0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL, + 0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL, + 0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL, + 0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL, + 0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL, + 0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL, + 0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL, + 0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL, + 0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL, + 0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL, + 0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL, + 0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL, + 0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL, + 0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL, + 0x44a411c286862286ULL, +}; + +static const u64 C5[256] = { + 0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL, + 0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL, + 0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL, + 0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL, + 0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL, + 0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL, + 0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL, + 0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL, + 0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL, + 0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL, + 0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL, + 0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL, + 0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL, + 0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL, + 0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL, + 0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL, + 0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL, + 0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL, + 0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL, + 0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL, + 0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL, + 0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL, + 0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL, + 0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL, + 0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL, + 0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL, + 0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL, + 0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL, + 0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL, + 0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL, + 0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL, + 0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL, + 0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL, + 0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL, + 0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL, + 0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL, + 0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL, + 0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL, + 0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL, + 0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL, + 0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL, + 0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL, + 0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL, + 0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL, + 0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL, + 0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL, + 0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL, + 0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL, + 0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL, + 0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL, + 0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL, + 0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL, + 0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL, + 0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL, + 0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL, + 0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL, + 0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL, + 0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL, + 0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL, + 0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL, + 0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL, + 0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL, + 0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL, + 0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL, + 0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL, + 0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL, + 0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL, + 0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL, + 0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL, + 0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL, + 0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL, + 0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL, + 0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL, + 0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL, + 0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL, + 0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL, + 0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL, + 0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL, + 0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL, + 0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL, + 0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL, + 0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL, + 0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL, + 0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL, + 0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL, + 0x8644a411c2868622ULL, +}; + +static const u64 C6[256] = { + 0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL, + 0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL, + 0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL, + 0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL, + 0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL, + 0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL, + 0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL, + 0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL, + 0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL, + 0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL, + 0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL, + 0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL, + 0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL, + 0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL, + 0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL, + 0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL, + 0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL, + 0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL, + 0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL, + 0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL, + 0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL, + 0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL, + 0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL, + 0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL, + 0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL, + 0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL, + 0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL, + 0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL, + 0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL, + 0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL, + 0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL, + 0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL, + 0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL, + 0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL, + 0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL, + 0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL, + 0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL, + 0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL, + 0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL, + 0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL, + 0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL, + 0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL, + 0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL, + 0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL, + 0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL, + 0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL, + 0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL, + 0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL, + 0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL, + 0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL, + 0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL, + 0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL, + 0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL, + 0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL, + 0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL, + 0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL, + 0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL, + 0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL, + 0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL, + 0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL, + 0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL, + 0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL, + 0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL, + 0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL, + 0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL, + 0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL, + 0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL, + 0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL, + 0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL, + 0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL, + 0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL, + 0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL, + 0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL, + 0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL, + 0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL, + 0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL, + 0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL, + 0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL, + 0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL, + 0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL, + 0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL, + 0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL, + 0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL, + 0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL, + 0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL, + 0x228644a411c28686ULL, +}; + +static const u64 C7[256] = { + 0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL, + 0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL, + 0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL, + 0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL, + 0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL, + 0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL, + 0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL, + 0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL, + 0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL, + 0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL, + 0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL, + 0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL, + 0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL, + 0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL, + 0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL, + 0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL, + 0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL, + 0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL, + 0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL, + 0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL, + 0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL, + 0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL, + 0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL, + 0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL, + 0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL, + 0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL, + 0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL, + 0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL, + 0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL, + 0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL, + 0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL, + 0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL, + 0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL, + 0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL, + 0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL, + 0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL, + 0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL, + 0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL, + 0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL, + 0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL, + 0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL, + 0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL, + 0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL, + 0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL, + 0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL, + 0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL, + 0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL, + 0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL, + 0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL, + 0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL, + 0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL, + 0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL, + 0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL, + 0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL, + 0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL, + 0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL, + 0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL, + 0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL, + 0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL, + 0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL, + 0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL, + 0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL, + 0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL, + 0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL, + 0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL, + 0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL, + 0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL, + 0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL, + 0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL, + 0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL, + 0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL, + 0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL, + 0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL, + 0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL, + 0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL, + 0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL, + 0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL, + 0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL, + 0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL, + 0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL, + 0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL, + 0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL, + 0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL, + 0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL, + 0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL, + 0x86228644a411c286ULL, +}; + +static const u64 rc[WHIRLPOOL_ROUNDS + 1] = { + 0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL, + 0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL, + 0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL, + 0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL, +}; + +/** + * The core Whirlpool transform. + */ + +static void wp512_process_buffer(struct wp512_ctx *wctx) { + int i, r; + u64 K[8]; /* the round key */ + u64 block[8]; /* mu(buffer) */ + u64 state[8]; /* the cipher state */ + u64 L[8]; + u8 *buffer = wctx->buffer; + + for (i = 0; i < 8; i++, buffer += 8) { + block[i] = + (((u64)buffer[0] ) << 56) ^ + (((u64)buffer[1] & 0xffL) << 48) ^ + (((u64)buffer[2] & 0xffL) << 40) ^ + (((u64)buffer[3] & 0xffL) << 32) ^ + (((u64)buffer[4] & 0xffL) << 24) ^ + (((u64)buffer[5] & 0xffL) << 16) ^ + (((u64)buffer[6] & 0xffL) << 8) ^ + (((u64)buffer[7] & 0xffL) ); + } + + state[0] = block[0] ^ (K[0] = wctx->hash[0]); + state[1] = block[1] ^ (K[1] = wctx->hash[1]); + state[2] = block[2] ^ (K[2] = wctx->hash[2]); + state[3] = block[3] ^ (K[3] = wctx->hash[3]); + state[4] = block[4] ^ (K[4] = wctx->hash[4]); + state[5] = block[5] ^ (K[5] = wctx->hash[5]); + state[6] = block[6] ^ (K[6] = wctx->hash[6]); + state[7] = block[7] ^ (K[7] = wctx->hash[7]); + + for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) { + + L[0] = C0[(int)(K[0] >> 56) ] ^ + C1[(int)(K[7] >> 48) & 0xff] ^ + C2[(int)(K[6] >> 40) & 0xff] ^ + C3[(int)(K[5] >> 32) & 0xff] ^ + C4[(int)(K[4] >> 24) & 0xff] ^ + C5[(int)(K[3] >> 16) & 0xff] ^ + C6[(int)(K[2] >> 8) & 0xff] ^ + C7[(int)(K[1] ) & 0xff] ^ + rc[r]; + + L[1] = C0[(int)(K[1] >> 56) ] ^ + C1[(int)(K[0] >> 48) & 0xff] ^ + C2[(int)(K[7] >> 40) & 0xff] ^ + C3[(int)(K[6] >> 32) & 0xff] ^ + C4[(int)(K[5] >> 24) & 0xff] ^ + C5[(int)(K[4] >> 16) & 0xff] ^ + C6[(int)(K[3] >> 8) & 0xff] ^ + C7[(int)(K[2] ) & 0xff]; + + L[2] = C0[(int)(K[2] >> 56) ] ^ + C1[(int)(K[1] >> 48) & 0xff] ^ + C2[(int)(K[0] >> 40) & 0xff] ^ + C3[(int)(K[7] >> 32) & 0xff] ^ + C4[(int)(K[6] >> 24) & 0xff] ^ + C5[(int)(K[5] >> 16) & 0xff] ^ + C6[(int)(K[4] >> 8) & 0xff] ^ + C7[(int)(K[3] ) & 0xff]; + + L[3] = C0[(int)(K[3] >> 56) ] ^ + C1[(int)(K[2] >> 48) & 0xff] ^ + C2[(int)(K[1] >> 40) & 0xff] ^ + C3[(int)(K[0] >> 32) & 0xff] ^ + C4[(int)(K[7] >> 24) & 0xff] ^ + C5[(int)(K[6] >> 16) & 0xff] ^ + C6[(int)(K[5] >> 8) & 0xff] ^ + C7[(int)(K[4] ) & 0xff]; + + L[4] = C0[(int)(K[4] >> 56) ] ^ + C1[(int)(K[3] >> 48) & 0xff] ^ + C2[(int)(K[2] >> 40) & 0xff] ^ + C3[(int)(K[1] >> 32) & 0xff] ^ + C4[(int)(K[0] >> 24) & 0xff] ^ + C5[(int)(K[7] >> 16) & 0xff] ^ + C6[(int)(K[6] >> 8) & 0xff] ^ + C7[(int)(K[5] ) & 0xff]; + + L[5] = C0[(int)(K[5] >> 56) ] ^ + C1[(int)(K[4] >> 48) & 0xff] ^ + C2[(int)(K[3] >> 40) & 0xff] ^ + C3[(int)(K[2] >> 32) & 0xff] ^ + C4[(int)(K[1] >> 24) & 0xff] ^ + C5[(int)(K[0] >> 16) & 0xff] ^ + C6[(int)(K[7] >> 8) & 0xff] ^ + C7[(int)(K[6] ) & 0xff]; + + L[6] = C0[(int)(K[6] >> 56) ] ^ + C1[(int)(K[5] >> 48) & 0xff] ^ + C2[(int)(K[4] >> 40) & 0xff] ^ + C3[(int)(K[3] >> 32) & 0xff] ^ + C4[(int)(K[2] >> 24) & 0xff] ^ + C5[(int)(K[1] >> 16) & 0xff] ^ + C6[(int)(K[0] >> 8) & 0xff] ^ + C7[(int)(K[7] ) & 0xff]; + + L[7] = C0[(int)(K[7] >> 56) ] ^ + C1[(int)(K[6] >> 48) & 0xff] ^ + C2[(int)(K[5] >> 40) & 0xff] ^ + C3[(int)(K[4] >> 32) & 0xff] ^ + C4[(int)(K[3] >> 24) & 0xff] ^ + C5[(int)(K[2] >> 16) & 0xff] ^ + C6[(int)(K[1] >> 8) & 0xff] ^ + C7[(int)(K[0] ) & 0xff]; + + K[0] = L[0]; + K[1] = L[1]; + K[2] = L[2]; + K[3] = L[3]; + K[4] = L[4]; + K[5] = L[5]; + K[6] = L[6]; + K[7] = L[7]; + + L[0] = C0[(int)(state[0] >> 56) ] ^ + C1[(int)(state[7] >> 48) & 0xff] ^ + C2[(int)(state[6] >> 40) & 0xff] ^ + C3[(int)(state[5] >> 32) & 0xff] ^ + C4[(int)(state[4] >> 24) & 0xff] ^ + C5[(int)(state[3] >> 16) & 0xff] ^ + C6[(int)(state[2] >> 8) & 0xff] ^ + C7[(int)(state[1] ) & 0xff] ^ + K[0]; + + L[1] = C0[(int)(state[1] >> 56) ] ^ + C1[(int)(state[0] >> 48) & 0xff] ^ + C2[(int)(state[7] >> 40) & 0xff] ^ + C3[(int)(state[6] >> 32) & 0xff] ^ + C4[(int)(state[5] >> 24) & 0xff] ^ + C5[(int)(state[4] >> 16) & 0xff] ^ + C6[(int)(state[3] >> 8) & 0xff] ^ + C7[(int)(state[2] ) & 0xff] ^ + K[1]; + + L[2] = C0[(int)(state[2] >> 56) ] ^ + C1[(int)(state[1] >> 48) & 0xff] ^ + C2[(int)(state[0] >> 40) & 0xff] ^ + C3[(int)(state[7] >> 32) & 0xff] ^ + C4[(int)(state[6] >> 24) & 0xff] ^ + C5[(int)(state[5] >> 16) & 0xff] ^ + C6[(int)(state[4] >> 8) & 0xff] ^ + C7[(int)(state[3] ) & 0xff] ^ + K[2]; + + L[3] = C0[(int)(state[3] >> 56) ] ^ + C1[(int)(state[2] >> 48) & 0xff] ^ + C2[(int)(state[1] >> 40) & 0xff] ^ + C3[(int)(state[0] >> 32) & 0xff] ^ + C4[(int)(state[7] >> 24) & 0xff] ^ + C5[(int)(state[6] >> 16) & 0xff] ^ + C6[(int)(state[5] >> 8) & 0xff] ^ + C7[(int)(state[4] ) & 0xff] ^ + K[3]; + + L[4] = C0[(int)(state[4] >> 56) ] ^ + C1[(int)(state[3] >> 48) & 0xff] ^ + C2[(int)(state[2] >> 40) & 0xff] ^ + C3[(int)(state[1] >> 32) & 0xff] ^ + C4[(int)(state[0] >> 24) & 0xff] ^ + C5[(int)(state[7] >> 16) & 0xff] ^ + C6[(int)(state[6] >> 8) & 0xff] ^ + C7[(int)(state[5] ) & 0xff] ^ + K[4]; + + L[5] = C0[(int)(state[5] >> 56) ] ^ + C1[(int)(state[4] >> 48) & 0xff] ^ + C2[(int)(state[3] >> 40) & 0xff] ^ + C3[(int)(state[2] >> 32) & 0xff] ^ + C4[(int)(state[1] >> 24) & 0xff] ^ + C5[(int)(state[0] >> 16) & 0xff] ^ + C6[(int)(state[7] >> 8) & 0xff] ^ + C7[(int)(state[6] ) & 0xff] ^ + K[5]; + + L[6] = C0[(int)(state[6] >> 56) ] ^ + C1[(int)(state[5] >> 48) & 0xff] ^ + C2[(int)(state[4] >> 40) & 0xff] ^ + C3[(int)(state[3] >> 32) & 0xff] ^ + C4[(int)(state[2] >> 24) & 0xff] ^ + C5[(int)(state[1] >> 16) & 0xff] ^ + C6[(int)(state[0] >> 8) & 0xff] ^ + C7[(int)(state[7] ) & 0xff] ^ + K[6]; + + L[7] = C0[(int)(state[7] >> 56) ] ^ + C1[(int)(state[6] >> 48) & 0xff] ^ + C2[(int)(state[5] >> 40) & 0xff] ^ + C3[(int)(state[4] >> 32) & 0xff] ^ + C4[(int)(state[3] >> 24) & 0xff] ^ + C5[(int)(state[2] >> 16) & 0xff] ^ + C6[(int)(state[1] >> 8) & 0xff] ^ + C7[(int)(state[0] ) & 0xff] ^ + K[7]; + + state[0] = L[0]; + state[1] = L[1]; + state[2] = L[2]; + state[3] = L[3]; + state[4] = L[4]; + state[5] = L[5]; + state[6] = L[6]; + state[7] = L[7]; + } + /* + * apply the Miyaguchi-Preneel compression function: + */ + wctx->hash[0] ^= state[0] ^ block[0]; + wctx->hash[1] ^= state[1] ^ block[1]; + wctx->hash[2] ^= state[2] ^ block[2]; + wctx->hash[3] ^= state[3] ^ block[3]; + wctx->hash[4] ^= state[4] ^ block[4]; + wctx->hash[5] ^= state[5] ^ block[5]; + wctx->hash[6] ^= state[6] ^ block[6]; + wctx->hash[7] ^= state[7] ^ block[7]; + +} + +static void wp512_init (void *ctx) { + int i; + struct wp512_ctx *wctx = ctx; + + memset(wctx->bitLength, 0, 32); + wctx->bufferBits = wctx->bufferPos = 0; + wctx->buffer[0] = 0; + for (i = 0; i < 8; i++) { + wctx->hash[i] = 0L; + } +} + +static void wp512_update(void *ctx, const u8 *source, unsigned int len) +{ + + struct wp512_ctx *wctx = ctx; + int sourcePos = 0; + unsigned int bits_len = len * 8; // convert to number of bits + int sourceGap = (8 - ((int)bits_len & 7)) & 7; + int bufferRem = wctx->bufferBits & 7; + int i; + u32 b, carry; + u8 *buffer = wctx->buffer; + u8 *bitLength = wctx->bitLength; + int bufferBits = wctx->bufferBits; + int bufferPos = wctx->bufferPos; + + u64 value = bits_len; + for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) { + carry += bitLength[i] + ((u32)value & 0xff); + bitLength[i] = (u8)carry; + carry >>= 8; + value >>= 8; + } + while (bits_len > 8) { + b = ((source[sourcePos] << sourceGap) & 0xff) | + ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap)); + buffer[bufferPos++] |= (u8)(b >> bufferRem); + bufferBits += 8 - bufferRem; + if (bufferBits == WP512_BLOCK_SIZE * 8) { + wp512_process_buffer(wctx); + bufferBits = bufferPos = 0; + } + buffer[bufferPos] = b << (8 - bufferRem); + bufferBits += bufferRem; + bits_len -= 8; + sourcePos++; + } + if (bits_len > 0) { + b = (source[sourcePos] << sourceGap) & 0xff; + buffer[bufferPos] |= b >> bufferRem; + } else { + b = 0; + } + if (bufferRem + bits_len < 8) { + bufferBits += bits_len; + } else { + bufferPos++; + bufferBits += 8 - bufferRem; + bits_len -= 8 - bufferRem; + if (bufferBits == WP512_BLOCK_SIZE * 8) { + wp512_process_buffer(wctx); + bufferBits = bufferPos = 0; + } + buffer[bufferPos] = b << (8 - bufferRem); + bufferBits += (int)bits_len; + } + + wctx->bufferBits = bufferBits; + wctx->bufferPos = bufferPos; + +} + +static void wp512_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + int i; + u8 *buffer = wctx->buffer; + u8 *bitLength = wctx->bitLength; + int bufferBits = wctx->bufferBits; + int bufferPos = wctx->bufferPos; + u8 *digest = out; + + buffer[bufferPos] |= 0x80U >> (bufferBits & 7); + bufferPos++; + if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + if (bufferPos < WP512_BLOCK_SIZE) { + memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos); + } + wp512_process_buffer(wctx); + bufferPos = 0; + } + if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) { + memset(&buffer[bufferPos], 0, + (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos); + } + bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES; + memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES], + bitLength, WP512_LENGTHBYTES); + wp512_process_buffer(wctx); + for (i = 0; i < WP512_DIGEST_SIZE/8; i++) { + digest[0] = (u8)(wctx->hash[i] >> 56); + digest[1] = (u8)(wctx->hash[i] >> 48); + digest[2] = (u8)(wctx->hash[i] >> 40); + digest[3] = (u8)(wctx->hash[i] >> 32); + digest[4] = (u8)(wctx->hash[i] >> 24); + digest[5] = (u8)(wctx->hash[i] >> 16); + digest[6] = (u8)(wctx->hash[i] >> 8); + digest[7] = (u8)(wctx->hash[i] ); + digest += 8; + } + wctx->bufferBits = bufferBits; + wctx->bufferPos = bufferPos; +} + +static void wp384_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP384_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static void wp256_final(void *ctx, u8 *out) +{ + struct wp512_ctx *wctx = ctx; + u8 D[64]; + + wp512_final (wctx, D); + memcpy (out, D, WP256_DIGEST_SIZE); + memset (D, 0, WP512_DIGEST_SIZE); +} + +static struct crypto_alg wp512 = { + .cra_name = "wp512", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp512.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP512_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp512_final } } +}; + +static struct crypto_alg wp384 = { + .cra_name = "wp384", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp384.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP384_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp384_final } } +}; + +static struct crypto_alg wp256 = { + .cra_name = "wp256", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct wp512_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(wp256.cra_list), + .cra_u = { .digest = { + .dia_digestsize = WP256_DIGEST_SIZE, + .dia_init = wp512_init, + .dia_update = wp512_update, + .dia_final = wp256_final } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&wp512); + + if (ret < 0) + goto out; + + ret = crypto_register_alg(&wp384); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + goto out; + } + + ret = crypto_register_alg(&wp256); + if (ret < 0) + { + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + } +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&wp512); + crypto_unregister_alg(&wp384); + crypto_unregister_alg(&wp256); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm"); diff -urN linux-2.4.27/drivers/acpi/Makefile linux-2.4.28/drivers/acpi/Makefile --- linux-2.4.27/drivers/acpi/Makefile 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.28/drivers/acpi/Makefile 2004-11-17 03:54:21.185380913 -0800 @@ -38,7 +38,7 @@ # ACPI Bus and Device Drivers # ifeq ($(CONFIG_ACPI_BUS),y) - obj-y += bus.o + obj-y += bus.o motherboard.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o diff -urN linux-2.4.27/drivers/acpi/bus.c linux-2.4.28/drivers/acpi/bus.c --- linux-2.4.27/drivers/acpi/bus.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/acpi/bus.c 2004-11-17 03:54:21.186380954 -0800 @@ -1844,10 +1844,9 @@ } -static int __init -acpi_bus_init (void) +void __init +acpi_early_init (void) { - int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt}; @@ -1871,7 +1870,7 @@ status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to get the FADT\n"); - goto error1; + goto error0; } #ifdef CONFIG_X86 @@ -1894,12 +1893,40 @@ } #endif - status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); + status = acpi_enable_subsystem(~(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE)); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); + goto error0; + } + + return; + +error0: + disable_acpi(); + return; +} + +static int __init +acpi_bus_init (void) +{ + int result = 0; + acpi_status status = AE_OK; + extern acpi_status acpi_os_initialize1(void); + + ACPI_FUNCTION_TRACE("acpi_bus_init"); + + status = acpi_os_initialize1(); + + status = acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); goto error1; } + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to initialize ACPI OS objects\n"); + goto error1; + } #ifdef CONFIG_ACPI_EC /* * ACPI 2.0 requires the EC driver to be loaded and work before @@ -1979,6 +2006,7 @@ if (result) goto error4; + acpi_motherboard_init(); return_VALUE(0); /* Mimic structured exception handling */ @@ -1991,7 +2019,6 @@ ACPI_SYSTEM_NOTIFY, &acpi_bus_notify); error1: acpi_terminate(); -error0: return_VALUE(-ENODEV); } diff -urN linux-2.4.27/drivers/acpi/dispatcher/dsopcode.c linux-2.4.28/drivers/acpi/dispatcher/dsopcode.c --- linux-2.4.27/drivers/acpi/dispatcher/dsopcode.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/drivers/acpi/dispatcher/dsopcode.c 2004-11-17 03:54:21.187380995 -0800 @@ -79,7 +79,6 @@ acpi_status status; union acpi_parse_object *op; struct acpi_walk_state *walk_state; - union acpi_parse_object *arg; ACPI_FUNCTION_TRACE ("ds_execute_arguments"); @@ -126,9 +125,7 @@ /* Get and init the Op created above */ - arg = op->common.value.arg; op->common.node = node; - arg->common.node = node; acpi_ps_delete_parse_tree (op); /* Evaluate the deferred arguments */ diff -urN linux-2.4.27/drivers/acpi/events/evmisc.c linux-2.4.28/drivers/acpi/events/evmisc.c --- linux-2.4.27/drivers/acpi/events/evmisc.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/drivers/acpi/events/evmisc.c 2004-11-17 03:54:21.188381036 -0800 @@ -139,7 +139,7 @@ acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "notify value: 0x2.2_x **Device Specific**\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", notify_value)); } diff -urN linux-2.4.27/drivers/acpi/hardware/hwsleep.c linux-2.4.28/drivers/acpi/hardware/hwsleep.c --- linux-2.4.27/drivers/acpi/hardware/hwsleep.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.28/drivers/acpi/hardware/hwsleep.c 2004-11-17 03:54:21.188381036 -0800 @@ -265,19 +265,19 @@ sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); - if (sleep_state != ACPI_STATE_S5) { - /* Clear wake status */ + /* Clear wake status */ - status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + if (sleep_state != ACPI_STATE_S5) { /* Disable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); diff -urN linux-2.4.27/drivers/acpi/motherboard.c linux-2.4.28/drivers/acpi/motherboard.c --- linux-2.4.27/drivers/acpi/motherboard.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/acpi/motherboard.c 2004-11-17 03:54:21.189381078 -0800 @@ -0,0 +1,159 @@ +/* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("acpi_motherboard") + +/* Dell use PNP0C01 instead of PNP0C02 */ +#define ACPI_MB_HID1 "PNP0C01" +#define ACPI_MB_HID2 "PNP0C02" + +/** + * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved + * Doesn't care about the failure of 'request_region', since other may reserve + * the io ports as well + */ +#define IS_RESERVED_ADDR(base, len) \ + (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ + && ((base) + (len) > PCIBIOS_MIN_IO)) + +static acpi_status +acpi_reserve_io_ranges (struct acpi_resource *res, void *data) +{ + ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges"); + + if (res->id == ACPI_RSTYPE_IO) { + struct acpi_resource_io *io_res = &res->data.io; + + if (io_res->min_base_address != io_res->max_base_address) + return AE_OK; + if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + io_res->min_base_address, + io_res->min_base_address + io_res->range_length)); + request_region(io_res->min_base_address, + io_res->range_length, "motherboard"); + } + }else if (res->id == ACPI_RSTYPE_FIXED_IO) { + struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io; + + if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + fixed_io_res->base_address, + fixed_io_res->base_address + fixed_io_res->range_length)); + request_region(fixed_io_res->base_address, + fixed_io_res->range_length, "motherboard"); + } + }else { + /* Memory mapped IO? */ + } + + return AE_OK; +} + +static int acpi_motherboard_add (struct acpi_device *device) +{ + if (!device) + return -EINVAL; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + acpi_reserve_io_ranges, NULL); + + return 0; +} + +static struct acpi_driver acpi_motherboard_driver1 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID1, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static struct acpi_driver acpi_motherboard_driver2 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID2, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static void __init +acpi_reserve_resources (void) +{ + if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1a_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1b_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK"); + + if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK"); + + if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4) + request_region(acpi_gbl_FADT->xpm_tmr_blk.address, + 4, "PM_TMR"); + + if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len) + request_region(acpi_gbl_FADT->xpm2_cnt_blk.address, + acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len && + !(acpi_gbl_FADT->gpe0_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe0_blk.address, + acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK"); + + if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len && + !(acpi_gbl_FADT->gpe1_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe1_blk.address, + acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK"); +} + +int __init acpi_motherboard_init(void) +{ + acpi_bus_register_driver(&acpi_motherboard_driver1); + acpi_bus_register_driver(&acpi_motherboard_driver2); + /* + * Guarantee motherboard IO reservation first + * This module must run after scan.c + */ + if (!acpi_disabled) + acpi_reserve_resources (); + return 0; +} diff -urN linux-2.4.27/drivers/acpi/osl.c linux-2.4.28/drivers/acpi/osl.c --- linux-2.4.27/drivers/acpi/osl.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/acpi/osl.c 2004-11-17 03:54:21.190381119 -0800 @@ -72,6 +72,12 @@ acpi_status acpi_os_initialize(void) { + return AE_OK; +} + +acpi_status +acpi_os_initialize1(void) +{ /* * Initialize PCI configuration space access, as we'll need to access * it while walking the namespace (bus 0 and root bridges w/ _BBNs). diff -urN linux-2.4.27/drivers/acpi/system.c linux-2.4.28/drivers/acpi/system.c --- linux-2.4.27/drivers/acpi/system.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/acpi/system.c 2004-11-17 03:54:21.191381160 -0800 @@ -102,7 +102,6 @@ BUG(); /* Some SMP machines only can poweroff in boot CPU */ set_cpus_allowed(current, 1UL << cpu_logical_map(0)); - acpi_system_save_state(ACPI_STATE_S5); acpi_enter_sleep_state_prep(ACPI_STATE_S5); ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); diff -urN linux-2.4.27/drivers/acpi/utilities/utglobal.c linux-2.4.28/drivers/acpi/utilities/utglobal.c --- linux-2.4.27/drivers/acpi/utilities/utglobal.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/acpi/utilities/utglobal.c 2004-11-17 03:54:21.192381201 -0800 @@ -783,12 +783,6 @@ ACPI_FUNCTION_TRACE ("ut_init_globals"); - /* Runtime configuration */ - - acpi_gbl_create_osi_method = TRUE; - acpi_gbl_all_methods_serialized = FALSE; - acpi_gbl_leave_wake_gpes_disabled = TRUE; - /* Memory allocation and cache lists */ ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (struct acpi_memory_list) * ACPI_NUM_MEM_LISTS); diff -urN linux-2.4.27/drivers/atm/atmtcp.c linux-2.4.28/drivers/atm/atmtcp.c --- linux-2.4.27/drivers/atm/atmtcp.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/drivers/atm/atmtcp.c 2004-11-17 03:54:21.193381242 -0800 @@ -246,7 +246,7 @@ dev_data = PRIV(atmtcp_dev); dev_data->vcc = NULL; if (dev_data->persist) return; - PRIV(atmtcp_dev) = NULL; + atmtcp_dev->dev_data = NULL; kfree(dev_data); shutdown_atm_dev(atmtcp_dev); vcc->dev_data = NULL; @@ -362,7 +362,7 @@ } dev->ci_range.vpi_bits = MAX_VPI_BITS; dev->ci_range.vci_bits = MAX_VCI_BITS; - PRIV(dev) = dev_data; + dev->dev_data = dev_data; PRIV(dev)->vcc = NULL; PRIV(dev)->persist = persist; if (result) *result = dev; diff -urN linux-2.4.27/drivers/atm/eni.c linux-2.4.28/drivers/atm/eni.c --- linux-2.4.27/drivers/atm/eni.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.28/drivers/atm/eni.c 2004-11-17 03:54:21.194381283 -0800 @@ -1879,7 +1879,7 @@ DPRINTK("eni_close: done waiting\n"); /* deallocate memory */ kfree(ENI_VCC(vcc)); - ENI_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); /*foo();*/ } @@ -1951,7 +1951,7 @@ DPRINTK(">eni_open\n"); EVENT("eni_open\n",0,0); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL; eni_dev = ENI_DEV(vcc->dev); error = get_ci(vcc,&vpi,&vci); if (error) return error; @@ -1966,7 +1966,7 @@ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL); if (!eni_vcc) return -ENOMEM; - ENI_VCC(vcc) = eni_vcc; + vcc->dev_data = eni_vcc; eni_vcc->tx = NULL; /* for eni_close after open_rx */ if ((error = open_rx_first(vcc))) { eni_close(vcc); @@ -2302,7 +2302,7 @@ if (!dev) goto out2; pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; - ENI_DEV(dev) = eni_dev; + dev->dev_data = eni_dev; eni_dev->asic = ent->driver_data; error = eni_do_init(dev); if (error) goto out3; diff -urN linux-2.4.27/drivers/atm/fore200e.c linux-2.4.28/drivers/atm/fore200e.c --- linux-2.4.27/drivers/atm/fore200e.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/atm/fore200e.c 2004-11-17 03:54:21.196381365 -0800 @@ -101,6 +101,7 @@ #if 1 +#undef ASSERT #define ASSERT(expr) if (!(expr)) { \ printk(FORE200E "assertion failed! %s[%d]: %s\n", \ __FUNCTION__, __LINE__, #expr); \ @@ -1620,7 +1621,7 @@ set_bit(ATM_VF_PARTIAL,&vcc->flags); set_bit(ATM_VF_ADDR, &vcc->flags); - FORE200E_VCC(vcc) = fore200e_vcc; + vcc->dev_data = fore200e_vcc; if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { @@ -1629,7 +1630,7 @@ clear_bit(ATM_VF_ADDR, &vcc->flags); clear_bit(ATM_VF_PARTIAL,&vcc->flags); - FORE200E_VCC(vcc) = NULL; + vcc->dev_data = NULL; fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; @@ -1691,7 +1692,7 @@ vcc->itf = vcc->vci = vcc->vpi = 0; fore200e_vcc = FORE200E_VCC(vcc); - FORE200E_VCC(vcc) = NULL; + vcc->dev_data = NULL; spin_unlock_irqrestore(&fore200e->q_lock, flags); @@ -2738,7 +2739,7 @@ return -ENODEV; } - FORE200E_DEV(atm_dev) = fore200e; + atm_dev->dev_data = fore200e; fore200e->atm_dev = atm_dev; atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS; diff -urN linux-2.4.27/drivers/atm/he.c linux-2.4.28/drivers/atm/he.c --- linux-2.4.27/drivers/atm/he.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/atm/he.c 2004-11-17 03:54:21.198381448 -0800 @@ -378,7 +378,7 @@ he_dev->pci_dev = pci_dev; he_dev->atm_dev = atm_dev; he_dev->atm_dev->dev_data = he_dev; - HE_DEV(atm_dev) = he_dev; + atm_dev->dev_data = he_dev; he_dev->number = atm_dev->number; if (he_start(atm_dev)) { he_stop(he_dev); @@ -2347,7 +2347,7 @@ init_waitqueue_head(&he_vcc->rx_waitq); init_waitqueue_head(&he_vcc->tx_waitq); - HE_VCC(vcc) = he_vcc; + vcc->dev_data = he_vcc; if (vcc->qos.txtp.traffic_class != ATM_NONE) { int pcr_goal; diff -urN linux-2.4.27/drivers/atm/idt77105.c linux-2.4.28/drivers/atm/idt77105.c --- linux-2.4.27/drivers/atm/idt77105.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/drivers/atm/idt77105.c 2004-11-17 03:54:21.199381489 -0800 @@ -267,7 +267,7 @@ { unsigned long flags; - if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL))) + if (!(dev->phy_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL))) return -ENOMEM; PRIV(dev)->dev = dev; spin_lock_irqsave(&idt77105_priv_lock, flags); @@ -345,7 +345,7 @@ else idt77105_all = walk->next; dev->phy = NULL; - PRIV(dev) = NULL; + dev->phy_data = NULL; kfree(walk); break; } diff -urN linux-2.4.27/drivers/atm/iphase.c linux-2.4.28/drivers/atm/iphase.c --- linux-2.4.27/drivers/atm/iphase.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.28/drivers/atm/iphase.c 2004-11-17 03:54:21.202381612 -0800 @@ -1782,7 +1782,7 @@ (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ printk("IA: SDU size over (%d) the configured SDU size %d\n", vcc->qos.txtp.max_sdu,iadev->tx_buf_sz); - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; kfree(ia_vcc); return -EINVAL; } @@ -2707,7 +2707,7 @@ } kfree(INPH_IA_VCC(vcc)); ia_vcc = NULL; - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); return; } @@ -2720,7 +2720,7 @@ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { IF_EVENT(printk("ia: not partially allocated resources\n");) - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; } iadev = INPH_IA_DEV(vcc->dev); error = atm_find_ci(vcc, &vpi, &vci); @@ -2744,7 +2744,7 @@ /* Device dependent initialization */ ia_vcc = kmalloc(sizeof(*ia_vcc), GFP_KERNEL); if (!ia_vcc) return -ENOMEM; - INPH_IA_VCC(vcc) = ia_vcc; + vcc->dev_data = ia_vcc; if ((error = open_rx(vcc))) { @@ -3256,7 +3256,7 @@ ret = -ENOMEM; goto err_out_disable_dev; } - INPH_IA_DEV(dev) = iadev; + dev->dev_data = iadev; IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);) IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev, iadev->LineRate);) diff -urN linux-2.4.27/drivers/atm/suni.c linux-2.4.28/drivers/atm/suni.c --- linux-2.4.27/drivers/atm/suni.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.28/drivers/atm/suni.c 2004-11-17 03:54:21.202381612 -0800 @@ -230,7 +230,7 @@ unsigned long flags; int first; - if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) + if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) return -ENOMEM; PRIV(dev)->dev = dev; diff -urN linux-2.4.27/drivers/atm/uPD98402.c linux-2.4.28/drivers/atm/uPD98402.c --- linux-2.4.27/drivers/atm/uPD98402.c 2001-09-13 15:21:32.000000000 -0700 +++ linux-2.4.28/drivers/atm/uPD98402.c 2004-11-17 03:54:21.203381653 -0800 @@ -212,7 +212,7 @@ static int uPD98402_start(struct atm_dev *dev) { DPRINTK("phy_start\n"); - if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) + if (!(dev->phy_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) return -ENOMEM; memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); (void) GET(PCR); /* clear performance events */ diff -urN linux-2.4.27/drivers/atm/zatm.c linux-2.4.28/drivers/atm/zatm.c --- linux-2.4.27/drivers/atm/zatm.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.28/drivers/atm/zatm.c 2004-11-17 03:54:21.204381694 -0800 @@ -1565,7 +1565,7 @@ DPRINTK("zatm_close: done waiting\n"); /* deallocate memory */ kfree(ZATM_VCC(vcc)); - ZATM_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); } @@ -1578,7 +1578,7 @@ DPRINTK(">zatm_open\n"); zatm_dev = ZATM_DEV(vcc->dev); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL; error = atm_find_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; @@ -1594,7 +1594,7 @@ clear_bit(ATM_VF_ADDR,&vcc->flags); return -ENOMEM; } - ZATM_VCC(vcc) = zatm_vcc; + vcc->dev_data = zatm_vcc; ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */ if ((error = open_rx_first(vcc))) { zatm_close(vcc); @@ -1828,7 +1828,7 @@ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) break; zatm_dev->pci_dev = pci_dev; - ZATM_DEV(dev) = zatm_dev; + dev->dev_data = zatm_dev; zatm_dev->copper = type; if (zatm_init(dev) || zatm_start(dev)) { atm_dev_deregister(dev); diff -urN linux-2.4.27/drivers/block/cciss.c linux-2.4.28/drivers/block/cciss.c --- linux-2.4.27/drivers/block/cciss.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/block/cciss.c 2004-11-17 03:54:21.207381818 -0800 @@ -80,7 +80,7 @@ 0x0E11, 0x4091, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS, 0x103C, 0x3211, 0, 0, 0}, {0,} }; @@ -125,7 +125,7 @@ /* Originally cciss driver only supports 8 major number */ #define MAX_CTLR_ORIG COMPAQ_CISS_MAJOR7 - COMPAQ_CISS_MAJOR + 1 -#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFF /* 64 bit DMA */ +#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFFULL /* 64 bit DMA */ #ifdef CONFIG_CISS_MONITOR_THREAD static int cciss_monitor(void *ctlr); @@ -168,6 +168,35 @@ static void cciss_procinit(int i) {} #endif /* CONFIG_PROC_FS */ +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline CommandList_struct *removeQ(CommandList_struct **Qptr, + CommandList_struct *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} + static struct block_device_operations cciss_fops = { owner: THIS_MODULE, open: cciss_open, @@ -503,10 +532,9 @@ extern int unregister_ioctl32_conversion(unsigned int cmd); static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file); -static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, - struct file *file); +static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file); -typedef long (*handler type) (unsigned int, unsigned int, unsigned long, +typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *); static struct ioctl32_map { @@ -576,13 +604,15 @@ IOCTL_Command_struct arg64; mm_segment_t old_fs; int err; + __u64 tmp_ptr; err = 0; err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request)); err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); err |= get_user(arg64.buf_size, &arg32->buf_size); - err |= get_user(arg64.buf, &arg32->buf); + err |= get_user(tmp_ptr, &arg32->buf); + arg64.buf = (BYTE *) tmp_ptr; if (err) return -EFAULT; @@ -592,7 +622,7 @@ set_fs(old_fs); if (err) return err; - err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -605,6 +635,7 @@ BIG_IOCTL_Command_struct arg64; mm_segment_t old_fs; int err; + __u64 tmp_ptr; err = 0; err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); @@ -612,7 +643,8 @@ err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); err |= get_user(arg64.buf_size, &arg32->buf_size); err |= get_user(arg64.malloc_size, &arg32->malloc_size); - err |= get_user(arg64.buf, &arg32->buf); + err |= get_user(tmp_ptr, &arg32->buf); + arg64.buf = (BYTE *) tmp_ptr; if (err) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -620,7 +652,7 @@ set_fs(old_fs); if (err) return err; - err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -629,6 +661,7 @@ static inline void register_cciss_ioctl32(void) {} static inline void unregister_cciss_ioctl32(void) {} #endif + /* * ioctl */ @@ -942,6 +975,8 @@ { kfree(buff); return -EFAULT; + } else { + memset(buff, 0, iocommand.buf_size); } } if ((c = cmd_alloc(h , 0)) == NULL) { @@ -1060,12 +1095,15 @@ goto cleanup1; } if (iocommand.Request.Type.Direction == - XFER_WRITE) + XFER_WRITE) { /* Copy the data into the buffer created */ if (copy_from_user(buff[sg_used], data_ptr, buff_size[sg_used])) { status = -ENOMEM; goto cleanup1; + } else { + memset(buff[sg_used], 0, buff_size[sg_used]); + } } size_left_alloc -= buff_size[sg_used]; data_ptr += buff_size[sg_used]; @@ -2129,35 +2167,6 @@ return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); } -/* - * Enqueuing and dequeuing functions for cmdlists. - */ -static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) -{ - if (*Qptr == NULL) { - *Qptr = c; - c->next = c->prev = c; - } else { - c->prev = (*Qptr)->prev; - c->next = (*Qptr); - (*Qptr)->prev->next = c; - (*Qptr)->prev = c; - } -} - -static inline CommandList_struct *removeQ(CommandList_struct **Qptr, - CommandList_struct *c) -{ - if (c && c->next != c) { - if (*Qptr == c) *Qptr = c->next; - c->prev->next = c->next; - c->next->prev = c->prev; - } else { - *Qptr = NULL; - } - return c; -} - /* * Takes jobs of the Q and sends them to the hardware, then puts it on * the Q to wait for completion. @@ -2671,7 +2680,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; - unchar irq = pdev->irq, ready = 0; + int ready = 0; __u32 board_id, scratchpad; __u64 cfg_offset; __u32 cfg_base_addr; @@ -2727,11 +2736,11 @@ #ifdef CCISS_DEBUG printk("command = %x\n", command); - printk("irq = %x\n", irq); + printk("irq = %x\n", pdev->irq); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = irq; + c->intr = pdev->irq; /* * Memory base addr is first addr , the second points to the config diff -urN linux-2.4.27/drivers/block/cciss.h linux-2.4.28/drivers/block/cciss.h --- linux-2.4.27/drivers/block/cciss.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/block/cciss.h 2004-11-17 03:54:21.208381859 -0800 @@ -51,7 +51,7 @@ unsigned long io_mem_addr; unsigned long io_mem_length; CfgTable_struct *cfgtable; - int intr; + unsigned int intr; int interrupts_enabled; int max_commands; int commands_outstanding; diff -urN linux-2.4.27/drivers/block/cpqarray.c linux-2.4.28/drivers/block/cpqarray.c --- linux-2.4.27/drivers/block/cpqarray.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/block/cpqarray.c 2004-11-17 03:54:21.209381900 -0800 @@ -960,6 +960,20 @@ return c; } +static inline void complete_buffers(struct buffer_head *bh, int ok) +{ + struct buffer_head *xbh; + while(bh) { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + + blk_finished_io(bh->b_size >> 9); + bh->b_end_io(bh, ok); + + bh = xbh; + } +} + /* * Get a request and submit it to the controller. * This routine needs to grab all the requests it possibly can from the @@ -1094,19 +1108,6 @@ } } -static inline void complete_buffers(struct buffer_head *bh, int ok) -{ - struct buffer_head *xbh; - while(bh) { - xbh = bh->b_reqnext; - bh->b_reqnext = NULL; - - blk_finished_io(bh->b_size >> 9); - bh->b_end_io(bh, ok); - - bh = xbh; - } -} /* * Mark all buffers that cmd was responsible for */ diff -urN linux-2.4.27/drivers/block/genhd.c linux-2.4.28/drivers/block/genhd.c --- linux-2.4.27/drivers/block/genhd.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/block/genhd.c 2004-11-17 03:54:21.210381941 -0800 @@ -49,8 +49,9 @@ add_gendisk(struct gendisk *gp) { struct gendisk *sgp; + unsigned long flags; - write_lock(&gendisk_lock); + write_lock_irqsave(&gendisk_lock, flags); /* * In 2.5 this will go away. Fix the drivers who rely on @@ -70,7 +71,7 @@ gp->next = gendisk_head; gendisk_head = gp; out: - write_unlock(&gendisk_lock); + write_unlock_irqrestore(&gendisk_lock, flags); } EXPORT_SYMBOL(add_gendisk); @@ -87,15 +88,16 @@ del_gendisk(struct gendisk *gp) { struct gendisk **gpp; + unsigned long flags; - write_lock(&gendisk_lock); + write_lock_irqsave(&gendisk_lock, flags); gendisk_array[gp->major] = NULL; for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next)) if (*gpp == gp) break; if (*gpp) *gpp = (*gpp)->next; - write_unlock(&gendisk_lock); + write_unlock_irqrestore(&gendisk_lock, flags); } EXPORT_SYMBOL(del_gendisk); @@ -113,8 +115,9 @@ { struct gendisk *gp = NULL; int maj = MAJOR(dev); + unsigned long flags; - read_lock(&gendisk_lock); + read_lock_irqsave(&gendisk_lock, flags); if ((gp = gendisk_array[maj])) goto out; @@ -123,7 +126,7 @@ if (gp->major == maj) break; out: - read_unlock(&gendisk_lock); + read_unlock_irqrestore(&gendisk_lock, flags); return gp; } @@ -143,12 +146,13 @@ { struct gendisk *gp; int error = 0; + unsigned long flags; - read_lock(&gendisk_lock); + read_lock_irqsave(&gendisk_lock, flags); for (gp = gendisk_head; gp; gp = gp->next) if ((error = walk(gp, data))) break; - read_unlock(&gendisk_lock); + read_unlock_irqrestore(&gendisk_lock, flags); return error; } @@ -160,7 +164,7 @@ struct gendisk *gp; loff_t pos = *ppos; - read_lock(&gendisk_lock); + read_lock_irq(&gendisk_lock); for (gp = gendisk_head; gp; gp = gp->next) if (!pos--) return gp; @@ -175,7 +179,7 @@ static void part_stop(struct seq_file *s, void *v) { - read_unlock(&gendisk_lock); + read_unlock_irq(&gendisk_lock); } static int part_show(struct seq_file *s, void *v) diff -urN linux-2.4.27/drivers/block/ll_rw_blk.c linux-2.4.28/drivers/block/ll_rw_blk.c --- linux-2.4.27/drivers/block/ll_rw_blk.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/block/ll_rw_blk.c 2004-11-17 03:54:21.211381982 -0800 @@ -132,7 +132,7 @@ return max_sectors[MAJOR(dev)][MINOR(dev)]; } -inline request_queue_t *blk_get_queue(kdev_t dev) +static inline request_queue_t *__blk_get_queue(kdev_t dev) { struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); @@ -142,6 +142,11 @@ return &blk_dev[MAJOR(dev)].request_queue; } +request_queue_t *blk_get_queue(kdev_t dev) +{ + return __blk_get_queue(dev); +} + static int __blk_cleanup_queue(struct request_list *list) { struct list_head *head = &list->free; @@ -303,7 +308,7 @@ /* * can we merge the two segments, or do we need to start a new one? */ -inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt) +static inline int __blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt) { /* * if bh and nxt are contigous and don't cross a 4g boundary, it's ok @@ -314,6 +319,11 @@ return 0; } +int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt) +{ + return __blk_seg_merge_ok(bh, nxt); +} + static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments) { if (req->nr_segments < max_segments) { @@ -326,7 +336,7 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req, struct buffer_head *bh, int max_segments) { - if (blk_seg_merge_ok(req->bhtail, bh)) + if (__blk_seg_merge_ok(req->bhtail, bh)) return 1; return ll_new_segment(q, req, max_segments); @@ -335,7 +345,7 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req, struct buffer_head *bh, int max_segments) { - if (blk_seg_merge_ok(bh, req->bh)) + if (__blk_seg_merge_ok(bh, req->bh)) return 1; return ll_new_segment(q, req, max_segments); @@ -346,7 +356,7 @@ { int total_segments = req->nr_segments + next->nr_segments; - if (blk_seg_merge_ok(req->bhtail, next->bh)) + if (__blk_seg_merge_ok(req->bhtail, next->bh)) total_segments--; if (total_segments > max_segments) @@ -1255,7 +1265,7 @@ * Stacking drivers are expected to know what they are doing. */ do { - q = blk_get_queue(bh->b_rdev); + q = __blk_get_queue(bh->b_rdev); if (!q) { printk(KERN_ERR "generic_make_request: Trying to access " diff -urN linux-2.4.27/drivers/char/agp/agp.h linux-2.4.28/drivers/char/agp/agp.h --- linux-2.4.27/drivers/char/agp/agp.h 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/char/agp/agp.h 2004-11-17 03:54:21.212382023 -0800 @@ -211,6 +211,12 @@ #ifndef PCI_DEVICE_ID_INTEL_865_G_1 #define PCI_DEVICE_ID_INTEL_865_G_1 0x2572 #endif +#ifndef PCI_DEVICE_ID_INTEL_915_G_0 +#define PCI_DEVICE_ID_INTEL_915_G_0 0x2580 +#endif +#ifndef PCI_DEVICE_ID_INTEL_915_G_1 +#define PCI_DEVICE_ID_INTEL_915_G_1 0x2582 +#endif #ifndef PCI_DEVICE_ID_INTEL_820_0 #define PCI_DEVICE_ID_INTEL_820_0 0x2500 #endif @@ -441,6 +447,12 @@ #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 +/* intel I915 registers */ +#define I915_GMADDR 0x18 +#define I915_MMADDR 0x10 +#define I915_PTEADDR 0x1C +#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) /* VIA register */ diff -urN linux-2.4.27/drivers/char/agp/agpgart_be.c linux-2.4.28/drivers/char/agp/agpgart_be.c --- linux-2.4.27/drivers/char/agp/agpgart_be.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/char/agp/agpgart_be.c 2004-11-17 03:54:21.217382229 -0800 @@ -794,7 +794,29 @@ } #endif get_page(page); - LockPage(page); + set_bit(PG_locked, &page->flags); + atomic_inc(&agp_bridge.current_memory_agp); + return (unsigned long)page_address(page); +} + +/* Exists to support ARGB cursors */ +static unsigned long i830_alloc_pages(void) +{ + struct page * page; + + page = alloc_pages(GFP_KERNEL, 2); + if (page == NULL) { + return 0; + } + +#ifdef CONFIG_X86 + if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + __free_page(page); + return 0; + } +#endif + get_page(page); + set_bit(PG_locked, &page->flags); atomic_inc(&agp_bridge.current_memory_agp); return (unsigned long)page_address(page); } @@ -818,6 +840,25 @@ atomic_dec(&agp_bridge.current_memory_agp); } +static void i830_destroy_pages(unsigned long addr) +{ + void *pt = (void *) addr; + struct page *page; + + if (pt == NULL) { + return; + } + + page = virt_to_page(pt); +#ifdef CONFIG_X86 + change_page_attr(page, 4, PAGE_KERNEL); +#endif + put_page(page); + UnlockPage(page); + free_pages((unsigned long) pt, 2); + atomic_dec(&agp_bridge.current_memory_agp); +} + /* End Basic Page Allocation Routines */ void agp_enable(u32 mode) @@ -1022,33 +1063,49 @@ return new; } if(type == AGP_PHYS_MEMORY) { + unsigned long physical; + /* The I810 requires a physical address to program * it's mouse pointer into hardware. However the * Xserver still writes to it through the agp * aperture */ - if (pg_count != 1) { - return NULL; - } - new = agp_create_memory(1); + if (pg_count != 1 && pg_count != 4) return(NULL); - if (new == NULL) { - return NULL; + new = agp_create_memory(pg_count); + + if (new == NULL) return(NULL); + + MOD_INC_USE_COUNT; + if (pg_count == 1) + new->memory[0] = agp_bridge.agp_alloc_page(); + else { + /* kludge to get 4 physical pages for ARGB cursor */ + new->memory[0] = i830_alloc_pages(); + new->memory[1] = new->memory[0] + PAGE_SIZE; + new->memory[2] = new->memory[1] + PAGE_SIZE; + new->memory[3] = new->memory[2] + PAGE_SIZE; } - MOD_INC_USE_COUNT; - new->memory[0] = agp_bridge.agp_alloc_page(); if (new->memory[0] == 0) { /* Free this structure */ agp_free_memory(new); return NULL; } + physical = new->memory[0]; + new->memory[0] = virt_to_phys((void *) new->memory[0]); - new->page_count = 1; - new->num_scratch_pages = 1; - new->type = AGP_PHYS_MEMORY; - new->physical = virt_to_phys((void *) new->memory[0]); - return new; + if (pg_count == 4) { + /* kludge to enable 4 physical pages for ARGB cursor */ + new->memory[1] = virt_to_phys((void *) new->memory[1]); + new->memory[2] = virt_to_phys((void *) new->memory[2]); + new->memory[3] = virt_to_phys((void *) new->memory[3]); + } + new->page_count = pg_count; + new->num_scratch_pages = pg_count; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) physical); + return(new); } return NULL; @@ -1058,7 +1115,11 @@ { agp_free_key(curr->key); if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge.agp_destroy_page((unsigned long) + if (curr->page_count == 4) + i830_destroy_pages((unsigned long) + phys_to_virt(curr->memory[0])); + else + agp_bridge.agp_destroy_page((unsigned long) phys_to_virt(curr->memory[0])); vfree(curr->memory); } @@ -1108,15 +1169,20 @@ { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ - {64, 16384, 5} + {64, 16384, 5}, + /* For I915G */ + {256, 65536, 6} }; static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ volatile u8 *registers; + volatile u32 *gtt; /* I915G */ int gtt_entries; } intel_i830_private; +static int intel_i830_fetch_size(void); + static void intel_i830_init_gtt_entries(void) { u16 gmch_ctrl; @@ -1124,26 +1190,47 @@ u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; + int size; + pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); + /* We obtain the size of the GTT, which is also stored (for some + * reason) at the top of stolen memory. Then we add 4KB to that + * for the video BIOS popup, which is also stored in there. */ + size = intel_i830_fetch_size() + 4; + if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 && agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) { switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: - gtt_entries = MB(4) - KB(132); + gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: - gtt_entries = MB(16) - KB(132); + gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(132); + gtt_entries = MB(32) - KB(size); + break; + case I915_GMCH_GMS_STOLEN_48M: + /* Check it's really I915 */ + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + gtt_entries = MB(48) - KB(size); + else + gtt_entries = 0; + break; + case I915_GMCH_GMS_STOLEN_64M: + /* Check it's really I915 */ + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + gtt_entries = MB(64) - KB(size); + else + gtt_entries = 0; break; default: gtt_entries = 0; @@ -1153,13 +1240,13 @@ { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - gtt_entries = KB(512) - KB(132); + gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: rdct = INREG8(intel_i830_private.registers, @@ -1193,14 +1280,24 @@ int page_order; aper_size_info_fixed *size; int num_entries; - u32 temp; + u32 temp, temp2; size = agp_bridge.current_size; page_order = size->page_order; num_entries = size->num_entries; agp_bridge.gatt_table_real = 0; - pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + pci_read_config_dword(intel_i830_private.i830_dev, + I915_MMADDR,&temp); + pci_read_config_dword(intel_i830_private.i830_dev, + I915_PTEADDR,&temp2); + intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) return (-ENOMEM); + } else + pci_read_config_dword(intel_i830_private.i830_dev, + I810_MMADDR,&temp); + temp &= 0xfff80000; intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); @@ -1234,6 +1331,20 @@ values = A_SIZE_FIX(agp_bridge.aperture_sizes); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + u32 temp, offset = 0; + pci_read_config_dword(intel_i830_private.i830_dev, + I915_GMADDR,&temp); +#define I915_256MB_ADDRESS_MASK (1<<27) + if (temp & I915_256MB_ADDRESS_MASK) + offset = 0; /* 128MB aperture */ + else + offset = 2; /* 256MB aperture */ + agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + offset); + agp_bridge.aperture_size_idx = offset; + return(values[offset].size); + } + if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 && agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) { agp_bridge.previous_size = agp_bridge.current_size = (void *) values; @@ -1247,7 +1358,7 @@ agp_bridge.aperture_size_idx = 0; return(values[0].size); } else { - agp_bridge.previous_size = agp_bridge.current_size = (void *) values; + agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + 1); agp_bridge.aperture_size_idx = 1; return(values[1].size); } @@ -1264,7 +1375,13 @@ current_size = A_SIZE_FIX(agp_bridge.current_size); - pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + pci_read_config_dword(intel_i830_private.i830_dev, + I915_GMADDR,&temp); + else + pci_read_config_dword(intel_i830_private.i830_dev, + I810_GMADDR,&temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); @@ -1274,15 +1391,24 @@ OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); CACHE_FLUSH(); - if (agp_bridge.needs_scratch_page == TRUE) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + if (agp_bridge.needs_scratch_page == TRUE) { + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page); + } else { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + } + } return (0); } static void intel_i830_cleanup(void) { + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + iounmap((void *)intel_i830_private.gtt); + iounmap((void *) intel_i830_private.registers); } @@ -1315,9 +1441,13 @@ CACHE_FLUSH(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge.mask_memory(mem->memory[i], mem->type)); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.gtt, j, agp_bridge.mask_memory(mem->memory[i], mem->type)); + } else { + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),agp_bridge.mask_memory(mem->memory[i], mem->type)); + } CACHE_FLUSH(); @@ -1337,8 +1467,13 @@ return (-EINVAL); } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page); + } else { + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + } CACHE_FLUSH(); @@ -1363,24 +1498,40 @@ * aperture */ - if (pg_count != 1) return(NULL); + if (pg_count != 1 && pg_count != 4) return(NULL); - nw = agp_create_memory(1); + nw = agp_create_memory(pg_count); if (nw == NULL) return(NULL); MOD_INC_USE_COUNT; - nw->memory[0] = agp_bridge.agp_alloc_page(); - physical = nw->memory[0]; + if (pg_count == 1) + nw->memory[0] = agp_bridge.agp_alloc_page(); + else { + /* kludge to get 4 physical pages for ARGB cursor */ + nw->memory[0] = i830_alloc_pages(); + nw->memory[1] = nw->memory[0] + PAGE_SIZE; + nw->memory[2] = nw->memory[1] + PAGE_SIZE; + nw->memory[3] = nw->memory[2] + PAGE_SIZE; + } + if (nw->memory[0] == 0) { /* free this structure */ agp_free_memory(nw); return(NULL); } + physical = nw->memory[0]; + nw->memory[0] = virt_to_phys((void *) nw->memory[0]); - nw->page_count = 1; - nw->num_scratch_pages = 1; + if (pg_count == 4) { + /* kludge to enable 4 physical pages for ARGB cursor */ + nw->memory[1] = virt_to_phys((void *) nw->memory[1]); + nw->memory[2] = virt_to_phys((void *) nw->memory[2]); + nw->memory[3] = virt_to_phys((void *) nw->memory[3]); + } + nw->page_count = pg_count; + nw->num_scratch_pages = pg_count; nw->type = AGP_PHYS_MEMORY; nw->physical = virt_to_phys((void *) physical); return(nw); @@ -3447,9 +3598,9 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge.mask_memory(mem->memory[i], mem->type); - BUG_ON(tmp & 0xffffff0000000ffc); - pte = (tmp & 0x000000ff00000000) >> 28; - pte |=(tmp & 0x00000000fffff000); + BUG_ON(tmp & 0xffffff0000000ffcULL); + pte = (tmp & 0x000000ff00000000ULL) >> 28; + pte |=(tmp & 0x00000000fffff000ULL); pte |= 1<<1|1<<0; agp_bridge.gatt_table[j] = pte; @@ -6112,6 +6263,13 @@ "865G", intel_845_setup }, + { PCI_DEVICE_ID_INTEL_915_G_0, + PCI_VENDOR_ID_INTEL, + INTEL_I915_G, + "Intel(R)", + "915G", + intel_845_setup }, + { PCI_DEVICE_ID_INTEL_840_0, PCI_VENDOR_ID_INTEL, INTEL_I840, @@ -6835,6 +6993,34 @@ "865G Chipset.\n"); agp_bridge.type = INTEL_I810; return intel_i830_setup(i810_dev); + + case PCI_DEVICE_ID_INTEL_915_G_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_915_G_1, NULL); + if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) { + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_915_G_1, i810_dev); + } + + if (i810_dev == NULL) { + /* + * We probably have a 915G chipset + * with an external graphics + * card. It will be initialized later + */ + printk(KERN_ERR PFX "Detected an " + "Intel(R) 915G, but could not" + " find the" + " secondary device. Assuming a " + "non-integrated video card.\n"); + agp_bridge.type = INTEL_I915_G; + break; + } + printk(KERN_INFO PFX "Detected an Intel(R) " + "915G Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i830_setup(i810_dev); + default: break; } diff -urN linux-2.4.27/drivers/char/applicom.c linux-2.4.28/drivers/char/applicom.c --- linux-2.4.27/drivers/char/applicom.c 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.28/drivers/char/applicom.c 2004-11-17 03:54:21.219382311 -0800 @@ -222,6 +222,7 @@ if (!RamIO) { printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev)); + pci_disable_device(dev); return -EIO; } @@ -233,12 +234,14 @@ (unsigned long)RamIO,0))) { printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); iounmap(RamIO); + pci_disable_device(dev); continue; } if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) { printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); + pci_disable_device(dev); apbs[boardno - 1].RamIO = 0; continue; } @@ -265,12 +268,6 @@ /* Now try the specified ISA cards */ -#warning "LEAK" - RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD); - - if (!RamIO) - printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem); - for (i = 0; i < MAX_ISA_BOARD; i++) { RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO); @@ -293,7 +290,8 @@ iounmap((void *) RamIO); apbs[boardno - 1].RamIO = 0; } - apbs[boardno - 1].irq = irq; + else + apbs[boardno - 1].irq = irq; } else apbs[boardno - 1].irq = 0; @@ -368,7 +366,7 @@ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { static int warncount = 5; if (warncount) { - printk(KERN_INFO "Hmmm. write() of Applicom card, length %d != expected %d\n", + printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); warncount--; } @@ -476,18 +474,17 @@ return 0; } -static int do_ac_read(int IndexCard, char *buf) +static int do_ac_read(int IndexCard, char *buf, + struct st_ram_io *st_loc, struct mailbox *mailbox) { - struct st_ram_io st_loc; - struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; - unsigned char *to = (unsigned char *)&tmpmailbox; + unsigned char *to = (unsigned char *)&mailbox; #ifdef DEBUG int c; #endif - st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); - st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); + st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); + st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); { @@ -510,32 +507,24 @@ printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); for (c = 0; c < sizeof(struct st_ram_io);) { - printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); + printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]); for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { - printk(" %2.2X", ((unsigned char *) &st_loc)[c]); + printk(" %2.2X", ((unsigned char *)st_loc)[c]); } } printk("\nstruct mailbox follows:"); for (c = 0; c < sizeof(struct mailbox);) { - printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); + printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]); for (c++; c % 8 && c < sizeof(struct mailbox); c++) { - printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); + printk(" %2.2X", ((unsigned char *)mailbox)[c]); } } printk("\n"); #endif - -#warning "Je suis stupide. DW. - copy*user in cli" - - if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io))) - return -EFAULT; - if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox))) - return -EFAULT; - return (sizeof(struct st_ram_io) + sizeof(struct mailbox)); } @@ -551,7 +540,7 @@ #endif /* No need to ratelimit this. Only root can trigger it anyway */ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { - printk( KERN_WARNING "Hmmm. read() of Applicom card, length %d != expected %d\n", + printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n", count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); return -EINVAL; } @@ -570,11 +559,19 @@ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); if (tmp == 2) { + struct st_ram_io st_loc; + struct mailbox mailbox; + /* Got a packet for us */ - ret = do_ac_read(i, buf); + ret = do_ac_read(i, buf, &st_loc, &mailbox); spin_unlock_irqrestore(&apbs[i].mutex, flags); set_current_state(TASK_RUNNING); remove_wait_queue(&FlagSleepRec, &wait); + + if (copy_to_user(buf, &st_loc, sizeof(st_loc))) + return -EFAULT; + if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox))) + return -EFAULT; return tmp; } diff -urN linux-2.4.27/drivers/char/drm/drm_dma.h linux-2.4.28/drivers/char/drm/drm_dma.h --- linux-2.4.27/drivers/char/drm/drm_dma.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/char/drm/drm_dma.h 2004-11-17 03:54:21.219382311 -0800 @@ -648,7 +648,7 @@ * for the same vblank sequence number; nothing to be done in * that case */ - list_for_each( ( (struct list_head *) vbl_sig ), &dev->vbl_sigs.head ) { + list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { if (vbl_sig->sequence == vblwait.request.sequence && vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->task == current) @@ -699,19 +699,20 @@ void DRM(vbl_send_signals)( drm_device_t *dev ) { - struct list_head *tmp; + struct list_head *list, *tmp; drm_vbl_sig_t *vbl_sig; unsigned int vbl_seq = atomic_read( &dev->vbl_received ); unsigned long flags; spin_lock_irqsave( &dev->vbl_lock, flags ); - list_for_each_safe( ( (struct list_head *) vbl_sig ), tmp, &dev->vbl_sigs.head ) { + list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { + vbl_sig = list_entry( list, drm_vbl_sig_t, head ); if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { vbl_sig->info.si_code = vbl_seq; send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - list_del( (struct list_head *) vbl_sig ); + list_del( list ); kfree( vbl_sig ); diff -urN linux-2.4.27/drivers/char/drm/radeon_state.c linux-2.4.28/drivers/char/drm/radeon_state.c --- linux-2.4.27/drivers/char/drm/radeon_state.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/char/drm/radeon_state.c 2004-11-17 03:54:21.221382393 -0800 @@ -1223,7 +1223,7 @@ /* Update the input parameters for next time */ image->y += height; image->height -= height; - (const u8 *)image->data += size; + image->data = (const u8 *)image->data + size; } while (image->height > 0); /* Flush the pixel cache after the blit completes. This ensures diff -urN linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.c linux-2.4.28/drivers/char/ftape/lowlevel/ftape-bsm.c --- linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.c 2000-10-16 12:58:51.000000000 -0700 +++ linux-2.4.28/drivers/char/ftape/lowlevel/ftape-bsm.c 2004-11-17 03:54:21.222382434 -0800 @@ -203,6 +203,7 @@ ft_format_code == fmt_1100ft) { SectorCount *ptr = (SectorCount *)bad_sector_map; unsigned int sector; + __u16 *ptr16; while((sector = get_sector(ptr++)) != 0) { if ((ft_format_code == fmt_big || @@ -218,9 +219,10 @@ } /* Display old ftape's end-of-file marks */ - while ((sector = get_unaligned(((__u16*)ptr)++)) != 0) { + ptr16 = (__u16*)ptr; + while ((sector = get_unaligned(ptr16++)) != 0) { TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", - sector, get_unaligned(((__u16*)ptr)++)); + sector, get_unaligned(ptr16++)); } } else { /* fixed size format */ for (i = ft_first_data_segment; diff -urN linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.h linux-2.4.28/drivers/char/ftape/lowlevel/ftape-bsm.h --- linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.h 1997-11-25 14:45:27.000000000 -0800 +++ linux-2.4.28/drivers/char/ftape/lowlevel/ftape-bsm.h 2004-11-17 03:54:21.222382434 -0800 @@ -47,7 +47,7 @@ */ typedef struct NewSectorMap { __u8 bytes[3]; -} SectorCount __attribute__((packed)); +} __attribute__((packed)) SectorCount; /* diff -urN linux-2.4.27/drivers/char/ftape/zftape/zftape-eof.c linux-2.4.28/drivers/char/ftape/zftape/zftape-eof.c --- linux-2.4.27/drivers/char/ftape/zftape/zftape-eof.c 1999-11-23 10:29:15.000000000 -0800 +++ linux-2.4.28/drivers/char/ftape/zftape/zftape-eof.c 2004-11-17 03:54:21.222382434 -0800 @@ -123,7 +123,7 @@ while (ptr + 3 < limit) { if (get_unaligned((__u32*)ptr)) { - ++(__u32*)ptr; + ptr += sizeof(__u32); } else { return ptr; } diff -urN linux-2.4.27/drivers/char/ib700wdt.c linux-2.4.28/drivers/char/ib700wdt.c --- linux-2.4.27/drivers/char/ib700wdt.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.28/drivers/char/ib700wdt.c 2004-11-17 03:54:21.223382475 -0800 @@ -133,7 +133,7 @@ ibwdt_ping(void) { /* Write a watchdog value */ - outb_p(wd_times[wd_margin], WDT_START); + outb_p(wd_margin, WDT_START); } static ssize_t diff -urN linux-2.4.27/drivers/char/ip2main.c linux-2.4.28/drivers/char/ip2main.c --- linux-2.4.27/drivers/char/ip2main.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/char/ip2main.c 2004-11-17 03:54:21.225382558 -0800 @@ -282,8 +282,8 @@ static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); -static inline void do_input(i2ChanStrPtr pCh); -static inline void do_status(i2ChanStrPtr pCh); +static void do_input(i2ChanStrPtr pCh); +static void do_status(i2ChanStrPtr pCh); static void ip2_wait_until_sent(PTTY,int); @@ -1433,7 +1433,7 @@ ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } -static inline void +static void do_input( i2ChanStrPtr pCh ) { unsigned long flags; @@ -1468,7 +1468,7 @@ } } -static inline void +static void do_status( i2ChanStrPtr pCh ) { int status; diff -urN linux-2.4.27/drivers/char/istallion.c linux-2.4.28/drivers/char/istallion.c --- linux-2.4.27/drivers/char/istallion.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/char/istallion.c 2004-11-17 03:54:21.229382722 -0800 @@ -4546,6 +4546,26 @@ /*****************************************************************************/ /* + * Find the next available board number that is free. + */ + +static inline int stli_getbrdnr() +{ + int i; + + for (i = 0; (i < STL_MAXBRDS); i++) { + if (stli_brds[i] == (stlibrd_t *) NULL) { + if (i >= stli_nrbrds) + stli_nrbrds = i + 1; + return(i); + } + } + return(-1); +} + +/*****************************************************************************/ + +/* * Probe around and try to find any EISA boards in system. The biggest * problem here is finding out what memory address is associated with * an EISA board after it is found. The registers of the ECPE and @@ -4625,26 +4645,6 @@ /*****************************************************************************/ -/* - * Find the next available board number that is free. - */ - -static inline int stli_getbrdnr() -{ - int i; - - for (i = 0; (i < STL_MAXBRDS); i++) { - if (stli_brds[i] == (stlibrd_t *) NULL) { - if (i >= stli_nrbrds) - stli_nrbrds = i + 1; - return(i); - } - } - return(-1); -} - -/*****************************************************************************/ - #ifdef CONFIG_PCI /* diff -urN linux-2.4.27/drivers/char/mxser.c linux-2.4.28/drivers/char/mxser.c --- linux-2.4.27/drivers/char/mxser.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.28/drivers/char/mxser.c 2004-11-17 03:54:21.231382804 -0800 @@ -1385,66 +1385,6 @@ wake_up_interruptible(&info->open_wait); } -/* - * This is the serial driver's generic interrupt routine - */ -static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int status, i; - struct mxser_struct *info; - struct mxser_struct *port; - int max, irqbits, bits, msr; - int pass_counter = 0; - - port = 0; - for (i = 0; i < MXSER_BOARDS; i++) { - if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { - port = dev_id; - break; - } - } - - if (i == MXSER_BOARDS) - return; - if (port == 0) - return; - max = mxser_numports[mxsercfg[i].board_type]; - - while (1) { - irqbits = inb(port->vector) & port->vectormask; - if (irqbits == port->vectormask) - break; - for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == port->vectormask) - break; - if (bits & irqbits) - continue; - info = port + i; - if (!info->tty || - (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) - continue; - status = inb(info->base + UART_LSR) & info->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(info, &status); - msr = inb(info->base + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(info, msr); - if (status & UART_LSR_THRE) { -/* 8-2-99 by William - if ( info->x_char || (info->xmit_cnt > 0) ) - */ - mxser_transmit_chars(info); - } - } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { -#if 0 - printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - } -} - static inline void mxser_receive_chars(struct mxser_struct *info, int *status) { @@ -1487,44 +1427,6 @@ } -static inline void mxser_transmit_chars(struct mxser_struct *info) -{ - int count, cnt; - - if (info->x_char) { - outb(info->x_char, info->base + UART_TX); - info->x_char = 0; - mxvar_log.txcnt[info->port]++; - return; - } - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - return; - } - cnt = info->xmit_cnt; - count = info->xmit_fifo_size; - do { - outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); - if (--info->xmit_cnt <= 0) - break; - } while (--count > 0); - mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt); - - if (info->xmit_cnt < WAKEUP_CHARS) { - set_bit(MXSER_EVENT_TXLOW, &info->event); - MOD_INC_USE_COUNT; - if (schedule_task(&info->tqueue) == 0) - MOD_DEC_USE_COUNT; - } - if (info->xmit_cnt <= 0) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } -} - static inline void mxser_check_modem_status(struct mxser_struct *info, int status) { @@ -1572,6 +1474,104 @@ } } +static inline void mxser_transmit_chars(struct mxser_struct *info) +{ + int count, cnt; + + if (info->x_char) { + outb(info->x_char, info->base + UART_TX); + info->x_char = 0; + mxvar_log.txcnt[info->port]++; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + return; + } + cnt = info->xmit_cnt; + count = info->xmit_fifo_size; + do { + outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt); + + if (info->xmit_cnt < WAKEUP_CHARS) { + set_bit(MXSER_EVENT_TXLOW, &info->event); + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; + } + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } +} + +/* + * This is the serial driver's generic interrupt routine + */ +static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status, i; + struct mxser_struct *info; + struct mxser_struct *port; + int max, irqbits, bits, msr; + int pass_counter = 0; + + port = 0; + for (i = 0; i < MXSER_BOARDS; i++) { + if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { + port = dev_id; + break; + } + } + + if (i == MXSER_BOARDS) + return; + if (port == 0) + return; + max = mxser_numports[mxsercfg[i].board_type]; + + while (1) { + irqbits = inb(port->vector) & port->vectormask; + if (irqbits == port->vectormask) + break; + for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { + if (irqbits == port->vectormask) + break; + if (bits & irqbits) + continue; + info = port + i; + if (!info->tty || + (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) + continue; + status = inb(info->base + UART_LSR) & info->read_status_mask; + if (status & UART_LSR_DR) + mxser_receive_chars(info, &status); + msr = inb(info->base + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, msr); + if (status & UART_LSR_THRE) { +/* 8-2-99 by William + if ( info->x_char || (info->xmit_cnt > 0) ) + */ + mxser_transmit_chars(info); + } + } + if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { +#if 0 + printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + } +} + static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info) { diff -urN linux-2.4.27/drivers/char/nwflash.c linux-2.4.28/drivers/char/nwflash.c --- linux-2.4.27/drivers/char/nwflash.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/char/nwflash.c 2004-11-17 03:54:21.232382845 -0800 @@ -159,7 +159,8 @@ if (ret == 0) { ret = count; *ppos = p + count; - } + } else + ret = -EFAULT; up(&nwflash_sem); } return ret; diff -urN linux-2.4.27/drivers/char/random.c linux-2.4.28/drivers/char/random.c --- linux-2.4.27/drivers/char/random.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/char/random.c 2004-11-17 03:54:21.233382887 -0800 @@ -750,6 +750,11 @@ __u32 high; rdtsc(time, high); num ^= high; +#elif defined (__sparc_v9__) + unsigned long tick = tick_ops->get_tick(); + + time = (unsigned int) tick; + num ^= (tick >> 32UL); #else time = jiffies; #endif diff -urN linux-2.4.27/drivers/char/serial.c linux-2.4.28/drivers/char/serial.c --- linux-2.4.27/drivers/char/serial.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/char/serial.c 2004-11-17 03:54:21.253383709 -0800 @@ -573,8 +573,19 @@ do { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { tty->flip.tqueue.routine((void *) tty); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + /* no room in flip buffer, discard rx FIFO contents to clear IRQ + * *FIXME* Hardware with auto flow control + * would benefit from leaving the data in the FIFO and + * disabling the rx IRQ until space becomes available. + */ + do { + serial_inp(info, UART_RX); + icount->overrun++; + *status = serial_inp(info, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); return; // if TTY_DONT_FLIP is set + } } ch = serial_inp(info, UART_RX); *tty->flip.char_buf_ptr = ch; diff -urN linux-2.4.27/drivers/char/synclinkmp.c linux-2.4.28/drivers/char/synclinkmp.c --- linux-2.4.27/drivers/char/synclinkmp.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/char/synclinkmp.c 2004-11-17 03:54:21.257383873 -0800 @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 3.22 2003/09/05 14:04:26 paulkf Exp $ + * $Id: synclinkmp.c,v 3.23 2004/08/24 19:49:48 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -504,7 +504,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 3.22 $"; +static char *driver_version = "$Revision: 3.23 $"; static int __devinit synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void __devexit synclinkmp_remove_one(struct pci_dev *dev); @@ -681,7 +681,7 @@ static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x0080002d; +static u32 lcr1_brdr_value = 0x00800029; static u32 read_ahead_count = 8; @@ -2036,16 +2036,15 @@ { struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; - unsigned char status = read_reg(info, SR1); - unsigned char status2 = read_reg(info, SR2); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); + unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; /* clear status bits */ - if ( status & (FLGD + IDLD + CDCD + BRKD) ) - write_reg(info, SR1, - (unsigned char)(status & (FLGD + IDLD + CDCD + BRKD))); + if (status) + write_reg(info, SR1, status); - if ( status2 & OVRN ) - write_reg(info, SR2, (unsigned char)(status2 & OVRN)); + if (status2) + write_reg(info, SR2, status2); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_rxint status=%02X %02x\n", @@ -2182,15 +2181,22 @@ printk("%s(%d):%s isr_txeom status=%02x\n", __FILE__,__LINE__,info->device_name,status); - /* disable and clear MSCI interrupts */ - info->ie1_value &= ~(IDLE + UDRN); - write_reg(info, IE1, info->ie1_value); - write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); - write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + if (status & UDRN) { + write_reg(info, CMD, TXRESET); + write_reg(info, CMD, TXENABLE); + } else + write_reg(info, CMD, TXBUFCLR); + + /* disable and clear tx interrupts */ + info->ie0_value &= ~TXRDYE; + info->ie1_value &= ~(IDLE + UDRN); + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); + if ( info->tx_active ) { if (info->params.mode != MGSL_MODE_ASYNC) { if (status & UDRN) @@ -2231,10 +2237,10 @@ */ void isr_txint(SLMP_INFO * info) { - unsigned char status = read_reg(info, SR1); + unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); /* clear status bits */ - write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS))); + write_reg(info, SR1, status); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txint status=%02x\n", @@ -2263,6 +2269,14 @@ printk("%s(%d):%s isr_txrdy() tx_count=%d\n", __FILE__,__LINE__,info->device_name,info->tx_count); + if (info->params.mode != MGSL_MODE_ASYNC) { + /* disable TXRDY IRQ, enable IDLE IRQ */ + info->ie0_value &= ~TXRDYE; + info->ie1_value |= IDLE; + write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); + return; + } + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; @@ -2317,13 +2331,6 @@ void isr_txdmaok(SLMP_INFO * info) { - /* BIT7 = EOT (end of transfer, used for async mode) - * BIT6 = EOM (end of message/frame, used for sync mode) - * - * We don't look at DMA status because only EOT is enabled - * and we always clear and disable all tx DMA IRQs. - */ -// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0; unsigned char status_reg1 = read_reg(info, SR1); write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ @@ -2334,19 +2341,10 @@ printk("%s(%d):%s isr_txdmaok(), status=%02x\n", __FILE__,__LINE__,info->device_name,status_reg1); - /* If transmitter already idle, do end of frame processing, - * otherwise enable interrupt for tx IDLE. - */ - if (status_reg1 & IDLE) - isr_txeom(info, IDLE); - else { - /* disable and clear underrun IRQ, enable IDLE interrupt */ - info->ie1_value |= IDLE; - info->ie1_value &= ~UDRN; - write_reg(info, IE1, info->ie1_value); - - write_reg(info, SR1, UDRN); - } + /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */ + write_reg16(info, TRC0, 0); + info->ie0_value |= TXRDYE; + write_reg(info, IE0, info->ie0_value); } void isr_txdmaerror(SLMP_INFO * info) @@ -3037,7 +3035,7 @@ unsigned char oldval = info->ie1_value; unsigned char newval = oldval + (mask & MgslEvent_ExitHuntMode ? FLGD:0) + - (mask & MgslEvent_IdleReceived ? IDLE:0); + (mask & MgslEvent_IdleReceived ? IDLD:0); if ( oldval != newval ) { info->ie1_value = newval; write_reg(info, IE1, info->ie1_value); @@ -3104,7 +3102,7 @@ spin_lock_irqsave(&info->lock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - info->ie1_value &= ~(FLGD|IDLE); + info->ie1_value &= ~(FLGD|IDLD); write_reg(info, IE1, info->ie1_value); } spin_unlock_irqrestore(&info->lock,flags); @@ -3554,9 +3552,10 @@ int claim_resources(SLMP_INFO *info) { - if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3565,22 +3564,25 @@ if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->lcr_mem_requested = 1; - if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else info->sca_base_requested = 1; - if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) { + if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); + info->init_error = DiagStatus_AddressConflict; goto errout; } else @@ -3590,33 +3592,41 @@ if (!info->memory_base) { printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } - if ( !memory_test(info) ) { - printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - goto errout; - } - - info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE); if (!info->lcr_base) { printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->lcr_base += info->lcr_offset; - info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset; + info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE); if (!info->sca_base) { printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base ); + info->init_error = DiagStatus_CantAssignPciResources; goto errout; } + info->sca_base += info->sca_offset; - info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset; + info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE); if (!info->statctrl_base) { printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); + info->init_error = DiagStatus_CantAssignPciResources; + goto errout; + } + info->statctrl_base += info->statctrl_offset; + + if ( !memory_test(info) ) { + printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + info->init_error = DiagStatus_MemoryError; goto errout; } @@ -3639,7 +3649,7 @@ } if ( info->shared_mem_requested ) { - release_mem_region(info->phys_memory_base,0x40000); + release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); info->shared_mem_requested = 0; } if ( info->lcr_mem_requested ) { @@ -3647,11 +3657,11 @@ info->lcr_mem_requested = 0; } if ( info->sca_base_requested ) { - release_mem_region(info->phys_sca_base + info->sca_offset,512); + release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); info->sca_base_requested = 0; } if ( info->sca_statctrl_requested ) { - release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16); + release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); info->sca_statctrl_requested = 0; } @@ -3982,34 +3992,25 @@ __FILE__,__LINE__,rc); restore_flags(flags); + /* reset devices */ info = synclinkmp_device_list; while(info) { -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - sppp_delete(info); -#endif reset_port(info); - if ( info->port_num == 0 ) { - if ( info->irq_requested ) { - free_irq(info->irq_level, info); - info->irq_requested = 0; - } - } info = info->next_device; } - /* port 0 of each adapter originally claimed - * all resources, release those now - */ + /* release devices */ info = synclinkmp_device_list; while(info) { +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->dosyncppp) + sppp_delete(info); +#endif free_dma_bufs(info); free_tmp_rx_buf(info); if ( info->port_num == 0 ) { - spin_lock_irqsave(&info->lock,flags); - reset_adapter(info); - write_reg(info, LPR, 1); /* set low power mode */ - spin_unlock_irqrestore(&info->lock,flags); + if (info->sca_base) + write_reg(info, LPR, 1); /* set low power mode */ release_resources(info); } tmp = info; @@ -4229,6 +4230,9 @@ } } + write_reg16(info, TRC0, + (unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level)); + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ @@ -4240,11 +4244,10 @@ write_reg16(info, TXDMA + EDA, info->tx_buf_list_ex[info->last_tx_buf].phys_entry); - /* clear IDLE and UDRN status bit */ - info->ie1_value &= ~(IDLE + UDRN); - if (info->params.mode != MGSL_MODE_ASYNC) - info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */ - write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */ + /* enable underrun IRQ */ + info->ie1_value &= ~IDLE; + info->ie1_value |= UDRN; + write_reg(info, IE1, info->ie1_value); write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ diff -urN linux-2.4.27/drivers/char/tty_io.c linux-2.4.28/drivers/char/tty_io.c --- linux-2.4.27/drivers/char/tty_io.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/char/tty_io.c 2004-11-17 03:54:21.259383956 -0800 @@ -1684,11 +1684,11 @@ static int send_break(struct tty_struct *tty, int duration) { - set_current_state(TASK_INTERRUPTIBLE); - tty->driver.break_ctl(tty, -1); - if (!signal_pending(current)) + if (!signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(duration); + } tty->driver.break_ctl(tty, 0); if (signal_pending(current)) return -EINTR; diff -urN linux-2.4.27/drivers/char/vc_screen.c linux-2.4.28/drivers/char/vc_screen.c --- linux-2.4.27/drivers/char/vc_screen.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/char/vc_screen.c 2004-11-17 03:54:21.260383997 -0800 @@ -136,10 +136,12 @@ if (!vc_cons_allocated(currcons)) goto unlock_out; - read = 0; - ret = 0; + ret = -EINVAL; if (pos != n) goto unlock_out; + + read = 0; + ret = 0; while (count) { char *con_buf0, *con_buf_start; long this_round, size; diff -urN linux-2.4.27/drivers/fc4/fc.c linux-2.4.28/drivers/fc4/fc.c --- linux-2.4.27/drivers/fc4/fc.c 2001-09-14 14:04:08.000000000 -0700 +++ linux-2.4.28/drivers/fc4/fc.c 2004-11-17 03:54:21.261384038 -0800 @@ -1155,3 +1155,5 @@ kfree(p); return status; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/hotplug/Makefile linux-2.4.28/drivers/hotplug/Makefile --- linux-2.4.27/drivers/hotplug/Makefile 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/Makefile 2004-11-17 03:54:21.262384079 -0800 @@ -20,7 +20,6 @@ cpqphp-objs := cpqphp_core.o \ cpqphp_ctrl.o \ - cpqphp_proc.o \ cpqphp_pci.o ibmphp-objs := ibmphp_core.o \ @@ -64,6 +63,10 @@ cpqphp-objs += cpqphp_nvram.o endif +ifeq ($(CONFIG_PROC_FS),y) + cpqphp-objs += cpqphp_proc.o +endif + include $(TOPDIR)/Rules.make pci_hotplug.o: $(pci_hotplug-objs) diff -urN linux-2.4.27/drivers/hotplug/cpqphp_ctrl.c linux-2.4.28/drivers/hotplug/cpqphp_ctrl.c --- linux-2.4.27/drivers/hotplug/cpqphp_ctrl.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/hotplug/cpqphp_ctrl.c 2004-11-17 03:54:21.263384120 -0800 @@ -1726,7 +1726,14 @@ // New name strcpy(current->comm, "phpd_event"); - + + /* avoid getting signals */ + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + unlock_kernel(); while (1) { diff -urN linux-2.4.27/drivers/hotplug/ibmphp_hpc.c linux-2.4.28/drivers/hotplug/ibmphp_hpc.c --- linux-2.4.27/drivers/hotplug/ibmphp_hpc.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/hotplug/ibmphp_hpc.c 2004-11-17 03:54:21.265384202 -0800 @@ -184,14 +184,14 @@ } wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- // READ - step 2 : clear the message buffer data = 0x00000000; wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- @@ -199,7 +199,7 @@ // 2020 : [20] OR operation at [20] offset 0x20 data = WPG_I2CMCNTL_STARTOP_MASK; wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- @@ -207,7 +207,7 @@ i = CMD_COMPLETE_TOUT_SEC; while (i) { long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) @@ -223,7 +223,7 @@ i = CMD_COMPLETE_TOUT_SEC; while (i) { long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); if (HPC_I2CSTATUS_CHECK (data)) @@ -237,7 +237,7 @@ //-------------------------------------------------------------------- // READ - step 6 : get DATA - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); @@ -295,14 +295,14 @@ } wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- // WRITE - step 2 : clear the message buffer data = 0x00000000 | (ulong) cmd; wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- @@ -310,7 +310,7 @@ // 2020 : [20] OR operation at [20] offset 0x20 data = WPG_I2CMCNTL_STARTOP_MASK; wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR; writel (wpg_data, wpg_addr); //-------------------------------------------------------------------- @@ -318,7 +318,7 @@ i = CMD_COMPLETE_TOUT_SEC; while (i) { long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) @@ -335,7 +335,7 @@ i = CMD_COMPLETE_TOUT_SEC; while (i) { long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; wpg_data = readl (wpg_addr); data = swab32 (wpg_data); if (HPC_I2CSTATUS_CHECK (data)) diff -urN linux-2.4.27/drivers/hotplug/ibmphp_res.c linux-2.4.28/drivers/hotplug/ibmphp_res.c --- linux-2.4.27/drivers/hotplug/ibmphp_res.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/hotplug/ibmphp_res.c 2004-11-17 03:54:21.266384243 -0800 @@ -42,7 +42,7 @@ static int update_bridge_ranges (struct bus_node **); static int add_range (int type, struct range_node *, struct bus_node *); static void fix_resources (struct bus_node *); -static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); +static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); static LIST_HEAD(gbuses); LIST_HEAD(ibmphp_res_head); @@ -1757,7 +1757,7 @@ return find_bus_wprev (bus_number, NULL, 0); } -static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) +static struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) { struct bus_node *bus_cur; struct list_head *tmp; diff -urN linux-2.4.27/drivers/hotplug/pciehp.h linux-2.4.28/drivers/hotplug/pciehp.h --- linux-2.4.27/drivers/hotplug/pciehp.h 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehp.h 2004-11-17 03:54:21.267384285 -0800 @@ -45,8 +45,6 @@ extern int pciehp_poll_time; extern int pciehp_debug; -extern int pciehp_msi_quirk; - /*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ #define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) diff -urN linux-2.4.27/drivers/hotplug/pciehp_ctrl.c linux-2.4.28/drivers/hotplug/pciehp_ctrl.c --- linux-2.4.27/drivers/hotplug/pciehp_ctrl.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehp_ctrl.c 2004-11-17 03:54:21.269384367 -0800 @@ -1053,6 +1053,34 @@ hotplug controller logic */ +static void set_slot_off(struct controller *ctrl, struct slot * pslot) +{ + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* turn off slot, turn on Amber LED, turn off Green LED */ + if (pslot->hpc_ops->power_off_slot(pslot)) { + err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return; + } + wait_for_ctrl_irq (ctrl); + + pslot->hpc_ops->green_led_off(pslot); + + wait_for_ctrl_irq (ctrl); + + /* turn on Amber LED */ + if (pslot->hpc_ops->set_attention_status(pslot, 1)) { + err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return; + } + wait_for_ctrl_irq (ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); +} /** * board_added - Called after a board has been added to the system. @@ -1066,7 +1094,7 @@ u8 hp_slot; int index; u32 temp_register = 0xFFFFFFFF; - u32 retval, rc = 0; + u32 rc = 0; struct pci_func *new_func = NULL; struct slot *p_slot; struct resource_lists res_lists; @@ -1082,8 +1110,10 @@ /* Power on slot */ rc = p_slot->hpc_ops->power_on_slot(p_slot); - if (rc) + if (rc) { + up(&ctrl->crit_sect); return -1; + } /* Wait for the command to complete */ wait_for_ctrl_irq(ctrl); @@ -1105,10 +1135,11 @@ dbg("%s: afterlong_delay\n", __FUNCTION__); dbg("%s: before check link status", __FUNCTION__); - /* Make this to check for link training status */ + /* Check link training status */ rc = p_slot->hpc_ops->check_lnk_status(ctrl); if (rc) { err("%s: Failed to check link status\n", __FUNCTION__); + set_slot_off(ctrl, p_slot); return -1; } @@ -1161,36 +1192,7 @@ pciehp_resource_sort_and_combine(&(ctrl->bus_head)); if (rc) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* Turn off slot, turn on Amber LED, turn off Green LED */ - retval = p_slot->hpc_ops->power_off_slot(p_slot); - /* In PCI Express, just power off slot */ - if (retval) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - /* Turn on Amber LED */ - retval = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (retval) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - + set_slot_off(ctrl, p_slot); return(rc); } pciehp_save_slot_config(ctrl, func); @@ -1220,42 +1222,12 @@ /* Wait for the command to complete */ wait_for_ctrl_irq(ctrl); - /* Done with exclusive hardware access */ up(&ctrl->crit_sect); } else { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* Turn off slot, turn on Amber LED, turn off Green LED */ - retval = p_slot->hpc_ops->power_off_slot(p_slot); - /* In PCI Express, just power off slot */ - if (retval) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - /* Turn on Amber LED */ - retval = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (retval) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq(ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - return(rc); + set_slot_off(ctrl, p_slot); + return -1; } return 0; } @@ -1323,6 +1295,7 @@ rc = p_slot->hpc_ops->power_off_slot(p_slot); if (rc) { err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); return rc; } /* Wait for the command to complete */ @@ -1592,7 +1565,10 @@ down(&ctrl->crit_sect); p_slot->hpc_ops->set_attention_status(p_slot, 1); + wait_for_ctrl_irq(ctrl); + p_slot->hpc_ops->green_led_off(p_slot); + wait_for_ctrl_irq(ctrl); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -1624,7 +1600,6 @@ { struct slot *p_slot = (struct slot *) slot; u8 getstatus; - int rc; pushbutton_pending = 0; @@ -1638,23 +1613,7 @@ p_slot->state = POWEROFF_STATE; dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - if (pciehp_disable_slot(p_slot)) { - /* Wait for exclusive access to hardware */ - down(&p_slot->ctrl->crit_sect); - - /* Turn on the Attention LED */ - rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (rc) { - err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); - return; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - up(&p_slot->ctrl->crit_sect); - } + pciehp_disable_slot(p_slot); p_slot->state = STATIC_STATE; } else { p_slot->state = POWERON_STATE; @@ -1664,15 +1623,6 @@ /* Wait for exclusive access to hardware */ down(&p_slot->ctrl->crit_sect); - /* Turn off the green LED */ - rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (rc) { - err("%s: Issue of Set Attn Indicator On command failed\n", __FUNCTION__); - return; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - p_slot->hpc_ops->green_led_off(p_slot); /* Wait for the command to complete */ @@ -1706,21 +1656,21 @@ if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } up(&p_slot->ctrl->crit_sect); @@ -1793,21 +1743,21 @@ if (ret || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } up(&p_slot->ctrl->crit_sect); diff -urN linux-2.4.27/drivers/hotplug/pciehp_hpc.c linux-2.4.28/drivers/hotplug/pciehp_hpc.c --- linux-2.4.27/drivers/hotplug/pciehp_hpc.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehp_hpc.c 2004-11-17 03:54:21.271384449 -0800 @@ -346,10 +346,11 @@ return retval; } - if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) { + dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status); + if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || + !(lnk_status & NEG_LINK_WD)) { err("%s : Link Training Error occurs \n", __FUNCTION__); - retval = -1; - return retval; + return -1; } DBG_LEAVE_ROUTINE @@ -911,7 +912,6 @@ err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return; } - /* dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); */ intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED ); @@ -932,8 +932,6 @@ return; } - dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__); - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); @@ -941,14 +939,12 @@ err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; @@ -957,7 +953,6 @@ err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); } if (intr_loc & CMD_COMPLETED) { @@ -995,8 +990,6 @@ err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return; } - dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__); - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); @@ -1004,14 +997,12 @@ err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; @@ -1020,7 +1011,6 @@ err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return; } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); } return; } @@ -1409,17 +1399,6 @@ start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ } else { /* Installs the interrupt handler */ -#ifdef CONFIG_PCI_USE_VECTOR - if (!pciehp_msi_quirk) { - rc = pci_enable_msi(pdev); - if (rc) { - info("Can't get msi for the hotplug controller\n"); - info("Use INTx for the hotplug controller\n"); - dbg("%s: rc = %x\n", __FUNCTION__, rc); - } else - php_ctlr->irq = pdev->irq; - } -#endif rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); if (rc) { diff -urN linux-2.4.27/drivers/hotplug/pciehp_pci.c linux-2.4.28/drivers/hotplug/pciehp_pci.c --- linux-2.4.27/drivers/hotplug/pciehp_pci.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehp_pci.c 2004-11-17 03:54:21.272384490 -0800 @@ -117,9 +117,7 @@ temp_func->pci_dev->bus->number, temp_func->pci_dev->devfn); dbg("%s: PCI_SLOT_NAME=%s\n", __FUNCTION__, temp_func->pci_dev->slot_name); - //pci_enable_device(temp_func->pci_dev); - //dbg("%s: after calling pci_enable_device, irq = %x\n", - // __FUNCTION__, temp_func->pci_dev->irq); + pci_enable_device(temp_func->pci_dev); pci_proc_attach_device(temp_func->pci_dev); pci_announce_device_to_drivers(temp_func->pci_dev); } diff -urN linux-2.4.27/drivers/hotplug/pciehprm_acpi.c linux-2.4.28/drivers/hotplug/pciehprm_acpi.c --- linux-2.4.27/drivers/hotplug/pciehprm_acpi.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehprm_acpi.c 2004-11-17 03:54:21.273384531 -0800 @@ -217,6 +217,10 @@ } ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); + if (!ab->_hpp) { + err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name); + goto free_and_return; + } memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); ab->_hpp->cache_line_size = nui[0]; @@ -1392,7 +1396,7 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl) { - struct pci_func *func; + struct pci_func *func, new_func; int busn = ctrl->slot_bus; int devn, funn; u32 vid; @@ -1411,11 +1415,19 @@ if (vid != 0xFFFFFFFF) { dbg("%s: vid = %x\n", __FUNCTION__, vid); func = pciehp_slot_find(busn, devn, funn); - if (!func) - continue; - configure_existing_function(ctrl, func); + if (!func) { + memset(&new_func, 0, sizeof(struct pci_func)); + new_func.bus = busn; + new_func.device = devn; + new_func.function = funn; + new_func.is_a_board = 1; + configure_existing_function(ctrl, &new_func); + pciehprm_dump_func_res(&new_func); + } else { + configure_existing_function(ctrl, func); + pciehprm_dump_func_res(func); + } dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - pciehprm_dump_func_res(func); } } } diff -urN linux-2.4.27/drivers/hotplug/pciehprm_nonacpi.c linux-2.4.28/drivers/hotplug/pciehprm_nonacpi.c --- linux-2.4.27/drivers/hotplug/pciehprm_nonacpi.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/pciehprm_nonacpi.c 2004-11-17 03:54:21.274384572 -0800 @@ -281,7 +281,7 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl) { - struct pci_func *func; + struct pci_func *func, new_func; int busn = ctrl->slot_bus; int devn, funn; u32 vid; @@ -301,11 +301,19 @@ vid, busn, devn, funn); func = pciehp_slot_find(busn, devn, funn); dbg("%s: func = %p\n", __FUNCTION__,func); - if (!func) - continue; - configure_existing_function(ctrl, func); + if (!func) { + memset(&new_func, 0, sizeof(struct pci_func)); + new_func.bus = busn; + new_func.device = devn; + new_func.function = funn; + new_func.is_a_board = 1; + configure_existing_function(ctrl, &new_func); + phprm_dump_func_res(&new_func); + } else { + configure_existing_function(ctrl, func); + phprm_dump_func_res(func); + } dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - phprm_dump_func_res(func); } } } diff -urN linux-2.4.27/drivers/hotplug/shpchp.h linux-2.4.28/drivers/hotplug/shpchp.h --- linux-2.4.27/drivers/hotplug/shpchp.h 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchp.h 2004-11-17 03:54:21.274384572 -0800 @@ -61,6 +61,7 @@ u8 configured; u8 switch_save; u8 presence_save; + u8 pwr_save; u32 base_length[0x06]; u8 base_type[0x06]; u16 reserved2; diff -urN linux-2.4.27/drivers/hotplug/shpchp_ctrl.c linux-2.4.28/drivers/hotplug/shpchp_ctrl.c --- linux-2.4.27/drivers/hotplug/shpchp_ctrl.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchp_ctrl.c 2004-11-17 03:54:21.277384696 -0800 @@ -137,6 +137,8 @@ p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + dbg("%s: Card present %x Power status %x\n", __FUNCTION__, + func->presence_save, func->pwr_save); if (getstatus) { /* @@ -145,6 +147,10 @@ info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; + if (func->pwr_save && func->presence_save) { + taskInfo->event_type = INT_POWER_FAULT; + err("Surprise Removal of card\n"); + } } else { /* * Switch closed @@ -1431,6 +1437,7 @@ rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed); if (rc) { err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } @@ -1442,6 +1449,7 @@ err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", __FUNCTION__); err("%s: Error code (%d)\n", __FUNCTION__, rc); + up(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } /* Done with exclusive hardware access */ @@ -1592,7 +1600,8 @@ func->status = 0; func->switch_save = 0x10; func->is_a_board = 0x01; - + func->pwr_save = 1; + /* Next, we will instantiate the linux pci_dev structures * (with appropriate driver notification, if already present) */ @@ -1785,6 +1794,7 @@ func->function = 0; func->configured = 0; func->switch_save = 0x10; + func->pwr_save = 0; func->is_a_board = 0; } @@ -2038,7 +2048,6 @@ { struct slot *p_slot = (struct slot *) slot; u8 getstatus; - int rc; pushbutton_pending = 0; @@ -2052,23 +2061,7 @@ p_slot->state = POWEROFF_STATE; dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - if (shpchp_disable_slot(p_slot)) { - /* Wait for exclusive access to hardware */ - down(&p_slot->ctrl->crit_sect); - - /* Turn on the Attention LED */ - rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (rc) { - err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); - return; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq(p_slot->ctrl); - - /* Done with exclusive hardware access */ - up(&p_slot->ctrl->crit_sect); - } + shpchp_disable_slot(p_slot); p_slot->state = STATIC_STATE; } else { p_slot->state = POWERON_STATE; @@ -2078,15 +2071,6 @@ /* Wait for exclusive access to hardware */ down(&p_slot->ctrl->crit_sect); - /* Turn off the green LED */ - rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (rc) { - err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); - return; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq(p_slot->ctrl); - p_slot->hpc_ops->green_led_off(p_slot); /* Wait for the command to complete */ @@ -2120,19 +2104,19 @@ if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } up(&p_slot->ctrl->crit_sect); @@ -2150,6 +2134,8 @@ /* We have to save the presence info for these slots */ p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save)); + dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); func->switch_save = !getstatus? 0x10:0; @@ -2205,19 +2191,19 @@ if (ret || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return (0); + return (1); } up(&p_slot->ctrl->crit_sect); diff -urN linux-2.4.27/drivers/hotplug/shpchp_hpc.c linux-2.4.28/drivers/hotplug/shpchp_hpc.c --- linux-2.4.27/drivers/hotplug/shpchp_hpc.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchp_hpc.c 2004-11-17 03:54:21.278384737 -0800 @@ -1547,15 +1547,6 @@ start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ } else { /* Installs the interrupt handler */ -#ifdef CONFIG_PCI_USE_VECTOR - rc = pci_enable_msi(pdev); - if (rc) { - info("Can't get msi for the hotplug controller\n"); - info("Use INTx for the hotplug controller\n"); - dbg("%s: rc = %x\n", __FUNCTION__, rc); - } else - php_ctlr->irq = pdev->irq; -#endif rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); @@ -1563,7 +1554,6 @@ err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); goto abort_free_ctlr; } - /* Execute OSHP method here */ } dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); diff -urN linux-2.4.27/drivers/hotplug/shpchp_pci.c linux-2.4.28/drivers/hotplug/shpchp_pci.c --- linux-2.4.27/drivers/hotplug/shpchp_pci.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchp_pci.c 2004-11-17 03:54:21.279384778 -0800 @@ -481,6 +481,7 @@ new_slot->function = (u8) function; new_slot->is_a_board = 1; new_slot->switch_save = 0x10; + new_slot->pwr_save = 1; /* In case of unsupported board */ new_slot->status = DevError; new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); diff -urN linux-2.4.27/drivers/hotplug/shpchprm_acpi.c linux-2.4.28/drivers/hotplug/shpchprm_acpi.c --- linux-2.4.27/drivers/hotplug/shpchprm_acpi.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchprm_acpi.c 2004-11-17 03:54:21.280384819 -0800 @@ -217,6 +217,10 @@ } ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); + if (!ab->_hpp) { + err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name); + goto free_and_return; + } memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); ab->_hpp->cache_line_size = nui[0]; @@ -1387,7 +1391,7 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl) { - struct pci_func *func; + struct pci_func *func, new_func; int busn = ctrl->bus; int devn, funn; u32 vid; @@ -1402,11 +1406,19 @@ if (vid != 0xFFFFFFFF) { func = shpchp_slot_find(busn, devn, funn); - if (!func) - continue; - configure_existing_function(ctrl, func); + if (!func) { + memset(&new_func, 0, sizeof(struct pci_func)); + new_func.bus = busn; + new_func.device = devn; + new_func.function = funn; + new_func.is_a_board = 1; + configure_existing_function(ctrl, &new_func); + shpchprm_dump_func_res(&new_func); + } else { + configure_existing_function(ctrl, func); + shpchprm_dump_func_res(func); + } dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - shpchprm_dump_func_res(func); } } } diff -urN linux-2.4.27/drivers/hotplug/shpchprm_nonacpi.c linux-2.4.28/drivers/hotplug/shpchprm_nonacpi.c --- linux-2.4.27/drivers/hotplug/shpchprm_nonacpi.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/hotplug/shpchprm_nonacpi.c 2004-11-17 03:54:21.281384860 -0800 @@ -213,7 +213,7 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl) { - struct pci_func *func; + struct pci_func *func, new_func; int busn = ctrl->slot_bus; int devn, funn; u32 vid; @@ -230,11 +230,19 @@ if (vid != 0xFFFFFFFF) { func = shpchp_slot_find(busn, devn, funn); - if (!func) - continue; - configure_existing_function(ctrl, func); + if (!func) { + memset(&new_func, 0, sizeof(struct pci_func)); + new_func.bus = busn; + new_func.device = devn; + new_func.function = funn; + new_func.is_a_board = 1; + configure_existing_function(ctrl, &new_func); + phprm_dump_func_res(&new_func); + } else { + configure_existing_function(ctrl, func); + phprm_dump_func_res(func); + } dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - phprm_dump_func_res(func); } } } diff -urN linux-2.4.27/drivers/ide/Config.in linux-2.4.28/drivers/ide/Config.in --- linux-2.4.27/drivers/ide/Config.in 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/ide/Config.in 2004-11-17 03:54:21.281384860 -0800 @@ -12,11 +12,13 @@ dep_bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86 define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE + dep_mbool ' Support for SATA (deprecated; conflicts with libata SATA driver)' CONFIG_BLK_DEV_IDE_SATA $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK dep_mbool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK dep_tristate ' PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA + dep_tristate ' Cardbus IDE support (Delkin/ASKA/Workbit)' CONFIG_BLK_DEV_DELKIN $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA $CONFIG_PCI dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE diff -urN linux-2.4.27/drivers/ide/pci/Makefile linux-2.4.28/drivers/ide/pci/Makefile --- linux-2.4.27/drivers/ide/pci/Makefile 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/Makefile 2004-11-17 03:54:21.282384901 -0800 @@ -34,6 +34,7 @@ obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o # Must appear at the end of the block obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o diff -urN linux-2.4.27/drivers/ide/pci/amd74xx.c linux-2.4.28/drivers/ide/pci/amd74xx.c --- linux-2.4.27/drivers/ide/pci/amd74xx.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/amd74xx.c 2004-11-17 03:54:21.283384942 -0800 @@ -70,11 +70,7 @@ { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, 0x50, AMD_UDMA_133 }, { 0 } }; @@ -466,17 +462,17 @@ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { 0, }, }; diff -urN linux-2.4.27/drivers/ide/pci/amd74xx.h linux-2.4.28/drivers/ide/pci/amd74xx.h --- linux-2.4.27/drivers/ide/pci/amd74xx.h 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/amd74xx.h 2004-11-17 03:54:21.283384942 -0800 @@ -188,28 +188,6 @@ }, { /* 14 */ .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, - .name = "NFORCE-CK804-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 15 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, - .name = "NFORCE-CK804-SATA2", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 16 */ - .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, .name = "NFORCE-MCP04", .init_chipset = init_chipset_amd74xx, @@ -219,28 +197,6 @@ .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, .bootable = ON_BOARD, }, - { /* 17 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, - .name = "NFORCE-MCP04-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 18 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, - .name = "NFORCE-MCP04-SATA2", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, { .vendor = 0, .device = 0, diff -urN linux-2.4.27/drivers/ide/pci/delkin_cb.c linux-2.4.28/drivers/ide/pci/delkin_cb.c --- linux-2.4.27/drivers/ide/pci/delkin_cb.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/ide/pci/delkin_cb.c 2004-11-17 03:54:21.284384984 -0800 @@ -0,0 +1,149 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 25 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_init_hwif_ports(&hw, (ide_ioreg_t)(base + 0x10), + (ide_ioreg_t)(base + 0x1e), NULL); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw(&hw, &hwif); + if (rc < 0) /* ide_register_hw likes to be invoked twice (buggy) */ + rc = ide_register_hw(&hw, &hwif); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + MOD_INC_USE_COUNT; + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->id->csfo = 0; /* workaround for idedisk_open bug */ + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) { + ide_unregister(hwif->index); + MOD_DEC_USE_COUNT; + } + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_WORKBIT, PCI_DEVICE_ID_WORKBIT_CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin/ASKA/Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + +EXPORT_NO_SYMBOLS; + diff -urN linux-2.4.27/drivers/ide/pci/piix.c linux-2.4.28/drivers/ide/pci/piix.c --- linux-2.4.27/drivers/ide/pci/piix.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/piix.c 2004-11-17 03:54:21.285385025 -0800 @@ -49,9 +49,9 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); + * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54); * * Documentation * Publically available from Intel web site. Errata documentation @@ -433,15 +433,14 @@ int w_flag = 0x10 << drive->dn; int u_speed = 0; int sitre; - u16 reg4042, reg44, reg48, reg4a, reg54; - u8 reg55; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { @@ -463,30 +462,26 @@ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); + pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed == XFER_UDMA_5) { pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); } else { pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if (!(reg4a & u_speed)) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) { - pci_write_config_word(dev, 0x54, reg54|v_flag); - } - } else { - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); - } + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { if (reg48 & u_flag) - pci_write_config_word(dev, 0x48, reg48 & ~u_flag); + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); if (reg54 & v_flag) - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); if (reg55 & w_flag) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } @@ -566,40 +561,40 @@ drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - /* Consult the list of known "bad" drives */ - if (hwif->ide_dma_bad_drive(drive)) - goto fast_ata_pio; - if (id->field_valid & 4) { - if (id->dma_ultra & hwif->ultra_mask) { - /* Force if Capable UltraDMA */ - if ((id->field_valid & 2) && - (!piix_config_drive_for_dma(drive))) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & hwif->mwdma_mask) || - (id->dma_1word & hwif->swdma_mask)) { - /* Force if Capable regular DMA modes */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; + if ((id->capability & 1) && (drive->autodma)) { + + /* Consult the list of known "bad" drives. */ + if (hwif->ide_dma_bad_drive(drive)) { + goto fast_ata_pio; + } + + /** + * Try to turn DMA on if: + * - UDMA or EIDE modes are supported or + * - drive is a known "good" drive + * + * Checks for best mode supported are down later by + * piix_config_drive_for_dma() -> ide_dma_speed() + */ + if ((id->field_valid & (4 | 2)) || + (hwif->ide_dma_good_drive(drive) && (id->eide_dma_time < 150))) { + if (piix_config_drive_for_dma(drive)) { + return hwif->ide_dma_on(drive); } - } else if (hwif->ide_dma_good_drive(drive) && - (id->eide_dma_time < 150)) { - /* Consult the list of known "good" drives */ - if (!piix_config_drive_for_dma(drive)) - goto no_dma_set; - } else { - goto fast_ata_pio; } - return hwif->ide_dma_on(drive); + + /* For some reason DMA wasn't turned on, so try PIO. */ + goto fast_ata_pio; + } else if ((id->capability & 8) || (id->field_valid & 2)) { + + /* Find best PIO mode. */ fast_ata_pio: -no_dma_set: hwif->tuneproc(drive, 255); return hwif->ide_dma_off_quietly(drive); + } + /* IORDY not supported */ return 0; } @@ -882,7 +877,9 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, +#endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, { 0, }, diff -urN linux-2.4.27/drivers/ide/pci/sc1200.c linux-2.4.28/drivers/ide/pci/sc1200.c --- linux-2.4.27/drivers/ide/pci/sc1200.c 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/sc1200.c 2004-11-17 03:54:21.286385066 -0800 @@ -418,7 +418,7 @@ ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL); if (ss == NULL) return -ENOMEM; - (sc1200_saved_state_t *)hwif->config_data = ss; + hwif->config_data = (unsigned long)ss; } ss = (sc1200_saved_state_t *)hwif->config_data; // diff -urN linux-2.4.27/drivers/ide/pci/siimage.c linux-2.4.28/drivers/ide/pci/siimage.c --- linux-2.4.27/drivers/ide/pci/siimage.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/siimage.c 2004-11-17 03:54:21.287385107 -0800 @@ -1194,8 +1194,10 @@ static struct pci_device_id siimage_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif { 0, }, }; diff -urN linux-2.4.27/drivers/ide/pci/triflex.c linux-2.4.28/drivers/ide/pci/triflex.c --- linux-2.4.27/drivers/ide/pci/triflex.c 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/triflex.c 2004-11-17 03:54:21.289385189 -0800 @@ -44,15 +44,17 @@ #include "ide_modes.h" #include "triflex.h" -static struct pci_dev *triflex_dev; +#ifdef CONFIG_PROC_FS +static u8 triflex_proc; -static int triflex_get_info(char *buf, char **addr, off_t offset, int count) -{ - char *p = buf; - int len; +#define TRIFLEX_MAX_DEVS 2 +static struct pci_dev *triflex_devs[TRIFLEX_MAX_DEVS]; +static unsigned int n_triflex_devs; - struct pci_dev *dev = triflex_dev; +static int triflex_info(char *buffer, struct pci_dev *dev) +{ unsigned long bibma = pci_resource_start(dev, 4); + char *p = buffer; u8 c0 = 0, c1 = 0; u32 pri_timing, sec_timing; @@ -87,11 +89,23 @@ p += sprintf(p, "DMA\n"); p += sprintf(p, "PIO\n"); + return p - buffer; +} + +static int triflex_get_info(char *buf, char **addr, off_t offset, int count) +{ + char *p = buf; + unsigned int i, len; + + for (i = 0; i < n_triflex_devs; i++) + buf += triflex_info(buf, triflex_devs[i]); + len = (p - buf) - offset; *addr = buf + offset; - + return len > count ? count : len; } +#endif static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) { @@ -211,9 +225,13 @@ const char *name) { #ifdef CONFIG_PROC_FS - ide_pci_register_host_proc(&triflex_proc); + triflex_devs[n_triflex_devs++] = dev; + if (!triflex_proc) { + triflex_proc = 1; + ide_pci_register_host_proc(&triflex_procs); + } #endif - return 0; + return 0; } static int __devinit triflex_init_one(struct pci_dev *dev, @@ -222,11 +240,10 @@ ide_pci_device_t *d = &triflex_devices[id->driver_data]; if (dev->device != d->device) BUG(); - + ide_setup_pci_device(dev, d); - triflex_dev = dev; MOD_INC_USE_COUNT; - + return 0; } diff -urN linux-2.4.27/drivers/ide/pci/triflex.h linux-2.4.28/drivers/ide/pci/triflex.h --- linux-2.4.27/drivers/ide/pci/triflex.h 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.28/drivers/ide/pci/triflex.h 2004-11-17 03:54:21.289385189 -0800 @@ -14,7 +14,6 @@ static unsigned int __devinit init_chipset_triflex(struct pci_dev *, const char *); static void init_hwif_triflex(ide_hwif_t *); -static int triflex_get_info(char *, char **, off_t, int); static ide_pci_device_t triflex_devices[] __devinitdata = { { @@ -34,7 +33,9 @@ }; #ifdef CONFIG_PROC_FS -static ide_pci_host_proc_t triflex_proc __initdata = { +static int triflex_get_info(char *, char **, off_t, int); + +static ide_pci_host_proc_t triflex_procs __initdata = { .name = "triflex", .set = 1, .get_info = triflex_get_info, diff -urN linux-2.4.27/drivers/ieee1394/eth1394.c linux-2.4.28/drivers/ieee1394/eth1394.c --- linux-2.4.27/drivers/ieee1394/eth1394.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/ieee1394/eth1394.c 2004-11-17 03:54:21.290385230 -0800 @@ -149,6 +149,20 @@ "(default = 25)."); static int max_partial_datagrams = 25; +static inline void purge_partial_datagram(struct list_head *old) +{ + struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); + struct list_head *lh, *n; + + list_for_each_safe(lh, n, &pd->frag_info) { + struct fragment_info *fi = list_entry(lh, struct fragment_info, list); + list_del(lh); + kfree(fi); + } + list_del(old); + kfree_skb(pd->skb); + kfree(pd); +} static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, @@ -885,21 +899,6 @@ return 0; } -static inline void purge_partial_datagram(struct list_head *old) -{ - struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); - struct list_head *lh, *n; - - list_for_each_safe(lh, n, &pd->frag_info) { - struct fragment_info *fi = list_entry(lh, struct fragment_info, list); - list_del(lh); - kfree(fi); - } - list_del(old); - kfree_skb(pd->skb); - kfree(pd); -} - static inline int is_datagram_complete(struct list_head *lh, int dg_size) { struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); diff -urN linux-2.4.27/drivers/isdn/divert/divert_procfs.c linux-2.4.28/drivers/isdn/divert/divert_procfs.c --- linux-2.4.27/drivers/isdn/divert/divert_procfs.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/isdn/divert/divert_procfs.c 2004-11-17 03:54:21.291385271 -0800 @@ -92,7 +92,7 @@ return (0); inf->usage_cnt--; /* new usage count */ - (struct divert_info **) file->private_data = &inf->next; /* next structure */ + file->private_data = &inf->next; /* next structure */ if ((len = strlen(inf->info_start)) <= count) { if (copy_to_user(buf, inf->info_start, len)) return -EFAULT; @@ -141,9 +141,9 @@ cli(); if_used++; if (divert_info_head) - (struct divert_info **) filep->private_data = &(divert_info_tail->next); + filep->private_data = &(divert_info_tail->next); else - (struct divert_info **) filep->private_data = &divert_info_head; + filep->private_data = &divert_info_head; restore_flags(flags); /* start_divert(); */ unlock_kernel(); diff -urN linux-2.4.27/drivers/isdn/eicon/eicon_idi.c linux-2.4.28/drivers/isdn/eicon/eicon_idi.c --- linux-2.4.27/drivers/isdn/eicon/eicon_idi.c 2001-12-21 09:41:54.000000000 -0800 +++ linux-2.4.28/drivers/isdn/eicon/eicon_idi.c 2004-11-17 03:54:21.293385354 -0800 @@ -2054,7 +2054,8 @@ OutBuf.Len++; } else { *OutBuf.Next++ = 0; - *((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len; + *(__u16 *) OutBuf.Next = (__u16) LineBuf.Len; + OutBuf.Next += sizeof(__u16); OutBuf.Len += 3; } memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len); diff -urN linux-2.4.27/drivers/isdn/hisax/avm_pci.c linux-2.4.28/drivers/isdn/hisax/avm_pci.c --- linux-2.4.27/drivers/isdn/hisax/avm_pci.c 2002-11-28 15:53:13.000000000 -0800 +++ linux-2.4.28/drivers/isdn/hisax/avm_pci.c 2004-11-17 03:54:21.294385395 -0800 @@ -291,7 +291,8 @@ debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); return; } - ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; + p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; + ptr = (u_int *)p; bcs->hw.hdlc.rcvidx += count; if (cs->subtyp == AVM_FRITZ_PCI) { outl(idx, cs->hw.avm.cfg_reg + 4); @@ -352,7 +353,8 @@ } if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len); - ptr = (u_int *) p = bcs->tx_skb->data; + p = bcs->tx_skb->data; + ptr = (u_int *)p; skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.hdlc.count += count; diff -urN linux-2.4.27/drivers/isdn/hisax/callc.c linux-2.4.28/drivers/isdn/hisax/callc.c --- linux-2.4.27/drivers/isdn/hisax/callc.c 2001-12-21 09:41:54.000000000 -0800 +++ linux-2.4.28/drivers/isdn/hisax/callc.c 2004-11-17 03:54:21.295385436 -0800 @@ -925,7 +925,7 @@ ic.driver = cs->myid; ic.command = ISDN_STAT_REDIR; ic.arg = chan; - (ulong)(ic.parm.num[0]) = result; + ic.parm.num[0] = result; cs->iif.statcallb(&ic); } /* stat_redir_result */ diff -urN linux-2.4.27/drivers/isdn/hisax/hfc_pci.c linux-2.4.28/drivers/isdn/hisax/hfc_pci.c --- linux-2.4.27/drivers/isdn/hisax/hfc_pci.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/isdn/hisax/hfc_pci.c 2004-11-17 03:54:21.297385518 -0800 @@ -1746,7 +1746,7 @@ printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); return 0; } - (ulong) cs->hw.hfcpci.fifos = + cs->hw.hfcpci.fifos = (void *) (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; pcibios_write_config_dword(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, 0x80, diff -urN linux-2.4.27/drivers/isdn/hisax/isar.c linux-2.4.28/drivers/isdn/hisax/isar.c --- linux-2.4.27/drivers/isdn/hisax/isar.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/isdn/hisax/isar.c 2004-11-17 03:54:21.298385559 -0800 @@ -428,6 +428,21 @@ return(ret); } +static inline void +ll_deliver_faxstat(struct BCState *bcs, u_char status) +{ + isdn_ctrl ic; + struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; + + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "HL->LL FAXIND %x", status); + ic.driver = bcs->cs->myid; + ic.command = ISDN_STAT_FAXIND; + ic.arg = chanp->chan; + ic.parm.aux.cmd = status; + bcs->cs->iif.statcallb(&ic); +} + extern void BChannel_bh(struct BCState *); #define B_LL_NOCARRIER 8 #define B_LL_CONNECT 9 @@ -962,21 +977,6 @@ } } -static inline void -ll_deliver_faxstat(struct BCState *bcs, u_char status) -{ - isdn_ctrl ic; - struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "HL->LL FAXIND %x", status); - ic.driver = bcs->cs->myid; - ic.command = ISDN_STAT_FAXIND; - ic.arg = chanp->chan; - ic.parm.aux.cmd = status; - bcs->cs->iif.statcallb(&ic); -} - static void isar_pump_statev_fax(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; diff -urN linux-2.4.27/drivers/isdn/hisax/st5481.h linux-2.4.28/drivers/isdn/hisax/st5481.h --- linux-2.4.27/drivers/isdn/hisax/st5481.h 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/isdn/hisax/st5481.h 2004-11-17 03:54:21.299385600 -0800 @@ -219,13 +219,13 @@ #define L1_EVENT_COUNT (EV_TIMER3 + 1) #define ERR(format, arg...) \ -printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) #define WARN(format, arg...) \ -printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) #define INFO(format, arg...) \ -printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) #include "isdnhdlc.h" #include "fsm.h" diff -urN linux-2.4.27/drivers/isdn/hysdn/hysdn_procconf.c linux-2.4.28/drivers/isdn/hysdn/hysdn_procconf.c --- linux-2.4.27/drivers/isdn/hysdn/hysdn_procconf.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/isdn/hysdn/hysdn_procconf.c 2004-11-17 03:54:21.299385600 -0800 @@ -219,20 +219,25 @@ if (off != &file->f_pos) /* fs error check */ return -ESPIPE; + if (!(file->f_mode & FMODE_READ)) + return -EPERM; + if (!(cp = file->private_data)) return (-EFAULT); /* should never happen */ + i = strlen(cp); /* get total string length */ - if (pos == (unsigned)pos && pos < i) { - /* still bytes to transfer */ - cp += pos; /* point to desired data offset */ - i -= pos; /* remaining length */ - if (i > count) - i = count; /* limit length to transfer */ - if (copy_to_user(buf, cp, i)) - return (-EFAULT); /* copy error */ - *off = pos + i; /* adjust offset */ - } else - return (0); + + if (pos != (unsigned)pos || pos >= i) + return 0; + + /* still bytes to transfer */ + cp += pos; /* point to desired data offset */ + i -= pos; /* remaining length */ + if (i > count) + i = count; /* limit length to transfer */ + if (copy_to_user(buf, cp, i)) + return (-EFAULT); /* copy error */ + *off = pos + i; /* adjust offset */ return (i); } /* hysdn_conf_read */ diff -urN linux-2.4.27/drivers/isdn/hysdn/hysdn_proclog.c linux-2.4.28/drivers/isdn/hysdn/hysdn_proclog.c --- linux-2.4.27/drivers/isdn/hysdn/hysdn_proclog.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/isdn/hysdn/hysdn_proclog.c 2004-11-17 03:54:21.300385641 -0800 @@ -235,7 +235,7 @@ return (0); inf->usage_cnt--; /* new usage count */ - (struct log_data **) file->private_data = &inf->next; /* next structure */ + file->private_data = &inf->next; /* next structure */ if ((len = strlen(inf->log_start)) <= count) { if (copy_to_user(buf, inf->log_start, len)) return -EFAULT; @@ -278,9 +278,9 @@ cli(); pd->if_used++; if (pd->log_head) - (struct log_data **) filep->private_data = &(pd->log_tail->next); + filep->private_data = &(pd->log_tail->next); else - (struct log_data **) filep->private_data = &(pd->log_head); + filep->private_data = &(pd->log_head); restore_flags(flags); } else { /* simultaneous read/write access forbidden ! */ unlock_kernel(); diff -urN linux-2.4.27/drivers/isdn/pcbit/callbacks.c linux-2.4.28/drivers/isdn/pcbit/callbacks.c --- linux-2.4.27/drivers/isdn/pcbit/callbacks.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/callbacks.c 2004-11-17 03:54:21.301385682 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/callbacks.h linux-2.4.28/drivers/isdn/pcbit/callbacks.h --- linux-2.4.27/drivers/isdn/pcbit/callbacks.h 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/callbacks.h 2004-11-17 03:54:21.301385682 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/capi.c linux-2.4.28/drivers/isdn/pcbit/capi.c --- linux-2.4.27/drivers/isdn/pcbit/capi.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/capi.c 2004-11-17 03:54:21.302385724 -0800 @@ -4,7 +4,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/capi.h linux-2.4.28/drivers/isdn/pcbit/capi.h --- linux-2.4.27/drivers/isdn/pcbit/capi.h 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/capi.h 2004-11-17 03:54:21.302385724 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/drv.c linux-2.4.28/drivers/isdn/pcbit/drv.c --- linux-2.4.27/drivers/isdn/pcbit/drv.c 2002-11-28 15:53:13.000000000 -0800 +++ linux-2.4.28/drivers/isdn/pcbit/drv.c 2004-11-17 03:54:21.303385765 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/edss1.c linux-2.4.28/drivers/isdn/pcbit/edss1.c --- linux-2.4.27/drivers/isdn/pcbit/edss1.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/edss1.c 2004-11-17 03:54:21.348387615 -0800 @@ -4,7 +4,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/edss1.h linux-2.4.28/drivers/isdn/pcbit/edss1.h --- linux-2.4.27/drivers/isdn/pcbit/edss1.h 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/edss1.h 2004-11-17 03:54:21.348387615 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/layer2.c linux-2.4.28/drivers/isdn/pcbit/layer2.c --- linux-2.4.27/drivers/isdn/pcbit/layer2.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/layer2.c 2004-11-17 03:54:21.349387656 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/layer2.h linux-2.4.28/drivers/isdn/pcbit/layer2.h --- linux-2.4.27/drivers/isdn/pcbit/layer2.h 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/layer2.h 2004-11-17 03:54:21.350387697 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/module.c linux-2.4.28/drivers/isdn/pcbit/module.c --- linux-2.4.27/drivers/isdn/pcbit/module.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/module.c 2004-11-17 03:54:21.351387738 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/isdn/pcbit/pcbit.h linux-2.4.28/drivers/isdn/pcbit/pcbit.h --- linux-2.4.27/drivers/isdn/pcbit/pcbit.h 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/isdn/pcbit/pcbit.h 2004-11-17 03:54:21.351387738 -0800 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -urN linux-2.4.27/drivers/md/lvm.c linux-2.4.28/drivers/md/lvm.c --- linux-2.4.27/drivers/md/lvm.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/md/lvm.c 2004-11-17 03:54:21.353387821 -0800 @@ -2689,6 +2689,10 @@ (&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; + if (copy_to_user + (&lv_status_byname_req.lv->lv_block_exception, + &saved_ptr2, sizeof(void *)) != 0) + return -EFAULT; return 0; } } @@ -2743,6 +2747,10 @@ (&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; + if (copy_to_user + (&lv_status_byindex_req.lv->lv_block_exception, &saved_ptr2, + sizeof(void *)) != 0) + return -EFAULT; return 0; } /* lvm_do_lv_status_byindex() */ @@ -2801,6 +2809,10 @@ (&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; + if (copy_to_user + (&lv_status_bydev_req.lv->lv_block_exception, &saved_ptr2, + sizeof(void *)) != 0) + return -EFAULT; return 0; } /* lvm_do_lv_status_bydev() */ diff -urN linux-2.4.27/drivers/md/raid1.c linux-2.4.28/drivers/md/raid1.c --- linux-2.4.27/drivers/md/raid1.c 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/md/raid1.c 2004-11-17 03:54:21.355387903 -0800 @@ -325,18 +325,22 @@ { raid1_conf_t *conf = mddev_to_conf(mddev); int i, disks = MD_SB_DISKS; + unsigned long flags; /* * Later we do read balancing on the read side * now we use the first available disk. */ + md_spin_lock_irqsave(&conf->device_lock, flags); for (i = 0; i < disks; i++) { if (conf->mirrors[i].operational) { *rdev = conf->mirrors[i].dev; + md_spin_unlock_irqrestore(&conf->device_lock, flags); return (0); } } + md_spin_unlock_irqrestore(&conf->device_lock, flags); printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n"); return (-1); @@ -592,6 +596,7 @@ int disks = MD_SB_DISKS; int i, sum_bhs = 0; struct mirror_info *mirror; + kdev_t dev; if (!buffer_locked(bh)) BUG(); @@ -635,13 +640,16 @@ /* * read balancing logic: */ + spin_lock_irq(&conf->device_lock); mirror = conf->mirrors + raid1_read_balance(conf, bh); + dev = mirror->dev; + spin_unlock_irq(&conf->device_lock); bh_req = &r1_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); bh_req->b_blocknr = bh->b_rsector; - bh_req->b_dev = mirror->dev; - bh_req->b_rdev = mirror->dev; + bh_req->b_dev = dev; + bh_req->b_rdev = dev; /* bh_req->b_rsector = bh->n_rsector; */ bh_req->b_end_io = raid1_end_request; bh_req->b_private = r1_bh; @@ -654,6 +662,7 @@ */ bhl = raid1_alloc_bh(conf, conf->raid_disks); + spin_lock_irq(&conf->device_lock); for (i = 0; i < disks; i++) { struct buffer_head *mbh; if (!conf->mirrors[i].operational) @@ -702,6 +711,7 @@ r1_bh->mirror_bh_list = mbh; sum_bhs++; } + spin_unlock_irq(&conf->device_lock); if (bhl) raid1_free_bh(conf,bhl); if (!sum_bhs) { /* Gag - all mirrors non-operational.. */ @@ -771,6 +781,8 @@ mark_disk_inactive(sb->disks+mirror->number); if (!mirror->write_only) sb->active_disks--; + else + sb->spare_disks--; sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; @@ -787,6 +799,7 @@ struct mirror_info * mirrors = conf->mirrors; int disks = MD_SB_DISKS; int i; + unsigned long flags; /* Find the drive. * If it is not operational, then we have already marked it as dead @@ -808,7 +821,9 @@ return 1; } + md_spin_lock_irqsave(&conf->device_lock, flags); mark_disk_bad(mddev, i); + md_spin_unlock_irqrestore(&conf->device_lock, flags); return 0; } @@ -876,7 +891,6 @@ mdp_disk_t *failed_desc, *spare_desc, *added_desc; mdk_rdev_t *spare_rdev, *failed_rdev; - print_raid1_conf(conf); switch (state) { case DISKOP_SPARE_ACTIVE: @@ -887,6 +901,10 @@ md_spin_lock_irq(&conf->device_lock); /* + * Need the conf lock when printing out state else we get BUG()s + */ + print_raid1_conf(conf); + /* * find the disk ... */ switch (state) { @@ -1136,12 +1154,12 @@ goto abort; } abort: + print_raid1_conf(conf); md_spin_unlock_irq(&conf->device_lock); if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE) /* should move to "END_REBUILD" when such exists */ raid1_shrink_buffers(conf); - print_raid1_conf(conf); return err; } @@ -1196,6 +1214,7 @@ conf = mddev_to_conf(mddev); bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ + spin_lock_irq(&conf->device_lock); for (i = 0; i < disks ; i++) { if (!conf->mirrors[i].operational) continue; @@ -1238,6 +1257,7 @@ sum_bhs++; } + spin_unlock_irq(&conf->device_lock); md_atomic_set(&r1_bh->remaining, sum_bhs); if (bhl) raid1_free_bh(conf, bhl); mbh = r1_bh->mirror_bh_list; @@ -1373,6 +1393,7 @@ int disk; int block_nr; int buffs; + kdev_t dev; if (!sector_nr) { /* we want enough buffers to hold twice the window of 128*/ @@ -1426,6 +1447,7 @@ * could dedicate one to rebuild and others to * service read requests .. */ + spin_lock_irq(&conf->device_lock); disk = conf->last_used; /* make sure disk is operational */ while (!conf->mirrors[disk].operational) { @@ -1437,6 +1459,8 @@ conf->last_used = disk; mirror = conf->mirrors+conf->last_used; + dev = mirror->dev; + spin_unlock_irq(&conf->device_lock); r1_bh = raid1_alloc_buf (conf); r1_bh->master_bh = NULL; @@ -1453,8 +1477,8 @@ } bh->b_size = bsize; bh->b_list = BUF_LOCKED; - bh->b_dev = mirror->dev; - bh->b_rdev = mirror->dev; + bh->b_dev = dev; + bh->b_rdev = dev; bh->b_state = (1<b_page) BUG(); diff -urN linux-2.4.27/drivers/media/radio/radio-maestro.c linux-2.4.28/drivers/media/radio/radio-maestro.c --- linux-2.4.27/drivers/media/radio/radio-maestro.c 2001-09-30 12:26:06.000000000 -0700 +++ linux-2.4.28/drivers/media/radio/radio-maestro.c 2004-11-17 03:54:21.356387944 -0800 @@ -307,30 +307,6 @@ video_unregister_device(&maestro_radio); } -int __init maestro_radio_init(void) -{ - register __u16 found=0; - struct pci_dev *pcidev = NULL; - if(!pci_present()) - return -ENODEV; - while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, - PCI_DEVICE_ID_ESS_ESS1968, - pcidev))) - found |= radio_install(pcidev); - while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, - PCI_DEVICE_ID_ESS_ESS1978, - pcidev))) - found |= radio_install(pcidev); - if(!found) { - printk(KERN_INFO "radio-maestro: no devices found.\n"); - return -ENODEV; - } - return 0; -} - -module_init(maestro_radio_init); -module_exit(maestro_radio_exit); - inline static __u16 radio_power_on(struct radio_device *dev) { register __u16 io=dev->io; @@ -378,3 +354,27 @@ return 0; } +int __init maestro_radio_init(void) +{ + register __u16 found=0; + struct pci_dev *pcidev = NULL; + if(!pci_present()) + return -ENODEV; + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1968, + pcidev))) + found |= radio_install(pcidev); + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1978, + pcidev))) + found |= radio_install(pcidev); + if(!found) { + printk(KERN_INFO "radio-maestro: no devices found.\n"); + return -ENODEV; + } + return 0; +} + +module_init(maestro_radio_init); +module_exit(maestro_radio_exit); + diff -urN linux-2.4.27/drivers/media/video/bttv-driver.c linux-2.4.28/drivers/media/video/bttv-driver.c --- linux-2.4.27/drivers/media/video/bttv-driver.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/media/video/bttv-driver.c 2004-11-17 03:54:21.359388067 -0800 @@ -558,7 +558,7 @@ .sram = -1, },{ /* PAL-N */ - .Fsc 35468950, + .Fsc = 35468950, .swidth = 768, .sheight = 576, .totalwidth = 1135, diff -urN linux-2.4.27/drivers/media/video/w9966.c linux-2.4.28/drivers/media/video/w9966.c --- linux-2.4.27/drivers/media/video/w9966.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/media/video/w9966.c 2004-11-17 03:54:21.360388108 -0800 @@ -691,6 +691,14 @@ udelay(W9966_I2C_UDELAY); } +// Get peripheral clock line +// Expects a claimed pdev. +static inline int w9966_i2c_getscl(struct w9966_dev* cam) +{ + const u8 pins = w9966_rreg(cam, 0x18); + return ((pins & W9966_I2C_R_CLOCK) > 0); +} + // Sets the clock line on the i2c bus. // Expects a claimed pdev. // 1 on success, else 0 @@ -723,14 +731,6 @@ return ((pins & W9966_I2C_R_DATA) > 0); } -// Get peripheral clock line -// Expects a claimed pdev. -static inline int w9966_i2c_getscl(struct w9966_dev* cam) -{ - const u8 pins = w9966_rreg(cam, 0x18); - return ((pins & W9966_I2C_R_CLOCK) > 0); -} - // Write a byte with ack to the i2c bus. // Expects a claimed pdev. // 1 on success, else 0 diff -urN linux-2.4.27/drivers/message/i2o/i2o_lan.c linux-2.4.28/drivers/message/i2o/i2o_lan.c --- linux-2.4.27/drivers/message/i2o/i2o_lan.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/message/i2o/i2o_lan.c 2004-11-17 03:54:21.362388191 -0800 @@ -1043,13 +1043,13 @@ printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name); else { dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.tx_packets = val64[0]; - priv->stats.tx_bytes = val64[1]; - priv->stats.rx_packets = val64[2]; - priv->stats.rx_bytes = val64[3]; - priv->stats.tx_errors = val64[4]; - priv->stats.rx_errors = val64[5]; - priv->stats.rx_dropped = val64[6]; + priv->stats.gen.tx_packets = val64[0]; + priv->stats.gen.tx_bytes = val64[1]; + priv->stats.gen.rx_packets = val64[2]; + priv->stats.gen.rx_bytes = val64[3]; + priv->stats.gen.tx_errors = val64[4]; + priv->stats.gen.rx_errors = val64[5]; + priv->stats.gen.rx_dropped = val64[6]; } if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1, @@ -1062,9 +1062,9 @@ printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name); else { dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.multicast = val64[4]; - priv->stats.rx_length_errors = val64[10]; - priv->stats.rx_crc_errors = val64[0]; + priv->stats.gen.multicast = val64[4]; + priv->stats.gen.rx_length_errors = val64[10]; + priv->stats.gen.rx_crc_errors = val64[0]; } } @@ -1075,9 +1075,9 @@ printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name); else { dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name); - priv->stats.transmit_collision = val64[1] + val64[2]; - priv->stats.rx_frame_errors = val64[0]; - priv->stats.tx_carrier_errors = val64[6]; + priv->stats.gen.collisions = val64[1] + val64[2]; + priv->stats.gen.rx_frame_errors = val64[0]; + priv->stats.gen.tx_carrier_errors = val64[6]; } if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1, @@ -1091,9 +1091,11 @@ else { dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name); if (supported_stats & 0x1) - priv->stats.rx_over_errors = val64[0]; + priv->stats.gen.rx_over_errors = + val64[0]; if (supported_stats & 0x4) - priv->stats.tx_heartbeat_errors = val64[2]; + priv->stats.gen.tx_heartbeat_errors = + val64[2]; } } } diff -urN linux-2.4.27/drivers/message/i2o/i2o_pci.c linux-2.4.28/drivers/message/i2o/i2o_pci.c --- linux-2.4.27/drivers/message/i2o/i2o_pci.c 2002-11-28 15:53:13.000000000 -0800 +++ linux-2.4.28/drivers/message/i2o/i2o_pci.c 2004-11-17 03:54:21.362388191 -0800 @@ -390,4 +390,3 @@ MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); module_init(i2o_pci_core_attach); module_exit(i2o_pci_core_detach); - \ No newline at end of file diff -urN linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0001.c --- linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-17 03:54:21.363388232 -0800 @@ -1201,13 +1201,17 @@ /* Write data */ for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { - map->write8 (map, *((__u8*)buf)++, adr+z); + map->write8 (map, *(__u8*)buf, adr+z); + buf += sizeof(__u8); } else if (cfi_buswidth_is_2()) { - map->write16 (map, *((__u16*)buf)++, adr+z); + map->write16 (map, *(__u16*)buf, adr+z); + buf += sizeof(__u16); } else if (cfi_buswidth_is_4()) { - map->write32 (map, *((__u32*)buf)++, adr+z); + map->write32 (map, *(__u32*)buf, adr+z); + buf += sizeof(__u32); } else if (cfi_buswidth_is_8()) { - map->write64 (map, *((__u64*)buf)++, adr+z); + map->write64 (map, *(__u64*)buf, adr+z); + buf += sizeof(__u64); } else { DISABLE_VPP(map); ret = -EINVAL; diff -urN linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0002.c --- linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-17 03:54:21.365388314 -0800 @@ -461,7 +461,6 @@ unsigned int dq6, dq5; struct cfi_private *cfi = map->fldrv_priv; DECLARE_WAITQUEUE(wait, current); - int ret = 0; retry: cfi_spin_lock(chip->mutex); @@ -554,7 +553,7 @@ wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); DISABLE_VPP(map); - ret = -EIO; + return -EIO; } } @@ -563,7 +562,7 @@ wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); - return ret; + return 0; } static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) diff -urN linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0020.c --- linux-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-17 03:54:21.366388355 -0800 @@ -540,11 +540,14 @@ /* Write data */ for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { - map->write8 (map, *((__u8*)buf)++, adr+z); + map->write8 (map, *(__u8*)buf, adr+z); + buf += sizeof(__u8); } else if (cfi_buswidth_is_2()) { - map->write16 (map, *((__u16*)buf)++, adr+z); + map->write16 (map, *(__u16*)buf, adr+z); + buf += sizeof(__u16); } else if (cfi_buswidth_is_4()) { - map->write32 (map, *((__u32*)buf)++, adr+z); + map->write32 (map, *(__u32*)buf, adr+z); + buf += sizeof(__u32); } else { DISABLE_VPP(map); return -EINVAL; diff -urN linux-2.4.27/drivers/mtd/devices/doc1000.c linux-2.4.28/drivers/mtd/devices/doc1000.c --- linux-2.4.27/drivers/mtd/devices/doc1000.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/devices/doc1000.c 2004-11-17 03:54:21.367388396 -0800 @@ -137,6 +137,119 @@ return 0; } +static inline int suspend_erase(volatile u_char *addr) +{ + __u16 status; + u_long i = 0; + + writew(IF_ERASE_SUSPEND, addr); + writew(IF_READ_CSR, addr); + + do { + status = readw(addr); + if ((status & CSR_WR_READY) == CSR_WR_READY) + return 0; + i++; + } while(i < max_tries); + + printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status); + return -EIO; + +} + +static inline void resume_erase(volatile u_char *addr) +{ + __u16 status; + + writew(IF_READ_CSR, addr); + status = readw(addr); + + /* Only give resume signal if the erase is really suspended */ + if (status & CSR_ERA_SUSPEND) + writew(IF_CONFIRM, addr); +} + +static inline int byte_write (volatile u_char *addr, u_char byte) +{ + register u_char status; + register u_short i = 0; + + do { + status = readb(addr); + if (status & CSR_WR_READY) + { + writeb(IF_WRITE & 0xff, addr); + writeb(byte, addr); + return 0; + } + i++; + } while(i < max_tries); + + + printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status); + return -EIO; +} + +static inline int word_write (volatile u_char *addr, __u16 word) +{ + register u_short status; + register u_short i = 0; + + do { + status = readw(addr); + if ((status & CSR_WR_READY) == CSR_WR_READY) + { + writew(IF_WRITE, addr); + writew(word, addr); + return 0; + } + i++; + } while(i < max_tries); + + printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status); + return -EIO; +} + +static inline void reset_block(volatile u_char *addr) +{ + u_short i; + __u16 status; + + writew(IF_CLEAR_CSR, addr); + + for (i = 0; i < 100; i++) { + writew(IF_READ_CSR, addr); + status = readw(addr); + if (status != 0xffff) break; + udelay(1000); + } + + writew(IF_READ_CSR, addr); +} + +static inline int check_write(volatile u_char *addr) +{ + u_short status, i = 0; + + writew(IF_READ_CSR, addr); + + do { + status = readw(addr); + if (status & (CSR_WR_ERR | CSR_VPP_LOW)) + { + printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status); + reset_block(addr); + return -EIO; + } + if ((status & CSR_WR_READY) == CSR_WR_READY) + return 0; + i++; + } while (i < max_tries); + + printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status); + return -EIO; +} + int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -281,47 +394,6 @@ /*====================================================================*/ -static inline int byte_write (volatile u_char *addr, u_char byte) -{ - register u_char status; - register u_short i = 0; - - do { - status = readb(addr); - if (status & CSR_WR_READY) - { - writeb(IF_WRITE & 0xff, addr); - writeb(byte, addr); - return 0; - } - i++; - } while(i < max_tries); - - - printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status); - return -EIO; -} - -static inline int word_write (volatile u_char *addr, __u16 word) -{ - register u_short status; - register u_short i = 0; - - do { - status = readw(addr); - if ((status & CSR_WR_READY) == CSR_WR_READY) - { - writew(IF_WRITE, addr); - writew(word, addr); - return 0; - } - i++; - } while(i < max_tries); - - printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status); - return -EIO; -} - static inline void block_erase (volatile u_char *addr) { writew(IF_BLOCK_ERASE, addr); @@ -350,79 +422,6 @@ return 0; } -static inline int suspend_erase(volatile u_char *addr) -{ - __u16 status; - u_long i = 0; - - writew(IF_ERASE_SUSPEND, addr); - writew(IF_READ_CSR, addr); - - do { - status = readw(addr); - if ((status & CSR_WR_READY) == CSR_WR_READY) - return 0; - i++; - } while(i < max_tries); - - printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status); - return -EIO; - -} - -static inline void resume_erase(volatile u_char *addr) -{ - __u16 status; - - writew(IF_READ_CSR, addr); - status = readw(addr); - - /* Only give resume signal if the erase is really suspended */ - if (status & CSR_ERA_SUSPEND) - writew(IF_CONFIRM, addr); -} - -static inline void reset_block(volatile u_char *addr) -{ - u_short i; - __u16 status; - - writew(IF_CLEAR_CSR, addr); - - for (i = 0; i < 100; i++) { - writew(IF_READ_CSR, addr); - status = readw(addr); - if (status != 0xffff) break; - udelay(1000); - } - - writew(IF_READ_CSR, addr); -} - -static inline int check_write(volatile u_char *addr) -{ - u_short status, i = 0; - - writew(IF_READ_CSR, addr); - - do { - status = readw(addr); - if (status & (CSR_WR_ERR | CSR_VPP_LOW)) - { - printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status); - reset_block(addr); - return -EIO; - } - if ((status & CSR_WR_READY) == CSR_WR_READY) - return 0; - i++; - } while (i < max_tries); - - printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status); - return -EIO; -} - - /*====================================================================*/ diff -urN linux-2.4.27/drivers/mtd/maps/amd76xrom.c linux-2.4.28/drivers/mtd/maps/amd76xrom.c --- linux-2.4.27/drivers/mtd/maps/amd76xrom.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/maps/amd76xrom.c 2004-11-17 03:54:21.367388396 -0800 @@ -178,7 +178,7 @@ iounmap((void *)(info->window_addr)); err_out_free_mmio_region: release_mem_region(window->start, window->size); -err_out_none: +//err_out_none: return -ENODEV; } diff -urN linux-2.4.27/drivers/mtd/maps/elan-104nc.c linux-2.4.28/drivers/mtd/maps/elan-104nc.c --- linux-2.4.27/drivers/mtd/maps/elan-104nc.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/mtd/maps/elan-104nc.c 2004-11-17 03:54:21.368388437 -0800 @@ -147,7 +147,7 @@ elan_104nc_page(map, from); memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); spin_unlock(&elan_104nc_spin); - (__u8*)to += thislen; + to += thislen; from += thislen; len -= thislen; } diff -urN linux-2.4.27/drivers/mtd/maps/sbc_gxx.c linux-2.4.28/drivers/mtd/maps/sbc_gxx.c --- linux-2.4.27/drivers/mtd/maps/sbc_gxx.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/mtd/maps/sbc_gxx.c 2004-11-17 03:54:21.368388437 -0800 @@ -155,7 +155,7 @@ sbc_gxx_page(map, from); memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); spin_unlock(&sbc_gxx_spin); - (__u8*)to += thislen; + to += thislen; from += thislen; len -= thislen; } diff -urN linux-2.4.27/drivers/net/8139too.c linux-2.4.28/drivers/net/8139too.c --- linux-2.4.27/drivers/net/8139too.c 2004-08-07 16:26:04.000000000 -0700 +++ linux-2.4.28/drivers/net/8139too.c 2004-11-17 03:54:21.370388519 -0800 @@ -614,7 +614,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location); static void mdio_write (struct net_device *dev, int phy_id, int location, int val); -static inline void rtl8139_start_thread(struct net_device *dev); +static void rtl8139_start_thread(struct net_device *dev); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, @@ -1626,7 +1626,7 @@ complete_and_exit (&tp->thr_exited, 0); } -static inline void rtl8139_start_thread(struct net_device *dev) +static void rtl8139_start_thread(struct net_device *dev) { struct rtl8139_private *tp = dev->priv; diff -urN linux-2.4.27/drivers/net/bonding/bond_main.c linux-2.4.28/drivers/net/bonding/bond_main.c --- linux-2.4.27/drivers/net/bonding/bond_main.c 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/net/bonding/bond_main.c 2004-11-17 03:54:21.373388643 -0800 @@ -3086,8 +3086,6 @@ #ifdef CONFIG_PROC_FS -#define SEQ_START_TOKEN ((void *)1) - static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) { struct bonding *bond = seq->private; diff -urN linux-2.4.27/drivers/net/defxx.c linux-2.4.28/drivers/net/defxx.c --- linux-2.4.27/drivers/net/defxx.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/defxx.c 2004-11-17 03:54:21.376388766 -0800 @@ -1809,16 +1809,18 @@ /* Fill the bp->stats structure with driver-maintained counters */ - bp->stats.rx_packets = bp->rcv_total_frames; - bp->stats.tx_packets = bp->xmt_total_frames; - bp->stats.rx_bytes = bp->rcv_total_bytes; - bp->stats.tx_bytes = bp->xmt_total_bytes; - bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors); - bp->stats.tx_errors = bp->xmt_length_errors; - bp->stats.rx_dropped = bp->rcv_discards; - bp->stats.tx_dropped = bp->xmt_discards; - bp->stats.multicast = bp->rcv_multicast_frames; - bp->stats.transmit_collision = 0; /* always zero (0) for FDDI */ + bp->stats.gen.rx_packets = bp->rcv_total_frames; + bp->stats.gen.tx_packets = bp->xmt_total_frames; + bp->stats.gen.rx_bytes = bp->rcv_total_bytes; + bp->stats.gen.tx_bytes = bp->xmt_total_bytes; + bp->stats.gen.rx_errors = bp->rcv_crc_errors + + bp->rcv_frame_status_errors + + bp->rcv_length_errors; + bp->stats.gen.tx_errors = bp->xmt_length_errors; + bp->stats.gen.rx_dropped = bp->rcv_discards; + bp->stats.gen.tx_dropped = bp->xmt_discards; + bp->stats.gen.multicast = bp->rcv_multicast_frames; + bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ /* Get FDDI SMT MIB objects */ diff -urN linux-2.4.27/drivers/net/dmfe.c linux-2.4.28/drivers/net/dmfe.c --- linux-2.4.27/drivers/net/dmfe.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/net/dmfe.c 2004-11-17 03:54:21.377388807 -0800 @@ -863,6 +863,20 @@ /* + * Calculate the CRC valude of the Rx packet + * flag = 1 : return the reverse CRC (for the received packet CRC) + * 0 : return the normal CRC (for Hash Table index) + */ + +static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) +{ + u32 crc = ether_crc_le(Len, Data); + if (flag) crc = ~crc; + return crc; +} + + +/* * Receive the come packet and pass to upper layer */ @@ -1753,20 +1767,6 @@ /* - * Calculate the CRC valude of the Rx packet - * flag = 1 : return the reverse CRC (for the received packet CRC) - * 0 : return the normal CRC (for Hash Table index) - */ - -static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) -{ - u32 crc = ether_crc_le(Len, Data); - if (flag) crc = ~crc; - return crc; -} - - -/* * Parser SROM and media mode */ diff -urN linux-2.4.27/drivers/net/e100/e100.h linux-2.4.28/drivers/net/e100/e100.h --- linux-2.4.27/drivers/net/e100/e100.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e100/e100.h 2004-11-17 03:54:21.379388890 -0800 @@ -501,7 +501,7 @@ u8 scb_fc_thld; /* Flow Control threshold */ u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ u8 scb_pmdr; /* Power Mgmt. Driver Reg */ -} d101_scb_ext __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) d101_scb_ext; /* Changed for 82559 enhancement */ typedef struct _d101m_scb_ext_t { @@ -517,7 +517,7 @@ u32 scb_function_event_mask; /* Cardbus Function Mask */ u32 scb_function_present_state; /* Cardbus Function state */ u32 scb_force_event; /* Cardbus Force Event */ -} d101m_scb_ext __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) d101m_scb_ext; /* Changed for 82550 enhancement */ typedef struct _d102_scb_ext_t { @@ -536,7 +536,7 @@ u32 scb_function_event_mask; /* Cardbus Function Mask */ u32 scb_function_present_state; /* Cardbus Function state */ u32 scb_force_event; /* Cardbus Force Event */ -} d102_scb_ext __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) d102_scb_ext; /* * 82557 status control block. this will be memory mapped & will hang of the @@ -558,7 +558,7 @@ d101m_scb_ext d101m_scb; /* 82559 specific fields */ d102_scb_ext d102_scb; } scb_ext; -} scb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) scb_t; /* Self test * This is used to dump results of the self test @@ -566,7 +566,7 @@ typedef struct _self_test_t { u32 st_sign; /* Self Test Signature */ u32 st_result; /* Self Test Results */ -} self_test_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) self_test_t; /* * Statistical Counters @@ -649,39 +649,39 @@ u16 cb_status; /* Command Block Status */ u16 cb_cmd; /* Command Block Command */ u32 cb_lnk_ptr; /* Link To Next CB */ -} cb_header_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) cb_header_t; //* Individual Address Command Block (IA_CB)*/ typedef struct _ia_cb_t { cb_header_t ia_cb_hdr; u8 ia_addr[ETH_ALEN]; -} ia_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) ia_cb_t; /* Configure Command Block (CONFIG_CB)*/ typedef struct _config_cb_t { cb_header_t cfg_cbhdr; u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; -} config_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) config_cb_t; /* MultiCast Command Block (MULTICAST_CB)*/ typedef struct _multicast_cb_t { cb_header_t mc_cbhdr; u16 mc_count; /* Number of multicast addresses */ u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)]; -} mltcst_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) mltcst_cb_t; #define UCODE_MAX_DWORDS 134 /* Load Microcode Command Block (LOAD_UCODE_CB)*/ typedef struct _load_ucode_cb_t { cb_header_t load_ucode_cbhdr; u32 ucode_dword[UCODE_MAX_DWORDS]; -} load_ucode_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) load_ucode_cb_t; /* Load Programmable Filter Data*/ typedef struct _filter_cb_t { cb_header_t filter_cb_hdr; u32 filter_data[MAX_FILTER]; -} filter_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) filter_cb_t; /* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block */ @@ -693,7 +693,7 @@ mltcst_cb_t multicast; filter_cb_t filter; } ntcb; -} nxmit_cb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) nxmit_cb_t; /*Block for queuing for postponed execution of the non-transmit commands*/ typedef struct _nxmit_cb_entry_t { @@ -724,7 +724,7 @@ u32 tbd_buf_addr; /* Physical Transmit Buffer Address */ u16 tbd_buf_cnt; /* Actual Count Of Bytes */ u16 padd; -} tbd_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) tbd_t; /* d102 specific fields */ typedef struct _tcb_ipcb_t { @@ -743,7 +743,7 @@ u16 tbd_zero_size; } tbd_sec_size; u16 total_tcp_payload; -} tcb_ipcb_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) tcb_ipcb_t; #define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS) @@ -806,7 +806,7 @@ u32 rbd_rcb_addr; /* Receive Buffer Address */ u16 rbd_sz; /* Receive Buffer Size */ u16 rbd_filler1; -} rbd_t __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) rbd_t; /* * This structure is used to maintain a FIFO access to a resource that is diff -urN linux-2.4.27/drivers/net/e100/e100_main.c linux-2.4.28/drivers/net/e100/e100_main.c --- linux-2.4.27/drivers/net/e100/e100_main.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e100/e100_main.c 2004-11-17 03:54:21.382389013 -0800 @@ -1073,6 +1073,116 @@ return 0; } +/** + * e100_prepare_xmit_buff - prepare a buffer for transmission + * @bdp: atapter's private data struct + * @skb: skb to send + * + * This routine prepare a buffer for transmission. It checks + * the message length for the appropiate size. It picks up a + * free tcb from the TCB pool and sets up the corresponding + * TBD's. If the number of fragments are more than the number + * of TBD/TCB it copies all the fragments in a coalesce buffer. + * It returns a pointer to the prepared TCB. + */ +static inline tcb_t * +e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) +{ + tcb_t *tcb, *prev_tcb; + + tcb = bdp->tcb_pool.data; + tcb += TCB_TO_USE(bdp->tcb_pool); + + if (bdp->flags & USE_IPCB) { + tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; + tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; + tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; + } + + if(bdp->vlgrp && vlan_tx_tag_present(skb)) { + (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; + (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); + } + + tcb->tcb_hdr.cb_status = 0; + tcb->tcb_thrshld = bdp->tx_thld; + tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); + + /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ + if (!(++bdp->tx_count % TX_FRAME_CNT)) + tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); + else + /* Clear I bit on other packets */ + tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); + + tcb->tcb_skb = skb; + + if (skb->ip_summed == CHECKSUM_HW) { + const struct iphdr *ip = skb->nh.iph; + + if ((ip->protocol == IPPROTO_TCP) || + (ip->protocol == IPPROTO_UDP)) { + + tcb->tcbu.ipcb.ip_activation_high |= + IPCB_HARDWAREPARSING_ENABLE; + tcb->tcbu.ipcb.ip_schedule |= + IPCB_TCPUDP_CHECKSUM_ENABLE; + + if (ip->protocol == IPPROTO_TCP) + tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; + } + } + + if (!skb_shinfo(skb)->nr_frags) { + (tcb->tbd_ptr)->tbd_buf_addr = + cpu_to_le32(pci_map_single(bdp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); + tcb->tcb_tbd_num = 1; + tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; + } else { + int i; + void *addr; + tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); + skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; + + (tcb->tbd_ptr)->tbd_buf_addr = + cpu_to_le32(pci_map_single(bdp->pdev, skb->data, + skb_headlen(skb), + PCI_DMA_TODEVICE)); + (tcb->tbd_ptr)->tbd_buf_cnt = + cpu_to_le16(skb_headlen(skb)); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; + i++, tbd_arr_ptr++, frag++) { + + addr = ((void *) page_address(frag->page) + + frag->page_offset); + + tbd_arr_ptr->tbd_buf_addr = + cpu_to_le32(pci_map_single(bdp->pdev, + addr, frag->size, + PCI_DMA_TODEVICE)); + tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); + } + tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; + tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; + } + + /* clear the S-BIT on the previous tcb */ + prev_tcb = bdp->tcb_pool.data; + prev_tcb += PREV_TCB_USED(bdp->tcb_pool); + prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); + + bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); + + wmb(); + + e100_start_cu(bdp, tcb); + + return tcb; +} + static int e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) { @@ -1605,6 +1715,32 @@ return 1; } +/** + * e100_tx_skb_free - free TX skbs resources + * @bdp: atapter's private data struct + * @tcb: associated tcb of the freed skb + * + * This routine frees resources of TX skbs. + */ +static inline void +e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) +{ + if (tcb->tcb_skb) { + int i; + tbd_t *tbd_arr = tcb->tbd_ptr; + int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; + + for (i = 0; i <= frags; i++, tbd_arr++) { + pci_unmap_single(bdp->pdev, + le32_to_cpu(tbd_arr->tbd_buf_addr), + le16_to_cpu(tbd_arr->tbd_buf_cnt), + PCI_DMA_TODEVICE); + } + dev_kfree_skb_irq(tcb->tcb_skb); + tcb->tcb_skb = NULL; + } +} + void e100_free_tcb_pool(struct e100_private *bdp) { @@ -1910,32 +2046,6 @@ } /** - * e100_tx_skb_free - free TX skbs resources - * @bdp: atapter's private data struct - * @tcb: associated tcb of the freed skb - * - * This routine frees resources of TX skbs. - */ -static inline void -e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) -{ - if (tcb->tcb_skb) { - int i; - tbd_t *tbd_arr = tcb->tbd_ptr; - int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; - - for (i = 0; i <= frags; i++, tbd_arr++) { - pci_unmap_single(bdp->pdev, - le32_to_cpu(tbd_arr->tbd_buf_addr), - le16_to_cpu(tbd_arr->tbd_buf_cnt), - PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(tcb->tcb_skb); - tcb->tcb_skb = NULL; - } -} - -/** * e100_tx_srv - service TX queues * @bdp: atapter's private data struct * @@ -2155,116 +2265,6 @@ } /* end underrun check */ } -/** - * e100_prepare_xmit_buff - prepare a buffer for transmission - * @bdp: atapter's private data struct - * @skb: skb to send - * - * This routine prepare a buffer for transmission. It checks - * the message length for the appropiate size. It picks up a - * free tcb from the TCB pool and sets up the corresponding - * TBD's. If the number of fragments are more than the number - * of TBD/TCB it copies all the fragments in a coalesce buffer. - * It returns a pointer to the prepared TCB. - */ -static inline tcb_t * -e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) -{ - tcb_t *tcb, *prev_tcb; - - tcb = bdp->tcb_pool.data; - tcb += TCB_TO_USE(bdp->tcb_pool); - - if (bdp->flags & USE_IPCB) { - tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; - } - - if(bdp->vlgrp && vlan_tx_tag_present(skb)) { - (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; - (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); - } - - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); - - /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ - if (!(++bdp->tx_count % TX_FRAME_CNT)) - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); - else - /* Clear I bit on other packets */ - tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); - - tcb->tcb_skb = skb; - - if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip = skb->nh.iph; - - if ((ip->protocol == IPPROTO_TCP) || - (ip->protocol == IPPROTO_UDP)) { - - tcb->tcbu.ipcb.ip_activation_high |= - IPCB_HARDWAREPARSING_ENABLE; - tcb->tcbu.ipcb.ip_schedule |= - IPCB_TCPUDP_CHECKSUM_ENABLE; - - if (ip->protocol == IPPROTO_TCP) - tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; - } - } - - if (!skb_shinfo(skb)->nr_frags) { - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); - tcb->tcb_tbd_num = 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; - } else { - int i; - void *addr; - tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); - skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; - - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb_headlen(skb), - PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = - cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; - i++, tbd_arr_ptr++, frag++) { - - addr = ((void *) page_address(frag->page) + - frag->page_offset); - - tbd_arr_ptr->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, - addr, frag->size, - PCI_DMA_TODEVICE)); - tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); - } - tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; - } - - /* clear the S-BIT on the previous tcb */ - prev_tcb = bdp->tcb_pool.data; - prev_tcb += PREV_TCB_USED(bdp->tcb_pool); - prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); - - bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); - - wmb(); - - e100_start_cu(bdp, tcb); - - return tcb; -} - /* Changed for 82558 enhancement */ /** * e100_start_cu - start the adapter's CU diff -urN linux-2.4.27/drivers/net/e1000/e1000.h linux-2.4.28/drivers/net/e1000/e1000.h --- linux-2.4.27/drivers/net/e1000/e1000.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000.h 2004-11-17 03:54:21.382389013 -0800 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,8 @@ #define PCI_DMA_64BIT 0xffffffffffffffffULL #define PCI_DMA_32BIT 0x00000000ffffffffULL +#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} struct e1000_adapter; @@ -99,11 +102,12 @@ #define E1000_MAX_INTR 10 -/* How many descriptors for TX and RX ? */ +/* TX/RX descriptor defines */ #define E1000_DEFAULT_TXD 256 #define E1000_MAX_TXD 256 #define E1000_MIN_TXD 80 #define E1000_MAX_82544_TXD 4096 + #define E1000_DEFAULT_RXD 256 #define E1000_MAX_RXD 256 #define E1000_MIN_RXD 80 @@ -124,14 +128,11 @@ #define E1000_TX_HEAD_ADDR_SHIFT 7 #define E1000_PBA_TX_MASK 0xFFFF0000 -/* Flow Control High-Watermark: 5688 bytes below Rx FIFO size */ -#define E1000_FC_HIGH_DIFF 0x1638 - -/* Flow Control Low-Watermark: 5696 bytes below Rx FIFO size */ -#define E1000_FC_LOW_DIFF 0x1640 +/* Flow Control Watermarks */ +#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ +#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -/* Flow Control Pause Time: 858 usec */ -#define E1000_FC_PAUSE_TIME 0x0680 +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -154,9 +155,9 @@ struct e1000_buffer { struct sk_buff *skb; uint64_t dma; - unsigned long length; unsigned long time_stamp; - unsigned int next_to_watch; + uint16_t length; + uint16_t next_to_watch; }; struct e1000_desc_ring { diff -urN linux-2.4.27/drivers/net/e1000/e1000_ethtool.c linux-2.4.28/drivers/net/e1000/e1000_ethtool.c --- linux-2.4.27/drivers/net/e1000/e1000_ethtool.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_ethtool.c 2004-11-17 03:54:21.385389136 -0800 @@ -88,13 +88,13 @@ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, - { "rx_long_byte_count", E1000_STAT(stats.gorcl) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) -static char e1000_gstrings_test[][ETH_GSTRING_LEN] = { +static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)" @@ -170,7 +170,8 @@ ecmd->duplex = -1; } - ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || + hw->autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; } @@ -192,6 +193,7 @@ if(netif_running(adapter->netdev)) { e1000_down(adapter); + e1000_reset(adapter); e1000_up(adapter); } else e1000_reset(adapter); @@ -199,12 +201,13 @@ return 0; } -static void +static void e1000_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; + pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); @@ -218,9 +221,9 @@ } } -static int +static int e1000_set_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -271,7 +274,7 @@ e1000_reset(adapter); return 0; } - + static uint32_t e1000_get_tx_csum(struct net_device *netdev) { @@ -337,7 +340,7 @@ static void e1000_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) + struct ethtool_regs *regs, void *p) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; @@ -418,6 +421,10 @@ e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ + if(hw->mac_type >= e1000_82540 && + hw->media_type == e1000_media_type_copper) { + regs_buff[26] = E1000_READ_REG(hw, MANC); + } } static int @@ -438,7 +445,7 @@ int ret_val = 0; uint16_t i; - if(eeprom->len == 0) + if(eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); @@ -446,9 +453,9 @@ first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(uint16_t) * + eeprom_buff = kmalloc(sizeof(uint16_t) * (last_word - first_word + 1), GFP_KERNEL); - if (!eeprom_buff) + if(!eeprom_buff) return -ENOMEM; if(hw->eeprom.type == e1000_eeprom_spi) @@ -466,9 +473,8 @@ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); - - memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset%2), - eeprom->len); + memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1), + eeprom->len); kfree(eeprom_buff); return ret_val; @@ -520,6 +526,7 @@ le16_to_cpus(&eeprom_buff[i]); memcpy(ptr, bytes, eeprom->len); + for (i = 0; i < last_word - first_word + 1; i++) eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); @@ -575,17 +582,16 @@ e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - int err; struct e1000_adapter *adapter = netdev->priv; e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_desc_ring *txdr = &adapter->tx_ring; struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new; - struct e1000_desc_ring rx_old, rx_new; + struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; + int err; tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; - + if(netif_running(adapter->netdev)) e1000_down(adapter); @@ -600,15 +606,15 @@ E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); if(netif_running(adapter->netdev)) { - /* try to get new resources before deleting old */ + /* Try to get new resources before deleting old */ if((err = e1000_setup_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_setup_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, - * then restore the new back again */ - + * then restore the new back again */ + rx_new = adapter->rx_ring; tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; @@ -620,6 +626,7 @@ if((err = e1000_up(adapter))) return err; } + return 0; err_setup_tx: e1000_free_rx_resources(adapter); @@ -630,7 +637,6 @@ return err; } - #define REG_PATTERN_TEST(R, M, W) \ { \ uint32_t pat, value; \ @@ -766,13 +772,15 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) { struct net_device *netdev = adapter->netdev; - uint32_t icr, mask, i=0; + uint32_t icr, mask, i=0, shared_int = TRUE; + uint32_t irq = adapter->pdev->irq; *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, - netdev->name, netdev)) { + if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { + shared_int = FALSE; + } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){ *data = 1; return -1; } @@ -802,20 +810,22 @@ /* Interrupt to test */ mask = 1 << i; - /* Disable the interrupt to be reported in - * the cause register and then force the same - * interrupt and see if one gets posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, mask); - E1000_WRITE_REG(&adapter->hw, ICS, mask); - msec_delay(10); - - if(adapter->test_icr & mask) { - *data = 3; - break; + if(!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(adapter->test_icr & mask) { + *data = 3; + break; + } } /* Enable the interrupt to be reported in @@ -834,20 +844,22 @@ break; } - /* Disable the other interrupts to be reported in - * the cause register and then force the other - * interrupts and see if any get posted. If - * an interrupt was posted to the bus, the - * test failed. - */ - adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, ~mask); - E1000_WRITE_REG(&adapter->hw, ICS, ~mask); - msec_delay(10); + if(!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, ~mask); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask); + msec_delay(10); - if(adapter->test_icr) { - *data = 5; - break; + if(adapter->test_icr) { + *data = 5; + break; + } } } @@ -856,7 +868,7 @@ msec_delay(10); /* Unhook test interrupt handler */ - free_irq(adapter->pdev->irq, netdev); + free_irq(irq, netdev); return *data; } @@ -1020,7 +1032,7 @@ return 0; - err_nomem: +err_nomem: e1000_free_desc_rings(adapter); return ret_val; } @@ -1356,7 +1368,7 @@ } static void -e1000_diag_test(struct net_device *netdev, +e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data) { struct e1000_adapter *adapter = netdev->priv; @@ -1367,7 +1379,7 @@ /* save speed, duplex, autoneg settings */ uint16_t autoneg_advertised = adapter->hw.autoneg_advertised; - uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; + uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; /* Link test performed before hardware reset so autoneg doesn't @@ -1395,10 +1407,11 @@ if(e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; - /* restore Autoneg/speed/duplex settings */ + /* restore speed, duplex, autoneg settings */ adapter->hw.autoneg_advertised = autoneg_advertised; - adapter->hw.forced_speed_duplex = forced_speed_duplex; - adapter->hw.autoneg = autoneg; + adapter->hw.forced_speed_duplex = forced_speed_duplex; + adapter->hw.autoneg = autoneg; + e1000_reset(adapter); if(if_running) e1000_up(adapter); @@ -1426,6 +1439,9 @@ case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: + case E1000_DEV_ID_82545EM_FIBER: + case E1000_DEV_ID_82545EM_COPPER: wol->supported = 0; wol->wolopts = 0; return; @@ -1468,6 +1484,7 @@ case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: return wol->wolopts ? -EOPNOTSUPP : 0; case E1000_DEV_ID_82546EB_FIBER: @@ -1570,8 +1587,8 @@ e1000_update_stats(adapter); for(i = 0; i < E1000_STATS_LEN; i++) { char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; - data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) - ? *(uint64_t *)p : *(uint32_t *)p; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } } diff -urN linux-2.4.27/drivers/net/e1000/e1000_hw.c linux-2.4.28/drivers/net/e1000/e1000_hw.c --- linux-2.4.27/drivers/net/e1000/e1000_hw.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_hw.c 2004-11-17 03:54:21.389389301 -0800 @@ -65,6 +65,7 @@ static void e1000_standby_eeprom(struct e1000_hw *hw); static int32_t e1000_id_led_init(struct e1000_hw * hw); static int32_t e1000_set_vco_speed(struct e1000_hw *hw); +static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw); static int32_t e1000_set_phy_mode(struct e1000_hw *hw); /* IGP cable length table */ @@ -124,6 +125,7 @@ { DEBUGFUNC("e1000_phy_init_script"); + if(hw->phy_init_script) { msec_delay(20); @@ -251,6 +253,7 @@ break; case E1000_DEV_ID_82541ER: case E1000_DEV_ID_82541GI: + case E1000_DEV_ID_82541GI_LF: case E1000_DEV_ID_82541GI_MOBILE: hw->mac_type = e1000_82541_rev_2; break; @@ -920,7 +923,8 @@ if(ret_val) return ret_val; - if(hw->mac_type == e1000_82545_rev_3) { + if((hw->mac_type == e1000_82545_rev_3) || + (hw->mac_type == e1000_82546_rev_3)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); phy_data |= 0x00000008; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); @@ -1388,6 +1392,7 @@ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + if(ret_val) return ret_val; @@ -1592,6 +1597,15 @@ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; + + if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) && + (!hw->autoneg) && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + ret_val = e1000_polarity_reversal_workaround(hw); + if(ret_val) + return ret_val; + } } return E1000_SUCCESS; } @@ -1981,6 +1995,7 @@ uint32_t ctrl; uint32_t status; uint32_t rctl; + uint32_t icr; uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; @@ -2030,6 +2045,25 @@ * link-up */ e1000_check_downshift(hw); + /* If we are on 82544 or 82543 silicon and speed/duplex + * are forced to 10H or 10F, then we will implement the polarity + * reversal workaround. We disable interrupts first, and upon + * returning, place the devices interrupt state to its previous + * value except for the link status change interrupt which will + * happen due to the execution of this workaround. + */ + + if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) && + (!hw->autoneg) && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + E1000_WRITE_REG(hw, IMC, 0xffffffff); + ret_val = e1000_polarity_reversal_workaround(hw); + icr = E1000_READ_REG(hw, ICR); + E1000_WRITE_REG(hw, ICS, (icr & ~E1000_ICS_LSC)); + E1000_WRITE_REG(hw, IMS, IMS_ENABLE_MASK); + } + } else { /* No link detected */ e1000_config_dsp_after_link_change(hw, FALSE); @@ -2434,6 +2468,7 @@ DEBUGFUNC("e1000_read_phy_reg"); + if(hw->phy_type == e1000_phy_igp && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -2538,6 +2573,7 @@ DEBUGFUNC("e1000_write_phy_reg"); + if(hw->phy_type == e1000_phy_igp && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -3057,16 +3093,6 @@ } break; default: - eeprom->type = e1000_eeprom_spi; - eeprom->opcode_bits = 8; - eeprom->delay_usec = 1; - if (eecd & E1000_EECD_ADDR_BITS) { - eeprom->page_size = 32; - eeprom->address_bits = 16; - } else { - eeprom->page_size = 8; - eeprom->address_bits = 8; - } break; } @@ -3453,7 +3479,6 @@ uint32_t i = 0; DEBUGFUNC("e1000_read_eeprom"); - /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -3516,6 +3541,7 @@ return E1000_SUCCESS; } + /****************************************************************************** * Verifies that the EEPROM has a valid checksum * @@ -3602,6 +3628,7 @@ DEBUGFUNC("e1000_write_eeprom"); + /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -5224,3 +5251,89 @@ } return FALSE; } + +static int32_t +e1000_polarity_reversal_workaround(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t mii_status_reg; + uint16_t i; + + /* Polarity reversal workaround for forced 10F/10H links. */ + + /* Disable the transmitter on the PHY */ + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); + if(ret_val) + return ret_val; + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF); + if(ret_val) + return ret_val; + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); + if(ret_val) + return ret_val; + + /* This loop will early-out if the NO link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Link Status bit + * to be clear. + */ + + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); + if(ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); + if(ret_val) + return ret_val; + + if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break; + msec_delay_irq(100); + } + + /* Recommended delay time after link has been lost */ + msec_delay_irq(1000); + + /* Now we will re-enable th transmitter on the PHY */ + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); + if(ret_val) + return ret_val; + msec_delay_irq(50); + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0); + if(ret_val) + return ret_val; + msec_delay_irq(50); + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00); + if(ret_val) + return ret_val; + msec_delay_irq(50); + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000); + if(ret_val) + return ret_val; + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); + if(ret_val) + return ret_val; + + /* This loop will early-out if the link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Link Status bit + * to be set. + */ + + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); + if(ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); + if(ret_val) + return ret_val; + + if(mii_status_reg & MII_SR_LINK_STATUS) break; + msec_delay_irq(100); + } + return E1000_SUCCESS; +} + diff -urN linux-2.4.27/drivers/net/e1000/e1000_hw.h linux-2.4.28/drivers/net/e1000/e1000_hw.h --- linux-2.4.27/drivers/net/e1000/e1000_hw.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_hw.h 2004-11-17 03:54:21.391389383 -0800 @@ -36,6 +36,7 @@ #include "e1000_osdep.h" + /* Forward declarations of structures used by the shared code */ struct e1000_hw; struct e1000_hw_stats; @@ -357,11 +358,11 @@ #define E1000_DEV_ID_82547GI 0x1075 #define E1000_DEV_ID_82541GI 0x1076 #define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82541GI_LF 0x107C #define E1000_DEV_ID_82546GB_COPPER 0x1079 #define E1000_DEV_ID_82546GB_FIBER 0x107A #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82547EI 0x1019 - #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -1043,7 +1044,6 @@ #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ #define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ - /* Register Bit Masks */ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ diff -urN linux-2.4.27/drivers/net/e1000/e1000_main.c linux-2.4.28/drivers/net/e1000/e1000_main.c --- linux-2.4.27/drivers/net/e1000/e1000_main.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_main.c 2004-11-17 03:54:21.396389589 -0800 @@ -27,73 +27,69 @@ *******************************************************************************/ #include "e1000.h" -#include /* Change Log + * 5.3.12 6/7/04 + * - kcompat NETIF_MSG for older kernels (2.4.9) + * - if_mii support and associated kcompat for older kernels + * - More errlogging support from Jon Mason + * - Fix TSO issues on PPC64 machines -- Jon Mason * - * 5.2.51 5/14/04 - * o set default configuration to 'NAPI disabled'. NAPI enabled driver - * causes kernel panic when the interface is shutdown while data is being - * transferred. - * 5.2.47 5/04/04 - * o fixed ethtool -t implementation - * 5.2.45 4/29/04 - * o fixed ethtool -e implementation - * o Support for ethtool ops [Stephen Hemminger (shemminger@osdl.org)] - * 5.2.42 4/26/04 - * o Added support for the DPRINTK macro for enhanced error logging. Some - * parts of the patch were supplied by Jon Mason. - * o Move the register_netdevice() donw in the probe routine due to a - * loading/unloading test issue. - * o Added a long RX byte count the the extra ethtool data members for BER - * testing purposes. - * 5.2.39 3/12/04 + * 5.3.11 6/4/04 + * - ethtool register dump reads MANC register conditionally. + * + * 5.3.10 6/1/04 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.52-k3"; +#ifndef CONFIG_E1000_NAPI +#define DRIVERNAPI +#else +#define DRIVERNAPI "-NAPI" +#endif +char e1000_driver_version[] = "5.4.11-k1"DRIVERNAPI; char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * - * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, private data (not used) } + * Macro expands to... + * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ static struct pci_device_id e1000_pci_tbl[] = { - {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + INTEL_E1000_ETHERNET_DEVICE(0x1000), + INTEL_E1000_ETHERNET_DEVICE(0x1001), + INTEL_E1000_ETHERNET_DEVICE(0x1004), + INTEL_E1000_ETHERNET_DEVICE(0x1008), + INTEL_E1000_ETHERNET_DEVICE(0x1009), + INTEL_E1000_ETHERNET_DEVICE(0x100C), + INTEL_E1000_ETHERNET_DEVICE(0x100D), + INTEL_E1000_ETHERNET_DEVICE(0x100E), + INTEL_E1000_ETHERNET_DEVICE(0x100F), + INTEL_E1000_ETHERNET_DEVICE(0x1010), + INTEL_E1000_ETHERNET_DEVICE(0x1011), + INTEL_E1000_ETHERNET_DEVICE(0x1012), + INTEL_E1000_ETHERNET_DEVICE(0x1013), + INTEL_E1000_ETHERNET_DEVICE(0x1015), + INTEL_E1000_ETHERNET_DEVICE(0x1016), + INTEL_E1000_ETHERNET_DEVICE(0x1017), + INTEL_E1000_ETHERNET_DEVICE(0x1018), + INTEL_E1000_ETHERNET_DEVICE(0x1019), + INTEL_E1000_ETHERNET_DEVICE(0x101D), + INTEL_E1000_ETHERNET_DEVICE(0x101E), + INTEL_E1000_ETHERNET_DEVICE(0x1026), + INTEL_E1000_ETHERNET_DEVICE(0x1027), + INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x1075), + INTEL_E1000_ETHERNET_DEVICE(0x1076), + INTEL_E1000_ETHERNET_DEVICE(0x1077), + INTEL_E1000_ETHERNET_DEVICE(0x1078), + INTEL_E1000_ETHERNET_DEVICE(0x1079), + INTEL_E1000_ETHERNET_DEVICE(0x107A), + INTEL_E1000_ETHERNET_DEVICE(0x107B), + INTEL_E1000_ETHERNET_DEVICE(0x107C), /* required last entry */ {0,} }; @@ -132,8 +128,8 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); -static inline void e1000_irq_disable(struct e1000_adapter *adapter); -static inline void e1000_irq_enable(struct e1000_adapter *adapter); +static void e1000_irq_disable(struct e1000_adapter *adapter); +static void e1000_irq_enable(struct e1000_adapter *adapter); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); #ifdef CONFIG_E1000_NAPI @@ -150,9 +146,9 @@ void set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); -static inline void e1000_rx_checksum(struct e1000_adapter *adapter, - struct e1000_rx_desc *rx_desc, - struct sk_buff *skb); +static void e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb); static void e1000_tx_timeout(struct net_device *dev); static void e1000_tx_timeout_task(struct net_device *dev); static void e1000_smartspeed(struct e1000_adapter *adapter); @@ -172,7 +168,7 @@ #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ -static void e1000_netpoll (struct net_device *dev); +static void e1000_netpoll (struct net_device *netdev); #endif struct notifier_block e1000_notifier_reboot = { @@ -185,7 +181,6 @@ extern void e1000_check_options(struct e1000_adapter *adapter); - static struct pci_driver e1000_driver = { .name = e1000_driver_name, .id_table = e1000_pci_tbl, @@ -202,7 +197,7 @@ MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); MODULE_LICENSE("GPL"); -static int debug = 3; +static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); @@ -256,6 +251,14 @@ /* hardware has been reset, we need to reload some things */ + /* Reset the PHY if it was previously powered down */ + if(adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + if(mii_reg & MII_CR_POWER_DOWN) + e1000_phy_reset(&adapter->hw); + } + e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -294,12 +297,22 @@ e1000_reset(adapter); e1000_clean_tx_ring(adapter); e1000_clean_rx_ring(adapter); + + /* If WoL is not enabled + * Power down the PHY so no link is implied when interface is down */ + if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) { + uint16_t mii_reg; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + } } void e1000_reset(struct e1000_adapter *adapter) { - uint32_t pba, manc; + uint32_t pba; + /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. */ @@ -323,10 +336,10 @@ E1000_WRITE_REG(&adapter->hw, PBA, pba); /* flow control settings */ - adapter->hw.fc_high_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_HIGH_DIFF; - adapter->hw.fc_low_water = - (pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_LOW_DIFF; + adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_HIGH_DIFF; + adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - + E1000_FC_LOW_DIFF; adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; @@ -334,19 +347,14 @@ e1000_reset_hw(&adapter->hw); if(adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); - e1000_init_hw(&adapter->hw); + if(e1000_init_hw(&adapter->hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); e1000_reset_adaptive(&adapter->hw); e1000_phy_get_info(&adapter->hw, &adapter->phy_info); - - if(adapter->en_mng_pt) { - manc = E1000_READ_REG(&adapter->hw, MANC); - manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); - E1000_WRITE_REG(&adapter->hw, MANC, manc); - } } /** @@ -409,11 +417,6 @@ adapter->hw.back = adapter; adapter->msg_enable = (1 << debug) - 1; - rtnl_lock(); - /* we need to set the name early since the DPRINTK macro needs it set */ - if (dev_alloc_name(netdev, netdev->name) < 0) - goto err_free_unlock; - mmio_start = pci_resource_start(pdev, BAR_0); mmio_len = pci_resource_len(pdev, BAR_0); @@ -453,6 +456,7 @@ #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e1000_netpoll; #endif + strcpy(netdev->name, pci_name(pdev)); netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; @@ -476,7 +480,6 @@ } #ifdef NETIF_F_TSO -#ifdef BROKEN_ON_NON_IA_ARCHS /* Disbaled for now until root-cause is found for * hangs reported against non-IA archs. TSO can be * enabled using ethtool -K eth tso on */ @@ -484,13 +487,9 @@ (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; #endif -#endif - if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); - /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ @@ -506,10 +505,12 @@ /* copy the MAC address out of the EEPROM */ - e1000_read_mac_addr(&adapter->hw); + if (e1000_read_mac_addr(&adapter->hw)) + DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; } @@ -538,7 +539,6 @@ netif_carrier_off(netdev); netif_stop_queue(netdev); - DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); e1000_check_options(adapter); /* Initial Wake on LAN setting @@ -569,15 +569,15 @@ adapter->wol |= E1000_WUFC_MAG; /* reset the hardware with the new settings */ - e1000_reset(adapter); - /* since we are holding the rtnl lock already, call the no-lock version */ - if((err = register_netdevice(netdev))) + strcpy(netdev->name, "eth%d"); + if((err = register_netdev(netdev))) goto err_register; + DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); + cards_found++; - rtnl_unlock(); return 0; err_register: @@ -585,8 +585,6 @@ err_eeprom: iounmap(adapter->hw.hw_addr); err_ioremap: -err_free_unlock: - rtnl_unlock(); free_netdev(netdev); err_alloc_etherdev: pci_release_regions(pdev); @@ -663,7 +661,7 @@ /* identify the MAC */ - if (e1000_set_mac_type(hw)) { + if(e1000_set_mac_type(hw)) { DPRINTK(PROBE, ERR, "Unknown MAC Type\n"); return -EIO; } @@ -672,19 +670,19 @@ e1000_init_eeprom_params(hw); - if((hw->mac_type == e1000_82541) || - (hw->mac_type == e1000_82547) || - (hw->mac_type == e1000_82541_rev_2) || - (hw->mac_type == e1000_82547_rev_2)) + switch(hw->mac_type) { + default: + break; + case e1000_82541: + case e1000_82547: + case e1000_82541_rev_2: + case e1000_82547_rev_2: hw->phy_init_script = 1; + break; + } e1000_set_media_type(hw); - if(hw->mac_type < e1000_82543) - hw->report_tx_early = 0; - else - hw->report_tx_early = 1; - hw->wait_autoneg_complete = FALSE; hw->tbi_compatibility_en = TRUE; hw->adaptive_ifs = TRUE; @@ -736,7 +734,7 @@ if((err = e1000_up(adapter))) goto err_up; - return 0; + return E1000_SUCCESS; err_up: e1000_free_rx_resources(adapter); @@ -788,8 +786,10 @@ int size; size = sizeof(struct e1000_buffer) * txdr->count; - txdr->buffer_info = kmalloc(size, GFP_KERNEL); + txdr->buffer_info = vmalloc(size); if(!txdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unable to Allocate Memory for the Transmit descriptor ring\n"); return -ENOMEM; } memset(txdr->buffer_info, 0, size); @@ -801,7 +801,9 @@ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if(!txdr->desc) { - kfree(txdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unable to Allocate Memory for the Transmit descriptor ring\n"); + vfree(txdr->buffer_info); return -ENOMEM; } memset(txdr->desc, 0, txdr->size); @@ -878,10 +880,10 @@ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.report_tx_early == 1) - adapter->txd_cmd |= E1000_TXD_CMD_RS; - else + if(adapter->hw.mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; + else + adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ @@ -905,8 +907,10 @@ int size; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = kmalloc(size, GFP_KERNEL); + rxdr->buffer_info = vmalloc(size); if(!rxdr->buffer_info) { + DPRINTK(PROBE, ERR, + "Unable to Allocate Memory for the Recieve descriptor ring\n"); return -ENOMEM; } memset(rxdr->buffer_info, 0, size); @@ -919,7 +923,9 @@ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); if(!rxdr->desc) { - kfree(rxdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unable to Allocate Memory for the Recieve descriptor ring\n"); + vfree(rxdr->buffer_info); return -ENOMEM; } memset(rxdr->desc, 0, rxdr->size); @@ -953,7 +959,9 @@ else rctl &= ~E1000_RCTL_SBP; + /* Setup buffer sizes */ rctl &= ~(E1000_RCTL_SZ_4096); + rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE); switch (adapter->rx_buffer_len) { case E1000_RXBUFFER_2048: default: @@ -961,13 +969,13 @@ rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE); break; case E1000_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_4096; break; case E1000_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_8192; break; case E1000_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + rctl |= E1000_RCTL_SZ_16384; break; } @@ -989,13 +997,11 @@ uint32_t rctl; uint32_t rxcsum; - /* make sure receives are disabled while setting up the descriptors */ - + /* disable receives while setting up the descriptors */ rctl = E1000_READ_REG(&adapter->hw, RCTL); E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); if(adapter->hw.mac_type >= e1000_82540) { @@ -1006,7 +1012,6 @@ } /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); @@ -1025,7 +1030,6 @@ } /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } @@ -1043,7 +1047,7 @@ e1000_clean_tx_ring(adapter); - kfree(adapter->tx_ring.buffer_info); + vfree(adapter->tx_ring.buffer_info); adapter->tx_ring.buffer_info = NULL; pci_free_consistent(pdev, adapter->tx_ring.size, @@ -1073,9 +1077,9 @@ if(buffer_info->skb) { pci_unmap_page(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_TODEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); dev_kfree_skb(buffer_info->skb); @@ -1112,7 +1116,7 @@ e1000_clean_rx_ring(adapter); - kfree(rx_ring->buffer_info); + vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); @@ -1141,12 +1145,11 @@ if(buffer_info->skb) { pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); dev_kfree_skb(buffer_info->skb); - buffer_info->skb = NULL; } } @@ -1312,7 +1315,8 @@ e1000_leave_82542_rst(adapter); } -/* need to wait a few seconds after link up to get diagnostic information from the phy */ +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ static void e1000_update_phy_info(unsigned long data) @@ -1420,7 +1424,7 @@ adapter->tpt_old = adapter->stats.tpt; adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; adapter->colc_old = adapter->stats.colc; - + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; adapter->gorcl_old = adapter->stats.gorcl; adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; @@ -1477,8 +1481,9 @@ #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; unsigned int i; - uint8_t ipcss, ipcso, tucss, tucso, hdr_len; + uint32_t cmd_length = 0; uint16_t ipcse, tucse, mss; + uint8_t ipcss, ipcso, tucss, tucso, hdr_len; if(skb_shinfo(skb)->tso_size) { hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); @@ -1497,6 +1502,10 @@ tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | + (skb->len - (hdr_len))); + i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); @@ -1508,10 +1517,7 @@ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; - context_desc->cmd_and_length = cpu_to_le32( - E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | - E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | - (skb->len - (hdr_len))); + context_desc->cmd_and_length = cpu_to_le32(cmd_length); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1528,22 +1534,21 @@ { struct e1000_context_desc *context_desc; unsigned int i; - uint8_t css, cso; + uint8_t css; - if(skb->ip_summed == CHECKSUM_HW) { + if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - cso = (skb->h.raw + skb->csum) - skb->data; i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = cso; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(++i == adapter->tx_ring.count) i = 0; + if(unlikely(++i == adapter->tx_ring.count)) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; @@ -1567,7 +1572,6 @@ unsigned int f; len -= skb->data_len; - i = tx_ring->next_to_use; while(len) { @@ -1576,14 +1580,14 @@ #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && !nr_frags && size == len && size > 8) + if(unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(skb->data + offset + size - 1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1597,7 +1601,7 @@ len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } for(f = 0; f < nr_frags; f++) { @@ -1613,15 +1617,15 @@ #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(mss && f == (nr_frags-1) && size == len && size > 8) + if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ - if(adapter->pcix_82544 && + if(unlikely(adapter->pcix_82544 && !((unsigned long)(frag->page+offset+size-1) & 4) && - size > 4) + size > 4)) size -= 4; buffer_info->length = size; @@ -1636,13 +1640,14 @@ len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } } + i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - + return count; } @@ -1655,18 +1660,18 @@ uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; - if(tx_flags & E1000_TX_FLAGS_TSO) { + if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; } - if(tx_flags & E1000_TX_FLAGS_CSUM) { + if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } - if(tx_flags & E1000_TX_FLAGS_VLAN) { + if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } @@ -1680,7 +1685,7 @@ tx_desc->lower.data = cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); @@ -1733,7 +1738,7 @@ return 0; } -#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -1741,22 +1746,23 @@ unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned long flags; unsigned int len = skb->len; - int count = 0; - unsigned int mss = 0; + unsigned long flags; unsigned int nr_frags = 0; + unsigned int mss = 0; + int count = 0; unsigned int f; nr_frags = skb_shinfo(skb)->nr_frags; len -= skb->data_len; - if(skb->len <= 0) { + + if(unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return 0; } #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; - /* The controller does a simple calculation to + /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: * 4 = ceil(buffer len/mss). To make sure we don't @@ -1766,57 +1772,60 @@ max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; } + if((mss) || (skb->ip_summed == CHECKSUM_HW)) count++; - count++; /*for sentinel desc*/ + count++; /* for sentinel desc */ #else if(skb->ip_summed == CHECKSUM_HW) count++; #endif - count += TXD_USE_COUNT(len, max_txd_pwr); + if(adapter->pcix_82544) count++; nr_frags = skb_shinfo(skb)->nr_frags; for(f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, - max_txd_pwr); + max_txd_pwr); if(adapter->pcix_82544) count += nr_frags; - + spin_lock_irqsave(&adapter->tx_lock, flags); - /* need: count + 2 desc gap to keep tail from touching + + /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2 ) { + if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) { netif_stop_queue(netdev); spin_unlock_irqrestore(&adapter->tx_lock, flags); return 1; } + spin_unlock_irqrestore(&adapter->tx_lock, flags); - if(adapter->hw.mac_type == e1000_82547) { - if(e1000_82547_fifo_workaround(adapter, skb)) { + if(unlikely(adapter->hw.mac_type == e1000_82547)) { + if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); return 1; } } - if(adapter->vlgrp && vlan_tx_tag_present(skb)) { + if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } first = adapter->tx_ring.next_to_use; - if(e1000_tso(adapter, skb)) + if(likely(e1000_tso(adapter, skb))) tx_flags |= E1000_TX_FLAGS_TSO; - else if(e1000_tx_csum(adapter, skb)) + else if(likely(e1000_tx_csum(adapter, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), + e1000_tx_queue(adapter, + e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), tx_flags); netdev->trans_start = jiffies; @@ -1843,10 +1852,8 @@ { struct e1000_adapter *adapter = netdev->priv; - netif_device_detach(netdev); e1000_down(adapter); e1000_up(adapter); - netif_device_attach(netdev); } /** @@ -1905,7 +1912,6 @@ } if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { - e1000_down(adapter); e1000_up(adapter); } @@ -1951,8 +1957,6 @@ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); - /* the rest of the counters are only modified here */ - adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(hw, MPC); adapter->stats.scc += E1000_READ_REG(hw, SCC); @@ -2059,7 +2063,7 @@ * @adapter: board private structure **/ -static inline void +static void e1000_irq_disable(struct e1000_adapter *adapter) { atomic_inc(&adapter->irq_sem); @@ -2073,10 +2077,10 @@ * @adapter: board private structure **/ -static inline void +static void e1000_irq_enable(struct e1000_adapter *adapter) { - if(atomic_dec_and_test(&adapter->irq_sem)) { + if(likely(atomic_dec_and_test(&adapter->irq_sem))) { E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); E1000_WRITE_FLUSH(&adapter->hw); } @@ -2095,21 +2099,21 @@ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; - uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); + uint32_t icr = E1000_READ_REG(hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; #endif - if(!icr) + if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ - if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } #ifdef CONFIG_E1000_NAPI - if(netif_rx_schedule_prep(netdev)) { + if(likely(netif_rx_schedule_prep(netdev))) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. @@ -2121,8 +2125,8 @@ } #else for(i = 0; i < E1000_MAX_INTR; i++) - if(!e1000_clean_rx_irq(adapter) & - !e1000_clean_tx_irq(adapter)) + if(unlikely(!e1000_clean_rx_irq(adapter) & + !e1000_clean_tx_irq(adapter))) break; #endif @@ -2140,15 +2144,18 @@ { struct e1000_adapter *adapter = netdev->priv; int work_to_do = min(*budget, netdev->quota); + int tx_cleaned; int work_done = 0; - e1000_clean_tx_irq(adapter); + tx_cleaned = e1000_clean_tx_irq(adapter); e1000_clean_rx_irq(adapter, &work_done, work_to_do); *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do || !netif_running(netdev)) { + /* if no Rx and Tx cleanup work was done, exit the polling mode */ + if(!tx_cleaned || (work_done < work_to_do) || + !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); return 0; @@ -2156,8 +2163,8 @@ return (work_done >= work_to_do); } -#endif +#endif /** * e1000_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -2174,19 +2181,16 @@ unsigned int i, eop; boolean_t cleaned = FALSE; - i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - for(cleaned = FALSE; !cleaned; ) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; - if(buffer_info->dma) { - + if(likely(buffer_info->dma)) { pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, @@ -2196,9 +2200,7 @@ } if(buffer_info->skb) { - dev_kfree_skb_any(buffer_info->skb); - buffer_info->skb = NULL; } @@ -2207,7 +2209,7 @@ tx_desc->upper.data = 0; cleaned = (i == eop); - if(++i == tx_ring->count) i = 0; + if(unlikely(++i == tx_ring->count)) i = 0; } eop = tx_ring->buffer_info[i].next_to_watch; @@ -2218,7 +2220,8 @@ spin_lock(&adapter->tx_lock); - if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) + if(unlikely(cleaned && netif_queue_stopped(netdev) && + netif_carrier_ok(netdev))) netif_wake_queue(netdev); spin_unlock(&adapter->tx_lock); @@ -2227,7 +2230,7 @@ } /** - * e1000_clean_rx_irq - Send received data up the network stack, + * e1000_clean_rx_irq - Send received data up the network stack * @adapter: board private structure **/ @@ -2256,14 +2259,11 @@ while(rx_desc->status & E1000_RXD_STAT_DD) { buffer_info = &rx_ring->buffer_info[i]; - #ifdef CONFIG_E1000_NAPI if(*work_done >= work_to_do) break; - (*work_done)++; #endif - cleaned = TRUE; pci_unmap_single(pdev, @@ -2274,49 +2274,28 @@ skb = buffer_info->skb; length = le16_to_cpu(rx_desc->length); - if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { - + if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ - - E1000_DBG("%s: Receive packet consumed multiple buffers\n", - netdev->name); - + E1000_DBG("%s: Receive packet consumed multiple" + " buffers\n", netdev->name); dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } - if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - + if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { last_byte = *(skb->data + length - 1); - if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { - spin_lock_irqsave(&adapter->stats_lock, flags); - e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); - spin_unlock_irqrestore(&adapter->stats_lock, flags); length--; } else { - dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; + goto next_desc; } } @@ -2328,28 +2307,30 @@ skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & - E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special) & + E1000_RXD_SPC_VLAN_MASK); } else { netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + if(unlikely(adapter->vlgrp && + (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special & - E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special) & + E1000_RXD_SPC_VLAN_MASK); } else { netif_rx(skb); } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +next_desc: rx_desc->status = 0; buffer_info->skb = NULL; - - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); } @@ -2382,11 +2363,10 @@ buffer_info = &rx_ring->buffer_info[i]; while(!buffer_info->skb) { - rx_desc = E1000_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len); - if(!skb) { + if(unlikely(!skb)) { /* Better luck next round */ break; } @@ -2401,15 +2381,15 @@ buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; - buffer_info->dma = - pci_map_single(pdev, - skb->data, - adapter->rx_buffer_len, - PCI_DMA_FROMDEVICE); + buffer_info->dma = pci_map_single(pdev, + skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); - if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { + if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, @@ -2419,7 +2399,7 @@ E1000_WRITE_REG(&adapter->hw, RDT, i); } - if(++i == rx_ring->count) i = 0; + if(unlikely(++i == rx_ring->count)) i = 0; buffer_info = &rx_ring->buffer_info[i]; } @@ -2538,22 +2518,24 @@ return -EFAULT; mii_reg = data->val_in; if (e1000_write_phy_reg(&adapter->hw, data->reg_num, - data->val_in)) + mii_reg)) return -EIO; if (adapter->hw.phy_type == e1000_phy_m88) { switch (data->reg_num) { case PHY_CTRL: - if(data->val_in & MII_CR_AUTO_NEG_EN) { + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(mii_reg & MII_CR_AUTO_NEG_EN) { adapter->hw.autoneg = 1; adapter->hw.autoneg_advertised = 0x2F; } else { - if (data->val_in & 0x40) + if (mii_reg & 0x40) spddplx = SPEED_1000; - else if (data->val_in & 0x2000) + else if (mii_reg & 0x2000) spddplx = SPEED_100; else spddplx = SPEED_10; - spddplx += (data->val_in & 0x100) + spddplx += (mii_reg & 0x100) ? FULL_DUPLEX : HALF_DUPLEX; retval = e1000_set_spd_dplx(adapter, @@ -2573,6 +2555,18 @@ return -EIO; break; } + } else { + switch (data->reg_num) { + case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) + break; + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + break; + } } break; default: @@ -2588,17 +2582,17 @@ * @sk_buff: socket buffer with received data **/ -static inline void +static void e1000_rx_checksum(struct e1000_adapter *adapter, struct e1000_rx_desc *rx_desc, struct sk_buff *skb) { /* 82543 or newer only */ - if((adapter->hw.mac_type < e1000_82543) || + if(unlikely((adapter->hw.mac_type < e1000_82543) || /* Ignore Checksum bit is set */ (rx_desc->status & E1000_RXD_STAT_IXSM) || /* TCP Checksum has not been calculated */ - (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + (!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) { skb->ip_summed = CHECKSUM_NONE; return; } @@ -2610,7 +2604,7 @@ skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_err++; } else { - /* TCP checksum is good */ + /* TCP checksum is good */ skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; } @@ -2621,7 +2615,8 @@ { struct e1000_adapter *adapter = hw->back; - pci_set_mwi(adapter->pdev); + int ret; + ret = pci_set_mwi(adapter->pdev); } void @@ -2671,26 +2666,22 @@ if(grp) { /* enable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* enable VLAN receive filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } else { /* disable VLAN tag insert/strip */ - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl &= ~E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); /* disable VLAN filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); @@ -2706,7 +2697,6 @@ uint32_t vfta, index; /* add VID to filter table */ - index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta |= (1 << (vid & 0x1F)); @@ -2726,8 +2716,7 @@ e1000_irq_enable(adapter); - /* remove VID from filter table*/ - + /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); vfta &= ~(1 << (vid & 0x1F)); @@ -2773,6 +2762,8 @@ break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: + DPRINTK(PROBE, ERR, + "Unsupported Speed/Duplexity configuration\n"); return -EINVAL; } return 0; @@ -2866,6 +2857,8 @@ } } + pci_disable_device(pdev); + state = (state > 0) ? 3 : 0; pci_set_power_state(pdev, state); @@ -2878,8 +2871,9 @@ { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev->priv; - uint32_t manc; + uint32_t manc, ret; + ret = pci_enable_device(pdev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, adapter->pci_state); @@ -2911,12 +2905,12 @@ * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */ - -static void e1000_netpoll (struct net_device *dev) +static void +e1000_netpoll (struct net_device *netdev) { - struct e1000_adapter *adapter = dev->priv; + struct e1000_adapter *adapter = netdev->priv; disable_irq(adapter->pdev->irq); - e1000_intr (adapter->pdev->irq, dev, NULL); + e1000_intr(adapter->pdev->irq, netdev, NULL); enable_irq(adapter->pdev->irq); } #endif diff -urN linux-2.4.27/drivers/net/e1000/e1000_osdep.h linux-2.4.28/drivers/net/e1000/e1000_osdep.h --- linux-2.4.27/drivers/net/e1000/e1000_osdep.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_osdep.h 2004-11-17 03:54:21.397389630 -0800 @@ -49,6 +49,12 @@ set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout((x * HZ)/1000 + 2); \ } } while(0) +/* Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ +#define msec_delay_irq(x) mdelay(x) #endif #define PCI_COMMAND_REGISTER PCI_COMMAND diff -urN linux-2.4.27/drivers/net/e1000/e1000_param.c linux-2.4.28/drivers/net/e1000/e1000_param.c --- linux-2.4.27/drivers/net/e1000/e1000_param.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/e1000/e1000_param.c 2004-11-17 03:54:21.403389876 -0800 @@ -34,10 +34,16 @@ #define E1000_MAX_NIC 32 -#define OPTION_UNSET -1 +#define OPTION_UNSET -1 #define OPTION_DISABLED 0 #define OPTION_ENABLED 1 +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } /* Module Parameters are always initialized to -1, so that the driver * can tell the difference between no user specified value or the * user asking for the default value. @@ -48,17 +54,10 @@ * "Extensions to the C Language Family" of the GCC documentation. */ -#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } - -/* All parameters are treated the same, as an integer array of values. - * This macro just reduces the need to repeat the same declaration code - * over and over (plus this helps to avoid typo bugs). - */ - -#define E1000_PARAM(X, S) \ -static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \ -MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ -MODULE_PARM_DESC(X, S); +#define E1000_PARAM(X, desc) \ + static const int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ + MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ + MODULE_PARM_DESC(X, desc); /* Transmit Descriptor Count * @@ -212,7 +211,7 @@ #define MAX_TXABSDELAY 0xFFFF #define MIN_TXABSDELAY 0 -#define DEFAULT_ITR 1 +#define DEFAULT_ITR 8000 #define MAX_ITR 100000 #define MIN_ITR 100 @@ -235,7 +234,7 @@ static int __devinit e1000_validate_option(int *value, struct e1000_option *opt, - struct e1000_adapter *adapter) + struct e1000_adapter *adapter) { if(*value == OPTION_UNSET) { *value = opt->def; @@ -256,7 +255,7 @@ case range_option: if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { DPRINTK(PROBE, INFO, - "%s set to %i\n", opt->name, *value); + "%s set to %i\n", opt->name, *value); return 0; } break; @@ -322,9 +321,10 @@ opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD; - tx_ring->count = TxDescriptors[bd]; - e1000_validate_option(&tx_ring->count, &opt, adapter); - E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + tx_ring->count = TxDescriptors[bd]; + e1000_validate_option(&tx_ring->count, &opt, adapter); + E1000_ROUNDUP(tx_ring->count, + REQ_TX_DESCRIPTOR_MULTIPLE); } { /* Receive Descriptor Count */ struct e1000_option opt = { @@ -340,9 +340,10 @@ opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD; - rx_ring->count = RxDescriptors[bd]; - e1000_validate_option(&rx_ring->count, &opt, adapter); - E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + rx_ring->count = RxDescriptors[bd]; + e1000_validate_option(&rx_ring->count, &opt, adapter); + E1000_ROUNDUP(rx_ring->count, + REQ_RX_DESCRIPTOR_MULTIPLE); } { /* Checksum Offload Enable/Disable */ struct e1000_option opt = { @@ -352,9 +353,9 @@ .def = OPTION_ENABLED }; - int rx_csum = XsumRX[bd]; - e1000_validate_option(&rx_csum, &opt, adapter); - adapter->rx_csum = rx_csum; + int rx_csum = XsumRX[bd]; + e1000_validate_option(&rx_csum, &opt, adapter); + adapter->rx_csum = rx_csum; } { /* Flow Control */ @@ -374,9 +375,9 @@ .p = fc_list }} }; - int fc = FlowControl[bd]; - e1000_validate_option(&fc, &opt, adapter); - adapter->hw.fc = adapter->hw.original_fc = fc; + int fc = FlowControl[bd]; + e1000_validate_option(&fc, &opt, adapter); + adapter->hw.fc = adapter->hw.original_fc = fc; } { /* Transmit Interrupt Delay */ struct e1000_option opt = { @@ -388,8 +389,9 @@ .max = MAX_TXDELAY }} }; - adapter->tx_int_delay = TxIntDelay[bd]; - e1000_validate_option(&adapter->tx_int_delay, &opt, adapter); + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt, + adapter); } { /* Transmit Absolute Interrupt Delay */ struct e1000_option opt = { @@ -401,8 +403,9 @@ .max = MAX_TXABSDELAY }} }; - adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; - e1000_validate_option(&adapter->tx_abs_int_delay, &opt, adapter); + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + adapter); } { /* Receive Interrupt Delay */ struct e1000_option opt = { @@ -414,8 +417,9 @@ .max = MAX_RXDELAY }} }; - adapter->rx_int_delay = RxIntDelay[bd]; - e1000_validate_option(&adapter->rx_int_delay, &opt, adapter); + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt, + adapter); } { /* Receive Absolute Interrupt Delay */ struct e1000_option opt = { @@ -427,8 +431,9 @@ .max = MAX_RXABSDELAY }} }; - adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; - e1000_validate_option(&adapter->rx_abs_int_delay, &opt, adapter); + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + adapter); } { /* Interrupt Throttling Rate */ struct e1000_option opt = { @@ -440,22 +445,24 @@ .max = MAX_ITR }} }; - adapter->itr = InterruptThrottleRate[bd]; - switch(adapter->itr) { - case -1: - adapter->itr = 1; - break; - case 0: - DPRINTK(PROBE, INFO, "%s turned off\n", opt.name); - break; - case 1: - DPRINTK(PROBE, INFO, - "%s set to dynamic mode\n", opt.name); - break; - default: - e1000_validate_option(&adapter->itr, &opt, adapter); - break; - } + adapter->itr = InterruptThrottleRate[bd]; + switch(adapter->itr) { + case -1: + adapter->itr = 1; + break; + case 0: + DPRINTK(PROBE, INFO, "%s turned off\n", + opt.name); + break; + case 1: + DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", + opt.name); + break; + default: + e1000_validate_option(&adapter->itr, &opt, + adapter); + break; + } } switch(adapter->hw.media_type) { @@ -483,18 +490,20 @@ { int bd = adapter->bd_number; bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; - if((Speed[bd] != OPTION_UNSET)) { DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, " "parameter ignored\n"); } + if((Duplex[bd] != OPTION_UNSET)) { DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, " "parameter ignored\n"); } + if((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) { - DPRINTK(PROBE, INFO, "AutoNeg other than Full/1000 is " - "not valid for fiber adapters, parameter ignored\n"); + DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is " + "not valid for fiber adapters, " + "parameter ignored\n"); } } @@ -527,8 +536,8 @@ .p = speed_list }} }; - speed = Speed[bd]; - e1000_validate_option(&speed, &opt, adapter); + speed = Speed[bd]; + e1000_validate_option(&speed, &opt, adapter); } { /* Duplex */ struct e1000_opt_list dplx_list[] = {{ 0, "" }, @@ -544,8 +553,8 @@ .p = dplx_list }} }; - dplx = Duplex[bd]; - e1000_validate_option(&dplx, &opt, adapter); + dplx = Duplex[bd]; + e1000_validate_option(&dplx, &opt, adapter); } if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) { @@ -611,24 +620,24 @@ break; case HALF_DUPLEX: DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Half Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Half Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | ADVERTISE_100_HALF; break; case FULL_DUPLEX: DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at Full Duplex only\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL; break; case SPEED_10: - DPRINTK(PROBE, INFO, - "10 Mbps Speed specified without Duplex\n"); + DPRINTK(PROBE, INFO, "10 Mbps Speed specified " + "without Duplex\n"); DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | @@ -647,10 +656,10 @@ adapter->hw.autoneg_advertised = 0; break; case SPEED_100: - DPRINTK(PROBE, INFO, - "100 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 100 Mbps only\n"); + DPRINTK(PROBE, INFO, "100 Mbps Speed specified " + "without Duplex\n"); + DPRINTK(PROBE, INFO, "Using Autonegotiation at " + "100 Mbps only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_100_HALF | ADVERTISE_100_FULL; @@ -668,10 +677,11 @@ adapter->hw.autoneg_advertised = 0; break; case SPEED_1000: + DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without " + "Duplex\n"); DPRINTK(PROBE, INFO, - "1000 Mbps Speed specified without Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -679,7 +689,8 @@ DPRINTK(PROBE, INFO, "Half Duplex is not supported at 1000 Mbps\n"); DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + "Using Autonegotiation at 1000 Mbps " + "Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -696,8 +707,8 @@ /* Speed, AutoNeg and MDI/MDI-X must all play nice */ if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) { DPRINTK(PROBE, INFO, - "Speed, AutoNeg and MDI-X specifications are " - "incompatible. Setting MDI-X to a compatible value.\n"); + "Speed, AutoNeg and MDI-X specifications are " + "incompatible. Setting MDI-X to a compatible value.\n"); } } diff -urN linux-2.4.27/drivers/net/eql.c linux-2.4.28/drivers/net/eql.c --- linux-2.4.27/drivers/net/eql.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/eql.c 2004-11-17 03:54:21.404389917 -0800 @@ -335,6 +335,152 @@ } +static inline int eql_number_slaves(slave_queue_t *queue) +{ + return queue->num_slaves; +} + + +static inline int eql_is_empty(slave_queue_t *queue) +{ + if (eql_number_slaves (queue) == 0) + return 1; + return 0; +} + +static inline int eql_is_full(slave_queue_t *queue) +{ + equalizer_t *eql = (equalizer_t *) queue->master_dev->priv; + + if (eql_number_slaves (queue) == eql->max_slaves) + return 1; + return 0; +} + +static inline slave_t *eql_first_slave(slave_queue_t *queue) +{ + return queue->head->next; +} + + +static inline slave_t *eql_next_slave(slave_queue_t *queue, slave_t *slave) +{ + return slave->next; +} + +static inline void eql_set_best_slave(slave_queue_t *queue, slave_t *slave) +{ + queue->best_slave = slave; +} + +static inline void eql_schedule_slaves(slave_queue_t *queue) +{ + struct net_device *master_dev = queue->master_dev; + slave_t *best_slave = 0; + slave_t *slave_corpse = 0; + +#ifdef EQL_DEBUG + if (eql_debug >= 100) + printk ("%s: schedule %d slaves\n", + master_dev->name, eql_number_slaves (queue)); +#endif + if ( eql_is_empty (queue) ) + { + /* + * No slaves to play with + */ + eql_set_best_slave (queue, (slave_t *) 0); + return; + } + else + { + /* + * Make a pass to set the best slave + */ + unsigned long best_load = (unsigned long) ULONG_MAX; + slave_t *slave = 0; + unsigned long flags; + int i; + + save_flags(flags); + cli (); + for (i = 1, slave = eql_first_slave (queue); + i <= eql_number_slaves (queue); + i++, slave = eql_next_slave (queue, slave)) + { + /* + * Go through the slave list once, updating best_slave + * whenever a new best_load is found, whenever a dead + * slave is found, it is marked to be pulled out of the + * queue + */ + + unsigned long slave_load; + unsigned long bytes_queued; + unsigned long priority_Bps; + + if (slave != 0) + { + bytes_queued = slave->bytes_queued; + priority_Bps = slave->priority_Bps; + if ( slave->dev != 0) + { + if ((slave->dev->flags & IFF_UP) == IFF_UP ) + { + slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - + (priority_Bps) + bytes_queued * 8; + + if (slave_load < best_load) + { + best_load = slave_load; + best_slave = slave; + } + } + else /* we found a dead slave */ + { + /* + * We only bury one slave at a time, if more than + * one slave dies, we will bury him on the next + * reschedule. slaves don't die all at once that + * much anyway + */ + slave_corpse = slave; + } + } + } + } /* for */ + restore_flags(flags); + eql_set_best_slave (queue, best_slave); + } /* else */ + if (slave_corpse != 0) + { + printk ("eql: scheduler found dead slave, burying...\n"); + eql_delete_slave (eql_remove_slave (queue, slave_corpse)); + } + return; +} + + +static inline struct net_device *eql_best_slave_dev(slave_queue_t *queue) +{ + if (queue->best_slave != 0) + { + if (queue->best_slave->dev != 0) + return queue->best_slave->dev; + else + return 0; + } + else + return 0; +} + + +static inline slave_t *eql_best_slave(slave_queue_t *queue) +{ + return queue->best_slave; +} + + static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) { equalizer_t *eql = (equalizer_t *) dev->priv; @@ -383,6 +529,28 @@ return eql->stats; } +static inline int eql_is_slave(struct net_device *dev) +{ + if (dev) + { + if ((dev->flags & IFF_SLAVE) == IFF_SLAVE) + return 1; + } + return 0; +} + + +static inline int eql_is_master(struct net_device *dev) +{ + if (dev) + { + if ((dev->flags & IFF_MASTER) == IFF_MASTER) + return 1; + } + return 0; +} + + /* * Private ioctl functions */ @@ -597,28 +765,6 @@ * Private device support functions */ -static inline int eql_is_slave(struct net_device *dev) -{ - if (dev) - { - if ((dev->flags & IFF_SLAVE) == IFF_SLAVE) - return 1; - } - return 0; -} - - -static inline int eql_is_master(struct net_device *dev) -{ - if (dev) - { - if ((dev->flags & IFF_MASTER) == IFF_MASTER) - return 1; - } - return 0; -} - - static slave_t *eql_new_slave(void) { slave_t *slave; @@ -650,27 +796,6 @@ #endif -static inline int eql_number_slaves(slave_queue_t *queue) -{ - return queue->num_slaves; -} - -static inline int eql_is_empty(slave_queue_t *queue) -{ - if (eql_number_slaves (queue) == 0) - return 1; - return 0; -} - -static inline int eql_is_full(slave_queue_t *queue) -{ - equalizer_t *eql = (equalizer_t *) queue->master_dev->priv; - - if (eql_number_slaves (queue) == eql->max_slaves) - return 1; - return 0; -} - static slave_queue_t *eql_new_slave_queue(struct net_device *dev) { slave_queue_t *queue; @@ -817,113 +942,6 @@ } -static inline struct net_device *eql_best_slave_dev(slave_queue_t *queue) -{ - if (queue->best_slave != 0) - { - if (queue->best_slave->dev != 0) - return queue->best_slave->dev; - else - return 0; - } - else - return 0; -} - - -static inline slave_t *eql_best_slave(slave_queue_t *queue) -{ - return queue->best_slave; -} - -static inline void eql_schedule_slaves(slave_queue_t *queue) -{ - struct net_device *master_dev = queue->master_dev; - slave_t *best_slave = 0; - slave_t *slave_corpse = 0; - -#ifdef EQL_DEBUG - if (eql_debug >= 100) - printk ("%s: schedule %d slaves\n", - master_dev->name, eql_number_slaves (queue)); -#endif - if ( eql_is_empty (queue) ) - { - /* - * No slaves to play with - */ - eql_set_best_slave (queue, (slave_t *) 0); - return; - } - else - { - /* - * Make a pass to set the best slave - */ - unsigned long best_load = (unsigned long) ULONG_MAX; - slave_t *slave = 0; - unsigned long flags; - int i; - - save_flags(flags); - cli (); - for (i = 1, slave = eql_first_slave (queue); - i <= eql_number_slaves (queue); - i++, slave = eql_next_slave (queue, slave)) - { - /* - * Go through the slave list once, updating best_slave - * whenever a new best_load is found, whenever a dead - * slave is found, it is marked to be pulled out of the - * queue - */ - - unsigned long slave_load; - unsigned long bytes_queued; - unsigned long priority_Bps; - - if (slave != 0) - { - bytes_queued = slave->bytes_queued; - priority_Bps = slave->priority_Bps; - if ( slave->dev != 0) - { - if ((slave->dev->flags & IFF_UP) == IFF_UP ) - { - slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - - (priority_Bps) + bytes_queued * 8; - - if (slave_load < best_load) - { - best_load = slave_load; - best_slave = slave; - } - } - else /* we found a dead slave */ - { - /* - * We only bury one slave at a time, if more than - * one slave dies, we will bury him on the next - * reschedule. slaves don't die all at once that - * much anyway - */ - slave_corpse = slave; - } - } - } - } /* for */ - restore_flags(flags); - eql_set_best_slave (queue, best_slave); - } /* else */ - if (slave_corpse != 0) - { - printk ("eql: scheduler found dead slave, burying...\n"); - eql_delete_slave (eql_remove_slave (queue, slave_corpse)); - } - return; -} - - static slave_t * eql_find_slave_dev(slave_queue_t *queue, struct net_device *dev) { slave_t *slave = 0; @@ -943,22 +961,6 @@ } -static inline slave_t *eql_first_slave(slave_queue_t *queue) -{ - return queue->head->next; -} - - -static inline slave_t *eql_next_slave(slave_queue_t *queue, slave_t *slave) -{ - return slave->next; -} - -static inline void eql_set_best_slave(slave_queue_t *queue, slave_t *slave) -{ - queue->best_slave = slave; -} - static void eql_timer(unsigned long param) { equalizer_t *eql = (equalizer_t *) param; diff -urN linux-2.4.27/drivers/net/fc/iph5526.c linux-2.4.28/drivers/net/fc/iph5526.c --- linux-2.4.27/drivers/net/fc/iph5526.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/net/fc/iph5526.c 2004-11-17 03:54:21.410390164 -0800 @@ -689,8 +689,8 @@ prev_IMQ_index = current_IMQ_index; } } /*end of for loop*/ - return; LEAVE("tachyon_interrupt"); + return; } @@ -2933,7 +2933,7 @@ { struct fc_info *fi = (struct fc_info*)dev->priv; printk(KERN_WARNING "%s: timed out on send.\n", dev->name); - fi->fc_stats.rx_dropped++; + fi->fc_stats.tx_dropped++; dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -2976,7 +2976,7 @@ fi->fc_stats.tx_packets++; } else - fi->fc_stats.rx_dropped++; + fi->fc_stats.tx_dropped++; dev->trans_start = jiffies; /* We free up the IP buffers in the OCI_interrupt handler. * status == 0 implies that the frame was not transmitted. So the @@ -3374,8 +3374,8 @@ q = q->next; } DPRINTK1("Port Name does not match. Txing LOGO."); - return 0; LEAVE("validate_login"); + return 0; } static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr) @@ -3758,8 +3758,10 @@ sprintf(fi->name, "fc%d", count); host = scsi_register(tmpt, sizeof(struct iph5526_hostdata)); - if(host==NULL) + if(host==NULL) { + kfree(fc[count]); return no_of_hosts; + } hostdata = (struct iph5526_hostdata *)host->hostdata; memset(hostdata, 0 , sizeof(struct iph5526_hostdata)); diff -urN linux-2.4.27/drivers/net/fealnx.c linux-2.4.28/drivers/net/fealnx.c --- linux-2.4.27/drivers/net/fealnx.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/fealnx.c 2004-11-17 03:54:21.411390205 -0800 @@ -1796,7 +1796,7 @@ unsigned long flags; spin_lock_irqsave(lp, flags); __set_rx_mode(dev); - spin_unlock_irqrestore(&lp, flags); + spin_unlock_irqrestore(lp, flags); } diff -urN linux-2.4.27/drivers/net/hamachi.c linux-2.4.28/drivers/net/hamachi.c --- linux-2.4.27/drivers/net/hamachi.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.28/drivers/net/hamachi.c 2004-11-17 03:54:21.413390287 -0800 @@ -1369,109 +1369,6 @@ return 0; } -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) -{ - struct net_device *dev = dev_instance; - struct hamachi_private *hmp; - long ioaddr, boguscnt = max_interrupt_work; - -#ifndef final_version /* Can never occur. */ - if (dev == NULL) { - printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); - return; - } -#endif - - ioaddr = dev->base_addr; - hmp = dev->priv; - spin_lock(&hmp->lock); - - do { - u32 intr_status = readl(ioaddr + InterruptClear); - - if (hamachi_debug > 4) - printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", - dev->name, intr_status); - - if (intr_status == 0) - break; - - if (intr_status & IntrRxDone) - hamachi_rx(dev); - - if (intr_status & IntrTxDone){ - /* This code should RARELY need to execute. After all, this is - * a gigabit link, it should consume packets as fast as we put - * them in AND we clear the Tx ring in hamachi_start_xmit(). - */ - if (hmp->tx_full){ - for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ - int entry = hmp->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - - if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) - break; - skb = hmp->tx_skbuff[entry]; - /* Free the original skb. */ - if (skb){ - pci_unmap_single(hmp->pci_dev, - hmp->tx_ring[entry].addr, - skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - hmp->tx_skbuff[entry] = 0; - } - hmp->tx_ring[entry].status_n_length = 0; - if (entry >= TX_RING_SIZE-1) - hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= - cpu_to_le32(DescEndRing); - hmp->stats.tx_packets++; - } - if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ - /* The ring is no longer full */ - hmp->tx_full = 0; - netif_wake_queue(dev); - } - } else { - netif_wake_queue(dev); - } - } - - - /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & - (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | - LinkChange | NegotiationChange | StatsMax)) - hamachi_error(dev, intr_status); - - if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, intr_status); - break; - } - } while (1); - - if (hamachi_debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); - -#ifndef final_version - /* Code that should never be run! Perhaps remove after testing.. */ - { - static int stopit = 10; - if (dev->start == 0 && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } -#endif - - spin_unlock(&hmp->lock); -} - /* This routine is logically part of the interrupt handler, but seperated for clarity and better register allocation. */ static int hamachi_rx(struct net_device *dev) @@ -1677,6 +1574,109 @@ return 0; } +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = dev_instance; + struct hamachi_private *hmp; + long ioaddr, boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + hmp = dev->priv; + spin_lock(&hmp->lock); + + do { + u32 intr_status = readl(ioaddr + InterruptClear); + + if (hamachi_debug > 4) + printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & IntrRxDone) + hamachi_rx(dev); + + if (intr_status & IntrTxDone){ + /* This code should RARELY need to execute. After all, this is + * a gigabit link, it should consume packets as fast as we put + * them in AND we clear the Tx ring in hamachi_start_xmit(). + */ + if (hmp->tx_full){ + for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ + int entry = hmp->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + + if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) + break; + skb = hmp->tx_skbuff[entry]; + /* Free the original skb. */ + if (skb){ + pci_unmap_single(hmp->pci_dev, + hmp->tx_ring[entry].addr, + skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + hmp->tx_skbuff[entry] = 0; + } + hmp->tx_ring[entry].status_n_length = 0; + if (entry >= TX_RING_SIZE-1) + hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= + cpu_to_le32(DescEndRing); + hmp->stats.tx_packets++; + } + if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ + /* The ring is no longer full */ + hmp->tx_full = 0; + netif_wake_queue(dev); + } + } else { + netif_wake_queue(dev); + } + } + + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & + (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | + LinkChange | NegotiationChange | StatsMax)) + hamachi_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (hamachi_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + spin_unlock(&hmp->lock); +} + /* This is more properly named "uncommon interrupt events", as it covers more than just errors. */ static void hamachi_error(struct net_device *dev, int intr_status) diff -urN linux-2.4.27/drivers/net/hamradio/dmascc.c linux-2.4.28/drivers/net/hamradio/dmascc.c --- linux-2.4.27/drivers/net/hamradio/dmascc.c 2002-02-25 11:37:59.000000000 -0800 +++ linux-2.4.28/drivers/net/hamradio/dmascc.c 2004-11-17 03:54:21.415390370 -0800 @@ -356,6 +356,12 @@ #endif +static inline unsigned char random(void) { + /* See "Numerical Recipes in C", second edition, p. 284 */ + rand = rand * 1664525L + 1013904223L; + return (unsigned char) (rand >> 24); +} + /* Initialization functions */ @@ -950,6 +956,34 @@ } +static inline void z8530_isr(struct scc_info *info) { + int is, i = 100; + + while ((is = read_scc(&info->priv[0], R3)) && i--) { + if (is & CHARxIP) { + rx_isr(&info->priv[0]); + } else if (is & CHATxIP) { + tx_isr(&info->priv[0]); + } else if (is & CHAEXT) { + es_isr(&info->priv[0]); + } else if (is & CHBRxIP) { + rx_isr(&info->priv[1]); + } else if (is & CHBTxIP) { + tx_isr(&info->priv[1]); + } else { + es_isr(&info->priv[1]); + } + write_scc(&info->priv[0], R0, RES_H_IUS); + i++; + } + if (i < 0) { + printk("dmascc: stuck in ISR with RR3=0x%02x.\n", is); + } + /* Ok, no interrupts pending from this 8530. The INT line should + be inactive now. */ +} + + static void scc_isr(int irq, void *dev_id, struct pt_regs * regs) { struct scc_info *info = dev_id; @@ -983,34 +1017,6 @@ } -static inline void z8530_isr(struct scc_info *info) { - int is, i = 100; - - while ((is = read_scc(&info->priv[0], R3)) && i--) { - if (is & CHARxIP) { - rx_isr(&info->priv[0]); - } else if (is & CHATxIP) { - tx_isr(&info->priv[0]); - } else if (is & CHAEXT) { - es_isr(&info->priv[0]); - } else if (is & CHBRxIP) { - rx_isr(&info->priv[1]); - } else if (is & CHBTxIP) { - tx_isr(&info->priv[1]); - } else { - es_isr(&info->priv[1]); - } - write_scc(&info->priv[0], R0, RES_H_IUS); - i++; - } - if (i < 0) { - printk("dmascc: stuck in ISR with RR3=0x%02x.\n", is); - } - /* Ok, no interrupts pending from this 8530. The INT line should - be inactive now. */ -} - - static void rx_isr(struct scc_priv *priv) { if (priv->param.dma >= 0) { /* Check special condition and perform error reset. See 2.4.7.5. */ @@ -1160,6 +1166,90 @@ } +static inline void tx_on(struct scc_priv *priv) { + int i, n; + unsigned long flags; + + if (priv->param.dma >= 0) { + n = (priv->chip == Z85230) ? 3 : 1; + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_WRITE); + set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); + set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); + release_dma_lock(flags); + /* Enable TX underrun interrupt */ + write_scc(priv, R15, TxUIE); + /* Configure DREQ */ + if (priv->type == TYPE_TWIN) + outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, + priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); + /* Write first byte(s) */ + save_flags(flags); + cli(); + for (i = 0; i < n; i++) + write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); + enable_dma(priv->param.dma); + restore_flags(flags); + } else { + write_scc(priv, R15, TxUIE); + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); + tx_isr(priv); + } + /* Reset EOM latch if we do not have the AUTOEOM feature */ + if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); +} + + +static inline void rx_on(struct scc_priv *priv) { + unsigned long flags; + + /* Clear RX FIFO */ + while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); + priv->rx_over = 0; + if (priv->param.dma >= 0) { + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_READ); + set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); + set_dma_count(priv->param.dma, BUF_SIZE); + release_dma_lock(flags); + enable_dma(priv->param.dma); + /* Configure PackeTwin DMA */ + if (priv->type == TYPE_TWIN) { + outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, + priv->card_base + TWIN_DMA_CFG); + } + /* Sp. cond. intr. only, ext int enable, RX DMA enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | + WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); + } else { + /* Reset current frame */ + priv->rx_ptr = 0; + /* Intr. on all Rx characters and Sp. cond., ext int enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | + WT_FN_RDYFN); + } + write_scc(priv, R0, ERR_RES); + write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); +} + + +static inline void rx_off(struct scc_priv *priv) { + /* Disable receiver */ + write_scc(priv, R3, Rx8); + /* Disable DREQ / RX interrupt */ + if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) + outb(0, priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); + /* Disable DMA */ + if (priv->param.dma >= 0) disable_dma(priv->param.dma); +} + + static void es_isr(struct scc_priv *priv) { int i, rr0, drr0, res; unsigned long flags; @@ -1301,90 +1391,6 @@ } -static inline void tx_on(struct scc_priv *priv) { - int i, n; - unsigned long flags; - - if (priv->param.dma >= 0) { - n = (priv->chip == Z85230) ? 3 : 1; - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_WRITE); - set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); - set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); - release_dma_lock(flags); - /* Enable TX underrun interrupt */ - write_scc(priv, R15, TxUIE); - /* Configure DREQ */ - if (priv->type == TYPE_TWIN) - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, - priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); - /* Write first byte(s) */ - save_flags(flags); - cli(); - for (i = 0; i < n; i++) - write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); - enable_dma(priv->param.dma); - restore_flags(flags); - } else { - write_scc(priv, R15, TxUIE); - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); - tx_isr(priv); - } - /* Reset EOM latch if we do not have the AUTOEOM feature */ - if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); -} - - -static inline void rx_on(struct scc_priv *priv) { - unsigned long flags; - - /* Clear RX FIFO */ - while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); - priv->rx_over = 0; - if (priv->param.dma >= 0) { - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_READ); - set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - enable_dma(priv->param.dma); - /* Configure PackeTwin DMA */ - if (priv->type == TYPE_TWIN) { - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, - priv->card_base + TWIN_DMA_CFG); - } - /* Sp. cond. intr. only, ext int enable, RX DMA enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | - WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - /* Reset current frame */ - priv->rx_ptr = 0; - /* Intr. on all Rx characters and Sp. cond., ext int enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | - WT_FN_RDYFN); - } - write_scc(priv, R0, ERR_RES); - write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); -} - - -static inline void rx_off(struct scc_priv *priv) { - /* Disable receiver */ - write_scc(priv, R3, Rx8); - /* Disable DREQ / RX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* Disable DMA */ - if (priv->param.dma >= 0) disable_dma(priv->param.dma); -} - - static void start_timer(struct scc_priv *priv, int t, int r15) { unsigned long flags; @@ -1404,10 +1410,3 @@ } } - -static inline unsigned char random(void) { - /* See "Numerical Recipes in C", second edition, p. 284 */ - rand = rand * 1664525L + 1013904223L; - return (unsigned char) (rand >> 24); -} - diff -urN linux-2.4.27/drivers/net/irda/ma600.c linux-2.4.28/drivers/net/irda/ma600.c --- linux-2.4.27/drivers/net/irda/ma600.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/net/irda/ma600.c 2004-11-17 03:54:21.415390370 -0800 @@ -48,7 +48,7 @@ #undef IRDA_DEBUG #define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args)) - #undef ASSERT(expr, func) + #undef ASSERT #define ASSERT(expr, func) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ diff -urN linux-2.4.27/drivers/net/irda/nsc-ircc.c linux-2.4.28/drivers/net/irda/nsc-ircc.c --- linux-2.4.27/drivers/net/irda/nsc-ircc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/net/irda/nsc-ircc.c 2004-11-17 03:54:21.417390452 -0800 @@ -6,8 +6,8 @@ * Status: Stable. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Wed Mar 1 11:29:34 2000 - * Modified by: Dag Brattli + * Modified at: Sat Aug 14 04:14:57 2004 + * Modified by: Maik Broemme * * Copyright (c) 1998-2000 Dag Brattli * Copyright (c) 1998 Lichen Wang, @@ -369,15 +369,22 @@ } MESSAGE("IrDA: Registered device %s\n", dev->name); - /* Check if user has supplied the dongle id or not */ + /* Check if user has supplied the dongle id and if it is in the range of available ids or not. */ if (!dongle_id) { dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); MESSAGE("%s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]); } else { - MESSAGE("%s, Using dongle: %s\n", driver_name, - dongle_types[dongle_id]); + if (dongle_id < sizeof(dongle_types) / sizeof(dongle_types[0])) { + MESSAGE("%s, Using dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } else { + MESSAGE("%s, dongle id %i out of range, start autodetect.\n", driver_name, dongle_id); + dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); + MESSAGE("%s, Found dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } } self->io.dongle_id = dongle_id; diff -urN linux-2.4.27/drivers/net/ne2k-pci.c linux-2.4.28/drivers/net/ne2k-pci.c --- linux-2.4.27/drivers/net/ne2k-pci.c 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/net/ne2k-pci.c 2004-11-17 03:54:21.418390493 -0800 @@ -505,8 +505,12 @@ insl(NE_BASE + NE_DATAPORT, buf, count>>2); if (count & 3) { buf += count & ~3; - if (count & 2) - *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT)); + if (count & 2) { + u16 *b = (u16 *)buf; + + *b++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT)); + buf = (char *)b; + } if (count & 1) *buf = inb(NE_BASE + NE_DATAPORT); } @@ -566,8 +570,12 @@ outsl(NE_BASE + NE_DATAPORT, buf, count>>2); if (count & 3) { buf += count & ~3; - if (count & 2) - outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT); + if (count & 2) { + u16 *b = (u16 *)buf; + + outw(cpu_to_le16(*b++), NE_BASE + NE_DATAPORT); + buf = (char *)b; + } } } diff -urN linux-2.4.27/drivers/net/ns83820.c linux-2.4.28/drivers/net/ns83820.c --- linux-2.4.27/drivers/net/ns83820.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/net/ns83820.c 2004-11-17 03:54:21.419390534 -0800 @@ -587,7 +587,7 @@ } static void FASTCALL(rx_refill_atomic(struct ns83820 *dev)); -static void rx_refill_atomic(struct ns83820 *dev) +static void fastcall rx_refill_atomic(struct ns83820 *dev) { rx_refill(dev, GFP_ATOMIC); } @@ -608,7 +608,7 @@ } static void FASTCALL(phy_intr(struct ns83820 *dev)); -static void phy_intr(struct ns83820 *dev) +static void fastcall phy_intr(struct ns83820 *dev) { static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; @@ -793,7 +793,7 @@ } static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev)); -static void ns83820_rx_kick(struct ns83820 *dev) +static void fastcall ns83820_rx_kick(struct ns83820 *dev) { /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { if (dev->rx_info.up) { @@ -814,7 +814,7 @@ * */ static void FASTCALL(rx_irq(struct ns83820 *dev)); -static void rx_irq(struct ns83820 *dev) +static void fastcall rx_irq(struct ns83820 *dev) { struct rx_info *info = &dev->rx_info; unsigned next_rx; @@ -1585,6 +1585,7 @@ dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops); } +#ifdef PHY_CODE_IS_FINISHED static void ns83820_mii_write_bit(struct ns83820 *dev, int bit) { /* drive MDC low */ @@ -1757,6 +1758,7 @@ dprintk("version: 0x%04x 0x%04x\n", a, b); } } +#endif static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) { diff -urN linux-2.4.27/drivers/net/pcnet32.c linux-2.4.28/drivers/net/pcnet32.c --- linux-2.4.27/drivers/net/pcnet32.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/pcnet32.c 2004-11-17 03:54:21.421390616 -0800 @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.30c" -#define DRV_RELDATE "05.25.2004" +#define DRV_VERSION "1.30h" +#define DRV_RELDATE "06.24.2004" #define PFX DRV_NAME ": " static const char *version = @@ -137,6 +137,7 @@ #define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; +static int homepna[MAX_UNITS]; /* * Theory of Operation @@ -245,6 +246,14 @@ * v1.30b 24 May 2004 Don Fry fix bogus tx carrier errors with 79c973, * assisted by Bruce Penrod . * v1.30c 25 May 2004 Don Fry added netif_wake_queue after pcnet32_restart. + * v1.30d 01 Jun 2004 Don Fry discard oversize rx packets. + * v1.30e 11 Jun 2004 Don Fry recover after fifo error and rx hang. + * v1.30f 16 Jun 2004 Don Fry cleanup IRQ to allow 0 and 1 for PCI, + * expanding on suggestions from Ralf Baechle , + * and Brian Murphy . + * v1.30g 22 Jun 2004 Patrick Simmons added option + * homepna for selecting HomePNA mode for PCNet/Home 79C978. + * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. */ @@ -360,7 +369,7 @@ static void pcnet32_probe_vlbus(void); static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); -static int pcnet32_probe1(unsigned long, unsigned int, int, struct pci_dev *); +static int pcnet32_probe1(unsigned long, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); @@ -957,7 +966,7 @@ if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { /* check if there is really a pcnet chip on that ioaddr */ if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) { - pcnet32_probe1(ioaddr, 0, 0, NULL); + pcnet32_probe1(ioaddr, 0, NULL); } else { release_region(ioaddr, PCNET32_TOTAL_SIZE); } @@ -998,7 +1007,7 @@ return -EBUSY; } - return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev); + return pcnet32_probe1(ioaddr, 1, pdev); } @@ -1007,8 +1016,7 @@ * pdev will be NULL when called from pcnet32_probe_vlbus. */ static int __devinit -pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, - struct pci_dev *pdev) +pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { struct pcnet32_private *lp; dma_addr_t lp_dma_addr; @@ -1079,15 +1087,17 @@ fdx = 1; /* * This is based on specs published at www.amd.com. This section - * assumes that a card with a 79C978 wants to go into 1Mb HomePNA - * mode. The 79C978 can also go into standard ethernet, and there - * probably should be some sort of module option to select the - * mode by which the card should operate + * assumes that a card with a 79C978 wants to go into standard + * ethernet mode. The 79C978 can also go into 1Mb HomePNA mode, + * and the module option homepna=1 can select this instead. */ - /* switch to home wiring mode */ media = a->read_bcr(ioaddr, 49); + media &= ~3; /* default to 10Mb ethernet */ + if (cards_found < MAX_UNITS && homepna[cards_found]) + media |= 1; /* switch to home wiring mode */ if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_DEBUG PFX "media reset to %#x.\n", media); + printk(KERN_DEBUG PFX "media set to %dMbit mode.\n", + (media & 1) ? 1 : 10); a->write_bcr(ioaddr, 49, media); break; case 0x2627: @@ -1269,11 +1279,8 @@ a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); - if (irq_line) { - dev->irq = irq_line; - } - - if (dev->irq >= 2) { + if (pdev) { /* use the IRQ provided by PCI */ + dev->irq = pdev->irq; if (pcnet32_debug & NETIF_MSG_PROBE) printk(" assigned IRQ %d.\n", dev->irq); } else { @@ -1361,8 +1368,7 @@ int rc; unsigned long flags; - if (dev->irq == 0 || - request_irq(dev->irq, &pcnet32_interrupt, + if (request_irq(dev->irq, &pcnet32_interrupt, lp->shared_irq ? SA_SHIRQ : 0, dev->name, (void *)dev)) { return -EAGAIN; } @@ -1416,9 +1422,13 @@ val |= 0x10; lp->a.write_csr (ioaddr, 124, val); + /* 24 Jun 2004 according AMD, in order to change the PHY, + * DANAS (or DISPM for 79C976) must be set; then select the speed, + * duplex, and/or enable auto negotiation, and clear DANAS */ if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); /* disable Auto Negotiation, set 10Mpbs, HD */ - val = lp->a.read_bcr (ioaddr, 32) & ~0x38; + val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; if (lp->options & PCNET32_PORT_FD) val |= 0x10; if (lp->options & PCNET32_PORT_100) @@ -1426,6 +1436,7 @@ lp->a.write_bcr (ioaddr, 32, val); } else { if (lp->options & PCNET32_PORT_ASEL) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); /* enable auto negotiate, setup, disable fd */ val = lp->a.read_bcr(ioaddr, 32) & ~0x98; val |= 0x20; @@ -1530,13 +1541,15 @@ int i; for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(lp->tx_skbuff[i]); - lp->tx_skbuff[i] = NULL; - lp->tx_dma_addr[i] = 0; } + lp->tx_skbuff[i] = NULL; + lp->tx_dma_addr[i] = 0; } } @@ -1565,21 +1578,23 @@ skb_reserve (rx_skbuff, 2); } + rmb(); if (lp->rx_dma_addr[i] == 0) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); + wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[i].status = le16_to_cpu(0x8000); } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ lp->tx_ring[i].base = 0; - lp->tx_ring[i].status = 0; lp->tx_dma_addr[i] = 0; } - wmb(); /* Make sure all changes are visible */ lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); for (i = 0; i < 6; i++) @@ -1588,9 +1603,14 @@ offsetof(struct pcnet32_private, rx_ring)); lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)); + wmb(); /* Make sure all changes are visible */ return 0; } +/* the pcnet32 has been issued a stop or reset. Wait for the stop bit + * then flush the pending transmit operations, re-initialize the ring, + * and tell the chip to initialize. + */ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { @@ -1598,6 +1618,15 @@ unsigned long ioaddr = dev->base_addr; int i; + /* wait for stop */ + for (i=0; i<100; i++) + if (lp->a.read_csr(ioaddr, 0) & 0x0004) + break; + + if (i >= 100 && netif_msg_drv(lp)) + printk(KERN_ERR "%s: pcnet32_restart timed out waiting for stop.\n", + dev->name); + pcnet32_purge_tx_ring(dev); if (pcnet32_init_ring(dev)) return; @@ -1734,7 +1763,7 @@ spin_lock(&lp->lock); rap = lp->a.read_rap(ioaddr); - while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { + while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) { if (csr0 == 0xffff) { break; /* PCMCIA remove happened */ } @@ -1856,15 +1885,16 @@ } if (must_restart) { - /* stop the chip to clear the error condition, then restart */ - lp->a.write_csr (ioaddr, 0, 0x0004); + /* reset the chip to clear the error condition, then restart */ + lp->a.reset(ioaddr); + lp->a.write_csr(ioaddr, 4, 0x0915); pcnet32_restart(dev, 0x0002); netif_wake_queue(dev); } } - /* Clear any other interrupt, and set interrupt enable. */ - lp->a.write_csr (ioaddr, 0, 0x7940); + /* Set interrupt enable. */ + lp->a.write_csr (ioaddr, 0, 0x0040); lp->a.write_rap (ioaddr,rap); if (netif_msg_intr(lp)) @@ -1904,7 +1934,13 @@ short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; struct sk_buff *skb; - if (pkt_len < 60) { + /* Discard oversize frames. */ + if (unlikely(pkt_len > PKT_BUF_SZ - 2)) { + if (netif_msg_drv(lp)) + printk(KERN_ERR "%s: Impossible packet size %d!\n", + dev->name, pkt_len); + lp->stats.rx_errors++; + } else if (pkt_len < 60) { if (netif_msg_rx_err(lp)) printk(KERN_ERR "%s: Runt packet!\n", dev->name); lp->stats.rx_errors++; @@ -2230,6 +2266,9 @@ MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)"); +/* Module Parameter for HomePNA cards added by Patrick Simmons, 2004 */ +MODULE_PARM(homepna,"1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(homepna, DRV_NAME " mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet"); MODULE_AUTHOR("Thomas Bogendoerfer"); MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards"); diff -urN linux-2.4.27/drivers/net/skfp/skfddi.c linux-2.4.28/drivers/net/skfp/skfddi.c --- linux-2.4.27/drivers/net/skfp/skfddi.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/net/skfp/skfddi.c 2004-11-17 03:54:21.423390699 -0800 @@ -1363,7 +1363,7 @@ */ if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { - bp->MacStat.tx_errors++; /* bump error counter */ + bp->MacStat.gen.tx_errors++; /* bump error counter */ // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); @@ -1814,8 +1814,8 @@ skb->len, PCI_DMA_TODEVICE); txd->txd_os.dma_addr = 0; - smc->os.MacStat.tx_packets++; // Count transmitted packets. - smc->os.MacStat.tx_bytes+=skb->len; // Count bytes + smc->os.MacStat.gen.tx_packets++; // Count transmitted packets. + smc->os.MacStat.gen.tx_bytes+=skb->len; // Count bytes // free the skb dev_kfree_skb_irq(skb); @@ -1897,7 +1897,7 @@ skb = rxd->rxd_os.skb; if (!skb) { PRINTK(KERN_INFO "No skb in rxd\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; goto RequeueRxd; } virt = skb->data; @@ -1950,13 +1950,14 @@ } // Count statistics. - smc->os.MacStat.rx_packets++; // Count indicated receive packets. - smc->os.MacStat.rx_bytes+=len; // Count bytes + smc->os.MacStat.gen.rx_packets++; // Count indicated receive + // packets. + smc->os.MacStat.gen.rx_bytes+=len; // Count bytes. // virt points to header again if (virt[1] & 0x01) { // Check group (multicast) bit. - smc->os.MacStat.multicast++; + smc->os.MacStat.gen.multicast++; } // deliver frame to system @@ -1974,7 +1975,8 @@ RequeueRxd: PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); mac_drv_requeue_rxd(smc, rxd, frag_count); - smc->os.MacStat.rx_errors++; // Count receive packets not indicated. + smc->os.MacStat.gen.rx_errors++; // Count receive packets + // not indicated. } // mac_drv_rx_complete @@ -2349,7 +2351,7 @@ break; case 1: PRINTK(KERN_INFO "Receive fifo overflow.\n"); - smc->os.MacStat.rx_errors++; + smc->os.MacStat.gen.rx_errors++; break; default: PRINTK(KERN_INFO "Unknown status (%d).\n", stat); diff -urN linux-2.4.27/drivers/net/smc9194.c linux-2.4.28/drivers/net/smc9194.c --- linux-2.4.27/drivers/net/smc9194.c 2003-06-13 07:51:35.000000000 -0700 +++ linux-2.4.28/drivers/net/smc9194.c 2004-11-17 03:54:21.425390781 -0800 @@ -1132,131 +1132,6 @@ netif_wake_queue(dev); } -/*-------------------------------------------------------------------- - . - . This is the main routine of the driver, to handle the device when - . it needs some attention. - . - . So: - . first, save state of the chipset - . branch off into routines to handle each case, and acknowledge - . each to the interrupt register - . and finally restore state. - . - ---------------------------------------------------------------------*/ - -static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; - - byte status; - word card_stats; - byte mask; - int timeout; - /* state registers */ - word saved_bank; - word saved_pointer; - - - - PRINTK3((CARDNAME": SMC interrupt started \n")); - - saved_bank = inw( ioaddr + BANK_SELECT ); - - SMC_SELECT_BANK(2); - saved_pointer = inw( ioaddr + POINTER ); - - mask = inb( ioaddr + INT_MASK ); - /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); - - - /* set a timeout value, so I don't stay here forever */ - timeout = 4; - - PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); - do { - /* read the status flag, and mask it */ - status = inb( ioaddr + INTERRUPT ) & mask; - if (!status ) - break; - - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x \n", status )); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); - smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); - smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { - /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats = inw( ioaddr + COUNTER ); - /* single collisions */ - lp->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; - - /* these are for when linux supports these statistics */ - - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); - mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; - - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt \n")); - /* clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet( dev ); - - /* enable xmit interrupts based on this */ - mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); - } - } while ( timeout -- ); - - - /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); - - PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); - outw( saved_pointer, ioaddr + POINTER ); - - SMC_SELECT_BANK( saved_bank ); - - PRINTK3((CARDNAME ": Interrupt done\n")); - return; -} - /*------------------------------------------------------------- . . smc_rcv - receive a packet from the card @@ -1448,6 +1323,131 @@ return; } +/*-------------------------------------------------------------------- + . + . This is the main routine of the driver, to handle the device when + . it needs some attention. + . + . So: + . first, save state of the chipset + . branch off into routines to handle each case, and acknowledge + . each to the interrupt register + . and finally restore state. + . + ---------------------------------------------------------------------*/ + +static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + + byte status; + word card_stats; + byte mask; + int timeout; + /* state registers */ + word saved_bank; + word saved_pointer; + + + + PRINTK3((CARDNAME": SMC interrupt started \n")); + + saved_bank = inw( ioaddr + BANK_SELECT ); + + SMC_SELECT_BANK(2); + saved_pointer = inw( ioaddr + POINTER ); + + mask = inb( ioaddr + INT_MASK ); + /* clear all interrupts */ + outb( 0, ioaddr + INT_MASK ); + + + /* set a timeout value, so I don't stay here forever */ + timeout = 4; + + PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); + do { + /* read the status flag, and mask it */ + status = inb( ioaddr + INTERRUPT ) & mask; + if (!status ) + break; + + PRINTK3((KERN_WARNING CARDNAME + ": Handling interrupt status %x \n", status )); + + if (status & IM_RCV_INT) { + /* Got a packet(s). */ + PRINTK2((KERN_WARNING CARDNAME + ": Receive Interrupt\n")); + smc_rcv(dev); + } else if (status & IM_TX_INT ) { + PRINTK2((KERN_WARNING CARDNAME + ": TX ERROR handled\n")); + smc_tx(dev); + outb(IM_TX_INT, ioaddr + INTERRUPT ); + } else if (status & IM_TX_EMPTY_INT ) { + /* update stats */ + SMC_SELECT_BANK( 0 ); + card_stats = inw( ioaddr + COUNTER ); + /* single collisions */ + lp->stats.collisions += card_stats & 0xF; + card_stats >>= 4; + /* multiple collisions */ + lp->stats.collisions += card_stats & 0xF; + + /* these are for when linux supports these statistics */ + + SMC_SELECT_BANK( 2 ); + PRINTK2((KERN_WARNING CARDNAME + ": TX_BUFFER_EMPTY handled\n")); + outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); + mask &= ~IM_TX_EMPTY_INT; + lp->stats.tx_packets += lp->packets_waiting; + lp->packets_waiting = 0; + + } else if (status & IM_ALLOC_INT ) { + PRINTK2((KERN_DEBUG CARDNAME + ": Allocation interrupt \n")); + /* clear this interrupt so it doesn't happen again */ + mask &= ~IM_ALLOC_INT; + + smc_hardware_send_packet( dev ); + + /* enable xmit interrupts based on this */ + mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); + + /* and let the card send more packets to me */ + netif_wake_queue(dev); + + PRINTK2((CARDNAME": Handoff done successfully.\n")); + } else if (status & IM_RX_OVRN_INT ) { + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); + } else if (status & IM_EPH_INT ) { + PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); + } else if (status & IM_ERCV_INT ) { + PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); + outb( IM_ERCV_INT, ioaddr + INTERRUPT ); + } + } while ( timeout -- ); + + + /* restore state register */ + SMC_SELECT_BANK( 2 ); + outb( mask, ioaddr + INT_MASK ); + + PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); + outw( saved_pointer, ioaddr + POINTER ); + + SMC_SELECT_BANK( saved_bank ); + + PRINTK3((CARDNAME ": Interrupt done\n")); + return; +} + /*---------------------------------------------------- . smc_close . diff -urN linux-2.4.27/drivers/net/sungem.c linux-2.4.28/drivers/net/sungem.c --- linux-2.4.27/drivers/net/sungem.c 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/net/sungem.c 2004-11-17 03:54:21.427390863 -0800 @@ -2920,7 +2920,7 @@ */ if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_GEM && - !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { pci_using_dac = 1; } else { err = pci_set_dma_mask(pdev, (u64) 0xffffffff); diff -urN linux-2.4.27/drivers/net/sungem.h linux-2.4.28/drivers/net/sungem.h --- linux-2.4.27/drivers/net/sungem.h 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/net/sungem.h 2004-11-17 03:54:21.428390904 -0800 @@ -805,14 +805,14 @@ u64 buffer; }; -#define TXDCTRL_BUFSZ 0x0000000000007fff /* Buffer Size */ -#define TXDCTRL_CSTART 0x00000000001f8000 /* CSUM Start Offset */ -#define TXDCTRL_COFF 0x000000001fe00000 /* CSUM Stuff Offset */ -#define TXDCTRL_CENAB 0x0000000020000000 /* CSUM Enable */ -#define TXDCTRL_EOF 0x0000000040000000 /* End of Frame */ -#define TXDCTRL_SOF 0x0000000080000000 /* Start of Frame */ -#define TXDCTRL_INTME 0x0000000100000000 /* "Interrupt Me" */ -#define TXDCTRL_NOCRC 0x0000000200000000 /* No CRC Present */ +#define TXDCTRL_BUFSZ 0x0000000000007fffULL /* Buffer Size */ +#define TXDCTRL_CSTART 0x00000000001f8000ULL /* CSUM Start Offset */ +#define TXDCTRL_COFF 0x000000001fe00000ULL /* CSUM Stuff Offset */ +#define TXDCTRL_CENAB 0x0000000020000000ULL /* CSUM Enable */ +#define TXDCTRL_EOF 0x0000000040000000ULL /* End of Frame */ +#define TXDCTRL_SOF 0x0000000080000000ULL /* Start of Frame */ +#define TXDCTRL_INTME 0x0000000100000000ULL /* "Interrupt Me" */ +#define TXDCTRL_NOCRC 0x0000000200000000ULL /* No CRC Present */ /* GEM requires that RX descriptors are provided four at a time, * aligned. Also, the RX ring may not wrap around. This means that @@ -840,13 +840,13 @@ u64 buffer; }; -#define RXDCTRL_TCPCSUM 0x000000000000ffff /* TCP Pseudo-CSUM */ -#define RXDCTRL_BUFSZ 0x000000007fff0000 /* Buffer Size */ -#define RXDCTRL_OWN 0x0000000080000000 /* GEM owns this entry */ -#define RXDCTRL_HASHVAL 0x0ffff00000000000 /* Hash Value */ -#define RXDCTRL_HPASS 0x1000000000000000 /* Passed Hash Filter */ -#define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ -#define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ +#define RXDCTRL_TCPCSUM 0x000000000000ffffULL /* TCP Pseudo-CSUM */ +#define RXDCTRL_BUFSZ 0x000000007fff0000ULL /* Buffer Size */ +#define RXDCTRL_OWN 0x0000000080000000ULL /* GEM owns this entry */ +#define RXDCTRL_HASHVAL 0x0ffff00000000000ULL /* Hash Value */ +#define RXDCTRL_HPASS 0x1000000000000000ULL /* Passed Hash Filter */ +#define RXDCTRL_ALTMAC 0x2000000000000000ULL /* Matched ALT MAC */ +#define RXDCTRL_BAD 0x4000000000000000ULL /* Frame has bad CRC */ #define RXDCTRL_FRESH(gp) \ ((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ diff -urN linux-2.4.27/drivers/net/tg3.c linux-2.4.28/drivers/net/tg3.c --- linux-2.4.27/drivers/net/tg3.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/tg3.c 2004-11-17 03:54:21.437391274 -0800 @@ -4,6 +4,9 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. + * + * Firmware is: + * Copyright (C) 2000-2003 Broadcom Corporation. */ #include @@ -56,8 +59,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.8" -#define DRV_MODULE_RELDATE "July 14, 2004" +#define DRV_MODULE_VERSION "3.14" +#define DRV_MODULE_RELDATE "November 15, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -201,6 +204,14 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX, @@ -441,9 +452,14 @@ 0x1f); tp->pci_clock_ctrl = clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { + tw32_f(TG3PCI_CLOCK_CTRL, + clock_ctrl | CLOCK_CTRL_625_CORE); + udelay(40); + } + } else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); @@ -857,34 +873,54 @@ GRC_LCLCTRL_GPIO_OUTPUT1)); udelay(100); } else { + int no_gpio2; + u32 grc_local_ctrl; + if (tp_peer != tp && (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) return; + /* On 5753 and variants, GPIO2 cannot be used. */ + no_gpio2 = (tp->nic_sram_data_cfg & + NIC_SRAM_DATA_CFG_NO_GPIO2) != 0; + + grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + GRC_LCLCTRL_GPIO_OUTPUT2; + if (no_gpio2) { + grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT2); + } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - (GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT1 | - GRC_LCLCTRL_GPIO_OUTPUT2)); + grc_local_ctrl); udelay(100); + grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + GRC_LCLCTRL_GPIO_OUTPUT2; + if (no_gpio2) { + grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT2); + } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - (GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | - GRC_LCLCTRL_GPIO_OUTPUT1 | - GRC_LCLCTRL_GPIO_OUTPUT2)); + grc_local_ctrl); udelay(100); - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - (GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | - GRC_LCLCTRL_GPIO_OUTPUT1)); - udelay(100); + grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1; + if (!no_gpio2) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + grc_local_ctrl); + udelay(100); + } } } else { if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && @@ -979,7 +1015,7 @@ tp->link_config.orig_autoneg = tp->link_config.autoneg; } - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->link_config.speed = SPEED_10; tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; @@ -991,7 +1027,7 @@ if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { u32 mac_mode; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); udelay(40); @@ -1113,29 +1149,33 @@ u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (local_adv & ADVERTISE_PAUSE_CAP) { - if (local_adv & ADVERTISE_PAUSE_ASYM) { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); - else if (remote_adv & LPA_PAUSE_ASYM) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE); - } else { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); + if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) { + if (local_adv & ADVERTISE_PAUSE_CAP) { + if (local_adv & ADVERTISE_PAUSE_ASYM) { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + else if (remote_adv & LPA_PAUSE_ASYM) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE); + } else { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + } + } else if (local_adv & ADVERTISE_PAUSE_ASYM) { + if ((remote_adv & LPA_PAUSE_CAP) && + (remote_adv & LPA_PAUSE_ASYM)) + new_tg3_flags |= TG3_FLAG_TX_PAUSE; } - } else if (local_adv & ADVERTISE_PAUSE_ASYM) { - if ((remote_adv & LPA_PAUSE_CAP) && - (remote_adv & LPA_PAUSE_ASYM)) - new_tg3_flags |= TG3_FLAG_TX_PAUSE; - } - tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); - tp->tg3_flags |= new_tg3_flags; + tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); + tp->tg3_flags |= new_tg3_flags; + } else { + new_tg3_flags = tp->tg3_flags; + } if (new_tg3_flags & TG3_FLAG_RX_PAUSE) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; @@ -1486,6 +1526,18 @@ current_speed = SPEED_INVALID; current_duplex = DUPLEX_INVALID; + if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) { + u32 val; + + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007); + tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); + if (!(val & (1 << 10))) { + val |= (1 << 10); + tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + goto relink; + } + } + bmsr = 0; for (i = 0; i < 100; i++) { tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1565,7 +1617,7 @@ tg3_setup_flow_control(tp, local_adv, remote_adv); } } - +relink: if (current_link_up == 0) { u32 tmp; @@ -1615,7 +1667,7 @@ tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) { + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { /* Polled via timer. */ tw32_f(MAC_EVENT, 0); } else { @@ -1964,62 +2016,273 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags) { int res = 0; + struct tg3_fiber_aneginfo aninfo; + int status = ANEG_FAILED; + unsigned int tick; + u32 tmp; - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - u32 dig_status; + tw32_f(MAC_TX_AUTO_NEG, 0); - dig_status = tr32(SG_DIG_STATUS); - *flags = 0; - if (dig_status & SG_DIG_PARTNER_ASYM_PAUSE) - *flags |= MR_LP_ADV_ASYM_PAUSE; - if (dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE) - *flags |= MR_LP_ADV_SYM_PAUSE; - - if ((dig_status & SG_DIG_AUTONEG_COMPLETE) && - !(dig_status & (SG_DIG_AUTONEG_ERROR | - SG_DIG_PARTNER_FAULT_MASK))) - res = 1; - } else { - struct tg3_fiber_aneginfo aninfo; - int status = ANEG_FAILED; - unsigned int tick; - u32 tmp; + tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; + tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); + udelay(40); + + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); + udelay(40); - tw32_f(MAC_TX_AUTO_NEG, 0); + memset(&aninfo, 0, sizeof(aninfo)); + aninfo.flags |= MR_AN_ENABLE; + aninfo.state = ANEG_STATE_UNKNOWN; + aninfo.cur_time = 0; + tick = 0; + while (++tick < 195000) { + status = tg3_fiber_aneg_smachine(tp, &aninfo); + if (status == ANEG_DONE || status == ANEG_FAILED) + break; - tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - udelay(40); + udelay(1); + } - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); - udelay(40); + tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); + + *flags = aninfo.flags; + + if (status == ANEG_DONE && + (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | + MR_LP_ADV_FULL_DUPLEX))) + res = 1; + + return res; +} + +static void tg3_init_bcm8002(struct tg3 *tp) +{ + u32 mac_status = tr32(MAC_STATUS); + int i; + + /* Reset when initting first time or we have a link. */ + if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) && + !(mac_status & MAC_STATUS_PCS_SYNCED)) + return; + + /* Set PLL lock range. */ + tg3_writephy(tp, 0x16, 0x8007); + + /* SW reset */ + tg3_writephy(tp, MII_BMCR, BMCR_RESET); + + /* Wait for reset to complete. */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 500; i++) + udelay(10); + + /* Config mode; select PMA/Ch 1 regs. */ + tg3_writephy(tp, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + tg3_writephy(tp, 0x11, 0x0a10); + + tg3_writephy(tp, 0x18, 0x00a0); + tg3_writephy(tp, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + tg3_writephy(tp, 0x13, 0x0400); + udelay(40); + tg3_writephy(tp, 0x13, 0x0000); + + tg3_writephy(tp, 0x11, 0x0a50); + udelay(40); + tg3_writephy(tp, 0x11, 0x0a10); + + /* Wait for signal to stabilize */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 15000; i++) + udelay(10); + + /* Deselect the channel register so we can read the PHYID + * later. + */ + tg3_writephy(tp, 0x10, 0x8011); +} + +static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) +{ + u32 sg_dig_ctrl, sg_dig_status; + u32 serdes_cfg, expected_sg_dig_ctrl; + int workaround, port_a; + int current_link_up; - memset(&aninfo, 0, sizeof(aninfo)); - aninfo.flags |= MR_AN_ENABLE; - aninfo.state = ANEG_STATE_UNKNOWN; - aninfo.cur_time = 0; - tick = 0; - while (++tick < 195000) { - status = tg3_fiber_aneg_smachine(tp, &aninfo); - if (status == ANEG_DONE || status == ANEG_FAILED) + serdes_cfg = 0; + expected_sg_dig_ctrl = 0; + workaround = 0; + port_a = 1; + current_link_up = 0; + + if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 && + tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) { + workaround = 1; + if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) + port_a = 0; + + serdes_cfg = tr32(MAC_SERDES_CFG) & + ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20)); + } + + sg_dig_ctrl = tr32(SG_DIG_CTRL); + + if (tp->link_config.autoneg != AUTONEG_ENABLE) { + if (sg_dig_ctrl & (1 << 31)) { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; + tw32_f(MAC_SERDES_CFG, val); + } + tw32_f(SG_DIG_CTRL, 0x01388400); + } + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + goto out; + } + + /* Want auto-negotiation. */ + expected_sg_dig_ctrl = 0x81388400; + + /* Pause capability */ + expected_sg_dig_ctrl |= (1 << 11); + + /* Asymettric pause */ + expected_sg_dig_ctrl |= (1 << 12); + + if (sg_dig_ctrl != expected_sg_dig_ctrl) { + if (workaround) + tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011880); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); + udelay(5); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); + + tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED; + } else if (mac_status & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + int i; + + /* Giver time to negotiate (~200ms) */ + for (i = 0; i < 40000; i++) { + sg_dig_status = tr32(SG_DIG_STATUS); + if (sg_dig_status & (0x3)) break; + udelay(5); + } + mac_status = tr32(MAC_STATUS); - udelay(1); + if ((sg_dig_status & (1 << 1)) && + (mac_status & MAC_STATUS_PCS_SYNCED)) { + u32 local_adv, remote_adv; + + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (sg_dig_status & (1 << 19)) + remote_adv |= LPA_PAUSE_CAP; + if (sg_dig_status & (1 << 20)) + remote_adv |= LPA_PAUSE_ASYM; + + tg3_setup_flow_control(tp, local_adv, remote_adv); + current_link_up = 1; + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + } else if (!(sg_dig_status & (1 << 1))) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) + tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; + else { + if (workaround) { + u32 val = serdes_cfg; + + if (port_a) + val |= 0xc010880; + else + val |= 0x4010880; + + tw32_f(MAC_SERDES_CFG, val); + } + + tw32_f(SG_DIG_CTRL, 0x01388400); + udelay(40); + + mac_status = tr32(MAC_STATUS); + if (mac_status & MAC_STATUS_PCS_SYNCED) { + tg3_setup_flow_control(tp, 0, 0); + current_link_up = 1; + } + } } + } - tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); +out: + return current_link_up; +} - *flags = aninfo.flags; +static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) +{ + int current_link_up = 0; - if (status == ANEG_DONE && - (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | - MR_LP_ADV_FULL_DUPLEX))) - res = 1; + if (!(mac_status & MAC_STATUS_PCS_SYNCED)) { + tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + goto out; } - return res; + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + u32 flags; + int i; + + if (fiber_autoneg(tp, &flags)) { + u32 local_adv, remote_adv; + + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (flags & MR_LP_ADV_SYM_PAUSE) + remote_adv |= LPA_PAUSE_CAP; + if (flags & MR_LP_ADV_ASYM_PAUSE) + remote_adv |= LPA_PAUSE_ASYM; + + tg3_setup_flow_control(tp, local_adv, remote_adv); + + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + current_link_up = 1; + } + for (i = 0; i < 30; i++) { + udelay(20); + tw32_f(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(40); + if ((tr32(MAC_STATUS) & + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + mac_status = tr32(MAC_STATUS); + if (current_link_up == 0 && + (mac_status & MAC_STATUS_PCS_SYNCED) && + !(mac_status & MAC_STATUS_RCVD_CFG)) + current_link_up = 1; + } else { + /* Forcing 1000FD link up. */ + current_link_up = 1; + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; + + tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS)); + udelay(40); + } + +out: + return current_link_up; } static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) @@ -2027,6 +2290,7 @@ u32 orig_pause_cfg; u16 orig_active_speed; u8 orig_active_duplex; + u32 mac_status; int current_link_up; int i; @@ -2036,118 +2300,43 @@ orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; - tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); - tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); - - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) { - /* Allow time for the hardware to auto-negotiate (195ms) */ - unsigned int tick = 0; - - while (++tick < 195000) { - if (tr32(SG_DIG_STATUS) & SG_DIG_AUTONEG_COMPLETE) - break; - udelay(1); + if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) && + netif_carrier_ok(tp->dev) && + (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) { + mac_status = tr32(MAC_STATUS); + mac_status &= (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET | + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_RCVD_CFG); + if (mac_status == (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET)) { + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + return 0; } - if (tick >= 195000) - printk(KERN_INFO PFX "%s: HW autoneg failed !\n", - tp->dev->name); } - /* Reset when initting first time or we have a link. */ - if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - /* Set PLL lock range. */ - tg3_writephy(tp, 0x16, 0x8007); - - /* SW reset */ - tg3_writephy(tp, MII_BMCR, BMCR_RESET); - - /* Wait for reset to complete. */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 500; i++) - udelay(10); - - /* Config mode; select PMA/Ch 1 regs. */ - tg3_writephy(tp, 0x10, 0x8411); - - /* Enable auto-lock and comdet, select txclk for tx. */ - tg3_writephy(tp, 0x11, 0x0a10); - - tg3_writephy(tp, 0x18, 0x00a0); - tg3_writephy(tp, 0x16, 0x41ff); - - /* Assert and deassert POR. */ - tg3_writephy(tp, 0x13, 0x0400); - udelay(40); - tg3_writephy(tp, 0x13, 0x0000); - - tg3_writephy(tp, 0x11, 0x0a50); - udelay(40); - tg3_writephy(tp, 0x11, 0x0a10); + tw32_f(MAC_TX_AUTO_NEG, 0); - /* Wait for signal to stabilize */ - /* XXX schedule_timeout() ... */ - for (i = 0; i < 15000; i++) - udelay(10); + tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); + tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); - /* Deselect the channel register so we can read the PHYID - * later. - */ - tg3_writephy(tp, 0x10, 0x8011); - } + if (tp->phy_id == PHY_ID_BCM8002) + tg3_init_bcm8002(tp); - /* Enable link change interrupt unless serdes polling. */ - if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES)) - tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); - else - tw32_f(MAC_EVENT, 0); + /* Enable link change event even when serdes polling. */ + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); udelay(40); current_link_up = 0; - if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - u32 flags; - - if (fiber_autoneg(tp, &flags)) { - u32 local_adv, remote_adv; + mac_status = tr32(MAC_STATUS); - local_adv = ADVERTISE_PAUSE_CAP; - remote_adv = 0; - if (flags & MR_LP_ADV_SYM_PAUSE) - remote_adv |= LPA_PAUSE_CAP; - if (flags & MR_LP_ADV_ASYM_PAUSE) - remote_adv |= LPA_PAUSE_ASYM; - - tg3_setup_flow_control(tp, local_adv, remote_adv); - - tp->tg3_flags |= - TG3_FLAG_GOT_SERDES_FLOWCTL; - current_link_up = 1; - } - for (i = 0; i < 60; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) - break; - } - if (current_link_up == 0 && - (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { - current_link_up = 1; - } - } else { - /* Forcing 1000FD link up. */ - current_link_up = 1; - tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; - } - } else - tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; + if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) + current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status); + else + current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; tw32_f(MAC_MODE, tp->mac_mode); @@ -2158,19 +2347,24 @@ (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { - udelay(20); - tw32_f(MAC_STATUS, - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - udelay(40); - if ((tr32(MAC_STATUS) & - (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)) == 0) + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(5); + if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) break; } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) + mac_status = tr32(MAC_STATUS); + if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) { current_link_up = 0; + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + tw32_f(MAC_MODE, (tp->mac_mode | + MAC_MODE_SEND_CONFIGS)); + udelay(1); + tw32_f(MAC_MODE, tp->mac_mode); + } + } if (current_link_up == 1) { tp->link_config.active_speed = SPEED_1000; @@ -2202,15 +2396,6 @@ tg3_link_report(tp); } - if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { - tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); - udelay(40); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - tw32_f(MAC_MODE, tp->mac_mode); - udelay(40); - } - } - return 0; } @@ -2218,7 +2403,7 @@ { int err; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { err = tg3_setup_fiber_phy(tp, force_reset); } else { err = tg3_setup_copper_phy(tp, force_reset); @@ -2736,11 +2921,11 @@ tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); - if (restart_timer) mod_timer(&tp->timer, jiffies + 1); } @@ -2810,6 +2995,7 @@ dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) { + struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; int is_end = (mss_and_is_end & 0x1); u32 mss = (mss_and_is_end >> 1); u32 vlan_tag = 0; @@ -2821,35 +3007,11 @@ flags &= 0xffff; } vlan_tag |= (mss << TXD_MSS_SHIFT); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; - txd->addr_hi = ((u64) mapping >> 32); - txd->addr_lo = ((u64) mapping & 0xffffffff); - txd->len_flags = (len << TXD_LEN_SHIFT) | flags; - txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; - } else { - struct tx_ring_info *txr = &tp->tx_buffers[entry]; - unsigned long txd; - - txd = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - txd += (entry * TXD_SIZE); - - /* Save some PIOs */ - if (sizeof(dma_addr_t) != sizeof(u32)) - writel(((u64) mapping >> 32), - txd + TXD_ADDR + TG3_64BIT_REG_HIGH); - - writel(((u64) mapping & 0xffffffff), - txd + TXD_ADDR + TG3_64BIT_REG_LOW); - writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS); - if (txr->prev_vlan_tag != vlan_tag) { - writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); - txr->prev_vlan_tag = vlan_tag; - } - } + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + txd->len_flags = (len << TXD_LEN_SHIFT) | flags; + txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) @@ -3038,19 +3200,7 @@ } /* Packets are ready, update Tx producer idx local and on card. */ - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } else { - /* First, make sure tg3 sees last descriptor fully - * in SRAM. - */ - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); - - tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - } + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) @@ -3100,9 +3250,10 @@ tg3_init_hw(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -3188,7 +3339,6 @@ */ static void tg3_init_rings(struct tg3 *tp) { - unsigned long start, end; u32 i; /* Free up all the SKBs. */ @@ -3198,21 +3348,7 @@ memset(tp->rx_std, 0, TG3_RX_RING_BYTES); memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - } else { - start = (tp->regs + - NIC_SRAM_WIN_BASE + - NIC_SRAM_TX_BUFFER_DESC); - end = start + TG3_TX_RING_BYTES; - while (start < end) { - writel(0, start); - start += 4; - } - for (i = 0; i < TG3_TX_RING_SIZE; i++) - tp->tx_buffers[i].prev_vlan_tag = 0; - } + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); /* Initialize invariants of the rings, we only set this * stuff once. This works because the card does not @@ -3343,15 +3479,10 @@ if (!tp->rx_rcb) goto err_out; - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tp->tx_desc_mapping); - if (!tp->tx_ring) - goto err_out; - } else { - tp->tx_ring = NULL; - tp->tx_desc_mapping = 0; - } + tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tp->tx_desc_mapping); + if (!tp->tx_ring) + goto err_out; tp->hw_status = pci_alloc_consistent(tp->pdev, TG3_HW_STATUS_SIZE, @@ -3593,6 +3724,8 @@ } } +static void tg3_stop_fw(struct tg3 *); + /* tp->lock is held. */ static int tg3_chip_reset(struct tg3 *tp) { @@ -3600,7 +3733,7 @@ u32 flags_save; int i; - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) + if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) tg3_nvram_lock(tp); /* @@ -3695,6 +3828,11 @@ tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) { + tg3_stop_fw(tp); + tw32(0x5000, 0x400); + } + tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { @@ -3711,7 +3849,7 @@ tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->mac_mode = MAC_MODE_PORT_MODE_TBI; tw32_f(MAC_MODE, tp->mac_mode); } else @@ -3726,7 +3864,7 @@ udelay(10); } if (i >= 100000 && - !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) { printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, " "firmware will not restart magic=%08x\n", tp->dev->name, val); @@ -4808,10 +4946,7 @@ GRC_MODE_4X_NIC_SEND_RINGS | GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) - tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - else - tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS; + tp->grc_mode |= GRC_MODE_HOST_SENDBDS; if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) @@ -4964,18 +5099,11 @@ tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); - } else { - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - 0, - BDINFO_FLAGS_DISABLED, - NIC_SRAM_TX_BUFFER_DESC); - } + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, + tp->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); /* There is only one receive return ring on 5705/5750, no need * to explicitly disable the others. @@ -5241,14 +5369,14 @@ tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tw32_f(MAC_RX_MODE, RX_MODE_RESET); udelay(10); } tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { /* Set drive transmission level to 1.2V */ val = tr32(MAC_SERDES_CFG); @@ -5266,22 +5394,8 @@ tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - tp->phy_id == PHY_ID_SERDES) { - /* Enable hardware link auto-negotiation */ - u32 digctrl, txctrl; - - digctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_CRC16_CLEAR_N | - SG_DIG_LOCAL_DUPLEX_STATUS | SG_DIG_LOCAL_LINK_STATUS | - (2 << SG_DIG_SPEED_STATUS_SHIFT) | SG_DIG_FIBER_MODE | - SG_DIG_GBIC_ENABLE; - - txctrl = tr32(MAC_SERDES_CFG); - tw32_f(MAC_SERDES_CFG, txctrl | MAC_SERDES_CFG_EDGE_SELECT); - tw32_f(SG_DIG_CTRL, digctrl | SG_DIG_SOFT_RESET); - tr32(SG_DIG_CTRL); - udelay(5); - tw32_f(SG_DIG_CTRL, digctrl); - + (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + /* Use hardware link auto-negotiation */ tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; } @@ -5289,7 +5403,7 @@ if (err) return err; - if (tp->phy_id != PHY_ID_SERDES) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { u32 tmp; /* Clear CRC stats. */ @@ -5481,7 +5595,8 @@ need_setup = 1; } if (! netif_carrier_ok(tp->dev) && - (mac_stat & MAC_STATUS_PCS_SYNCED)) { + (mac_stat & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DET))) { need_setup = 1; } if (need_setup) { @@ -5534,8 +5649,8 @@ spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - /* If you move this call, make sure TG3_FLAG_HOST_TXDS in - * tp->tg3_flags is accurate at that new place. + /* The placement of this call is tied + * to the setup and use of Host TX descriptors. */ err = tg3_alloc_consistent(tp); if (err) @@ -5877,7 +5992,7 @@ { struct tg3_hw_stats *hw_stats = tp->hw_stats; - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { unsigned long flags; @@ -6233,8 +6348,8 @@ return EEPROM_CHIP_SIZE; } -static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp, - u32 offset, u32 *val); +static int tg3_nvram_read_using_eeprom(struct tg3 *tp, + u32 offset, u32 *val); static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct tg3 *tp = dev->priv; @@ -6308,7 +6423,7 @@ cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (tp->phy_id != PHY_ID_SERDES) + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -6337,7 +6452,7 @@ tp->link_config.phy_is_low_power) return -EAGAIN; - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -6395,7 +6510,7 @@ if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - tp->phy_id == PHY_ID_SERDES && + tp->tg3_flags2 & TG3_FLG2_PHY_SERDES && !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) return -EINVAL; @@ -6491,10 +6606,9 @@ tg3_halt(tp); tg3_init_hw(tp); - netif_wake_queue(tp->dev); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6504,8 +6618,8 @@ struct tg3 *tp = netdev_priv(dev); epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0; - epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0; + epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0; + epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0; } static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) @@ -6520,18 +6634,18 @@ else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_RX; + tp->tg3_flags |= TG3_FLAG_RX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX; + tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE; if (epause->tx_pause) - tp->tg3_flags |= TG3_FLAG_PAUSE_TX; + tp->tg3_flags |= TG3_FLAG_TX_PAUSE; else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX; + tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; tg3_halt(tp); tg3_init_hw(tp); + tg3_netif_start(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); return 0; } @@ -6618,7 +6732,7 @@ case SIOCGMIIREG: { u32 mii_regval; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ spin_lock_irq(&tp->lock); @@ -6631,7 +6745,7 @@ } case SIOCSMIIREG: - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ if (!capable(CAP_NET_ADMIN)) @@ -6718,7 +6832,7 @@ { int j; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) return; tw32_f(GRC_EEPROM_ADDR, @@ -6766,8 +6880,8 @@ } } -static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp, - u32 offset, u32 *val) +static int tg3_nvram_read_using_eeprom(struct tg3 *tp, + u32 offset, u32 *val) { u32 tmp; int i; @@ -6805,8 +6919,8 @@ { int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { - printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n"); + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n"); return -EINVAL; } @@ -6868,10 +6982,10 @@ { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ - { PCI_VENDOR_ID_BROADCOM, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ + { PCI_VENDOR_ID_BROADCOM, 0x0003, 0 }, /* BCM95700A9 */ { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ - { PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ + { PCI_VENDOR_ID_BROADCOM, 0x0007, 0 }, /* BCM95701A7 */ { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */ @@ -6880,7 +6994,7 @@ /* 3com boards. */ { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */ { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */ - { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */ + { PCI_VENDOR_ID_3COM, 0x1004, 0 }, /* 3C996SX */ { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */ { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */ @@ -6893,37 +7007,43 @@ /* Compaq boards. */ { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */ { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */ - { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */ + { PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */ { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */ { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */ /* IBM boards. */ - { PCI_VENDOR_ID_IBM, 0x0281, PHY_ID_SERDES } /* IBM??? */ + { PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */ }; -static int __devinit tg3_phy_probe(struct tg3 *tp) +static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) { - u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; - u32 hw_phy_id, hw_phy_id_masked; - u32 val; - int i, eeprom_signature_found, err; + int i; - tp->phy_id = PHY_ID_INVALID; for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) { if ((subsys_id_to_phy_id[i].subsys_vendor == tp->pdev->subsystem_vendor) && (subsys_id_to_phy_id[i].subsys_devid == - tp->pdev->subsystem_device)) { - tp->phy_id = subsys_id_to_phy_id[i].phy_id; - break; - } + tp->pdev->subsystem_device)) + return &subsys_id_to_phy_id[i]; } + return NULL; +} + +static int __devinit tg3_phy_probe(struct tg3 *tp) +{ + u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; + u32 hw_phy_id, hw_phy_id_masked; + u32 val; + int eeprom_signature_found, eeprom_phy_serdes, err; + tp->phy_id = PHY_ID_INVALID; eeprom_phy_id = PHY_ID_INVALID; + eeprom_phy_serdes = 0; eeprom_signature_found = 0; tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; + u32 nic_phy_id, cfg2; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); tp->nic_sram_data_cfg = nic_cfg; @@ -6931,21 +7051,19 @@ eeprom_signature_found = 1; if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == - NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) { - eeprom_phy_id = PHY_ID_SERDES; - } else { - u32 nic_phy_id; + NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) + eeprom_phy_serdes = 1; - tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); - if (nic_phy_id != 0) { - u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; - u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; - - eeprom_phy_id = (id1 >> 16) << 10; - eeprom_phy_id |= (id2 & 0xfc00) << 16; - eeprom_phy_id |= (id2 & 0x03ff) << 0; - } - } + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); + if (nic_phy_id != 0) { + u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; + u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; + + eeprom_phy_id = (id1 >> 16) << 10; + eeprom_phy_id |= (id2 & 0xfc00) << 16; + eeprom_phy_id |= (id2 & 0x03ff) << 0; + } else + eeprom_phy_id = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg); @@ -7007,6 +7125,10 @@ } if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP; + + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &cfg2); + if (cfg2 & (1 << 17)) + tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; } /* Reading the PHY ID register can conflict with ASF @@ -7033,20 +7155,31 @@ if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) { tp->phy_id = hw_phy_id; + if (hw_phy_id_masked == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } else { - /* phy_id currently holds the value found in the - * subsys_id_to_phy_id[] table or PHY_ID_INVALID - * if a match was not found there. - */ - if (tp->phy_id == PHY_ID_INVALID) { - if (!eeprom_signature_found || - !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK)) - return -ENODEV; + if (eeprom_signature_found) { tp->phy_id = eeprom_phy_id; + if (eeprom_phy_serdes) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + } else { + struct subsys_tbl_ent *p; + + /* No eeprom signature? Try the hardcoded + * subsys device table. + */ + p = lookup_by_subsys(tp); + if (!p) + return -ENODEV; + + tp->phy_id = p->phy_id; + if (!tp->phy_id || + tp->phy_id == PHY_ID_BCM8002) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } } - if (tp->phy_id != PHY_ID_SERDES && + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl; @@ -7103,7 +7236,7 @@ if (!eeprom_signature_found) tp->led_ctrl = LED_CTRL_MODE_PHY_1; - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->link_config.advertising = (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | @@ -7122,11 +7255,11 @@ unsigned char vpd_data[256]; int i; - if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) { + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { /* Sun decided not to put the necessary bits in the * NVRAM of their onboard tg3 parts :( */ - strcpy(tp->board_part_number, "Sun 5704"); + strcpy(tp->board_part_number, "Sun 570X"); return; } @@ -7187,27 +7320,21 @@ } #ifdef CONFIG_SPARC64 -static int __devinit tg3_is_sun_5704(struct tg3 *tp) +static int __devinit tg3_is_sun_570X(struct tg3 *tp) { struct pci_dev *pdev = tp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { int node = pcp->prom_node; - u32 venid, devid; + u32 venid; int err; err = prom_getproperty(node, "subsystem-vendor-id", (char *) &venid, sizeof(venid)); if (err == 0 || err == -1) return 0; - err = prom_getproperty(node, "subsystem-id", - (char *) &devid, sizeof(devid)); - if (err == 0 || err == -1) - return 0; - - if (venid == PCI_VENDOR_ID_SUN && - devid == PCI_DEVICE_ID_TIGON3_5704) + if (venid == PCI_VENDOR_ID_SUN) return 1; } return 0; @@ -7224,8 +7351,8 @@ int err; #ifdef CONFIG_SPARC64 - if (tg3_is_sun_5704(tp)) - tp->tg3_flags2 |= TG3_FLG2_SUN_5704; + if (tg3_is_sun_570X(tp)) + tp->tg3_flags2 |= TG3_FLG2_SUN_570X; #endif /* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write @@ -7470,32 +7597,17 @@ udelay(50); tg3_nvram_init(tp); - /* Always use host TXDs, it performs better in particular - * with multi-frag packets. The tests below are kept here - * as documentation should we change this decision again - * in the future. - */ - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; - -#if 0 - /* Determine if TX descriptors will reside in - * main memory or in the chip SRAM. - */ - if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; -#endif - grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; + /* Broadcom's driver says that CIOBE multisplit has a bug */ +#if 0 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) { tp->tg3_flags |= TG3_FLAG_SPLIT_MODE; tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ; } - +#endif if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) @@ -7510,7 +7622,8 @@ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) || (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F)) + (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F || + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F))) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); @@ -7522,7 +7635,7 @@ tg3_read_partno(tp); - if (tp->phy_id == PHY_ID_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; } else { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) @@ -7545,13 +7658,13 @@ * upon subsystem IDs. */ if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && - tp->phy_id != PHY_ID_SERDES) { + !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT | TG3_FLAG_USE_LINKCHG_REG); } /* For all SERDES we poll the MAC status register. */ - if (tp->phy_id == PHY_ID_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->tg3_flags |= TG3_FLAG_POLL_SERDES; else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; @@ -7622,7 +7735,7 @@ mac_offset = 0x7c; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - !(tp->tg3_flags & TG3_FLG2_SUN_5704)) { + !(tp->tg3_flags & TG3_FLG2_SUN_570X)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -7644,7 +7757,7 @@ dev->dev_addr[5] = (lo >> 0) & 0xff; } /* Next, try NVRAM. */ - else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) && + else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && !tg3_nvram_read(tp, mac_offset + 0, &hi) && !tg3_nvram_read(tp, mac_offset + 4, &lo)) { dev->dev_addr[0] = ((hi >> 16) & 0xff); @@ -7818,7 +7931,8 @@ #endif if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { - tp->dma_rwctrl |= 0x001f0000; + /* DMA read watermark not used on PCIE */ + tp->dma_rwctrl |= 0x00180000; } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) @@ -7987,8 +8101,8 @@ case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; - case PHY_ID_BCM8002: return "8002"; - case PHY_ID_SERDES: return "serdes"; + case PHY_ID_BCM8002: return "8002/serdes"; + case 0: return "serdes"; default: return "unknown"; }; } @@ -8133,7 +8247,7 @@ spin_lock_init(&tp->indirect_lock); INIT_TQUEUE(&tp->reset_task, tg3_reset_task, tp); - tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); + tp->regs = (unsigned long) ioremap_nocache(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -8249,6 +8363,9 @@ if (tp->tg3_flags2 & TG3_FLG2_IS_5788) dev->features &= ~NETIF_F_HIGHDMA; + /* flow control autonegotiation is default behavior */ + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " @@ -8280,11 +8397,10 @@ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] " + printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] " "TSOcap[%d] \n", dev->name, - (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, @@ -8363,11 +8479,11 @@ tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); - netif_device_attach(dev); tg3_netif_start(tp); + + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); } return err; @@ -8400,11 +8516,11 @@ tg3_enable_ints(tp); + tg3_netif_start(tp); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - tg3_netif_start(tp); - return 0; } diff -urN linux-2.4.27/drivers/net/tg3.h linux-2.4.28/drivers/net/tg3.h --- linux-2.4.27/drivers/net/tg3.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/tg3.h 2004-11-17 03:54:21.439391356 -0800 @@ -124,6 +124,7 @@ #define CHIPREV_ID_5705_A3 0x3003 #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 +#define CHIPREV_ID_5750_A3 0x4003 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -1435,6 +1436,7 @@ #define NIC_SRAM_DATA_CFG_EEPROM_WP 0x00000100 #define NIC_SRAM_DATA_CFG_MINI_PCI 0x00001000 #define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000 +#define NIC_SRAM_DATA_CFG_NO_GPIO2 0x00100000 #define NIC_SRAM_DATA_PHY_ID 0x00000b74 #define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000 @@ -1548,7 +1550,7 @@ * exist only in the cards on-chip SRAM. All 16 send bds are under * the same mode, they may not be configured individually. * - * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags. + * This driver always uses host memory TX descriptors. * * To use host memory TX descriptors: * 1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register. @@ -2004,7 +2006,6 @@ spinlock_t tx_lock; - /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ struct tg3_tx_buffer_desc *tx_ring; struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; @@ -2040,7 +2041,6 @@ u32 rx_offset; u32 tg3_flags; -#define TG3_FLAG_HOST_TXDS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 #define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 @@ -2070,15 +2070,13 @@ #define TG3_FLAG_JUMBO_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 -#define TG3_FLAG_PAUSE_RX 0x04000000 -#define TG3_FLAG_PAUSE_TX 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_SUN_5704 0x00000002 +#define TG3_FLG2_SUN_570X 0x00000002 #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 @@ -2089,6 +2087,9 @@ #define TG3_FLG2_PCI_EXPRESS 0x00000200 #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 #define TG3_FLG2_HW_AUTONEG 0x00000800 +#define TG3_FLG2_PHY_JUST_INITTED 0x00001000 +#define TG3_FLG2_PHY_SERDES 0x00002000 +#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2136,7 +2137,6 @@ #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM8002 0x60010140 -#define PHY_ID_SERDES 0xfeedbee0 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f #define PHY_REV_BCM5401_B0 0x1 @@ -2159,7 +2159,7 @@ (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff -urN linux-2.4.27/drivers/net/tun.c linux-2.4.28/drivers/net/tun.c --- linux-2.4.27/drivers/net/tun.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/tun.c 2004-11-17 03:54:21.440391398 -0800 @@ -188,7 +188,7 @@ size_t len = count; if (!(tun->flags & TUN_NO_PI)) { - if ((len -= sizeof(pi)) < 0) + if ((len -= sizeof(pi)) > len) return -EINVAL; memcpy_fromiovec((void *)&pi, iv, sizeof(pi)); diff -urN linux-2.4.27/drivers/net/wan/dscc4.c linux-2.4.28/drivers/net/wan/dscc4.c --- linux-2.4.27/drivers/net/wan/dscc4.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/net/wan/dscc4.c 2004-11-17 03:54:21.442391480 -0800 @@ -351,8 +351,8 @@ #endif /* Functions prototypes */ -static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); -static inline void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); +static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static int dscc4_found1(struct pci_dev *, unsigned long ioaddr); static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); static int dscc4_open(struct net_device *); @@ -366,7 +366,6 @@ static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); static int dscc4_hdlc_attach(hdlc_device *, unsigned short, unsigned short); static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *); -static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int); #ifdef DSCC4_POLLING static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *); #endif @@ -857,6 +856,18 @@ //scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2); } +static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) +{ + int ret = 0; + + if ((hz < 0) || (hz > DSCC4_HZ_MAX)) + ret = -EOPNOTSUPP; + else + dpriv->pci_priv->xtal_hz = hz; + + return ret; +} + static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) { struct dscc4_pci_priv *ppriv; @@ -1325,18 +1336,6 @@ return ret; } -static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz) -{ - int ret = 0; - - if ((hz < 0) || (hz > DSCC4_HZ_MAX)) - ret = -EOPNOTSUPP; - else - dpriv->pci_priv->xtal_hz = hz; - - return ret; -} - static int dscc4_match(struct thingie *p, int value) { int i; @@ -1512,7 +1511,7 @@ spin_unlock_irqrestore(&priv->lock, flags); } -static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, +static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = hdlc_to_dev(&dpriv->hdlc); @@ -1681,7 +1680,7 @@ goto try; } -static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, +static void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct dscc4_dev_priv *dpriv) { struct net_device *dev = hdlc_to_dev(&dpriv->hdlc); diff -urN linux-2.4.27/drivers/net/wan/farsync.c linux-2.4.28/drivers/net/wan/farsync.c --- linux-2.4.27/drivers/net/wan/farsync.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/net/wan/farsync.c 2004-11-17 03:54:21.443391521 -0800 @@ -25,6 +25,7 @@ #include #include #include +#include #include "farsync.h" diff -urN linux-2.4.27/drivers/net/wan/hd6457x.c linux-2.4.28/drivers/net/wan/hd6457x.c --- linux-2.4.27/drivers/net/wan/hd6457x.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/net/wan/hd6457x.c 2004-11-17 03:54:21.444391562 -0800 @@ -452,8 +452,8 @@ brv >>= 1; /* brv = 2^9 = 512 max in specs */ /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ - tmc = CLOCK_BASE / (brv * port->settings.clock_rate); - }while(br > 1 && tmc <= 128); + tmc = CLOCK_BASE / brv / port->settings.clock_rate; + }while (br > 1 && tmc <= 128); if (tmc < 1) { tmc = 1; @@ -462,7 +462,7 @@ } else if (tmc > 255) tmc = 256; /* tmc=0 means 256 - low baud rates */ - port->settings.clock_rate = CLOCK_BASE / (brv * tmc); + port->settings.clock_rate = CLOCK_BASE / brv / tmc; } else { br = 9; /* Minimum clock rate */ tmc = 256; /* 8bit = 0 */ diff -urN linux-2.4.27/drivers/net/wan/lmc/lmc_debug.c linux-2.4.28/drivers/net/wan/lmc/lmc_debug.c --- linux-2.4.27/drivers/net/wan/lmc/lmc_debug.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/net/wan/lmc/lmc_debug.c 2004-11-17 03:54:21.445391603 -0800 @@ -66,7 +66,7 @@ #endif } -inline void lmc_trace(struct net_device *dev, char *msg){ +void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE unsigned long j = jiffies + 3; /* Wait for 50 ms */ diff -urN linux-2.4.27/drivers/net/wan/lmc/lmc_debug.h linux-2.4.28/drivers/net/wan/lmc/lmc_debug.h --- linux-2.4.27/drivers/net/wan/lmc/lmc_debug.h 2000-04-21 16:08:45.000000000 -0700 +++ linux-2.4.28/drivers/net/wan/lmc/lmc_debug.h 2004-11-17 03:54:21.445391603 -0800 @@ -47,6 +47,6 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen); void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3); -inline void lmc_trace(struct net_device *dev, char *msg); +void lmc_trace(struct net_device *dev, char *msg); #endif diff -urN linux-2.4.27/drivers/net/wan/pc300_tty.c linux-2.4.28/drivers/net/wan/pc300_tty.c --- linux-2.4.27/drivers/net/wan/pc300_tty.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/net/wan/pc300_tty.c 2004-11-17 03:54:21.446391644 -0800 @@ -702,7 +702,7 @@ if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, buf->data, + cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, &flags, buf->size); } cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; diff -urN linux-2.4.27/drivers/net/wireless/Config.in linux-2.4.28/drivers/net/wireless/Config.in --- linux-2.4.27/drivers/net/wireless/Config.in 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/net/wireless/Config.in 2004-11-17 03:54:21.446391644 -0800 @@ -27,6 +27,15 @@ dep_tristate ' Atmel at76c502/at76c504 PCMCIA cards' CONFIG_PCMCIA_ATMEL $CONFIG_FW_LOADER fi +# If PCI enabled, allow for prism54 driver. CONFIG_FW_LOADER required +comment 'Prism54 PCI/PCMCIA GT/Duette Driver - 802.11(a/b/g)' +dep_tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA' CONFIG_PRISM54 $CONFIG_EXPERIMENTAL $CONFIG_PCI $CONFIG_HOTPLUG +if [ "$CONFIG_PRISM54" != "n" ]; then + if [ "$CONFIG_FW_LOADER" != "y" ]; then + define_tristate CONFIG_FW_LOADER $CONFIG_PRISM54 + fi +fi + # yes, this works even when no drivers are selected if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" -o \ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" ]; then diff -urN linux-2.4.27/drivers/net/wireless/Makefile linux-2.4.28/drivers/net/wireless/Makefile --- linux-2.4.27/drivers/net/wireless/Makefile 2004-04-14 06:05:30.000000000 -0700 +++ linux-2.4.28/drivers/net/wireless/Makefile 2004-11-17 03:54:21.447391685 -0800 @@ -25,4 +25,9 @@ obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o +ifeq ($(CONFIG_PRISM54),y) +obj-$(CONFIG_PRISM54) += prism54/prism54.o +endif +subdir-$(CONFIG_PRISM54) += prism54 + include $(TOPDIR)/Rules.make diff -urN linux-2.4.27/drivers/net/wireless/prism54/Makefile linux-2.4.28/drivers/net/wireless/prism54/Makefile --- linux-2.4.27/drivers/net/wireless/prism54/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/Makefile 2004-11-17 03:54:21.448391727 -0800 @@ -0,0 +1,12 @@ + +O_TARGET := prism54.o + +EXTRA_CFLAGS += -DPRISM54_COMPAT24 + +obj-y := isl_38xx.o islpci_dev.o islpci_eth.o \ + islpci_mgt.o islpci_hotplug.o isl_ioctl.o \ + oid_mgt.o + +obj-m += prism54.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.c linux-2.4.28/drivers/net/wireless/prism54/isl_38xx.c --- linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/isl_38xx.c 2004-11-17 03:54:21.449391768 -0800 @@ -0,0 +1,260 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003-2004 Luis R. Rodriguez _ + * + * 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 + * + * 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 + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Device Interface & Control functions +******************************************************************************/ + +/** + * isl38xx_disable_interrupts - disable all interrupts + * @device: pci memory base address + * + * Instructs the device to disable all interrupt reporting by asserting + * the IRQ line. New events may still show up in the interrupt identification + * register located at offset %ISL38XX_INT_IDENT_REG. + */ +void +isl38xx_disable_interrupts(void *device) +{ + isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_sleep_request(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device requests to go into sleep mode + * check whether the transmit queues for data and management are empty */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) + /* data tx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + /* management tx queue not empty */ + return; + + /* check also whether received frames are pending */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) + /* data rx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) + /* management rx queue not empty */ + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); +#endif + + /* all queues are empty, allow the device to go into sleep mode */ + *powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* assert the Sleep interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_wakeup(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device is in active state, update the powerstate flag */ + *powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* now check whether there are frames pending for the card */ + if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) + && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); +#endif + + /* either data or management transmit queue has a frame pending + * trigger the device by setting the Update bit in the Device Int reg */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_trigger_device(int asleep, void *device_base) +{ + struct timeval current_time; + u32 reg, counter = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); +#endif + + /* check whether the device is in power save mode */ + if (asleep) { + /* device is in powersave, trigger the device for wakeup */ +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", + current_time.tv_sec, current_time.tv_usec); +#endif + + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + + reg = readl(device_base + ISL38XX_INT_IDENT_REG); + if (reg == 0xabadface) { +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device register abadface\n", + current_time.tv_sec, current_time.tv_usec); +#endif + /* read the Device Status Register until Sleepmode bit is set */ + while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), + (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { + udelay(ISL38XX_WRITEIO_DELAY); + counter++; + } + + DEBUG(SHOW_TRACING, + "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device asleep counter %i\n", + current_time.tv_sec, current_time.tv_usec, + counter); +#endif + } + /* assert the Wakeup interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* perform another read on the Device Status Register */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, reg); +#endif + } else { + /* device is (still) awake */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device is in active state\n"); +#endif + /* trigger the device by setting the Update bit in the Device Int reg */ + + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + } +} + +void +isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +{ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n"); +#endif + + /* load the address of the control block in the device */ + isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* enable the interrupt for detecting initialization */ + + /* Note: Do not enable other interrupts here. We want the + * device to have come up first 100% before allowing any other + * interrupts. */ + isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ +} + +void +isl38xx_enable_common_interrupts(void *device_base) { + u32 reg; + reg = ( ISL38XX_INT_IDENT_UPDATE | + ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +int +isl38xx_in_queue(isl38xx_control_block *cb, int queue) +{ + const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - + le32_to_cpu(cb->device_curr_frag[queue])); + + /* determine the amount of fragments in the queue depending on the type + * of the queue, either transmit or receive */ + + BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ + + switch (queue) { + /* send queues */ + case ISL38XX_CB_TX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + case ISL38XX_CB_TX_DATA_LQ: + case ISL38XX_CB_TX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_TX_QSIZE); + return delta; + break; + + /* receive queues */ + case ISL38XX_CB_RX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + return ISL38XX_CB_MGMT_QSIZE - delta; + break; + + case ISL38XX_CB_RX_DATA_LQ: + case ISL38XX_CB_RX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_RX_QSIZE); + return ISL38XX_CB_RX_QSIZE - delta; + break; + } + BUG(); + return 0; +} diff -urN linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.h linux-2.4.28/drivers/net/wireless/prism54/isl_38xx.h --- linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/isl_38xx.h 2004-11-17 03:54:21.450391809 -0800 @@ -0,0 +1,173 @@ +/* + * + * Copyright (C) 2002 Intersil Americas 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 + * + * 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 _ISL_38XX_H +#define _ISL_38XX_H + +#include +#include +#include + +#define ISL38XX_CB_RX_QSIZE 8 +#define ISL38XX_CB_TX_QSIZE 32 + +/* ISL38XX Access Point Specific definitions */ +#define ISL38XX_MAX_WDS_LINKS 8 + +/* ISL38xx Client Specific definitions */ +#define ISL38XX_PSM_ACTIVE_STATE 0 +#define ISL38XX_PSM_POWERSAVE_STATE 1 + +/* ISL38XX Host Interface Definitions */ +#define ISL38XX_PCI_MEM_SIZE 0x02000 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */ +#define ISL38XX_RESET_DELAY 50 /* in ms */ +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ +#define ISL38XX_MAX_WAIT_CYCLES 10 + +/* PCI Memory Area */ +#define ISL38XX_HARDWARE_REG 0x0000 +#define ISL38XX_CARDBUS_CIS 0x0800 +#define ISL38XX_DIRECT_MEM_WIN 0x1000 + +/* Hardware registers */ +#define ISL38XX_DEV_INT_REG 0x0000 +#define ISL38XX_INT_IDENT_REG 0x0010 +#define ISL38XX_INT_ACK_REG 0x0014 +#define ISL38XX_INT_EN_REG 0x0018 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030 +#define ISL38XX_CTRL_STAT_REG 0x0078 + +/* High end mobos queue up pci writes, the following + * is used to "read" from after a write to force flush */ +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG + +/** + * isl38xx_w32_flush - PCI iomem write helper + * @base: (host) memory base address of the device + * @val: 32bit value (host order) to write + * @offset: byte offset into @base to write value to + * + * This helper takes care of writing a 32bit datum to the + * specified offset into the device's pci memory space, and making sure + * the pci memory buffers get flushed by performing one harmless read + * from the %ISL38XX_PCI_POSTING_FLUSH offset. + */ +static inline void +isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +{ + writel(val, base + offset); + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); +} + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_SOURCES 0x001E + +/* Control/Status register bits */ +/* Looks like there are other meaningful bits + 0x20004400 seen in normal operation, + 0x200044db at 'timeout waiting for mgmt response' +*/ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +/* Control Block definitions */ +#define ISL38XX_CB_RX_DATA_LQ 0 +#define ISL38XX_CB_TX_DATA_LQ 1 +#define ISL38XX_CB_RX_DATA_HQ 2 +#define ISL38XX_CB_TX_DATA_HQ 3 +#define ISL38XX_CB_RX_MGMTQ 4 +#define ISL38XX_CB_TX_MGMTQ 5 +#define ISL38XX_CB_QCOUNT 6 +#define ISL38XX_CB_MGMT_QSIZE 4 +#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ + +/* Memory Manager definitions */ +#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ +#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ +#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ +#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) +#define CONTROL_BLOCK_SIZE 1024 /* should be enough */ +#define PSM_FRAME_SIZE 1536 +#define PSM_MINIMAL_STATION_COUNT 64 +#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT +#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT +#define MAX_TRAP_RX_QUEUE 4 +#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE + +/* Fragment package definitions */ +#define FRAGMENT_FLAG_MF 0x0001 +#define MAX_FRAGMENT_SIZE 1536 + +/* In monitor mode frames have a header. I don't know exactly how big those + * frame can be but I've never seen any frame bigger than 1584... : + */ +#define MAX_FRAGMENT_SIZE_RX 1600 + +typedef struct { + u32 address; /* physical address on host */ + u16 size; /* packet size */ + u16 flags; /* set of bit-wise flags */ +} isl38xx_fragment; + +struct isl38xx_cb { + u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; + u32 device_curr_frag[ISL38XX_CB_QCOUNT]; + isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; + isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; +}; + +typedef struct isl38xx_cb isl38xx_control_block; + +/* determine number of entries currently in queue */ +int isl38xx_in_queue(isl38xx_control_block *cb, int queue); + +void isl38xx_disable_interrupts(void *); +void isl38xx_enable_common_interrupts(void *); + +void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, + void *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); +void isl38xx_trigger_device(int, void *); +void isl38xx_interface_reset(void *, dma_addr_t); + +#endif /* _ISL_38XX_H */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.c linux-2.4.28/drivers/net/wireless/prism54/isl_ioctl.c --- linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/isl_ioctl.c 2004-11-17 03:54:21.455392014 -0800 @@ -0,0 +1,2738 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003,2004 Aurelien Alleaume + * (C) 2003 Herbert Valerio Riedel + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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 + * + */ + +#include +#include +#include +#include +#include + +#include + +#include "prismcompat.h" +#include "isl_ioctl.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "oid_mgt.h" + +#include /* New driver API */ + +/** + * prism54_mib_mode_helper - MIB change mode helper function + * @mib: the &struct islpci_mib object to modify + * @iw_mode: new mode (%IW_MODE_*) + * + * This is a helper function, hence it does not lock. Make sure + * caller deals with locking *if* necessary. This function sets the + * mode-dependent mib values and does the mapping of the Linux + * Wireless API modes to Device firmware modes. It also checks for + * correct valid Linux wireless modes. + */ +int +prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) +{ + u32 config = INL_CONFIG_MANUALRUN; + u32 mode, bsstype; + + /* For now, just catch early the Repeater and Secondary modes here */ + if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { + printk(KERN_DEBUG + "%s(): Sorry, Repeater mode and Secondary mode " + "are not yet supported by this driver.\n", __FUNCTION__); + return -EINVAL; + } + + priv->iw_mode = iw_mode; + + switch (iw_mode) { + case IW_MODE_AUTO: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_ANY; + break; + case IW_MODE_ADHOC: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_IBSS; + break; + case IW_MODE_INFRA: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MASTER: + mode = INL_MODE_AP; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MONITOR: + mode = INL_MODE_PROMISCUOUS; + bsstype = DOT11_BSSTYPE_ANY; + config |= INL_CONFIG_RXANNEX; + break; + default: + return -EINVAL; + } + + if (init_wds) + config |= INL_CONFIG_WDS; + mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); + mgt_set(priv, OID_INL_CONFIG, &config); + mgt_set(priv, OID_INL_MODE, &mode); + + return 0; +} + +/** + * prism54_mib_init - fill MIB cache with defaults + * + * this function initializes the struct given as @mib with defaults, + * of which many are retrieved from the global module parameter + * variables. + */ + +void +prism54_mib_init(islpci_private *priv) +{ + u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; + struct obj_buffer psm_buffer = { + .size = PSM_BUFFER_SIZE, + .addr = priv->device_psm_buffer + }; + + channel = CARD_DEFAULT_CHANNEL; + authen = CARD_DEFAULT_AUTHEN; + wep = CARD_DEFAULT_WEP; + filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ + dot1x = CARD_DEFAULT_DOT1X; + mlme = CARD_DEFAULT_MLME_MODE; + conformance = CARD_DEFAULT_CONFORMANCE; + power = 127; + mode = CARD_DEFAULT_IW_MODE; + + mgt_set(priv, DOT11_OID_CHANNEL, &channel); + mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); + mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); + mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); + mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); + mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); + mgt_set(priv, OID_INL_OUTPUTPOWER, &power); + + /* This sets all of the mode-dependent values */ + prism54_mib_mode_helper(priv, mode); +} + +/* this will be executed outside of atomic context thanks to + * schedule_work(), thus we can as well use sleeping semaphore + * locking */ +void +prism54_update_stats(islpci_private *priv) +{ + char *data; + int j; + struct obj_bss bss, *bss2; + union oid_res_t r; + + if (down_interruptible(&priv->stats_sem)) + return; + +/* Noise floor. + * I'm not sure if the unit is dBm. + * Note : If we are not connected, this value seems to be irrelevant. */ + + mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + priv->local_iwstatistics.qual.noise = r.u; + +/* Get the rssi of the link. To do this we need to retrieve a bss. */ + + /* First get the MAC address of the AP we are associated with. */ + mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + data = r.ptr; + + /* copy this MAC to the bss */ + memcpy(bss.address, data, 6); + kfree(data); + + /* now ask for the corresponding bss */ + j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); + bss2 = r.ptr; + /* report the rssi and use it to calculate + * link quality through a signal-noise + * ratio */ + priv->local_iwstatistics.qual.level = bss2->rssi; + priv->local_iwstatistics.qual.qual = + bss2->rssi - priv->iwstatistics.qual.noise; + + kfree(bss2); + + /* report that the stats are new */ + priv->local_iwstatistics.qual.updated = 0x7; + +/* Rx : unable to decrypt the MPDU */ + mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.code = r.u; + +/* Tx : Max MAC retries num reached */ + mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.retries = r.u; + + up(&priv->stats_sem); + + return; +} + +struct iw_statistics * +prism54_get_wireless_stats(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + /* If the stats are being updated return old data */ + if (down_trylock(&priv->stats_sem) == 0) { + memcpy(&priv->iwstatistics, &priv->local_iwstatistics, + sizeof (struct iw_statistics)); + /* They won't be marked updated for the next time */ + priv->local_iwstatistics.qual.updated = 0; + up(&priv->stats_sem); + } else + priv->iwstatistics.qual.updated = 0; + + /* Update our wireless stats, but do not schedule to often + * (max 1 HZ) */ + if ((priv->stats_timestamp == 0) || + time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { + schedule_work(&priv->stats_work); + priv->stats_timestamp = jiffies; + } + + return &priv->iwstatistics; +} + +static int +prism54_commit(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + /* simply re-set the last set SSID, this should commit most stuff */ + + /* Commit in Monitor mode is not necessary, also setting essid + * in Monitor mode does not make sense and isn't allowed for this + * device's firmware */ + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); + return 0; +} + +static int +prism54_get_name(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char *capabilities; + union oid_res_t r; + int rvalue; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + strncpy(cwrq, "NOT READY!", IFNAMSIZ); + return 0; + } + rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); + + switch (r.u) { + case INL_PHYCAP_5000MHZ: + capabilities = "IEEE 802.11a/b/g"; + break; + case INL_PHYCAP_FAA: + capabilities = "IEEE 802.11b/g - FAA Support"; + break; + case INL_PHYCAP_2400MHZ: + default: + capabilities = "IEEE 802.11b/g"; /* Default */ + break; + } + strncpy(cwrq, capabilities, IFNAMSIZ); + return rvalue; +} + +static int +prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + u32 c; + + if (fwrq->m < 1000) + /* we have a channel number */ + c = fwrq->m; + else + c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; + + rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; + + /* Call commit handler */ + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); + fwrq->i = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); + fwrq->m = r.u; + fwrq->e = 3; + + return rvalue; +} + +static int +prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; + + /* Let's see if the user passed a valid Linux Wireless mode */ + if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { + printk(KERN_DEBUG + "%s: %s() You passed a non-valid init_mode.\n", + priv->ndev->name, __FUNCTION__); + return -EINVAL; + } + + down_write(&priv->mib_sem); + + if (prism54_mib_mode_helper(priv, *uwrq)) { + up_write(&priv->mib_sem); + return -EOPNOTSUPP; + } + + /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an + * extended one. + */ + if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + + if (mgt_commit(priv)) { + up_write(&priv->mib_sem); + return -EIO; + } + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) + ? priv->monitor_type : ARPHRD_ETHER; + up_write(&priv->mib_sem); + + return 0; +} + +/* Use mib cache */ +static int +prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > + IW_MODE_MONITOR)); + *uwrq = priv->iw_mode; + + return 0; +} + +/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to + * emit data if (sensitivity > rssi - noise) (in dBm). + * prism54_set_sens does not seem to work. + */ + +static int +prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 sens; + + /* by default the card sets this to 20. */ + sens = vwrq->disabled ? 20 : vwrq->value; + + return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); +} + +static int +prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); + + vwrq->value = r.u; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + + return rvalue; +} + +static int +prism54_get_range(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + islpci_private *priv = netdev_priv(ndev); + u8 *data; + int i, m, rvalue; + struct obj_frequencies *freq; + union oid_res_t r; + + memset(range, 0, sizeof (struct iw_range)); + dwrq->length = sizeof (struct iw_range); + + /* set the wireless extension version number */ + range->we_version_source = SUPPORTED_WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + + /* Now the encoding capabilities */ + range->num_encoding_sizes = 3; + /* 64(40) bits WEP */ + range->encoding_size[0] = 5; + /* 128(104) bits WEP */ + range->encoding_size[1] = 13; + /* 256 bits for WPA-PSK */ + range->encoding_size[2] = 32; + /* 4 keys are allowed */ + range->max_encoding_tokens = 4; + + /* we don't know the quality range... */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.qual = 0; + /* these value describe an average quality. Needs more tweaking... */ + range->avg_qual.level = -80; /* -80 dBm */ + range->avg_qual.noise = 0; /* don't know what to put here */ + range->avg_qual.qual = 0; + + range->sensitivity = 200; + + /* retry limit capabilities */ + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + + /* I don't know the range. Put stupid things here */ + range->min_retry = 1; + range->max_retry = 65535; + range->min_r_time = 1024; + range->max_r_time = 65535 * 1024; + + /* txpower is supported in dBm's */ + range->txpower_capa = IW_TXPOW_DBM; + +#if WIRELESS_EXT > 16 + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | + IW_EVENT_CAPA_MASK(SIOCGIWAP)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); +#endif /* WIRELESS_EXT > 16 */ + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* Request the device for the supported frequencies + * not really relevant since some devices will report the 5 GHz band + * frequencies even if they don't support them. + */ + rvalue = + mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); + freq = r.ptr; + + range->num_channels = freq->nr; + range->num_frequency = freq->nr; + + m = min(IW_MAX_FREQUENCIES, (int) freq->nr); + for (i = 0; i < m; i++) { + range->freq[i].m = freq->mhz[i]; + range->freq[i].e = 6; + range->freq[i].i = channel_of_freq(freq->mhz[i]); + } + kfree(freq); + + rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); + data = r.ptr; + + /* We got an array of char. It is NULL terminated. */ + i = 0; + while ((i < IW_MAX_BITRATES) && (*data != 0)) { + /* the result must be in bps. The card gives us 500Kbps */ + range->bitrate[i] = *data * 500000; + i++; + data++; + } + range->num_bitrates = i; + kfree(r.ptr); + + return rvalue; +} + +/* Set AP address*/ + +static int +prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char bssid[6]; + int rvalue; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* prepare the structure for the set object */ + memcpy(&bssid[0], awrq->sa_data, 6); + + /* set the bssid -- does this make sense when in AP mode? */ + rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); + + return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ +} + +/* get AP address*/ + +static int +prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + memcpy(awrq->sa_data, r.ptr, 6); + awrq->sa_family = ARPHRD_ETHER; + kfree(r.ptr); + + return rvalue; +} + +static int +prism54_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + /* hehe the device does this automagicaly */ + return 0; +} + +/* a little helper that will translate our data into a card independent + * format that the Wireless Tools will understand. This was inspired by + * the "Aironet driver for 4500 and 4800 series cards" (GPL) + */ + +static char * +prism54_translate_bss(struct net_device *ndev, char *current_ev, + char *end_buf, struct obj_bss *bss, char noise) +{ + struct iw_event iwe; /* Temporary buffer */ + short cap; + islpci_private *priv = netdev_priv(ndev); + + /* The first entry must be the MAC address */ + memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.cmd = SIOCGIWAP; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* The following entries will be displayed in the same order we give them */ + + /* The ESSID. */ + iwe.u.data.length = bss->ssid.length; + iwe.u.data.flags = 1; + iwe.cmd = SIOCGIWESSID; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, bss->ssid.octets); + + /* Capabilities */ +#define CAP_ESS 0x01 +#define CAP_IBSS 0x02 +#define CAP_CRYPT 0x10 + + /* Mode */ + cap = bss->capinfo; + iwe.u.mode = 0; + if (cap & CAP_ESS) + iwe.u.mode = IW_MODE_MASTER; + else if (cap & CAP_IBSS) + iwe.u.mode = IW_MODE_ADHOC; + iwe.cmd = SIOCGIWMODE; + if (iwe.u.mode) + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + + /* Encryption capability */ + if (cap & CAP_CRYPT) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.cmd = SIOCGIWENCODE; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); + + /* Add frequency. (short) bss->channel is the frequency in MHz */ + iwe.u.freq.m = bss->channel; + iwe.u.freq.e = 6; + iwe.cmd = SIOCGIWFREQ; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.u.qual.level = bss->rssi; + iwe.u.qual.noise = noise; + /* do a simple SNR for quality */ + iwe.u.qual.qual = bss->rssi - noise; + iwe.cmd = IWEVQUAL; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + if (priv->wpa) { + u8 wpa_ie[MAX_WPA_IE_LEN]; + char *buf, *p; + size_t wpa_ie_len; + int i; + + wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); + if (wpa_ie_len > 0 && + (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { + p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < wpa_ie_len; i++) { + p += sprintf(p, "%02x", wpa_ie[i]); + } + memset(&iwe, 0, sizeof (iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + return current_ev; +} + +int +prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *current_ev = extra; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + dwrq->length = 0; + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. + * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. + * The new API, using SIOCGIWSCAN, is only limited by the buffer size. + * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. + * Starting with WE-17, the buffer can be as big as needed. + * But the device won't repport anything if you change the value + * of IWMAX_BSS=24. */ + + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < (int) bsslist->nr; i++) { + current_ev = prism54_translate_bss(ndev, current_ev, + extra + dwrq->length, + &(bsslist->bsslist[i]), + noise); +#if WIRELESS_EXT > 16 + /* Check if there is space for one more entry */ + if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a bigger buffer */ + rvalue = -E2BIG; + break; + } +#endif /* WIRELESS_EXT > 16 */ + } + + kfree(bsslist); + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return rvalue; +} + +static int +prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid essid; + + memset(essid.octets, 0, 33); + + /* Check if we were asked for `any' */ + if (dwrq->flags && dwrq->length) { + if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) + return -E2BIG; + essid.length = dwrq->length - 1; + memcpy(essid.octets, extra, dwrq->length); + } else + essid.length = 0; + + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); + + /* If in monitor mode, just save to mib */ + mgt_set(priv, DOT11_OID_SSID, &essid); + return 0; + +} + +static int +prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid *essid; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); + essid = r.ptr; + + if (essid->length) { + dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ + /* if it is to big, trunk it */ + dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); + } else { + dwrq->flags = 0; + dwrq->length = 0; + } + essid->octets[essid->length] = '\0'; + memcpy(extra, essid->octets, dwrq->length); + kfree(essid); + + return rvalue; +} + +/* Provides no functionality, just completes the ioctl. In essence this is a + * just a cosmetic ioctl. + */ +static int +prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + if (dwrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + down_write(&priv->mib_sem); + memset(priv->nickname, 0, sizeof (priv->nickname)); + memcpy(priv->nickname, extra, dwrq->length); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + dwrq->length = 0; + + down_read(&priv->mib_sem); + dwrq->length = strlen(priv->nickname) + 1; + memcpy(extra, priv->nickname, dwrq->length); + up_read(&priv->mib_sem); + + return 0; +} + +/* Set the allowed Bitrates */ + +static int +prism54_set_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + + islpci_private *priv = netdev_priv(ndev); + u32 rate, profile; + char *data; + int ret, i; + union oid_res_t r; + + if (vwrq->value == -1) { + /* auto mode. No limit. */ + profile = 1; + return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + } + + ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); + if (ret) { + kfree(r.ptr); + return ret; + } + + rate = (u32) (vwrq->value / 500000); + data = r.ptr; + i = 0; + + while (data[i]) { + if (rate && (data[i] == rate)) { + break; + } + if (vwrq->value == i) { + break; + } + data[i] |= 0x80; + i++; + } + + if (!data[i]) { + kfree(r.ptr); + return -EINVAL; + } + + data[i] |= 0x80; + data[i + 1] = 0; + + /* Now, check if we want a fixed or auto value */ + if (vwrq->fixed) { + data[0] = data[i]; + data[1] = 0; + } + +/* + i = 0; + printk("prism54 rate: "); + while(data[i]) { + printk("%u ", data[i]); + i++; + } + printk("0\n"); +*/ + profile = -1; + ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); + ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); + + kfree(r.ptr); + + return ret; +} + +/* Get the current bit rate */ +static int +prism54_get_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + char *data; + union oid_res_t r; + + /* Get the current bit rate */ + if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) + return rvalue; + vwrq->value = r.u * 500000; + + /* request the device for the enabled rates */ + rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r); + if (rvalue) { + kfree(r.ptr); + return rvalue; + } + data = r.ptr; + vwrq->fixed = (data[0] != 0) && (data[1] == 0); + kfree(r.ptr); + + return 0; +} + +static int +prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + /* get the rts threshold */ + rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +static int +prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +/* Here we have (min,max) = max retries for (small frames, big frames). Where + * big frame <=> bigger than the rts threshold + * small frame <=> smaller than the rts threshold + * This is not really the behavior expected by the wireless tool but it seems + * to be a common behavior in other drivers. + */ + +static int +prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 slimit = 0, llimit = 0; /* short and long limit */ + u32 lifetime = 0; + int rvalue = 0; + + if (vwrq->disabled) + /* we cannot disable this feature */ + return -EINVAL; + + if (vwrq->flags & IW_RETRY_LIMIT) { + if (vwrq->flags & IW_RETRY_MIN) + slimit = vwrq->value; + else if (vwrq->flags & IW_RETRY_MAX) + llimit = vwrq->value; + else { + /* we are asked to set both */ + slimit = vwrq->value; + llimit = vwrq->value; + } + } + if (vwrq->flags & IW_RETRY_LIFETIME) + /* Wireless tools use us unit while the device uses 1024 us unit */ + lifetime = vwrq->value / 1024; + + /* now set what is requested */ + if (slimit) + rvalue = + mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); + if (llimit) + rvalue |= + mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); + if (lifetime) + rvalue |= + mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, + &lifetime); + return rvalue; +} + +static int +prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue = 0; + vwrq->disabled = 0; /* It cannot be disabled */ + + if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + /* we are asked for the life time */ + rvalue = + mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); + vwrq->value = r.u * 1024; + vwrq->flags = IW_RETRY_LIFETIME; + } else if ((vwrq->flags & IW_RETRY_MAX)) { + /* we are asked for the long retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else { + /* default. get the short retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } + + return rvalue; +} + +static int +prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (dwrq->length > 0) { + /* we have a key to set */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index; + struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { + key.length = dwrq->length > sizeof (key.key) ? + sizeof (key.key) : dwrq->length; + memcpy(key.key, extra, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!dwrq->flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + /* now read the flags */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (dwrq->flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((dwrq->flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_key *key; + u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + u32 authen = 0, invoke = 0, exunencrypt = 0; + int rvalue; + union oid_res_t r; + + /* first get the flags */ + rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + invoke = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + + if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) + dwrq->flags = IW_ENCODE_RESTRICTED; + else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { + if (invoke) + dwrq->flags = IW_ENCODE_OPEN; + else + dwrq->flags = IW_ENCODE_DISABLED; + } else + /* The card should not work in this state */ + dwrq->flags = 0; + + /* get the current device key index */ + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + devindex = r.u; + /* Now get the key, return it */ + if ((index < 0) || (index > 3)) + /* no index provided, use the current one */ + index = devindex; + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); + key = r.ptr; + dwrq->length = key->length; + memcpy(extra, key->key, dwrq->length); + kfree(key); + /* return the used key index */ + dwrq->flags |= devindex + 1; + + return rvalue; +} + +static int +prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); + /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ + vwrq->value = (s32) r.u / 4; + vwrq->fixed = 1; + /* radio is not turned of + * btw: how is possible to turn off only the radio + */ + vwrq->disabled = 0; + + return rvalue; +} + +static int +prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + s32 u = vwrq->value; + + /* intersil firmware operates in 0.25 dBm (1/4) */ + u *= 4; + if (vwrq->disabled) { + /* don't know how to disable radio */ + printk(KERN_DEBUG + "%s: %s() disabling radio is not yet supported.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } else if (vwrq->fixed) + /* currently only fixed value is supported */ + return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); + else { + printk(KERN_DEBUG + "%s: %s() auto power will be implemented later.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } +} + +static int +prism54_reset(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_reset(netdev_priv(ndev), 0); + + return 0; +} + +static int +prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + union oid_res_t r; + int rvalue; + enum oid_num_t n = dwrq->flags; + + rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r); + dwrq->length = mgt_response_to_str(n, &r, extra); + if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) + kfree(r.ptr); + return rvalue; +} + +static int +prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + u32 oid = uwrq[0], u = uwrq[1]; + + return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u); +} + +static int +prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + u32 oid = dwrq->flags; + + return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra); +} + +void +prism54_acl_init(struct islpci_acl *acl) +{ + sema_init(&acl->sem, 1); + INIT_LIST_HEAD(&acl->mac_list); + acl->size = 0; + acl->policy = MAC_POLICY_OPEN; +} + +static void +prism54_clear_mac(struct islpci_acl *acl) +{ + struct list_head *ptr, *next; + struct mac_entry *entry; + + if (down_interruptible(&acl->sem)) + return; + + if (acl->size == 0) { + up(&acl->sem); + return; + } + + for (ptr = acl->mac_list.next, next = ptr->next; + ptr != &acl->mac_list; ptr = next, next = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + list_del(ptr); + kfree(entry); + } + acl->size = 0; + up(&acl->sem); +} + +void +prism54_acl_clean(struct islpci_acl *acl) +{ + prism54_clear_mac(acl); +} + +static int +prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); + if (entry == NULL) + return -ENOMEM; + + memcpy(entry->addr, addr->sa_data, ETH_ALEN); + + if (down_interruptible(&acl->sem)) { + kfree(entry); + return -ERESTARTSYS; + } + list_add_tail(&entry->_list, &acl->mac_list); + acl->size++; + up(&acl->sem); + + return 0; +} + +static int +prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { + list_del(ptr); + acl->size--; + kfree(entry); + up(&acl->sem); + return 0; + } + } + up(&acl->sem); + return -EINVAL; +} + +static int +prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *dst = (struct sockaddr *) extra; + + dwrq->length = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + memcpy(dst->sa_data, entry->addr, ETH_ALEN); + dst->sa_family = ARPHRD_ETHER; + dwrq->length++; + dst++; + } + up(&acl->sem); + return 0; +} + +/* Setting policy also clears the MAC acl, even if we don't change the defaut + * policy + */ + +static int +prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + u32 mlmeautolevel; + + prism54_clear_mac(acl); + + if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) + return -EINVAL; + + down_write(&priv->mib_sem); + + acl->policy = *uwrq; + + /* the ACL code needs an intermediate mlmeautolevel */ + if ((priv->iw_mode == IW_MODE_MASTER) && + (acl->policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + else + mlmeautolevel = CARD_DEFAULT_MLME_MODE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + /* restart the card with our new policy */ + if (mgt_commit(priv)) { + up_write(&priv->mib_sem); + return -EIO; + } + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + + *uwrq = acl->policy; + + return 0; +} + +/* Return 1 only if client should be accepted. */ + +static int +prism54_mac_accept(struct islpci_acl *acl, char *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + int res = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + if (acl->policy == MAC_POLICY_OPEN) { + up(&acl->sem); + return 1; + } + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + res = 1; + break; + } + } + res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; + up(&acl->sem); + + return res; +} + +static int +prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct obj_mlme *mlme; + int rvalue; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to kick every client */ + mlme->id = 0; + rvalue = + mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + kfree(mlme); + + return rvalue; +} + +static int +prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + struct obj_mlme *mlme; + struct sockaddr *addr = (struct sockaddr *) extra; + int rvalue; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to only kick the corresponding bastard */ + memcpy(mlme->address, addr->sa_data, ETH_ALEN); + mlme->id = -1; + rvalue = + mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + + kfree(mlme); + + return rvalue; +} + +/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ + +static void +format_event(islpci_private *priv, char *dest, const char *str, + const struct obj_mlme *mlme, u16 *length, int error) +{ + const u8 *a = mlme->address; + int n = snprintf(dest, IW_CUSTOM_MAX, + "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)", + str, + ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), + a[0], a[1], a[2], a[3], a[4], a[5], + (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") + : ""), mlme->code); + BUG_ON(n > IW_CUSTOM_MAX); + *length = n; +} + +static void +send_formatted_event(islpci_private *priv, const char *str, + const struct obj_mlme *mlme, int error) +{ + union iwreq_data wrqu; + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + wrqu.data.length = 0; + format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length, + error); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +send_simple_event(islpci_private *priv, const char *str) +{ + union iwreq_data wrqu; + int n = strlen(str); + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + BUG_ON(n > IW_CUSTOM_MAX); + wrqu.data.length = n; + strcpy(wrqu.data.pointer, str); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +link_changed(struct net_device *ndev, u32 bitrate) +{ + islpci_private *priv = netdev_priv(ndev); + + if (bitrate) { + if (priv->iw_mode == IW_MODE_INFRA) { + union iwreq_data uwrq; + prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, + NULL); + wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); + } else + send_simple_event(netdev_priv(ndev), + "Link established"); + } else + send_simple_event(netdev_priv(ndev), "Link lost"); +} + +/* Beacon/ProbeResp payload header */ +struct ieee80211_beacon_phdr { + u8 timestamp[8]; + u16 beacon_int; + u16 capab_info; +} __attribute__ ((packed)); + +#define WLAN_EID_GENERIC 0xdd +static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void +prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + + if (wpa_ie_len > MAX_WPA_IE_LEN) + wpa_ie_len = MAX_WPA_IE_LEN; + + if (down_interruptible(&priv->wpa_sem)) + return; + + /* try to use existing entry */ + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + list_move(&bss->list, &priv->bss_wpa_list); + break; + } + bss = NULL; + } + + if (bss == NULL) { + /* add a new BSS entry; if max number of entries is already + * reached, replace the least recently updated */ + if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + list_del(&bss->list); + } else { + bss = kmalloc(sizeof (*bss), GFP_ATOMIC); + if (bss != NULL) { + priv->num_bss_wpa++; + memset(bss, 0, sizeof (*bss)); + } + } + if (bss != NULL) { + memcpy(bss->bssid, bssid, ETH_ALEN); + list_add(&bss->list, &priv->bss_wpa_list); + } + } + + if (bss != NULL) { + memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); + bss->wpa_ie_len = wpa_ie_len; + bss->last_update = jiffies; + } else { + printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR + "\n", MAC2STR(bssid)); + } + + /* expire old entries from WPA list */ + while (priv->num_bss_wpa > 0) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + if (!time_after(jiffies, bss->last_update + 60 * HZ)) + break; + + list_del(&bss->list); + priv->num_bss_wpa--; + kfree(bss); + } + + up(&priv->wpa_sem); +} + +size_t +prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + size_t len = 0; + + if (down_interruptible(&priv->wpa_sem)) + return 0; + + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + break; + bss = NULL; + } + if (bss) { + len = bss->wpa_ie_len; + memcpy(wpa_ie, bss->wpa_ie, len); + } + up(&priv->wpa_sem); + + return len; +} + +void +prism54_wpa_ie_init(islpci_private *priv) +{ + INIT_LIST_HEAD(&priv->bss_wpa_list); + sema_init(&priv->wpa_sem, 1); +} + +void +prism54_wpa_ie_clean(islpci_private *priv) +{ + struct list_head *ptr, *n; + + list_for_each_safe(ptr, n, &priv->bss_wpa_list) { + struct islpci_bss_wpa_ie *bss; + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + kfree(bss); + } +} + +static void +prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, + u8 *payload, size_t len) +{ + struct ieee80211_beacon_phdr *hdr; + u8 *pos, *end; + + if (!priv->wpa) + return; + + hdr = (struct ieee80211_beacon_phdr *) payload; + pos = (u8 *) (hdr + 1); + end = payload + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " + "for " MACSTR "\n", MAC2STR(addr)); + return; + } + if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && + memcmp(pos + 2, wpa_oid, 4) == 0) { + prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); + return; + } + pos += 2 + pos[1]; + } +} + +static void +handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) +{ + if (((mlme->state == DOT11_STATE_AUTHING) || + (mlme->state == DOT11_STATE_ASSOCING)) + && mgt_mlme_answer(priv)) { + /* Someone is requesting auth and we must respond. Just send back + * the trap with error code set accordingly. + */ + mlme->code = prism54_mac_accept(&priv->acl, + mlme->address) ? 0 : 1; + mgt_set_request(priv, oid, 0, mlme); + } +} + +int +prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, + char *data) +{ + struct obj_mlme *mlme = (struct obj_mlme *) data; + struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; + struct obj_mlmeex *confirm; + u8 wpa_ie[MAX_WPA_IE_LEN]; + int wpa_ie_len; + size_t len = 0; /* u16, better? */ + u8 *payload = 0, *pos = 0; + int ret; + + /* I think all trapable objects are listed here. + * Some oids have a EX version. The difference is that they are emitted + * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) + * with more info. + * The few events already defined by the wireless tools are not really + * suited. We use the more flexible custom event facility. + */ + + if (oid >= DOT11_OID_BEACON) { + len = mlmeex->size; + payload = pos = mlmeex->data; + } + + /* I fear prism54_process_bss_data won't work with big endian data */ + if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) + prism54_process_bss_data(priv, oid, mlmeex->address, + payload, len); + + mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); + + switch (oid) { + + case GEN_OID_LINKSTATE: + link_changed(priv->ndev, (u32) *data); + break; + + case DOT11_OID_MICFAILURE: + send_simple_event(priv, "Mic failure"); + break; + + case DOT11_OID_DEAUTHENTICATE: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATE: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "ReAssociate request", mlme, 1); + break; + + case DOT11_OID_BEACON: + send_formatted_event(priv, + "Received a beacon from an unkown AP", + mlme, 0); + break; + + case DOT11_OID_PROBE: + /* we received a probe from a client. */ + send_formatted_event(priv, "Received a probe from client", mlme, + 0); + break; + + /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this + * is backward compatible layout-wise with "struct obj_mlme". + */ + + case DOT11_OID_DEAUTHENTICATEEX: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_AUTHING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + confirm->id = -1; /* or mlmeex->id ? */ + confirm->state = 0; /* not used */ + confirm->code = 0; + confirm->size = 6; + confirm->data[0] = 0x00; + confirm->data[1] = 0x00; + confirm->data[2] = 0x02; + confirm->data[3] = 0x00; + confirm->data[4] = 0x00; + confirm->data[5] = 0x00; + + ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); + + kfree(confirm); + if (ret) + return ret; + break; + + case DOT11_OID_DISASSOCIATEEX: + send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); + break; + + case DOT11_OID_ASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_AUTHING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + + confirm->id = ((struct obj_mlmeex *)mlme)->id; + confirm->state = 0; /* not used */ + confirm->code = 0; + + wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + + if (!wpa_ie_len) { + printk(KERN_DEBUG "No WPA IE found from " + "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + kfree(confirm); + break; + } + + confirm->size = wpa_ie_len; + memcpy(&confirm->data, wpa_ie, wpa_ie_len); + + mgt_set_varlen(priv, oid, confirm, wpa_ie_len); + + kfree(confirm); + + break; + + case DOT11_OID_REASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_ASSOCING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + + confirm->id = mlmeex->id; + confirm->state = 0; /* not used */ + confirm->code = 0; + + wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + + if (!wpa_ie_len) { + printk(KERN_DEBUG "No WPA IE found from " + "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + kfree(confirm); + break; + } + + confirm->size = wpa_ie_len; + memcpy(&confirm->data, wpa_ie, wpa_ie_len); + + mgt_set_varlen(priv, oid, confirm, wpa_ie_len); + + kfree(confirm); + + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Process a device trap. This is called via schedule_work(), outside of + * interrupt context, no locks held. + */ +void +prism54_process_trap(void *data) +{ + struct islpci_mgmtframe *frame = data; + struct net_device *ndev = frame->ndev; + enum oid_num_t n = mgt_oidtonum(frame->header->oid); + + if (n != OID_NUM_LAST) + prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); + islpci_mgt_release(frame); +} + +int +prism54_set_mac_address(struct net_device *ndev, void *addr) +{ + islpci_private *priv = netdev_priv(ndev); + int ret; + + if (ndev->addr_len != 6) + return -EINVAL; + ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, + &((struct sockaddr *) addr)->sa_data); + if (!ret) + memcpy(priv->ndev->dev_addr, + &((struct sockaddr *) addr)->sa_data, 6); + + return ret; +} + +/* Note: currently, use hostapd ioctl from the Host AP driver for WPA + * support. This is to be replaced with Linux wireless extensions once they + * get WPA support. */ + +/* Note II: please leave all this together as it will be easier to remove later, + * once wireless extensions add WPA support -mcgrof */ + +/* PRISM54_HOSTAPD ioctl() cmd: */ +enum { + PRISM2_SET_ENCRYPTION = 6, + PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, + PRISM2_HOSTAPD_MLME = 13, + PRISM2_HOSTAPD_SCAN_REQ = 14, +}; + +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 +#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 +#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 + +#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 +#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ +((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) + +/* Maximum length for algorithm names (-1 for nul termination) + * used in ioctl() */ +#define HOSTAP_CRYPT_ALG_NAME_LEN 16 + +struct prism2_hostapd_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; + u32 flags; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + struct { + u8 len; + u8 data[0]; + } generic_elem; + struct { +#define MLME_STA_DEAUTH 0 +#define MLME_STA_DISASSOC 1 + u16 cmd; + u16 reason_code; + } mlme; + struct { + u8 ssid_len; + u8 ssid[32]; + } scan_req; + } u; +}; + + +static int +prism2_ioctl_set_encryption(struct net_device *dev, + struct prism2_hostapd_param *param, + int param_len) +{ + islpci_private *priv = netdev_priv(dev); + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (param->u.crypt.key_len > 0) { + /* we have a key to set */ + int index = param->u.crypt.idx; + int current_index; + struct obj_key key = { DOT11_PRIV_TKIP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) { + key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ? + sizeof (param->u.crypt.key) : param->u.crypt.key_len; + memcpy(key.key, param->u.crypt.key, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!param->u.crypt.flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + /* now read the flags */ + if (param->u.crypt.flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (param->u.crypt.flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism2_ioctl_set_generic_element(struct net_device *ndev, + struct prism2_hostapd_param *param, + int param_len) +{ + islpci_private *priv = netdev_priv(ndev); + int max_len, len, alen, ret=0; + struct obj_attachment *attach; + + len = param->u.generic_elem.len; + max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; + if (max_len < 0 || max_len < len) + return -EINVAL; + + alen = sizeof(*attach) + len; + attach = kmalloc(alen, GFP_KERNEL); + if (attach == NULL) + return -ENOMEM; + + memset(attach, 0, alen); +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_REASSOC_REQ 2 + + /* Note: endianness is covered by mgt_set_varlen */ + + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ASSOC_REQ << 4); + attach->id = -1; + attach->size = len; + memcpy(attach->data, param->u.generic_elem.data, len); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); + + if (ret == 0) { + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_REASSOC_REQ << 4); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); + + if (ret == 0) + printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", + ndev->name); + } + + kfree(attach); + return ret; + +} + +static int +prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param) +{ + return -EOPNOTSUPP; +} + +static int +prism2_ioctl_scan_req(struct net_device *ndev, + struct prism2_hostapd_param *param) +{ + islpci_private *priv = netdev_priv(ndev); + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *extra = ""; + char *current_ev = "foo"; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. We can report at most + * IW_MAX_AP=64 to the range struct. But the device won't repport anything + * if you change the value of IWMAX_BSS=24. + */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) + current_ev = prism54_translate_bss(ndev, current_ev, + extra + IW_SCAN_MAX_DATA, + &(bsslist->bsslist[i]), + noise); + kfree(bsslist); + + return rvalue; +} + +static int +prism54_hostapd(struct net_device *ndev, struct iw_point *p) +{ + struct prism2_hostapd_param *param; + int ret = 0; + u32 uwrq; + + printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length); + if (p->length < sizeof(struct prism2_hostapd_param) || + p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) + return -EINVAL; + + param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + kfree(param); + return -EFAULT; + } + + switch (param->cmd) { + case PRISM2_SET_ENCRYPTION: + printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n", + ndev->name); + ret = prism2_ioctl_set_encryption(ndev, param, p->length); + break; + case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: + printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n", + ndev->name); + ret = prism2_ioctl_set_generic_element(ndev, param, + p->length); + break; + case PRISM2_HOSTAPD_MLME: + printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n", + ndev->name); + ret = prism2_ioctl_mlme(ndev, param); + break; + case PRISM2_HOSTAPD_SCAN_REQ: + printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n", + ndev->name); + ret = prism2_ioctl_scan_req(ndev, param); + break; + case PRISM54_SET_WPA: + printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n", + ndev->name); + uwrq = 1; + ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL); + break; + case PRISM54_DROP_UNENCRYPTED: + printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n", + ndev->name); +#if 0 + uwrq = 0x01; + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq); + down_write(&priv->mib_sem); + mgt_commit(priv); + up_write(&priv->mib_sem); +#endif + /* Not necessary, as set_wpa does it, should we just do it here though? */ + ret = 0; + break; + default: + printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n", + ndev->name); + ret = -EOPNOTSUPP; + break; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); + + return ret; +} + +int +prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 mlme, authen, dot1x, filter, wep; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + wep = 1; /* For privacy invoked */ + filter = 1; /* Filter out all unencrypted frames */ + dot1x = 0x01; /* To enable eap filter */ + mlme = DOT11_MLME_EXTENDED; + authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ + + down_write(&priv->mib_sem); + priv->wpa = *uwrq; + + switch (priv->wpa) { + default: + case 0: /* Clears/disables WPA and friends */ + wep = 0; + filter = 0; /* Do not filter un-encrypted data */ + dot1x = 0; + mlme = DOT11_MLME_AUTO; + printk("%s: Disabling WPA\n", ndev->name); + break; + case 2: + case 1: /* WPA */ + printk("%s: Enabling WPA\n", ndev->name); + break; + } + up_write(&priv->mib_sem); + + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); + mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); + mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); + + return 0; +} + +int +prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + *uwrq = priv->wpa; + return 0; +} + +int +prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + priv->monitor_type = + (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); + if (priv->iw_mode == IW_MODE_MONITOR) + priv->ndev->type = priv->monitor_type; + + return 0; +} + +int +prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); + return 0; +} + +int +prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + priv->priv_oid = *uwrq; + printk("%s: oid 0x%08X\n", ndev->name, *uwrq); + + return 0; +} + +int +prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response; + int ret = -EIO; + + printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); + data->length = 0; + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = + islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + priv->priv_oid, extra, 256, + &response); + printk("%s: ret: %i\n", ndev->name, ret); + if (ret || !response + || response->header->operation == PIMFOR_OP_ERROR) { + if (response) { + islpci_mgt_release(response); + } + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + if (!ret) { + data->length = response->header->length; + memcpy(extra, response->data, data->length); + islpci_mgt_release(response); + printk("%s: len: %i\n", ndev->name, data->length); + } + } + + return ret; +} + +int +prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response; + int ret = 0, response_op = PIMFOR_OP_ERROR; + + printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, + data->length); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = + islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + priv->priv_oid, extra, data->length, + &response); + printk("%s: ret: %i\n", ndev->name, ret); + if (ret || !response + || response->header->operation == PIMFOR_OP_ERROR) { + if (response) { + islpci_mgt_release(response); + } + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + if (!ret) { + response_op = response->header->operation; + printk("%s: response_op: %i\n", ndev->name, + response_op); + islpci_mgt_release(response); + } + } + + return (ret ? ret : -EINPROGRESS); +} + +static int +prism54_set_spy(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 u, oid = OID_INL_CONFIG; + + down_write(&priv->mib_sem); + mgt_get(priv, OID_INL_CONFIG, &u); + + if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) + /* disable spy */ + u &= ~INL_CONFIG_RXANNEX; + else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) + /* enable spy */ + u |= INL_CONFIG_RXANNEX; + + mgt_set(priv, OID_INL_CONFIG, &u); + mgt_commit_list(priv, &oid, 1); + up_write(&priv->mib_sem); + + return iw_handler_set_spy(ndev, info, uwrq, extra); +} + +static const iw_handler prism54_handler[] = { + (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ + (iw_handler) prism54_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ + (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ + (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ + (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ + (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ + (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + prism54_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) prism54_set_wap, /* SIOCSIWAP */ + (iw_handler) prism54_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */ + (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ + (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ + (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ + (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ + (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ + (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ + (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ + (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ + (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ + (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ + (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ + (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ + (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ + (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ + (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ + (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ + (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +}; + +/* The low order bit identify a SET (0) or a GET (1) ioctl. */ + +#define PRISM54_RESET SIOCIWFIRSTPRIV +#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 +#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 +#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 +#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 + +#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 + +#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 + +#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 + +#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 + +#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 +#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 +#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 + +#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 +#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 +#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 +#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 + +#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 +#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 + +#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } + +#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) +#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) +#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) + +/* Note : limited to 128 private ioctls (wireless tools 26) */ + +static const struct iw_priv_args prism54_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + {PRISM54_RESET, 0, 0, "reset"}, + {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_prismhdr"}, + {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_prismhdr"}, + {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getPolicy"}, + {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setPolicy"}, + {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, + {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "addMac"}, + {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "delMac"}, + {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "kickMac"}, + {PRISM54_KICK_ALL, 0, 0, "kickAll"}, + {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_wpa"}, + {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_wpa"}, + {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "dbg_oid"}, + {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, + {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, + /* --- sub-ioctls handlers --- */ + {PRISM54_GET_OID, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, + {PRISM54_SET_OID_U32, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {PRISM54_SET_OID_STR, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {PRISM54_SET_OID_ADDR, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + /* --- sub-ioctls definitions --- */ + IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), + IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), + IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), + IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), + IWPRIV_U32(DOT11_OID_STATE, "state"), + IWPRIV_U32(DOT11_OID_AID, "aid"), + + IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), + + IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), + IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), + IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), + + IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), + IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), + IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), + + IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), + + IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), + IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), + IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), + IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), + IWPRIV_U32(DOT11_OID_PSM, "psm"), + + IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), + IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), + IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), + IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), + IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), + IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), + IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), + IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), + IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), + IWPRIV_GET(DOT11_OID_RATES, "rates"), + IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), + IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), + IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), + + IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), + IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), + IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), + IWPRIV_U32(DOT11_OID_PROFILES, "profile"), + IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), + IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), + + IWPRIV_GET(DOT11_OID_BSSS, "bsss"), + IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), + IWPRIV_U32(OID_INL_MODE, "mode"), + IWPRIV_U32(OID_INL_CONFIG, "config"), + IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), + IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), + IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), +}; + +static const iw_handler prism54_private_handler[] = { + (iw_handler) prism54_reset, + (iw_handler) prism54_get_policy, + (iw_handler) prism54_set_policy, + (iw_handler) prism54_get_mac, + (iw_handler) prism54_add_mac, + (iw_handler) NULL, + (iw_handler) prism54_del_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_all, + (iw_handler) prism54_get_wpa, + (iw_handler) prism54_set_wpa, + (iw_handler) NULL, + (iw_handler) prism54_debug_oid, + (iw_handler) prism54_debug_get_oid, + (iw_handler) prism54_debug_set_oid, + (iw_handler) prism54_get_oid, + (iw_handler) prism54_set_u32, + (iw_handler) NULL, + (iw_handler) prism54_set_raw, + (iw_handler) NULL, + (iw_handler) prism54_set_raw, + (iw_handler) prism54_get_prismhdr, + (iw_handler) prism54_set_prismhdr, +}; + +const struct iw_handler_def prism54_handler_def = { + .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), + .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), + .num_private_args = + sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .standard = (iw_handler *) prism54_handler, + .private = (iw_handler *) prism54_private_handler, + .private_args = (struct iw_priv_args *) prism54_private_args, +#if WIRELESS_EXT == 16 + .spy_offset = offsetof(islpci_private, spy_data), +#endif /* WIRELESS_EXT == 16 */ +}; + +/* For wpa_supplicant */ + +int +prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + struct iwreq *wrq = (struct iwreq *) rq; + int ret = -1; + switch (cmd) { + case PRISM54_HOSTAPD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + ret = prism54_hostapd(ndev, &wrq->u.data); + return ret; + } + return -EOPNOTSUPP; +} diff -urN linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.h linux-2.4.28/drivers/net/wireless/prism54/isl_ioctl.h --- linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/isl_ioctl.h 2004-11-17 03:54:21.456392055 -0800 @@ -0,0 +1,56 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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 _ISL_IOCTL_H +#define _ISL_IOCTL_H + +#include "islpci_mgt.h" +#include "islpci_dev.h" + +#include /* New driver API */ + +#define SUPPORTED_WIRELESS_EXT 16 + +void prism54_mib_init(islpci_private *); + +struct iw_statistics *prism54_get_wireless_stats(struct net_device *); +void prism54_update_stats(islpci_private *); + +void prism54_acl_init(struct islpci_acl *); +void prism54_acl_clean(struct islpci_acl *); + +void prism54_process_trap(void *); + +void prism54_wpa_ie_init(islpci_private *priv); +void prism54_wpa_ie_clean(islpci_private *priv); +void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len); +size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); + +int prism54_set_mac_address(struct net_device *, void *); + +int prism54_ioctl(struct net_device *, struct ifreq *, int); +int prism54_set_wpa(struct net_device *, struct iw_request_info *, + __u32 *, char *); + +extern const struct iw_handler_def prism54_handler_def; + +#endif /* _ISL_IOCTL_H */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/isl_oid.h linux-2.4.28/drivers/net/wireless/prism54/isl_oid.h --- linux-2.4.27/drivers/net/wireless/prism54/isl_oid.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/isl_oid.h 2004-11-17 03:54:21.457392097 -0800 @@ -0,0 +1,507 @@ +/* + * + * + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2004 Luis R. Rodriguez + * Copyright (C) 2004 Aurelien Alleaume + * + * 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 + * + * 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 + * + */ + +#if !defined(_ISL_OID_H) +#define _ISL_OID_H + +/* + * MIB related constant and structure definitions for communicating + * with the device firmware + */ + +struct obj_ssid { + u8 length; + char octets[33]; +} __attribute__ ((packed)); + +struct obj_key { + u8 type; /* dot11_priv_t */ + u8 length; + char key[32]; +} __attribute__ ((packed)); + +struct obj_mlme { + u8 address[6]; + u16 id; + u16 state; + u16 code; +} __attribute__ ((packed)); + +struct obj_mlmeex { + u8 address[6]; + u16 id; + u16 state; + u16 code; + u16 size; + u8 data[0]; +} __attribute__ ((packed)); + +struct obj_buffer { + u32 size; + u32 addr; /* 32bit bus address */ +} __attribute__ ((packed)); + +struct obj_bss { + u8 address[6]; + int:16; /* padding */ + + char state; + char reserved; + short age; + + char quality; + char rssi; + + struct obj_ssid ssid; + short channel; + char beacon_period; + char dtim_period; + short capinfo; + short rates; + short basic_rates; + int:16; /* padding */ +} __attribute__ ((packed)); + +struct obj_bsslist { + u32 nr; + struct obj_bss bsslist[0]; +} __attribute__ ((packed)); + +struct obj_frequencies { + u16 nr; + u16 mhz[0]; +} __attribute__ ((packed)); + +struct obj_attachment { + char type; + char reserved; + short id; + short size; + char data[0]; +} __attribute__((packed)); + +/* + * in case everything's ok, the inlined function below will be + * optimized away by the compiler... + */ +static inline void +__bug_on_wrong_struct_sizes(void) +{ + BUG_ON(sizeof (struct obj_ssid) != 34); + BUG_ON(sizeof (struct obj_key) != 34); + BUG_ON(sizeof (struct obj_mlme) != 12); + BUG_ON(sizeof (struct obj_mlmeex) != 14); + BUG_ON(sizeof (struct obj_buffer) != 8); + BUG_ON(sizeof (struct obj_bss) != 60); + BUG_ON(sizeof (struct obj_bsslist) != 4); + BUG_ON(sizeof (struct obj_frequencies) != 2); +} + +enum dot11_state_t { + DOT11_STATE_NONE = 0, + DOT11_STATE_AUTHING = 1, + DOT11_STATE_AUTH = 2, + DOT11_STATE_ASSOCING = 3, + + DOT11_STATE_ASSOC = 5, + DOT11_STATE_IBSS = 6, + DOT11_STATE_WDS = 7 +}; + +enum dot11_bsstype_t { + DOT11_BSSTYPE_NONE = 0, + DOT11_BSSTYPE_INFRA = 1, + DOT11_BSSTYPE_IBSS = 2, + DOT11_BSSTYPE_ANY = 3 +}; + +enum dot11_auth_t { + DOT11_AUTH_NONE = 0, + DOT11_AUTH_OS = 1, + DOT11_AUTH_SK = 2, + DOT11_AUTH_BOTH = 3 +}; + +enum dot11_mlme_t { + DOT11_MLME_AUTO = 0, + DOT11_MLME_INTERMEDIATE = 1, + DOT11_MLME_EXTENDED = 2 +}; + +enum dot11_priv_t { + DOT11_PRIV_WEP = 0, + DOT11_PRIV_TKIP = 1 +}; + +/* Prism "Nitro" / Frameburst / "Packet Frame Grouping" + * Value is in microseconds. Represents the # microseconds + * the firmware will take to group frames before sending out then out + * together with a CSMA contention. Without this all frames are + * sent with a CSMA contention. + * Bibliography: + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html + */ +enum dot11_maxframeburst_t { + /* Values for DOT11_OID_MAXFRAMEBURST */ + DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */ + DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */ + DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */ + DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max, + * Note: firmware allows for greater values. This is a + * recommended max. I'll update this as I find + * out what the real MAX is. Also note that you don't necessarily + * get better results with a greater value here. + */ +}; + +/* Support for 802.11 long and short frame preambles. + * Long preamble uses 128-bit sync field, 8-bit CRC + * Short preamble uses 56-bit sync field, 16-bit CRC + * + * 802.11a -- not sure, both optionally ? + * 802.11b supports long and optionally short + * 802.11g supports both */ +enum dot11_preamblesettings_t { + DOT11_PREAMBLESETTING_LONG = 0, + /* Allows *only* long 802.11 preambles */ + DOT11_PREAMBLESETTING_SHORT = 1, + /* Allows *only* short 802.11 preambles */ + DOT11_PREAMBLESETTING_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* Support for 802.11 slot timing (time between packets). + * + * Long uses 802.11a slot timing (9 usec ?) + * Short uses 802.11b slot timing (20 use ?) */ +enum dot11_slotsettings_t { + DOT11_SLOTSETTINGS_LONG = 0, + /* Allows *only* long 802.11b slot timing */ + DOT11_SLOTSETTINGS_SHORT = 1, + /* Allows *only* long 802.11a slot timing */ + DOT11_SLOTSETTINGS_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* All you need to know, ERP is "Extended Rate PHY". + * An Extended Rate PHY (ERP) STA or AP shall support three different + * preamble and header formats: + * Long preamble (refer to above) + * Short preamble (refer to above) + * OFDM preamble ( ? ) + * + * I'm assuming here Protection tells the AP + * to be careful, a STA which cannot handle the long pre-amble + * has joined. + */ +enum do11_nonerpstatus_t { + DOT11_ERPSTAT_NONEPRESENT = 0, + DOT11_ERPSTAT_USEPROTECTION = 1 +}; + +/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-* + * The key here is DOT11 NON ERP NEVER protects against + * NON ERP STA's. You *don't* want this unless + * you know what you are doing. It means you will only + * get Extended Rate capabilities */ +enum dot11_nonerpprotection_t { + DOT11_NONERP_NEVER = 0, + DOT11_NONERP_ALWAYS = 1, + DOT11_NONERP_DYNAMIC = 2 +}; + +/* Preset OID configuration for 802.11 modes + * Note: DOT11_OID_CW[MIN|MAX] hold the values of the + * DCS MIN|MAX backoff used */ +enum dot11_profile_t { /* And set/allowed values */ + /* Allowed values for DOT11_OID_PROFILES */ + DOT11_PROFILE_B_ONLY = 0, + /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 31 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG + */ + DOT11_PROFILE_MIXED_G_WIFI = 1, + /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 15 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC + */ + DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */ + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_G_ONLY = 3, + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_TEST = 4, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT + */ + DOT11_PROFILE_B_WIFI = 5, + /* Same as Profile B_ONLY */ + DOT11_PROFILE_A_ONLY = 6, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs + */ + DOT11_PROFILE_MIXED_SHORT = 7 + /* Same as MIXED_G_WIFI */ +}; + + +/* The dot11d conformance level configures the 802.11d conformance levels. + * The following conformance levels exist:*/ +enum oid_inl_conformance_t { + OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ + OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ + OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to + * determine channel AND/OR just make assumption that active + * channels are valid channels */ +}; + +enum oid_inl_mode_t { + INL_MODE_NONE = -1, + INL_MODE_PROMISCUOUS = 0, + INL_MODE_CLIENT = 1, + INL_MODE_AP = 2, + INL_MODE_SNIFFER = 3 +}; + +enum oid_inl_config_t { + INL_CONFIG_NOTHING = 0x00, + INL_CONFIG_MANUALRUN = 0x01, + INL_CONFIG_FRAMETRAP = 0x02, + INL_CONFIG_RXANNEX = 0x04, + INL_CONFIG_TXANNEX = 0x08, + INL_CONFIG_WDS = 0x10 +}; + +enum oid_inl_phycap_t { + INL_PHYCAP_2400MHZ = 1, + INL_PHYCAP_5000MHZ = 2, + INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ +}; + + +enum oid_num_t { + GEN_OID_MACADDRESS = 0, + GEN_OID_LINKSTATE, + GEN_OID_WATCHDOG, + GEN_OID_MIBOP, + GEN_OID_OPTIONS, + GEN_OID_LEDCONFIG, + + /* 802.11 */ + DOT11_OID_BSSTYPE, + DOT11_OID_BSSID, + DOT11_OID_SSID, + DOT11_OID_STATE, + DOT11_OID_AID, + DOT11_OID_COUNTRYSTRING, + DOT11_OID_SSIDOVERRIDE, + + DOT11_OID_MEDIUMLIMIT, + DOT11_OID_BEACONPERIOD, + DOT11_OID_DTIMPERIOD, + DOT11_OID_ATIMWINDOW, + DOT11_OID_LISTENINTERVAL, + DOT11_OID_CFPPERIOD, + DOT11_OID_CFPDURATION, + + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYID, + DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + DOT11_OID_STAKEY, + DOT11_OID_REKEYTHRESHOLD, + DOT11_OID_STASC, + + DOT11_OID_PRIVTXREJECTED, + DOT11_OID_PRIVRXPLAIN, + DOT11_OID_PRIVRXFAILED, + DOT11_OID_PRIVRXNOKEY, + + DOT11_OID_RTSTHRESH, + DOT11_OID_FRAGTHRESH, + DOT11_OID_SHORTRETRIES, + DOT11_OID_LONGRETRIES, + DOT11_OID_MAXTXLIFETIME, + DOT11_OID_MAXRXLIFETIME, + DOT11_OID_AUTHRESPTIMEOUT, + DOT11_OID_ASSOCRESPTIMEOUT, + + DOT11_OID_ALOFT_TABLE, + DOT11_OID_ALOFT_CTRL_TABLE, + DOT11_OID_ALOFT_RETREAT, + DOT11_OID_ALOFT_PROGRESS, + DOT11_OID_ALOFT_FIXEDRATE, + DOT11_OID_ALOFT_RSSIGRAPH, + DOT11_OID_ALOFT_CONFIG, + + DOT11_OID_VDCFX, + DOT11_OID_MAXFRAMEBURST, + + DOT11_OID_PSM, + DOT11_OID_CAMTIMEOUT, + DOT11_OID_RECEIVEDTIMS, + DOT11_OID_ROAMPREFERENCE, + + DOT11_OID_BRIDGELOCAL, + DOT11_OID_CLIENTS, + DOT11_OID_CLIENTSASSOCIATED, + DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + DOT11_OID_CLIENTFIND, + DOT11_OID_WDSLINKADD, + DOT11_OID_WDSLINKREMOVE, + DOT11_OID_EAPAUTHSTA, + DOT11_OID_EAPUNAUTHSTA, + DOT11_OID_DOT1XENABLE, + DOT11_OID_MICFAILURE, + DOT11_OID_REKEYINDICATE, + + DOT11_OID_MPDUTXSUCCESSFUL, + DOT11_OID_MPDUTXONERETRY, + DOT11_OID_MPDUTXMULTIPLERETRIES, + DOT11_OID_MPDUTXFAILED, + DOT11_OID_MPDURXSUCCESSFUL, + DOT11_OID_MPDURXDUPS, + DOT11_OID_RTSSUCCESSFUL, + DOT11_OID_RTSFAILED, + DOT11_OID_ACKFAILED, + DOT11_OID_FRAMERECEIVES, + DOT11_OID_FRAMEERRORS, + DOT11_OID_FRAMEABORTS, + DOT11_OID_FRAMEABORTSPHY, + + DOT11_OID_SLOTTIME, + DOT11_OID_CWMIN, /* MIN DCS backoff */ + DOT11_OID_CWMAX, /* MAX DCS backoff */ + DOT11_OID_ACKWINDOW, + DOT11_OID_ANTENNARX, + DOT11_OID_ANTENNATX, + DOT11_OID_ANTENNADIVERSITY, + DOT11_OID_CHANNEL, + DOT11_OID_EDTHRESHOLD, + DOT11_OID_PREAMBLESETTINGS, + DOT11_OID_RATES, + DOT11_OID_CCAMODESUPPORTED, + DOT11_OID_CCAMODE, + DOT11_OID_RSSIVECTOR, + DOT11_OID_OUTPUTPOWERTABLE, + DOT11_OID_OUTPUTPOWER, + DOT11_OID_SUPPORTEDRATES, + DOT11_OID_FREQUENCY, + DOT11_OID_SUPPORTEDFREQUENCIES, + DOT11_OID_NOISEFLOOR, + DOT11_OID_FREQUENCYACTIVITY, + DOT11_OID_IQCALIBRATIONTABLE, + DOT11_OID_NONERPPROTECTION, + DOT11_OID_SLOTSETTINGS, + DOT11_OID_NONERPTIMEOUT, + DOT11_OID_PROFILES, + DOT11_OID_EXTENDEDRATES, + + DOT11_OID_DEAUTHENTICATE, + DOT11_OID_AUTHENTICATE, + DOT11_OID_DISASSOCIATE, + DOT11_OID_ASSOCIATE, + DOT11_OID_SCAN, + DOT11_OID_BEACON, + DOT11_OID_PROBE, + DOT11_OID_DEAUTHENTICATEEX, + DOT11_OID_AUTHENTICATEEX, + DOT11_OID_DISASSOCIATEEX, + DOT11_OID_ASSOCIATEEX, + DOT11_OID_REASSOCIATE, + DOT11_OID_REASSOCIATEEX, + + DOT11_OID_NONERPSTATUS, + + DOT11_OID_STATIMEOUT, + DOT11_OID_MLMEAUTOLEVEL, + DOT11_OID_BSSTIMEOUT, + DOT11_OID_ATTACHMENT, + DOT11_OID_PSMBUFFER, + + DOT11_OID_BSSS, + DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + DOT11_OID_BSSFIND, + DOT11_OID_BSSLIST, + + OID_INL_TUNNEL, + OID_INL_MEMADDR, + OID_INL_MEMORY, + OID_INL_MODE, + OID_INL_COMPONENT_NR, + OID_INL_VERSION, + OID_INL_INTERFACE_ID, + OID_INL_COMPONENT_ID, + OID_INL_CONFIG, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_PHYCAPABILITIES, + OID_INL_OUTPUTPOWER, + + OID_NUM_LAST +}; + +#define OID_FLAG_CACHED 0x80 +#define OID_FLAG_TYPE 0x7f + +#define OID_TYPE_U32 0x01 +#define OID_TYPE_SSID 0x02 +#define OID_TYPE_KEY 0x03 +#define OID_TYPE_BUFFER 0x04 +#define OID_TYPE_BSS 0x05 +#define OID_TYPE_BSSLIST 0x06 +#define OID_TYPE_FREQUENCIES 0x07 +#define OID_TYPE_MLME 0x08 +#define OID_TYPE_MLMEEX 0x09 +#define OID_TYPE_ADDR 0x0A +#define OID_TYPE_RAW 0x0B +#define OID_TYPE_ATTACH 0x0C + +/* OID_TYPE_MLMEEX is special because of a variable size field when sending. + * Not yet implemented (not used in driver anyway). + */ + +struct oid_t { + enum oid_num_t oid; + short range; /* to define a range of oid */ + short size; /* max size of the associated data */ + char flags; +}; + +union oid_res_t { + void *ptr; + u32 u; +}; + +#define IWMAX_BITRATES 20 +#define IWMAX_BSS 24 +#define IWMAX_FREQ 30 +#define PRIV_STR_SIZE 1024 + +#endif /* !defined(_ISL_OID_H) */ +/* EOF */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.c linux-2.4.28/drivers/net/wireless/prism54/islpci_dev.c --- linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_dev.c 2004-11-17 03:54:21.460392220 -0800 @@ -0,0 +1,955 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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 + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "isl_ioctl.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "islpci_eth.h" +#include "oid_mgt.h" + +#define ISL3877_IMAGE_FILE "isl3877" +#define ISL3886_IMAGE_FILE "isl3886" +#define ISL3890_IMAGE_FILE "isl3890" + +static int prism54_bring_down(islpci_private *); +static int islpci_alloc_memory(islpci_private *); + +/* Temporary dummy MAC address to use until firmware is loaded. + * The idea there is that some tools (such as nameif) may query + * the MAC address before the netdev is 'open'. By using a valid + * OUI prefix, they can process the netdev properly. + * Of course, this is not the final/real MAC address. It doesn't + * matter, as you are suppose to be able to change it anytime via + * ndev->set_mac_address. Jean II */ +const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; + +static int +isl_upload_firmware(islpci_private *priv) +{ + u32 reg, rc; + void *device_base = priv->device_base; + + /* clear the RAMBoot and the Reset bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the Reset bit without reading the register ! */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reboot */ + mdelay(50); + + { + const struct firmware *fw_entry = NULL; + long fw_len; + const u32 *fw_ptr; + + rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV); + if (rc) { + printk(KERN_ERR + "%s: request_firmware() failed for '%s'\n", + "prism54", priv->firmware); + return rc; + } + /* prepare the Direct Memory Base register */ + reg = ISL38XX_DEV_FIRMWARE_ADDRES; + + fw_ptr = (u32 *) fw_entry->data; + fw_len = fw_entry->size; + + if (fw_len % 4) { + printk(KERN_ERR + "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", + "prism54", priv->firmware); + release_firmware(fw_entry); + return -EILSEQ; /* Illegal byte sequence */; + } + + while (fw_len > 0) { + long _fw_len = + (fw_len > + ISL38XX_MEMORY_WINDOW_SIZE) ? + ISL38XX_MEMORY_WINDOW_SIZE : fw_len; + u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + + /* set the cards base address for writting the data */ + isl38xx_w32_flush(device_base, reg, + ISL38XX_DIR_MEM_BASE_REG); + wmb(); /* be paranoid */ + + /* increment the write address for next iteration */ + reg += _fw_len; + fw_len -= _fw_len; + + /* write the data to the Direct Memory Window 32bit-wise */ + /* memcpy_toio() doesn't guarantee 32bit writes :-| */ + while (_fw_len > 0) { + /* use non-swapping writel() */ + __raw_writel(*fw_ptr, dev_fw_ptr); + fw_ptr++, dev_fw_ptr++; + _fw_len -= 4; + } + + /* flush PCI posting */ + (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); + wmb(); /* be paranoid again */ + + BUG_ON(_fw_len != 0); + } + + BUG_ON(fw_len != 0); + + /* Firmware version is at offset 40 (also for "newmac") */ + printk(KERN_DEBUG "%s: firmware version: %.8s\n", + priv->ndev->name, fw_entry->data + 40); + + release_firmware(fw_entry); + } + + /* now reset the device + * clear the Reset & ClkRun bit, set the RAMBoot bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_CLKRUN; + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg |= ISL38XX_CTRL_STAT_RAMBOOT; + isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit latches the host override and RAMBoot bits + * into the device for operation when the reset bit is reset */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the reset bit should start the whole circus */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + return 0; +} + +/****************************************************************************** + Device Interrupt Handler +******************************************************************************/ + +irqreturn_t +islpci_interrupt(int irq, void *config, struct pt_regs *regs) +{ + u32 reg; + islpci_private *priv = config; + struct net_device *ndev = priv->ndev; + void *device = priv->device_base; + int powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* lock the interrupt handler */ + spin_lock(&priv->slock); + + /* received an interrupt request on a shared IRQ line + * first check whether the device is in sleep mode */ + reg = readl(device + ISL38XX_CTRL_STAT_REG); + if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) + /* device is in sleep mode, IRQ was generated by someone else */ + { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); +#endif + spin_unlock(&priv->slock); + return IRQ_NONE; + } + + + /* check whether there is any source of interrupt on the device */ + reg = readl(device + ISL38XX_INT_IDENT_REG); + + /* also check the contents of the Interrupt Enable Register, because this + * will filter out interrupt sources from other devices on the same irq ! */ + reg &= readl(device + ISL38XX_INT_EN_REG); + reg &= ISL38XX_INT_SOURCES; + + if (reg != 0) { + if (islpci_get_state(priv) != PRV_STATE_SLEEP) + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* reset the request bits in the Identification register */ + isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, + "IRQ: Identification register 0x%p 0x%x \n", device, reg); +#endif + + /* check for each bit in the register separately */ + if (reg & ISL38XX_INT_IDENT_UPDATE) { +#if VERBOSE > SHOW_ERROR_MESSAGES + /* Queue has been updated */ + DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + driver_curr_frag[0]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[1]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[2]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[3]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[4]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[5]) + ); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + device_curr_frag[0]), + le32_to_cpu(priv->control_block-> + device_curr_frag[1]), + le32_to_cpu(priv->control_block-> + device_curr_frag[2]), + le32_to_cpu(priv->control_block-> + device_curr_frag[3]), + le32_to_cpu(priv->control_block-> + device_curr_frag[4]), + le32_to_cpu(priv->control_block-> + device_curr_frag[5]) + ); +#endif + + /* cleanup the data low transmit queue */ + islpci_eth_cleanup_transmit(priv, priv->control_block); + + /* device is in active state, update the + * powerstate flag if necessary */ + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* check all three queues in priority order + * call the PIMFOR receive function until the + * queue is empty */ + if (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_MGMTQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Management Queue\n"); +#endif + islpci_mgt_receive(ndev); + + islpci_mgt_cleanup_transmit(ndev); + + /* Refill slots in receive queue */ + islpci_mgmt_rx_fill(ndev); + + /* no need to trigger the device, next + islpci_mgt_transaction does it */ + } + + while (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_DATA_LQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Data Low Queue \n"); +#endif + islpci_eth_receive(priv); + } + + /* check whether the data transmit queues were full */ + if (priv->data_low_tx_full) { + /* check whether the transmit is not full anymore */ + if (ISL38XX_CB_TX_QSIZE - + isl38xx_in_queue(priv->control_block, + ISL38XX_CB_TX_DATA_LQ) >= + ISL38XX_MIN_QTHRESHOLD) { + /* nope, the driver is ready for more network frames */ + netif_wake_queue(priv->ndev); + + /* reset the full flag */ + priv->data_low_tx_full = 0; + } + } + } + + if (reg & ISL38XX_INT_IDENT_INIT) { + /* Device has been initialized */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "IRQ: Init flag, device initialized \n"); +#endif + wake_up(&priv->reset_done); + } + + if (reg & ISL38XX_INT_IDENT_SLEEP) { + /* Device intends to move to powersave state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); +#endif + isl38xx_handle_sleep_request(priv->control_block, + &powerstate, + priv->device_base); + } + + if (reg & ISL38XX_INT_IDENT_WAKEUP) { + /* Device has been woken up to active state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); +#endif + + isl38xx_handle_wakeup(priv->control_block, + &powerstate, priv->device_base); + } + } else { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); +#endif + spin_unlock(&priv->slock); + return IRQ_NONE; + } + + /* sleep -> ready */ + if (islpci_get_state(priv) == PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_ACTIVE_STATE) + islpci_set_state(priv, PRV_STATE_READY); + + /* !sleep -> sleep */ + if (islpci_get_state(priv) != PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_POWERSAVE_STATE) + islpci_set_state(priv, PRV_STATE_SLEEP); + + /* unlock the interrupt handler */ + spin_unlock(&priv->slock); + + return IRQ_HANDLED; +} + +/****************************************************************************** + Network Interface Control & Statistical functions +******************************************************************************/ +static int +islpci_open(struct net_device *ndev) +{ + u32 rc; + islpci_private *priv = netdev_priv(ndev); + + /* reset data structures, upload firmware and reset device */ + rc = islpci_reset(priv,1); + if (rc) { + prism54_bring_down(priv); + return rc; /* Returns informative message */ + } + + netif_start_queue(ndev); +/* netif_mark_up( ndev ); */ + + return 0; +} + +static int +islpci_close(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); + + netif_stop_queue(ndev); + + return prism54_bring_down(priv); +} + +static int +prism54_bring_down(islpci_private *priv) +{ + void *device_base = priv->device_base; + u32 reg; + /* we are going to shutdown the device */ + islpci_set_state(priv, PRV_STATE_PREBOOT); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* For safety reasons, we may want to ensure that no DMA transfer is + * currently in progress by emptying the TX and RX queues. */ + + /* wait until interrupts have finished executing on other CPUs */ + prism54_synchronize_irq(priv->pdev->irq); + + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(50*HZ/1000); + + return 0; +} + +static int +islpci_upload_fw(islpci_private *priv) +{ + islpci_state_t old_state; + u32 rc; + + old_state = islpci_set_state(priv, PRV_STATE_BOOT); + + printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); + + rc = isl_upload_firmware(priv); + if (rc) { + /* error uploading the firmware */ + printk(KERN_ERR "%s: could not upload firmware ('%s')\n", + priv->ndev->name, priv->firmware); + + islpci_set_state(priv, old_state); + return rc; + } + + printk(KERN_DEBUG "%s: firmware upload complete\n", + priv->ndev->name); + + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + return 0; +} + +static int +islpci_reset_if(islpci_private *priv) +{ + long remaining; + int result = -ETIME; + int count; + + DEFINE_WAIT(wait); + prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); + + /* now the last step is to reset the interface */ + isl38xx_interface_reset(priv->device_base, priv->device_host_address); + islpci_set_state(priv, PRV_STATE_PREINIT); + + for(count = 0; count < 2 && result; count++) { + /* The software reset acknowledge needs about 220 msec here. + * Be conservative and wait for up to one second. */ + + set_current_state(TASK_UNINTERRUPTIBLE); + remaining = schedule_timeout(HZ); + + if(remaining > 0) { + result = 0; + break; + } + + /* If we're here it's because our IRQ hasn't yet gone through. + * Retry a bit more... + */ + printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n", + priv->ndev->name); + } + + finish_wait(&priv->reset_done, &wait); + + if (result) { + printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); + return result; + } + + islpci_set_state(priv, PRV_STATE_INIT); + + /* Now that the device is 100% up, let's allow + * for the other interrupts -- + * NOTE: this is not *yet* true since we've only allowed the + * INIT interrupt on the IRQ line. We can perhaps poll + * the IRQ line until we know for sure the reset went through */ + isl38xx_enable_common_interrupts(priv->device_base); + + down_write(&priv->mib_sem); + result = mgt_commit(priv); + if (result) { + printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); + up_write(&priv->mib_sem); + return result; + } + up_write(&priv->mib_sem); + + islpci_set_state(priv, PRV_STATE_READY); + + printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name); + return 0; +} + +int +islpci_reset(islpci_private *priv, int reload_firmware) +{ + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + unsigned counter; + int rc; + + if (reload_firmware) + islpci_set_state(priv, PRV_STATE_PREBOOT); + else + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* flush all management queues */ + priv->index_mgmt_tx = 0; + priv->index_mgmt_rx = 0; + + /* clear the indexes in the frame pointer */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + cb->driver_curr_frag[counter] = cpu_to_le32(0); + cb->device_curr_frag[counter] = cpu_to_le32(0); + } + + /* reset the mgmt receive queue */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr); + } + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + cb->rx_data_low[counter].address = + cpu_to_le32((u32) priv->pci_map_rx_address[counter]); + } + + /* since the receive queues are filled with empty fragments, now we can + * set the corresponding indexes in the Control Block */ + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = + cpu_to_le32(ISL38XX_CB_RX_QSIZE); + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); + + /* reset the remaining real index registers and full flags */ + priv->free_data_rx = 0; + priv->free_data_tx = 0; + priv->data_low_tx_full = 0; + + if (reload_firmware) { /* Should we load the firmware ? */ + /* now that the data structures are cleaned up, upload + * firmware and reset interface */ + rc = islpci_upload_fw(priv); + if (rc) { + printk(KERN_ERR "%s: islpci_reset: failure\n", + priv->ndev->name); + return rc; + } + } + + /* finally reset interface */ + rc = islpci_reset_if(priv); + if (rc) + printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); + return rc; +} + +struct net_device_stats * +islpci_statistics(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n"); +#endif + + return &priv->statistics; +} + +/****************************************************************************** + Network device configuration functions +******************************************************************************/ +static int +islpci_alloc_memory(islpci_private *priv) +{ + int counter; + +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG "islpci_alloc_memory\n"); +#endif + + /* remap the PCI device base address to accessable */ + if (!(priv->device_base = + ioremap(pci_resource_start(priv->pdev, 0), + ISL38XX_PCI_MEM_SIZE))) { + /* error in remapping the PCI device memory address range */ + printk(KERN_ERR "PCI memory remapping failed \n"); + return -1; + } + + /* memory layout for consistent DMA region: + * + * Area 1: Control Block for the device interface + * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that + * the number of supported stations in the AP determines the minimal + * size of the buffer ! + */ + + /* perform the allocation */ + priv->driver_mem_address = pci_alloc_consistent(priv->pdev, + HOST_MEM_BLOCK, + &priv-> + device_host_address); + + if (!priv->driver_mem_address) { + /* error allocating the block of PCI memory */ + printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", + "prism54"); + return -1; + } + + /* assign the Control Block to the first address of the allocated area */ + priv->control_block = + (isl38xx_control_block *) priv->driver_mem_address; + + /* set the Power Save Buffer pointer directly behind the CB */ + priv->device_psm_buffer = + priv->device_host_address + CONTROL_BLOCK_SIZE; + + /* make sure all buffer pointers are initialized */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); + priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); + } + + priv->index_mgmt_rx = 0; + memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); + memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); + + /* allocate rx queue for management frames */ + if (islpci_mgmt_rx_fill(priv->ndev) < 0) + goto out_free; + + /* now get the data rx skb's */ + memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); + memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + struct sk_buff *skb; + + /* allocate an sk_buff for received data frames storage + * each frame on receive size consists of 1 fragment + * include any required allignment operations */ + if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { + /* error allocating an sk_buff structure elements */ + printk(KERN_ERR "Error allocating skb.\n"); + skb = NULL; + goto out_free; + } + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + /* add the new allocated sk_buff to the buffer array */ + priv->data_low_rx[counter] = skb; + + /* map the allocated skb data area to pci */ + priv->pci_map_rx_address[counter] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (!priv->pci_map_rx_address[counter]) { + /* error mapping the buffer to device + accessable memory address */ + printk(KERN_ERR "failed to map skb DMA'able\n"); + goto out_free; + } + } + + prism54_acl_init(&priv->acl); + prism54_wpa_ie_init(priv); + if (mgt_init(priv)) + goto out_free; + + return 0; + out_free: + islpci_free_memory(priv); + return -1; +} + +int +islpci_free_memory(islpci_private *priv) +{ + int counter; + + if (priv->device_base) + iounmap(priv->device_base); + priv->device_base = NULL; + + /* free consistent DMA area... */ + if (priv->driver_mem_address) + pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); + + /* clear some dangling pointers */ + priv->driver_mem_address = NULL; + priv->device_host_address = 0; + priv->device_psm_buffer = 0; + priv->control_block = NULL; + + /* clean up mgmt rx buffers */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + struct islpci_membuf *buf = &priv->mgmt_rx[counter]; + if (buf->pci_addr) + pci_unmap_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + buf->pci_addr = 0; + if (buf->mem) + kfree(buf->mem); + buf->size = 0; + buf->mem = NULL; + } + + /* clean up data rx buffers */ + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + if (priv->pci_map_rx_address[counter]) + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[counter], + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + priv->pci_map_rx_address[counter] = 0; + + if (priv->data_low_rx[counter]) + dev_kfree_skb(priv->data_low_rx[counter]); + priv->data_low_rx[counter] = NULL; + } + + /* Free the acces control list and the WPA list */ + prism54_acl_clean(&priv->acl); + prism54_wpa_ie_clean(priv); + mgt_clean(priv); + + return 0; +} + +#if 0 +static void +islpci_set_multicast_list(struct net_device *dev) +{ + /* put device into promisc mode and let network layer handle it */ +} +#endif + +struct net_device * +islpci_setup(struct pci_dev *pdev) +{ + islpci_private *priv; + struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); + + if (!ndev) + return ndev; + + SET_MODULE_OWNER(ndev); + pci_set_drvdata(pdev, ndev); +#if defined(SET_NETDEV_DEV) + SET_NETDEV_DEV(ndev, &pdev->dev); +#endif + + /* setup the structure members */ + ndev->base_addr = pci_resource_start(pdev, 0); + ndev->irq = pdev->irq; + + /* initialize the function pointers */ + ndev->open = &islpci_open; + ndev->stop = &islpci_close; + ndev->get_stats = &islpci_statistics; + ndev->get_wireless_stats = &prism54_get_wireless_stats; + ndev->do_ioctl = &prism54_ioctl; + ndev->wireless_handlers = + (struct iw_handler_def *) &prism54_handler_def; + + ndev->hard_start_xmit = &islpci_eth_transmit; + /* ndev->set_multicast_list = &islpci_set_multicast_list; */ + ndev->addr_len = ETH_ALEN; + ndev->set_mac_address = &prism54_set_mac_address; + /* Get a non-zero dummy MAC address for nameif. Jean II */ + memcpy(ndev->dev_addr, dummy_mac, 6); + +#ifdef HAVE_TX_TIMEOUT + ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; + ndev->tx_timeout = &islpci_eth_tx_timeout; +#endif + + /* allocate a private device structure to the network device */ + priv = netdev_priv(ndev); + priv->ndev = ndev; + priv->pdev = pdev; + priv->monitor_type = ARPHRD_IEEE80211; + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? + priv->monitor_type : ARPHRD_ETHER; + +#if WIRELESS_EXT > 16 + /* Add pointers to enable iwspy support. */ + priv->wireless_data.spy_data = &priv->spy_data; + ndev->wireless_data = &priv->wireless_data; +#endif /* WIRELESS_EXT > 16 */ + + /* save the start and end address of the PCI memory area */ + ndev->mem_start = (unsigned long) priv->device_base; + ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); +#endif + + init_waitqueue_head(&priv->reset_done); + + /* init the queue read locks, process wait counter */ + sema_init(&priv->mgmt_sem, 1); + priv->mgmt_received = NULL; + init_waitqueue_head(&priv->mgmt_wqueue); + sema_init(&priv->stats_sem, 1); + spin_lock_init(&priv->slock); + + /* init state machine with off#1 state */ + priv->state = PRV_STATE_OFF; + priv->state_off = 1; + + /* initialize workqueue's */ + INIT_WORK(&priv->stats_work, + (void (*)(void *)) prism54_update_stats, priv); + priv->stats_timestamp = 0; + + INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv); + priv->reset_task_pending = 0; + + /* allocate various memory areas */ + if (islpci_alloc_memory(priv)) + goto do_free_netdev; + + /* select the firmware file depending on the device id */ + switch (pdev->device) { + case 0x3877: + strcpy(priv->firmware, ISL3877_IMAGE_FILE); + break; + + case 0x3886: + strcpy(priv->firmware, ISL3886_IMAGE_FILE); + break; + + default: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + } + + if (register_netdev(ndev)) { + DEBUG(SHOW_ERROR_MESSAGES, + "ERROR: register_netdev() failed \n"); + goto do_islpci_free_memory; + } + + return ndev; + + do_islpci_free_memory: + islpci_free_memory(priv); + do_free_netdev: + pci_set_drvdata(pdev, NULL); + free_netdev(ndev); + priv = NULL; + return NULL; +} + +islpci_state_t +islpci_set_state(islpci_private *priv, islpci_state_t new_state) +{ + islpci_state_t old_state; + + /* lock */ + old_state = priv->state; + + /* this means either a race condition or some serious error in + * the driver code */ + switch (new_state) { + case PRV_STATE_OFF: + priv->state_off++; + default: + priv->state = new_state; + break; + + case PRV_STATE_PREBOOT: + /* there are actually many off-states, enumerated by + * state_off */ + if (old_state == PRV_STATE_OFF) + priv->state_off--; + + /* only if hw_unavailable is zero now it means we either + * were in off#1 state, or came here from + * somewhere else */ + if (!priv->state_off) + priv->state = new_state; + break; + }; +#if 0 + printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", + priv->ndev->name, old_state, new_state, priv->state_off); +#endif + + /* invariants */ + BUG_ON(priv->state_off < 0); + BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); + BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); + + /* unlock */ + return old_state; +} diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.h linux-2.4.28/drivers/net/wireless/prism54/islpci_dev.h --- linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_dev.h 2004-11-17 03:54:21.461392261 -0800 @@ -0,0 +1,219 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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 _ISLPCI_DEV_H +#define _ISLPCI_DEV_H + +#include +#include +#include +#include +#include + +#include "isl_38xx.h" +#include "isl_oid.h" +#include "islpci_mgt.h" + +/* some states might not be superflous and may be removed when + design is finalized (hvr) */ +typedef enum { + PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ + PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ + PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ + PRV_STATE_POSTBOOT, /* after boot state, need reset now */ + PRV_STATE_PREINIT, /* pre-init state */ + PRV_STATE_INIT, /* init state (restore MIB backup to device) */ + PRV_STATE_READY, /* driver&device are in operational state */ + PRV_STATE_SLEEP /* device in sleep mode */ +} islpci_state_t; + +/* ACL using MAC address */ +struct mac_entry { + struct list_head _list; + char addr[ETH_ALEN]; +}; + +struct islpci_acl { + enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; + struct list_head mac_list; /* a list of mac_entry */ + int size; /* size of queue */ + struct semaphore sem; /* accessed in ioctls and trap_work */ +}; + +struct islpci_membuf { + int size; /* size of memory */ + void *mem; /* address of memory as seen by CPU */ + dma_addr_t pci_addr; /* address of memory as seen by device */ +}; + +#define MAX_BSS_WPA_IE_COUNT 64 +#define MAX_WPA_IE_LEN 64 +struct islpci_bss_wpa_ie { + struct list_head list; + unsigned long last_update; + u8 bssid[ETH_ALEN]; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + +}; + +typedef struct { + spinlock_t slock; /* generic spinlock; */ + + u32 priv_oid; + + /* our mib cache */ + u32 iw_mode; + struct rw_semaphore mib_sem; + void **mib; + char nickname[IW_ESSID_MAX_SIZE+1]; + + /* Take care of the wireless stats */ + struct work_struct stats_work; + struct semaphore stats_sem; + /* remember when we last updated the stats */ + unsigned long stats_timestamp; + /* The first is accessed under semaphore locking. + * The second is the clean one we return to iwconfig. + */ + struct iw_statistics local_iwstatistics; + struct iw_statistics iwstatistics; + + struct iw_spy_data spy_data; /* iwspy support */ + +#if WIRELESS_EXT > 16 + struct iw_public_data wireless_data; +#endif /* WIRELESS_EXT > 16 */ + + int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ + + struct islpci_acl acl; + + /* PCI bus allocation & configuration members */ + struct pci_dev *pdev; /* PCI structure information */ + u32 pci_state[16]; /* used for suspend/resume */ + char firmware[33]; + + void *device_base; /* ioremapped device base address */ + + /* consistent DMA region */ + void *driver_mem_address; /* base DMA address */ + dma_addr_t device_host_address; /* base DMA address (bus address) */ + dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ + + /* our network_device structure */ + struct net_device *ndev; + + /* device queue interface members */ + struct isl38xx_cb *control_block; /* device control block + (== driver_mem_address!) */ + + /* Each queue has three indexes: + * free/index_mgmt/data_rx/tx (called index, see below), + * driver_curr_frag, and device_curr_frag (in the control block) + * All indexes are ever-increasing, but interpreted modulo the + * device queue size when used. + * index <= device_curr_frag <= driver_curr_frag at all times + * For rx queues, [index, device_curr_frag) contains fragments + * that the interrupt processing needs to handle (owned by driver). + * [device_curr_frag, driver_curr_frag) is the free space in the + * rx queue, waiting for data (owned by device). The driver + * increments driver_curr_frag to indicate to the device that more + * buffers are available. + * If device_curr_frag == driver_curr_frag, no more rx buffers are + * available, and the rx DMA engine of the device is halted. + * For tx queues, [index, device_curr_frag) contains fragments + * where tx is done; they need to be freed (owned by driver). + * [device_curr_frag, driver_curr_frag) contains the frames + * that are being transferred (owned by device). The driver + * increments driver_curr_frag to indicate that more tx work + * needs to be done. + */ + u32 index_mgmt_rx; /* real index mgmt rx queue */ + u32 index_mgmt_tx; /* read index mgmt tx queue */ + u32 free_data_rx; /* free pointer data rx queue */ + u32 free_data_tx; /* free pointer data tx queue */ + u32 data_low_tx_full; /* full detected flag */ + + /* frame memory buffers for the device queues */ + struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; + struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; + struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; + struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; + dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; + dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; + + /* driver network interface members */ + struct net_device_stats statistics; + + /* wait for a reset interrupt */ + wait_queue_head_t reset_done; + + /* used by islpci_mgt_transaction */ + struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ + struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ + wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ + + /* state machine */ + islpci_state_t state; + int state_off; /* enumeration of off-state, if 0 then + * we're not in any off-state */ + + /* WPA stuff */ + int wpa; /* WPA mode enabled */ + struct list_head bss_wpa_list; + int num_bss_wpa; + struct semaphore wpa_sem; + + struct work_struct reset_task; + int reset_task_pending; +} islpci_private; + +static inline islpci_state_t +islpci_get_state(islpci_private *priv) +{ + /* lock */ + return priv->state; + /* unlock */ +} + +islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); + +#define ISLPCI_TX_TIMEOUT (2*HZ) + +irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); + +int prism54_post_setup(islpci_private *, int); +int islpci_reset(islpci_private *, int); + +static inline void +islpci_trigger(islpci_private *priv) +{ + isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, + priv->device_base); +} + +struct net_device_stats *islpci_statistics(struct net_device *); + +int islpci_free_memory(islpci_private *); +struct net_device *islpci_setup(struct pci_dev *); +#endif /* _ISLPCI_DEV_H */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.c linux-2.4.28/drivers/net/wireless/prism54/islpci_eth.c --- linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_eth.c 2004-11-17 03:54:21.462392302 -0800 @@ -0,0 +1,519 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2004 Aurelien Alleaume + * 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 + * + * 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 + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_eth.h" +#include "islpci_mgt.h" +#include "oid_mgt.h" + +/****************************************************************************** + Network Interface functions +******************************************************************************/ +void +islpci_eth_cleanup_transmit(islpci_private *priv, + isl38xx_control_block *control_block) +{ + struct sk_buff *skb; + u32 index; + + /* compare the control block read pointer with the free pointer */ + while (priv->free_data_tx != + le32_to_cpu(control_block-> + device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { + /* read the index of the first fragment to be freed */ + index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; + + /* check for holes in the arrays caused by multi fragment frames + * searching for the last fragment of a frame */ + if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + /* entry is the last fragment of a frame + * free the skb structure and unmap pci memory */ + skb = priv->data_low_tx[index]; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", + skb, skb->data, skb->len, skb->truesize); +#endif + + pci_unmap_single(priv->pdev, + priv->pci_map_tx_address[index], + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + skb = NULL; + } + /* increment the free data low queue pointer */ + priv->free_data_tx++; + } +} + +int +islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = priv->control_block; + u32 index; + dma_addr_t pci_map_address; + int frame_size; + isl38xx_fragment *fragment; + int offset; + struct sk_buff *newskb; + int newskb_offset; + unsigned long flags; + unsigned char wds_mac[6]; + u32 curr_frag; + int err = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); +#endif + + /* lock the driver code */ + spin_lock_irqsave(&priv->slock, flags); + + /* determine the amount of fragments needed to store the frame */ + + frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + if (init_wds) + frame_size += 6; + + /* check whether the destination queue has enough fragments for the frame */ + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); + if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { + printk(KERN_ERR "%s: transmit device queue full when awake\n", + ndev->name); + netif_stop_queue(ndev); + + /* trigger the device */ + isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + err = -EBUSY; + goto drop_free; + } + /* Check alignment and WDS frame formatting. The start of the packet should + * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes + * and add WDS address information */ + if (likely(((long) skb->data & 0x03) | init_wds)) { + /* get the number of bytes to add and re-allign */ + offset = (4 - (long) skb->data) & 0x03; + offset += init_wds ? 6 : 0; + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, + init_wds); +#endif + + /* align the buffer on 4-byte boundary */ + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + if (init_wds) { + /* wds requires an additional address field of 6 bytes */ + skb_put(skb, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + memmove(skb->data + 6, src, skb->len); + memcpy(skb->data, wds_mac, 6); + } else { + memmove(skb->data, src, skb->len); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, + src, skb->len); +#endif + } else { + newskb = + dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); + if (unlikely(newskb == NULL)) { + printk(KERN_ERR "%s: Cannot allocate skb\n", + ndev->name); + err = -ENOMEM; + goto drop_free; + } + newskb_offset = (4 - (long) newskb->data) & 0x03; + + /* Check if newskb->data is aligned */ + if (newskb_offset) + skb_reserve(newskb, newskb_offset); + + skb_put(newskb, init_wds ? skb->len + 6 : skb->len); + if (init_wds) { + memcpy(newskb->data + 6, skb->data, skb->len); + memcpy(newskb->data, wds_mac, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + } else + memcpy(newskb->data, skb->data, skb->len); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", + newskb->data, skb->data, skb->len, init_wds); +#endif + + newskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = newskb; + } + } + /* display the buffer contents for debugging */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* map the skb buffer to pci memory for DMA operation */ + pci_map_address = pci_map_single(priv->pdev, + (void *) skb->data, skb->len, + PCI_DMA_TODEVICE); + if (unlikely(pci_map_address == 0)) { + printk(KERN_WARNING "%s: cannot map buffer to PCI\n", + ndev->name); + + err = -EIO; + goto drop_free; + } + /* Place the fragment in the control block structure. */ + index = curr_frag % ISL38XX_CB_TX_QSIZE; + fragment = &cb->tx_data_low[index]; + + priv->pci_map_tx_address[index] = pci_map_address; + /* store the skb address for future freeing */ + priv->data_low_tx[index] = skb; + /* set the proper fragment start address and size information */ + fragment->size = cpu_to_le16(frame_size); + fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ + fragment->address = cpu_to_le32(pci_map_address); + curr_frag++; + + /* The fragment address in the control block must have been + * written before announcing the frame buffer to device. */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); + + if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD + > ISL38XX_CB_TX_QSIZE) { + /* stop sends from upper layers */ + netif_stop_queue(ndev); + + /* set the full flag for the transmission queue */ + priv->data_low_tx_full = 1; + } + + /* trigger the device */ + islpci_trigger(priv); + + /* unlock the driver code */ + spin_unlock_irqrestore(&priv->slock, flags); + + /* set the transmission time */ + ndev->trans_start = jiffies; + priv->statistics.tx_packets++; + priv->statistics.tx_bytes += skb->len; + + return 0; + + drop_free: + /* free the skbuf structure before aborting */ + dev_kfree_skb(skb); + skb = NULL; + + priv->statistics.tx_dropped++; + spin_unlock_irqrestore(&priv->slock, flags); + return err; +} + +static inline int +islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) +{ + /* The card reports full 802.11 packets but with a 20 bytes + * header and without the FCS. But there a is a bit that + * indicates if the packet is corrupted :-) */ + struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data; + if (hdr->flags & 0x01) + /* This one is bad. Drop it ! */ + return -1; + if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) { + struct avs_80211_1_header *avs; + /* extract the relevant data from the header */ + u32 clock = le32_to_cpu(hdr->clock); + u8 rate = hdr->rate; + u16 freq = le16_to_cpu(hdr->freq); + u8 rssi = hdr->rssi; + + skb_pull(*skb, sizeof (struct rfmon_header)); + + if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) { + struct sk_buff *newskb = skb_copy_expand(*skb, + sizeof (struct + avs_80211_1_header), + 0, GFP_ATOMIC); + if (newskb) { + dev_kfree_skb_irq(*skb); + *skb = newskb; + } else + return -1; + /* This behavior is not very subtile... */ + } + + /* make room for the new header and fill it. */ + avs = + (struct avs_80211_1_header *) skb_push(*skb, + sizeof (struct + avs_80211_1_header)); + + avs->version = cpu_to_be32(P80211CAPTURE_VERSION); + avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); + avs->mactime = cpu_to_be64(le64_to_cpu(clock)); + avs->hosttime = cpu_to_be64(jiffies); + avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */ + avs->channel = cpu_to_be32(channel_of_freq(freq)); + avs->datarate = cpu_to_be32(rate * 5); + avs->antenna = cpu_to_be32(0); /*unknown */ + avs->priority = cpu_to_be32(0); /*unknown */ + avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */ + avs->ssi_signal = cpu_to_be32(rssi & 0x7f); + avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */ + avs->preamble = cpu_to_be32(0); /*unknown */ + avs->encoding = cpu_to_be32(0); /*unknown */ + } else + skb_pull(*skb, sizeof (struct rfmon_header)); + + (*skb)->protocol = htons(ETH_P_802_2); + (*skb)->mac.raw = (*skb)->data; + (*skb)->pkt_type = PACKET_OTHERHOST; + + return 0; +} + +int +islpci_eth_receive(islpci_private *priv) +{ + struct net_device *ndev = priv->ndev; + isl38xx_control_block *control_block = priv->control_block; + struct sk_buff *skb; + u16 size; + u32 index, offset; + unsigned char *src; + int discard = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n"); +#endif + + /* the device has written an Ethernet frame in the data area + * of the sk_buff without updating the structure, do it now */ + index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; + size = le16_to_cpu(control_block->rx_data_low[index].size); + skb = priv->data_low_rx[index]; + offset = ((unsigned long) + le32_to_cpu(control_block->rx_data_low[index].address) - + (unsigned long) skb->data) & 3; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", + control_block->rx_data_low[priv->free_data_rx].address, skb->data, + skb->len, offset, skb->truesize); +#endif + + /* delete the streaming DMA mapping before processing the skb */ + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + + /* update the skb structure and allign the buffer */ + skb_put(skb, size); + if (offset) { + /* shift the buffer allocation offset bytes to get the right frame */ + skb_pull(skb, 2); + skb_put(skb, 2); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* check whether WDS is enabled and whether the data frame is a WDS frame */ + + if (init_wds) { + /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ + src = skb->data + 6; + memmove(skb->data, src, skb->len - 6); + skb_trim(skb, skb->len - 6); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); + DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); + + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* do some additional sk_buff and network layer parameters */ + skb->dev = ndev; + + /* take care of monitor mode and spy monitoring. */ + if (unlikely(priv->iw_mode == IW_MODE_MONITOR)) + discard = islpci_monitor_rx(priv, &skb); + else { + if (unlikely(skb->data[2 * ETH_ALEN] == 0)) { + /* The packet has a rx_annex. Read it for spy monitoring, Then + * remove it, while keeping the 2 leading MAC addr. + */ + struct iw_quality wstats; + struct rx_annex_header *annex = + (struct rx_annex_header *) skb->data; + wstats.level = annex->rfmon.rssi; + /* The noise value can be a bit outdated if nobody's + * reading wireless stats... */ + wstats.noise = priv->local_iwstatistics.qual.noise; + wstats.qual = wstats.level - wstats.noise; + wstats.updated = 0x07; + /* Update spy records */ + wireless_spy_update(ndev, annex->addr2, &wstats); + + memcpy(skb->data + sizeof (struct rfmon_header), + skb->data, 2 * ETH_ALEN); + skb_pull(skb, sizeof (struct rfmon_header)); + } + skb->protocol = eth_type_trans(skb, ndev); + } + skb->ip_summed = CHECKSUM_NONE; + priv->statistics.rx_packets++; + priv->statistics.rx_bytes += size; + + /* deliver the skb to the network layer */ +#ifdef ISLPCI_ETH_DEBUG + printk + ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5]); +#endif + if (unlikely(discard)) { + dev_kfree_skb_irq(skb); + skb = NULL; + } else + netif_rx(skb); + + /* increment the read index for the rx data low queue */ + priv->free_data_rx++; + + /* add one or more sk_buff structures */ + while (index = + le32_to_cpu(control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), + index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { + /* allocate an sk_buff for received data frames storage + * include any required allignment operations */ + skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2); + if (unlikely(skb == NULL)) { + /* error allocating an sk_buff structure elements */ + DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n"); + break; + } + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + /* store the new skb structure pointer */ + index = index % ISL38XX_CB_RX_QSIZE; + priv->data_low_rx[index] = skb; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", + skb, skb->data, skb->len, index, skb->truesize); +#endif + + /* set the streaming DMA mapping for proper PCI bus operation */ + priv->pci_map_rx_address[index] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) { + /* error mapping the buffer to device accessable memory address */ + DEBUG(SHOW_ERROR_MESSAGES, + "Error mapping DMA address\n"); + + /* free the skbuf structure before aborting */ + dev_kfree_skb_irq((struct sk_buff *) skb); + skb = NULL; + break; + } + /* update the fragment address */ + control_block->rx_data_low[index].address = cpu_to_le32((u32) + priv-> + pci_map_rx_address + [index]); + wmb(); + + /* increment the driver read pointer */ + add_le32p((u32 *) &control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); + } + + /* trigger the device */ + islpci_trigger(priv); + + return 0; +} + +void +islpci_do_reset_and_wake(void *data) +{ + islpci_private *priv = (islpci_private *) data; + islpci_reset(priv, 1); + netif_wake_queue(priv->ndev); + priv->reset_task_pending = 0; +} + +void +islpci_eth_tx_timeout(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + struct net_device_stats *statistics = &priv->statistics; + + /* increment the transmit error counter */ + statistics->tx_errors++; + + printk(KERN_WARNING "%s: tx_timeout", ndev->name); + if (!priv->reset_task_pending) { + priv->reset_task_pending = 1; + printk(", scheduling a reset"); + netif_stop_queue(ndev); + schedule_work(&priv->reset_task); + } + printk("\n"); +} diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.h linux-2.4.28/drivers/net/wireless/prism54/islpci_eth.h --- linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_eth.h 2004-11-17 03:54:21.463392343 -0800 @@ -0,0 +1,73 @@ +/* + * + * Copyright (C) 2002 Intersil Americas 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 + * + * 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 _ISLPCI_ETH_H +#define _ISLPCI_ETH_H + +#include "isl_38xx.h" +#include "islpci_dev.h" + +struct rfmon_header { + u16 unk0; /* = 0x0000 */ + u16 length; /* = 0x1400 */ + u32 clock; /* 1MHz clock */ + u8 flags; + u8 unk1; + u8 rate; + u8 unk2; + u16 freq; + u16 unk3; + u8 rssi; + u8 padding[3]; +} __attribute__ ((packed)); + +struct rx_annex_header { + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + struct rfmon_header rfmon; +} __attribute__ ((packed)); + +/* wlan-ng (and hopefully others) AVS header, version one. Fields in + * network byte order. */ +#define P80211CAPTURE_VERSION 0x80211001 + +struct avs_80211_1_header { + uint32_t version; + uint32_t length; + uint64_t mactime; + uint64_t hosttime; + uint32_t phytype; + uint32_t channel; + uint32_t datarate; + uint32_t antenna; + uint32_t priority; + uint32_t ssi_type; + int32_t ssi_signal; + int32_t ssi_noise; + uint32_t preamble; + uint32_t encoding; +}; + +void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); +int islpci_eth_transmit(struct sk_buff *, struct net_device *); +int islpci_eth_receive(islpci_private *); +void islpci_eth_tx_timeout(struct net_device *); +void islpci_do_reset_and_wake(void *data); + +#endif /* _ISL_GEN_H */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_hotplug.c linux-2.4.28/drivers/net/wireless/prism54/islpci_hotplug.c --- linux-2.4.27/drivers/net/wireless/prism54/islpci_hotplug.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_hotplug.c 2004-11-17 03:54:21.464392384 -0800 @@ -0,0 +1,337 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * + * 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 + * + * 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 + * + */ + +#include +#include +#include +#include +#include /* For __init, __exit */ + +#include "prismcompat.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" /* for pc_debug */ +#include "isl_oid.h" + +#define DRV_NAME "prism54" +#define DRV_VERSION "1.2" + +MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team "); +MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); +MODULE_LICENSE("GPL"); + +static int init_pcitm = 0; +module_param(init_pcitm, int, 0); + +/* In this order: vendor, device, subvendor, subdevice, class, class_mask, + * driver_data + * If you have an update for this please contact prism54-devel@prism54.org + * The latest list can be found at http://prism54.org/supported_cards.php */ +static const struct pci_device_id prism54_id_tbl[] = { + /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ + { + 0x1260, 0x3890, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* 3COM 3CRWE154G72 Wireless LAN adapter */ + { + 0x10b7, 0x6001, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* Intersil PRISM Indigo Wireless LAN adapter */ + { + 0x1260, 0x3877, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ + { + 0x1260, 0x3886, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* End of list */ + {0,0,0,0,0,0,0} +}; + +/* register the device with the Hotplug facilities of the kernel */ +MODULE_DEVICE_TABLE(pci, prism54_id_tbl); + +static int prism54_probe(struct pci_dev *, const struct pci_device_id *); +static void prism54_remove(struct pci_dev *); +static int prism54_suspend(struct pci_dev *, u32 state); +static int prism54_resume(struct pci_dev *); + +static struct pci_driver prism54_driver = { + .name = DRV_NAME, + .id_table = prism54_id_tbl, + .probe = prism54_probe, + .remove = prism54_remove, + .suspend = prism54_suspend, + .resume = prism54_resume, + /* .enable_wake ; we don't support this yet */ +}; + +/****************************************************************************** + Module initialization functions +******************************************************************************/ + +int +prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *ndev; + u8 latency_tmr; + u32 mem_addr; + islpci_private *priv; + int rvalue; + + /* Enable the pci device */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); + return -ENODEV; + } + + /* check whether the latency timer is set correctly */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); +#endif + if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { + /* set the latency timer */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + PCIDEVICE_LATENCY_TIMER_VAL); + } + + /* enable PCI DMA */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); + goto do_pci_disable_device; + } + + /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) + * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) + * The RETRY_TIMEOUT is used to set the number of retries that the core, as a + * Master, will perform before abandoning a cycle. The default value for + * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new + * devices. A write of zero to the RETRY_TIMEOUT register disables this + * function to allow use with any non-compliant legacy devices that may + * execute more retries. + * + * Writing zero to both these two registers will disable both timeouts and + * *can* solve problems caused by devices that are slow to respond. + * Make this configurable - MSW + */ + if ( init_pcitm >= 0 ) { + pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); + pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); + } else { + printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); + } + + /* request the pci device I/O regions */ + rvalue = pci_request_regions(pdev, DRV_NAME); + if (rvalue) { + printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", + DRV_NAME, rvalue); + goto do_pci_disable_device; + } + + /* check if the memory window is indeed set */ + rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); + if (rvalue || !mem_addr) { + printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", + DRV_NAME); + goto do_pci_disable_device; + } + + /* enable PCI bus-mastering */ + DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); + pci_set_master(pdev); + + /* enable MWI */ + pci_set_mwi(pdev); + + /* setup the network device interface and its structure */ + if (!(ndev = islpci_setup(pdev))) { + /* error configuring the driver as a network device */ + printk(KERN_ERR "%s: could not configure network device\n", + DRV_NAME); + goto do_pci_release_regions; + } + + priv = netdev_priv(ndev); + islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ + + /* card is in unknown state yet, might have some interrupts pending */ + isl38xx_disable_interrupts(priv->device_base); + + /* request for the interrupt before uploading the firmware */ + rvalue = request_irq(pdev->irq, &islpci_interrupt, + SA_SHIRQ, ndev->name, priv); + + if (rvalue) { + /* error, could not hook the handler to the irq */ + printk(KERN_ERR "%s: could not install IRQ handler\n", + ndev->name); + goto do_unregister_netdev; + } + + /* firmware upload is triggered in islpci_open */ + + return 0; + + do_unregister_netdev: + unregister_netdev(ndev); + islpci_free_memory(priv); + pci_set_drvdata(pdev, NULL); + free_netdev(ndev); + priv = NULL; + do_pci_release_regions: + pci_release_regions(pdev); + do_pci_disable_device: + pci_disable_device(pdev); + return -EIO; +} + +/* set by cleanup_module */ +static volatile int __in_cleanup_module = 0; + +/* this one removes one(!!) instance only */ +void +prism54_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; + BUG_ON(!priv); + + if (!__in_cleanup_module) { + printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); + islpci_set_state(priv, PRV_STATE_OFF); + } + + printk(KERN_DEBUG "%s: removing device\n", ndev->name); + + unregister_netdev(ndev); + + /* free the interrupt request */ + + if (islpci_get_state(priv) != PRV_STATE_OFF) { + isl38xx_disable_interrupts(priv->device_base); + islpci_set_state(priv, PRV_STATE_OFF); + /* This bellow causes a lockup at rmmod time. It might be + * because some interrupts still linger after rmmod time, + * see bug #17 */ + /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ + } + + free_irq(pdev->irq, priv); + + /* free the PCI memory and unmap the remapped page */ + islpci_free_memory(priv); + + pci_set_drvdata(pdev, NULL); + free_netdev(ndev); + priv = NULL; + + pci_release_regions(pdev); + + pci_disable_device(pdev); +} + +int +prism54_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got suspend request (state %d)\n", + ndev->name, state); + + pci_save_state(pdev, priv->pci_state); + + /* tell the device not to trigger interrupts for now... */ + isl38xx_disable_interrupts(priv->device_base); + + /* from now on assume the hardware was already powered down + and don't touch it anymore */ + islpci_set_state(priv, PRV_STATE_OFF); + + netif_stop_queue(ndev); + netif_device_detach(ndev); + + return 0; +} + +int +prism54_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got resume request\n", ndev->name); + + pci_restore_state(pdev, priv->pci_state); + + /* alright let's go into the PREBOOT state */ + islpci_reset(priv, 1); + + netif_device_attach(ndev); + netif_start_queue(ndev); + + return 0; +} + +static int __init +prism54_module_init(void) +{ + printk(KERN_INFO "Loaded %s driver, version %s\n", + DRV_NAME, DRV_VERSION); + + __bug_on_wrong_struct_sizes (); + + return pci_module_init(&prism54_driver); +} + +/* by the time prism54_module_exit() terminates, as a postcondition + * all instances will have been destroyed by calls to + * prism54_remove() */ +static void __exit +prism54_module_exit(void) +{ + __in_cleanup_module = 1; + + pci_unregister_driver(&prism54_driver); + + printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); + + __in_cleanup_module = 0; +} + +/* register entry points */ +module_init(prism54_module_init); +module_exit(prism54_module_exit); +/* EOF */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.c linux-2.4.28/drivers/net/wireless/prism54/islpci_mgt.c --- linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_mgt.c 2004-11-17 03:54:21.466392467 -0800 @@ -0,0 +1,511 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright 2004 Jens Maurer + * + * 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 + * + * 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 + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "isl_ioctl.h" + +#include + +/****************************************************************************** + Global variable definition section +******************************************************************************/ +int pc_debug = VERBOSE; +module_param(pc_debug, int, 0); + +/****************************************************************************** + Driver general functions +******************************************************************************/ +void +display_buffer(char *buffer, int length) +{ + if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) + return; + + while (length > 0) { + printk("[%02x]", *buffer & 255); + length--; + buffer++; + } + + printk("\n"); +} + +/***************************************************************************** + Queue handling for management frames +******************************************************************************/ + +/* + * Helper function to create a PIMFOR management frame header. + */ +static void +pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) +{ + h->version = PIMFOR_VERSION; + h->operation = operation; + h->device_id = PIMFOR_DEV_ID_MHLI_MIB; + h->flags = 0; + h->oid = cpu_to_be32(oid); + h->length = cpu_to_be32(length); +} + +/* + * Helper function to analyze a PIMFOR management frame header. + */ +static pimfor_header_t * +pimfor_decode_header(void *data, int len) +{ + pimfor_header_t *h = data; + + while ((void *) h < data + len) { + if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { + le32_to_cpus(&h->oid); + le32_to_cpus(&h->length); + } else { + be32_to_cpus(&h->oid); + be32_to_cpus(&h->length); + } + if (h->oid != OID_INL_TUNNEL) + return h; + h++; + } + return NULL; +} + +/* + * Fill the receive queue for management frames with fresh buffers. + */ +int +islpci_mgmt_rx_fill(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n"); +#endif + + while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { + u32 index = curr % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; + + if (buf->mem == NULL) { + buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); + if (!buf->mem) { + printk(KERN_WARNING + "Error allocating management frame.\n"); + return -ENOMEM; + } + buf->size = MGMT_FRAME_SIZE; + } + if (buf->pci_addr == 0) { + buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + MGMT_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + if (!buf->pci_addr) { + printk(KERN_WARNING + "Failed to make memory DMA'able\n."); + return -ENOMEM; + } + } + + /* be safe: always reset control block information */ + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(buf->pci_addr); + curr++; + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr); + } + return 0; +} + +/* + * Create and transmit a management frame using "operation" and "oid", + * with arguments data/length. + * We either return an error and free the frame, or we return 0 and + * islpci_mgt_cleanup_transmit() frees the frame in the tx-done + * interrupt. + */ +static int +islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, + void *data, int length) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + void *p; + int err = -EINVAL; + unsigned long flags; + isl38xx_fragment *frag; + struct islpci_membuf buf; + u32 curr_frag; + int index; + int frag_len = length + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); +#endif + + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_DEBUG "%s: mgmt frame too large %d\n", + ndev->name, frag_len); + goto error; + } + + err = -ENOMEM; + p = buf.mem = kmalloc(frag_len, GFP_KERNEL); + if (!buf.mem) { + printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n", + ndev->name); + goto error; + } + buf.size = frag_len; + + /* create the header directly in the fragment data area */ + pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); + p += PIMFOR_HEADER_SIZE; + + if (data) + memcpy(p, data, length); + else + memset(p, 0, length); + +#if VERBOSE > SHOW_ERROR_MESSAGES + { + pimfor_header_t *h = buf.mem; + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n", + h->operation, oid, h->device_id, h->flags, length); + + /* display the buffer contents for debugging */ + display_buffer((char *) h, sizeof (pimfor_header_t)); + display_buffer(p, length); + } +#endif + + err = -ENOMEM; + buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, + PCI_DMA_TODEVICE); + if (!buf.pci_addr) { + printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", + ndev->name); + goto error_free; + } + + /* Protect the control block modifications against interrupts. */ + spin_lock_irqsave(&priv->slock, flags); + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); + if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { + printk(KERN_WARNING "%s: mgmt tx queue is still full\n", + ndev->name); + goto error_unlock; + } + + /* commit the frame to the tx device queue */ + index = curr_frag % ISL38XX_CB_MGMT_QSIZE; + priv->mgmt_tx[index] = buf; + frag = &cb->tx_data_mgmt[index]; + frag->size = cpu_to_le16(frag_len); + frag->flags = 0; /* for any other than the last fragment, set to 1 */ + frag->address = cpu_to_le32(buf.pci_addr); + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1); + spin_unlock_irqrestore(&priv->slock, flags); + + /* trigger the device */ + islpci_trigger(priv); + return 0; + + error_unlock: + spin_unlock_irqrestore(&priv->slock, flags); + error_free: + kfree(buf.mem); + error: + return err; +} + +/* + * Receive a management frame from the device. + * This can be an arbitrary number of traps, and at most one response + * frame for a previous request sent via islpci_mgt_transmit(). + */ +int +islpci_mgt_receive(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n"); +#endif + + /* Only once per interrupt, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * frames come in faster than we can process them. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); + barrier(); + + for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { + pimfor_header_t *header; + u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + u16 frag_len; + int size; + struct islpci_mgmtframe *frame; + + /* I have no idea (and no documentation) if flags != 0 + * is possible. Drop the frame, reuse the buffer. */ + if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { + printk(KERN_WARNING "%s: unknown flags 0x%04x\n", + ndev->name, + le16_to_cpu(cb->rx_data_mgmt[index].flags)); + continue; + } + + /* The device only returns the size of the header(s) here. */ + frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); + + /* + * We appear to have no way to tell the device the + * size of a receive buffer. Thus, if this check + * triggers, we likely have kernel heap corruption. */ + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_WARNING + "%s: Bogus packet size of %d (%#x).\n", + ndev->name, frag_len, frag_len); + frag_len = MGMT_FRAME_SIZE; + } + + /* Ensure the results of device DMA are visible to the CPU. */ + pci_dma_sync_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + + /* Perform endianess conversion for PIMFOR header in-place. */ + header = pimfor_decode_header(buf->mem, frag_len); + if (!header) { + printk(KERN_WARNING "%s: no PIMFOR header found\n", + ndev->name); + continue; + } + + /* The device ID from the PIMFOR packet received from + * the MVC is always 0. We forward a sensible device_id. + * Not that anyone upstream would care... */ + header->device_id = priv->ndev->ifindex; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n", + header->operation, header->oid, header->device_id, + header->flags, header->length); + + /* display the buffer contents for debugging */ + display_buffer((char *) header, PIMFOR_HEADER_SIZE); + display_buffer((char *) header + PIMFOR_HEADER_SIZE, + header->length); +#endif + + /* nobody sends these */ + if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { + printk(KERN_DEBUG + "%s: errant PIMFOR application frame\n", + ndev->name); + continue; + } + + /* Determine frame size, skipping OID_INL_TUNNEL headers. */ + size = PIMFOR_HEADER_SIZE + header->length; + frame = kmalloc(sizeof (struct islpci_mgmtframe) + size, + GFP_ATOMIC); + if (!frame) { + printk(KERN_WARNING + "%s: Out of memory, cannot handle oid 0x%08x\n", + ndev->name, header->oid); + continue; + } + frame->ndev = ndev; + memcpy(&frame->buf, header, size); + frame->header = (pimfor_header_t *) frame->buf; + frame->data = frame->buf + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "frame: header: %p, data: %p, size: %d\n", + frame->header, frame->data, size); +#endif + + if (header->operation == PIMFOR_OP_TRAP) { +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG + "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", + header->oid, header->device_id, header->flags, + header->length); +#endif + + /* Create work to handle trap out of interrupt + * context. */ + INIT_WORK(&frame->ws, prism54_process_trap, frame); + schedule_work(&frame->ws); + + } else { + /* Signal the one waiting process that a response + * has been received. */ + if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { + printk(KERN_WARNING + "%s: mgmt response not collected\n", + ndev->name); + kfree(frame); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n"); +#endif + wake_up(&priv->mgmt_wqueue); + } + + } + + return 0; +} + +/* + * Cleanup the transmit queue by freeing all frames handled by the device. + */ +void +islpci_mgt_cleanup_transmit(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); +#endif + + /* Only once per cleanup, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * the device became confused, incrementing device_curr_frag + * rapidly. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); + barrier(); + + for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { + int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_tx[index]; + pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, + PCI_DMA_TODEVICE); + buf->pci_addr = 0; + kfree(buf->mem); + buf->mem = NULL; + buf->size = 0; + } +} + +/* + * Perform one request-response transaction to the device. + */ +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe) +{ + islpci_private *priv = netdev_priv(ndev); + const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; + int err; + DEFINE_WAIT(wait); + + *recvframe = NULL; + + if (down_interruptible(&priv->mgmt_sem)) + return -ERESTARTSYS; + + prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); + err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); + if (err) + goto out; + + err = -ETIMEDOUT; + while (timeout_left > 0) { + int timeleft; + struct islpci_mgmtframe *frame; + + set_current_state(TASK_UNINTERRUPTIBLE); + timeleft = schedule_timeout(wait_cycle_jiffies); + frame = xchg(&priv->mgmt_received, NULL); + if (frame) { + if (frame->header->oid == oid) { + *recvframe = frame; + err = 0; + goto out; + } else { + printk(KERN_DEBUG + "%s: expecting oid 0x%x, received 0x%x.\n", + ndev->name, (unsigned int) oid, + frame->header->oid); + kfree(frame); + frame = NULL; + } + } + if (timeleft == 0) { + printk(KERN_DEBUG + "%s: timeout waiting for mgmt response %lu, " + "triggering device\n", + ndev->name, timeout_left); + islpci_trigger(priv); + } + timeout_left += timeleft - wait_cycle_jiffies; + } + printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", + ndev->name); + + /* TODO: we should reset the device here */ + out: + finish_wait(&priv->mgmt_wqueue, &wait); + up(&priv->mgmt_sem); + return err; +} + diff -urN linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.h linux-2.4.28/drivers/net/wireless/prism54/islpci_mgt.h --- linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/islpci_mgt.h 2004-11-17 03:54:21.466392467 -0800 @@ -0,0 +1,145 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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 _ISLPCI_MGT_H +#define _ISLPCI_MGT_H + +#include +#include + +/* + * Function definitions + */ + +#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) +#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) + +extern int pc_debug; +#define init_wds 0 /* help compiler optimize away dead code */ + + +/* General driver definitions */ +#define PCIDEVICE_LATENCY_TIMER_MIN 0x40 +#define PCIDEVICE_LATENCY_TIMER_VAL 0x50 + +/* Debugging verbose definitions */ +#define SHOW_NOTHING 0x00 /* overrules everything */ +#define SHOW_ANYTHING 0xFF +#define SHOW_ERROR_MESSAGES 0x01 +#define SHOW_TRAPS 0x02 +#define SHOW_FUNCTION_CALLS 0x04 +#define SHOW_TRACING 0x08 +#define SHOW_QUEUE_INDEXES 0x10 +#define SHOW_PIMFOR_FRAMES 0x20 +#define SHOW_BUFFER_CONTENTS 0x40 +#define VERBOSE 0x01 + +/* Default card definitions */ +#define CARD_DEFAULT_CHANNEL 6 +#define CARD_DEFAULT_MODE INL_MODE_CLIENT +#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA +#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA +#define CARD_DEFAULT_CLIENT_SSID "" +#define CARD_DEFAULT_AP_SSID "default" +#define CARD_DEFAULT_KEY1 "default_key_1" +#define CARD_DEFAULT_KEY2 "default_key_2" +#define CARD_DEFAULT_KEY3 "default_key_3" +#define CARD_DEFAULT_KEY4 "default_key_4" +#define CARD_DEFAULT_WEP 0 +#define CARD_DEFAULT_FILTER 0 +#define CARD_DEFAULT_WDS 0 +#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS +#define CARD_DEFAULT_DOT1X 0 +#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO +#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE +#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI +#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE + +/* PIMFOR package definitions */ +#define PIMFOR_ETHERTYPE 0x8828 +#define PIMFOR_HEADER_SIZE 12 +#define PIMFOR_VERSION 1 +#define PIMFOR_OP_GET 0 +#define PIMFOR_OP_SET 1 +#define PIMFOR_OP_RESPONSE 2 +#define PIMFOR_OP_ERROR 3 +#define PIMFOR_OP_TRAP 4 +#define PIMFOR_OP_RESERVED 5 /* till 255 */ +#define PIMFOR_DEV_ID_MHLI_MIB 0 +#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 +#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 + +static inline void +add_le32p(u32 * le_number, u32 add) +{ + *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); +} + +void display_buffer(char *, int); + +/* + * Type definition section + * + * the structure defines only the header allowing copyless + * frame handling + */ +typedef struct { + u8 version; + u8 operation; + u32 oid; + u8 device_id; + u8 flags; + u32 length; +} __attribute__ ((packed)) +pimfor_header_t; + +/* A received and interrupt-processed management frame, either for + * schedule_work(prism54_process_trap) or for priv->mgmt_received, + * processed by islpci_mgt_transaction(). */ +struct islpci_mgmtframe { + struct net_device *ndev; /* pointer to network device */ + pimfor_header_t *header; /* payload header, points into buf */ + void *data; /* payload ex header, points into buf */ + struct work_struct ws; /* argument for schedule_work() */ + char buf[0]; /* fragment buffer */ +}; + +int +islpci_mgt_receive(struct net_device *ndev); + +int +islpci_mgmt_rx_fill(struct net_device *ndev); + +void +islpci_mgt_cleanup_transmit(struct net_device *ndev); + +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe); + +static inline void +islpci_mgt_release(struct islpci_mgmtframe *frame) +{ + kfree(frame); +} + +#endif /* _ISLPCI_MGT_H */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.c linux-2.4.28/drivers/net/wireless/prism54/oid_mgt.c --- linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/oid_mgt.c 2004-11-17 03:54:21.468392549 -0800 @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2003,2004 Aurelien Alleaume + * + * 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 + * + * 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 + * + */ + +#include "prismcompat.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "isl_oid.h" +#include "oid_mgt.h" +#include "isl_ioctl.h" + +/* to convert between channel and freq */ +const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +int +channel_of_freq(int f) +{ + int c = 0; + + if ((f >= 2412) && (f <= 2484)) { + while ((c < 14) && (f != frequency_list_bg[c])) + c++; + return (c >= 14) ? 0 : ++c; + } else if ((f >= (int) 5000) && (f <= (int) 6000)) { + return ( (f - 5000) / 5 ); + } else + return 0; +} + +#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t} +#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED) +#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32) +#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32) +#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME) +#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX) + +#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0) + +struct oid_t isl_oid[] = { + OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR), + OID_U32(GEN_OID_LINKSTATE, 0x00000001), + OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002), + OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003), + OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004), + OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005), + + /* 802.11 */ + OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000), + OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW), + OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid, + OID_TYPE_SSID), + OID_U32(DOT11_OID_STATE, 0x10000003), + OID_U32(DOT11_OID_AID, 0x10000004), + OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW), + OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid, + OID_TYPE_SSID), + + OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000), + OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001), + OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002), + OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003), + OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004), + OID_U32(DOT11_OID_CFPPERIOD, 0x11000005), + OID_U32(DOT11_OID_CFPDURATION, 0x11000006), + + OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000), + OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001), + OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002), + OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003), + [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), + OID_FLAG_CACHED | OID_TYPE_KEY}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008), + OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009), + OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a), + + OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000), + OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001), + OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002), + OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003), + + OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000), + OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001), + OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002), + OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003), + OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004), + OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005), + OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006), + OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007), + + OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000), + OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001), + OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002), + OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003), + OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004), + OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005), + OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006), + + [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, + OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008), + + OID_U32(DOT11_OID_PSM, 0x14000000), + OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001), + OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002), + OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003), + + OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000), + OID_U32(DOT11_OID_CLIENTS, 0x15000001), + OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002), + [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR), + OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0), + OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1), + OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2), + + OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000), + OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001), + OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002), + OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003), + OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004), + OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005), + OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006), + OID_U32(DOT11_OID_RTSFAILED, 0x16000007), + OID_U32(DOT11_OID_ACKFAILED, 0x16000008), + OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009), + OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A), + OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B), + OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C), + + OID_U32(DOT11_OID_SLOTTIME, 0x17000000), + OID_U32(DOT11_OID_CWMIN, 0x17000001), + OID_U32(DOT11_OID_CWMAX, 0x17000002), + OID_U32(DOT11_OID_ACKWINDOW, 0x17000003), + OID_U32(DOT11_OID_ANTENNARX, 0x17000004), + OID_U32(DOT11_OID_ANTENNATX, 0x17000005), + OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006), + OID_U32_C(DOT11_OID_CHANNEL, 0x17000007), + OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008), + OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009), + OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1], + OID_TYPE_RAW), + OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B), + OID_U32(DOT11_OID_CCAMODE, 0x1700000C), + OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D), + OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E), + OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F), + OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010, + u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), + OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011), + [DOT11_OID_SUPPORTEDFREQUENCIES] = + {0x17000012, 0, sizeof (struct obj_frequencies) + + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES}, + + OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013), + OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1], + OID_TYPE_RAW), + OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015), + OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016), + OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017), + OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018), + OID_U32(DOT11_OID_PROFILES, 0x17000019), + OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020, + u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), + + OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000), + OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001), + OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002), + OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003), + OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004), + OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005), + OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006), + OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007), + OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008), + OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009), + OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A), + OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B), + OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C), + + OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000), + + OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), + OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), + OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), + [DOT11_OID_ATTACHMENT] = {0x19000003, 0, + sizeof(struct obj_attachment), OID_TYPE_ATTACH}, + OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer, + OID_TYPE_BUFFER), + + OID_U32(DOT11_OID_BSSS, 0x1C000000), + [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), + OID_TYPE_BSS}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS), + [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct + obj_bsslist) + + sizeof (struct obj_bss[IWMAX_BSS]), + OID_TYPE_BSSLIST}, + + OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000), + OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001), + OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002), + OID_U32_C(OID_INL_MODE, 0xFF020003), + OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004), + OID_STRUCT(OID_INL_VERSION, 0xFF020005, u8[8], OID_TYPE_RAW), + OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006), + OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007), + OID_U32_C(OID_INL_CONFIG, 0xFF020008), + OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C), + OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D), + OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F), + +}; + +int +mgt_init(islpci_private *priv) +{ + int i; + + priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL); + if (!priv->mib) + return -ENOMEM; + + memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *)); + + /* Alloc the cache */ + for (i = 0; i < OID_NUM_LAST; i++) { + if (isl_oid[i].flags & OID_FLAG_CACHED) { + priv->mib[i] = kmalloc(isl_oid[i].size * + (isl_oid[i].range + 1), + GFP_KERNEL); + if (!priv->mib[i]) + return -ENOMEM; + memset(priv->mib[i], 0, + isl_oid[i].size * (isl_oid[i].range + 1)); + } else + priv->mib[i] = NULL; + } + + init_rwsem(&priv->mib_sem); + prism54_mib_init(priv); + + return 0; +} + +void +mgt_clean(islpci_private *priv) +{ + int i; + + if (!priv->mib) + return; + for (i = 0; i < OID_NUM_LAST; i++) + if (priv->mib[i]) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } + kfree(priv->mib); + priv->mib = NULL; +} + +void +mgt_le_to_cpu(int type, void *data) +{ + switch (type) { + case OID_TYPE_U32: + *(u32 *) data = le32_to_cpu(*(u32 *) data); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = data; + buff->size = le32_to_cpu(buff->size); + buff->addr = le32_to_cpu(buff->addr); + break; + } + case OID_TYPE_BSS:{ + struct obj_bss *bss = data; + bss->age = le16_to_cpu(bss->age); + bss->channel = le16_to_cpu(bss->channel); + bss->capinfo = le16_to_cpu(bss->capinfo); + bss->rates = le16_to_cpu(bss->rates); + bss->basic_rates = le16_to_cpu(bss->basic_rates); + break; + } + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = data; + int i; + list->nr = le32_to_cpu(list->nr); + for (i = 0; i < list->nr; i++) + mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]); + break; + } + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = data; + int i; + freq->nr = le16_to_cpu(freq->nr); + for (i = 0; i < freq->nr; i++) + freq->mhz[i] = le16_to_cpu(freq->mhz[i]); + break; + } + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = data; + mlme->id = le16_to_cpu(mlme->id); + mlme->state = le16_to_cpu(mlme->state); + mlme->code = le16_to_cpu(mlme->code); + break; + } + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = data; + mlme->id = le16_to_cpu(mlme->id); + mlme->state = le16_to_cpu(mlme->state); + mlme->code = le16_to_cpu(mlme->code); + mlme->size = le16_to_cpu(mlme->size); + break; + } + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = data; + attach->id = le16_to_cpu(attach->id); + attach->size = le16_to_cpu(attach->size);; + break; + } + case OID_TYPE_SSID: + case OID_TYPE_KEY: + case OID_TYPE_ADDR: + case OID_TYPE_RAW: + break; + default: + BUG(); + } +} + +static void +mgt_cpu_to_le(int type, void *data) +{ + switch (type) { + case OID_TYPE_U32: + *(u32 *) data = cpu_to_le32(*(u32 *) data); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = data; + buff->size = cpu_to_le32(buff->size); + buff->addr = cpu_to_le32(buff->addr); + break; + } + case OID_TYPE_BSS:{ + struct obj_bss *bss = data; + bss->age = cpu_to_le16(bss->age); + bss->channel = cpu_to_le16(bss->channel); + bss->capinfo = cpu_to_le16(bss->capinfo); + bss->rates = cpu_to_le16(bss->rates); + bss->basic_rates = cpu_to_le16(bss->basic_rates); + break; + } + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = data; + int i; + list->nr = cpu_to_le32(list->nr); + for (i = 0; i < list->nr; i++) + mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]); + break; + } + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = data; + int i; + freq->nr = cpu_to_le16(freq->nr); + for (i = 0; i < freq->nr; i++) + freq->mhz[i] = cpu_to_le16(freq->mhz[i]); + break; + } + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = data; + mlme->id = cpu_to_le16(mlme->id); + mlme->state = cpu_to_le16(mlme->state); + mlme->code = cpu_to_le16(mlme->code); + break; + } + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = data; + mlme->id = cpu_to_le16(mlme->id); + mlme->state = cpu_to_le16(mlme->state); + mlme->code = cpu_to_le16(mlme->code); + mlme->size = cpu_to_le16(mlme->size); + break; + } + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = data; + attach->id = cpu_to_le16(attach->id); + attach->size = cpu_to_le16(attach->size);; + break; + } + case OID_TYPE_SSID: + case OID_TYPE_KEY: + case OID_TYPE_ADDR: + case OID_TYPE_RAW: + break; + default: + BUG(); + } +} + +/* Note : data is modified during this function */ + +int +mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) +{ + int ret = 0; + struct islpci_mgmtframe *response = NULL; + int response_op = PIMFOR_OP_ERROR; + int dlen; + void *cache, *_data = data; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += (cache ? extra * dlen : 0); + oid = isl_oid[n].oid + extra; + + if (_data == NULL) + /* we are requested to re-set a cached value */ + _data = cache; + else + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data); + /* If we are going to write to the cache, we don't want anyone to read + * it -> acquire write lock. + * Else we could acquire a read lock to be sure we don't bother the + * commit process (which takes a write lock). But I'm not sure if it's + * needed. + */ + if (cache) + down_write(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + _data, dlen, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else if (!cache) + ret = -EIO; + + if (cache) { + if (!ret && data) + memcpy(cache, _data, dlen); + up_write(&priv->mib_sem); + } + + /* re-set given data to what it was */ + if (data) + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); + + return ret; +} + +/* None of these are cached */ +int +mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len) +{ + int ret = 0; + struct islpci_mgmtframe *response; + int response_op = PIMFOR_OP_ERROR; + int dlen; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + + dlen = isl_oid[n].size; + oid = isl_oid[n].oid; + + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + data, dlen + extra_len, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else + ret = -EIO; + + /* re-set given data to what it was */ + if (data) + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); + + return ret; +} + +int +mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, + union oid_res_t *res) +{ + + int ret = -EIO; + int reslen = 0; + struct islpci_mgmtframe *response = NULL; + + int dlen; + void *cache, *_res = NULL; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + res->ptr = NULL; + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += cache ? extra * dlen : 0; + oid = isl_oid[n].oid + extra; + reslen = dlen; + + if (cache) + down_read(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + oid, data, dlen, &response); + if (ret || !response || + response->header->operation == PIMFOR_OP_ERROR) { + if (response) + islpci_mgt_release(response); + ret = -EIO; + } + if (!ret) { + _res = response->data; + reslen = response->header->length; + } + } else if (cache) { + _res = cache; + ret = 0; + } + if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32) + res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res); + else { + res->ptr = kmalloc(reslen, GFP_KERNEL); + BUG_ON(res->ptr == NULL); + if (ret) + memset(res->ptr, 0, reslen); + else { + memcpy(res->ptr, _res, reslen); + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, + res->ptr); + } + } + if (cache) + up_read(&priv->mib_sem); + + if (response && !ret) + islpci_mgt_release(response); + + if (reslen > isl_oid[n].size) + printk(KERN_DEBUG + "mgt_get_request(0x%x): received data length was bigger " + "than expected (%d > %d). Memory is probably corrupted...", + oid, reslen, isl_oid[n].size); + + return ret; +} + +/* lock outside */ +int +mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) +{ + int i, ret = 0; + struct islpci_mgmtframe *response; + + for (i = 0; i < n; i++) { + struct oid_t *t = &(isl_oid[l[i]]); + void *data = priv->mib[l[i]]; + int j = 0; + u32 oid = t->oid; + BUG_ON(data == NULL); + while (j <= t->range) { + int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + oid, data, t->size, + &response); + if (response) { + r |= (response->header->operation == PIMFOR_OP_ERROR); + islpci_mgt_release(response); + } + if (r) + printk(KERN_ERR "%s: mgt_commit_list: failure. " + "oid=%08x err=%d\n", + priv->ndev->name, oid, r); + ret |= r; + j++; + oid++; + data += t->size; + } + } + return ret; +} + +/* Lock outside */ + +void +mgt_set(islpci_private *priv, enum oid_num_t n, void *data) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + + memcpy(priv->mib[n], data, isl_oid[n].size); + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]); +} + +void +mgt_get(islpci_private *priv, enum oid_num_t n, void *res) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + BUG_ON(res == NULL); + + memcpy(res, priv->mib[n], isl_oid[n].size); + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res); +} + +/* Commits the cache. Lock outside. */ + +static enum oid_num_t commit_part1[] = { + OID_INL_CONFIG, + OID_INL_MODE, + DOT11_OID_BSSTYPE, + DOT11_OID_CHANNEL, + DOT11_OID_MLMEAUTOLEVEL +}; + +static enum oid_num_t commit_part2[] = { + DOT11_OID_SSID, + DOT11_OID_PSMBUFFER, + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYX, /* MULTIPLE */ + DOT11_OID_DEFKEYID, + DOT11_OID_DOT1XENABLE, + OID_INL_DOT11D_CONFORMANCE, + /* Do not initialize this - fw < 1.0.4.3 rejects it + OID_INL_OUTPUTPOWER, + */ +}; + +/* update the MAC addr. */ +static int +mgt_update_addr(islpci_private *priv) +{ + struct islpci_mgmtframe *res; + int ret; + + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + isl_oid[GEN_OID_MACADDRESS].oid, NULL, + isl_oid[GEN_OID_MACADDRESS].size, &res); + + if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR)) + memcpy(priv->ndev->dev_addr, res->data, 6); + else + ret = -EIO; + if (res) + islpci_mgt_release(res); + + if (ret) + printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name); + return ret; +} + +#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0])) + +int +mgt_commit(islpci_private *priv) +{ + int rvalue; + u32 u; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); + + if (priv->iw_mode != IW_MODE_MONITOR) + rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + rvalue |= mgt_update_addr(priv); + + if (rvalue) { + /* some request have failed. The device might be in an + incoherent state. We should reset it ! */ + printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); + } + return rvalue; +} + +/* The following OIDs need to be "unlatched": + * + * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL + * FREQUENCY,EXTENDEDRATES. + * + * The way to do this is to set ESSID. Note though that they may get + * unlatch before though by setting another OID. */ +void +mgt_unlatch_all(islpci_private *priv) +{ + u32 u; + int rvalue = 0; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return; + + u = DOT11_OID_SSID; + rvalue = mgt_commit_list(priv, &u, 1); + /* Necessary if in MANUAL RUN mode? */ +#if 0 + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + + u = DOT11_OID_MLMEAUTOLEVEL; + rvalue |= mgt_commit_list(priv, &u, 1); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); +#endif + + if (rvalue) + printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name); +} + +/* This will tell you if you are allowed to answer a mlme(ex) request .*/ + +int +mgt_mlme_answer(islpci_private *priv) +{ + u32 mlmeautolevel; + /* Acquire a read lock because if we are in a mode change, it's + * possible to answer true, while the card is leaving master to managed + * mode. Answering to a mlme in this situation could hang the card. + */ + down_read(&priv->mib_sem); + mlmeautolevel = + le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); + up_read(&priv->mib_sem); + + return ((priv->iw_mode == IW_MODE_MASTER) && + (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); +} + +enum oid_num_t +mgt_oidtonum(u32 oid) +{ + int i; + + for (i = 0; i < OID_NUM_LAST; i++) + if (isl_oid[i].oid == oid) + return i; + + printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); + + return OID_NUM_LAST; +} + +int +mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) +{ + switch (isl_oid[n].flags & OID_FLAG_TYPE) { + case OID_TYPE_U32: + return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "size=%u\naddr=0x%X\n", buff->size, + buff->addr); + } + break; + case OID_TYPE_BSS:{ + struct obj_bss *bss = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "age=%u\nchannel=%u\n" + "capinfo=0x%X\nrates=0x%X\n" + "basic_rates=0x%X\n", bss->age, + bss->channel, bss->capinfo, + bss->rates, bss->basic_rates); + } + break; + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = r->ptr; + int i, k; + k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr); + for (i = 0; i < list->nr; i++) + k += snprintf(str + k, PRIV_STR_SIZE - k, + "bss[%u] : \nage=%u\nchannel=%u\n" + "capinfo=0x%X\nrates=0x%X\n" + "basic_rates=0x%X\n", + i, list->bsslist[i].age, + list->bsslist[i].channel, + list->bsslist[i].capinfo, + list->bsslist[i].rates, + list->bsslist[i].basic_rates); + return k; + } + break; + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = r->ptr; + int i, t; + printk("nr : %u\n", freq->nr); + t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr); + for (i = 0; i < freq->nr; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "mhz[%u]=%u\n", i, freq->mhz[i]); + return t; + } + break; + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=0x%X\nstate=0x%X\ncode=0x%X\n", + mlme->id, mlme->state, mlme->code); + } + break; + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=0x%X\nstate=0x%X\n" + "code=0x%X\nsize=0x%X\n", mlme->id, + mlme->state, mlme->code, mlme->size); + } + break; + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=%d\nsize=%d\n", + attach->id, + attach->size); + } + break; + case OID_TYPE_SSID:{ + struct obj_ssid *ssid = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "length=%u\noctets=%.*s\n", + ssid->length, ssid->length, + ssid->octets); + } + break; + case OID_TYPE_KEY:{ + struct obj_key *key = r->ptr; + int t, i; + t = snprintf(str, PRIV_STR_SIZE, + "type=0x%X\nlength=0x%X\nkey=0x", + key->type, key->length); + for (i = 0; i < key->length; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "%02X:", key->key[i]); + t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); + return t; + } + break; + case OID_TYPE_RAW: + case OID_TYPE_ADDR:{ + unsigned char *buff = r->ptr; + int t, i; + t = snprintf(str, PRIV_STR_SIZE, "hex data="); + for (i = 0; i < isl_oid[n].size; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "%02X:", buff[i]); + t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); + return t; + } + break; + default: + BUG(); + } + return 0; +} diff -urN linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.h linux-2.4.28/drivers/net/wireless/prism54/oid_mgt.h --- linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/oid_mgt.h 2004-11-17 03:54:21.469392590 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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 + * + */ + +#if !defined(_OID_MGT_H) +#define _OID_MGT_H + +#include "isl_oid.h" +#include "islpci_dev.h" + +extern struct oid_t isl_oid[]; + +int mgt_init(islpci_private *); + +void mgt_clean(islpci_private *); + +/* I don't know where to put these 3 */ +extern const int frequency_list_bg[]; +extern const int frequency_list_a[]; +int channel_of_freq(int); + +void mgt_le_to_cpu(int, void *); + +int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); +int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int); + + +int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, + union oid_res_t *); + +int mgt_commit_list(islpci_private *, enum oid_num_t *, int); + +void mgt_set(islpci_private *, enum oid_num_t, void *); + +void mgt_get(islpci_private *, enum oid_num_t, void *); + +int mgt_commit(islpci_private *); +void mgt_unlatch_all(islpci_private *); + +int mgt_mlme_answer(islpci_private *); + +enum oid_num_t mgt_oidtonum(u32 oid); + +int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *); + +#endif /* !defined(_OID_MGT_H) */ +/* EOF */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/prismcompat.h linux-2.4.28/drivers/net/wireless/prism54/prismcompat.h --- linux-2.4.27/drivers/net/wireless/prism54/prismcompat.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/prismcompat.h 2004-11-17 03:54:21.470392631 -0800 @@ -0,0 +1,46 @@ +/* + * (C) 2004 Margit Schubert-While + * + * 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 + * + * 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 + * + */ + +/* + * Compatibility header file to aid support of different kernel versions + */ + +#ifdef PRISM54_COMPAT24 +#include "prismcompat24.h" +#else /* PRISM54_COMPAT24 */ + +#ifndef _PRISM_COMPAT_H +#define _PRISM_COMPAT_H + +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error Firmware Loading is not configured in the kernel ! +#endif + +#define prism54_synchronize_irq(irq) synchronize_irq(irq) + +#define PRISM_FW_PDEV &priv->pdev->dev + +#endif /* _PRISM_COMPAT_H */ +#endif /* PRISM54_COMPAT24 */ diff -urN linux-2.4.27/drivers/net/wireless/prism54/prismcompat24.h linux-2.4.28/drivers/net/wireless/prism54/prismcompat24.h --- linux-2.4.27/drivers/net/wireless/prism54/prismcompat24.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/net/wireless/prism54/prismcompat24.h 2004-11-17 03:54:21.471392672 -0800 @@ -0,0 +1,72 @@ +/* + * (C) 2004 Margit Schubert-While + * + * 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 + * + * 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 + * + */ + +/* + * Compatibility header file to aid support of different kernel versions + */ + +#ifndef _PRISM_COMPAT_H +#define _PRISM_COMPAT_H + +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) +#define module_param(x, y, z) MODULE_PARM(x, "i") +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +#define free_netdev(x) kfree(x) +#define pci_name(x) x->slot_name +#define irqreturn_t void +#define IRQ_HANDLED +#define IRQ_NONE +#else +#include +#endif + +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task + +#if !defined(HAVE_NETDEV_PRIV) +#define netdev_priv(x) (x)->priv +#endif + +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error Firmware Loading is not configured in the kernel ! +#endif + +#define prism54_synchronize_irq(irq) synchronize_irq() + +#define DEFINE_WAIT(y) DECLARE_WAITQUEUE(y, current) +#define prepare_to_wait(x, y, z) set_current_state(z); \ + add_wait_queue(x, y) +#define finish_wait(x, y) remove_wait_queue(x, y); \ + set_current_state(TASK_RUNNING) + +#define PRISM_FW_PDEV pci_name(priv->pdev) + +#endif /* _PRISM_COMPAT_H */ diff -urN linux-2.4.27/drivers/parport/parport_pc.c linux-2.4.28/drivers/parport/parport_pc.c --- linux-2.4.27/drivers/parport/parport_pc.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/parport/parport_pc.c 2004-11-17 03:54:21.473392754 -0800 @@ -266,95 +266,6 @@ parport_generic_irq(irq, (struct parport *) dev_id, regs); } -void parport_pc_write_data(struct parport *p, unsigned char d) -{ - outb (d, DATA (p)); -} - -unsigned char parport_pc_read_data(struct parport *p) -{ - return inb (DATA (p)); -} - -void parport_pc_write_control(struct parport *p, unsigned char d) -{ - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); - - /* Take this out when drivers have adapted to the newer interface. */ - if (d & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", - p->name, p->cad->name); - parport_pc_data_reverse (p); - } - - __parport_pc_frob_control (p, wm, d & wm); -} - -unsigned char parport_pc_read_control(struct parport *p) -{ - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); - const struct parport_pc_private *priv = p->physport->private_data; - return priv->ctr & wm; /* Use soft copy */ -} - -unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, - unsigned char val) -{ - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); - - /* Take this out when drivers have adapted to the newer interface. */ - if (mask & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_%s for this!\n", - p->name, p->cad->name, - (val & 0x20) ? "reverse" : "forward"); - if (val & 0x20) - parport_pc_data_reverse (p); - else - parport_pc_data_forward (p); - } - - /* Restrict mask and val to control lines. */ - mask &= wm; - val &= wm; - - return __parport_pc_frob_control (p, mask, val); -} - -unsigned char parport_pc_read_status(struct parport *p) -{ - return inb (STATUS (p)); -} - -void parport_pc_disable_irq(struct parport *p) -{ - __parport_pc_frob_control (p, 0x10, 0); -} - -void parport_pc_enable_irq(struct parport *p) -{ - if (p->irq != PARPORT_IRQ_NONE) - __parport_pc_frob_control (p, 0x10, 0x10); -} - -void parport_pc_data_forward (struct parport *p) -{ - __parport_pc_frob_control (p, 0x20, 0); -} - -void parport_pc_data_reverse (struct parport *p) -{ - __parport_pc_frob_control (p, 0x20, 0x20); -} - void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) { s->u.pc.ctr = 0xc; @@ -414,7 +325,8 @@ left -= 16; } else { /* grab single byte from the warp fifo */ - *((char *)buf)++ = inb (EPPDATA (port)); + *((char *)buf) = inb (EPPDATA (port)); + buf++; got++; left--; } @@ -441,7 +353,8 @@ return length; } for (; got < length; got++) { - *((char*)buf)++ = inb (EPPDATA(port)); + *((char*)buf) = inb (EPPDATA(port)); + buf++; if (inb (STATUS (port)) & 0x01) { /* EPP timeout */ clear_epp_timeout (port); @@ -470,7 +383,8 @@ return length; } for (; written < length; written++) { - outb (*((char*)buf)++, EPPDATA(port)); + outb (*((char*)buf), EPPDATA(port)); + buf++; if (inb (STATUS(port)) & 0x01) { clear_epp_timeout (port); break; @@ -494,7 +408,8 @@ return length; } for (; got < length; got++) { - *((char*)buf)++ = inb (EPPADDR (port)); + *((char*)buf) = inb (EPPADDR (port)); + buf++; if (inb (STATUS (port)) & 0x01) { clear_epp_timeout (port); break; @@ -519,7 +434,8 @@ return length; } for (; written < length; written++) { - outb (*((char*)buf)++, EPPADDR (port)); + outb (*((char*)buf), EPPADDR (port)); + buf++; if (inb (STATUS (port)) & 0x01) { clear_epp_timeout (port); break; @@ -2692,6 +2608,7 @@ syba_2p_epp, syba_1p_ecp, titan_010l, + titan_1284p1, titan_1284p2, avlab_1p, avlab_2p, @@ -2763,6 +2680,7 @@ /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } }, /* titan_010l */ { 1, { { 3, -1 }, } }, + /* titan_1284p1 */ { 1, { { 0, 1 }, } }, /* titan_1284p2 */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* avlab_1p */ { 1, { { 0, 1}, } }, /* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} }, @@ -2834,6 +2752,7 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l }, + { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 }, { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 }, /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */ diff -urN linux-2.4.27/drivers/pci/pci.c linux-2.4.28/drivers/pci/pci.c --- linux-2.4.27/drivers/pci/pci.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/pci/pci.c 2004-11-17 03:54:21.475392837 -0800 @@ -1238,6 +1238,8 @@ * Allocate a new bus, and inherit stuff from the parent.. */ child = pci_alloc_bus(); + if (!child) + return NULL; list_add_tail(&child->node, &parent->children); child->self = dev; @@ -1291,7 +1293,11 @@ */ if (pass) return max; + child = pci_add_new_bus(bus, dev, 0); + if (!child) + return max; + child->primary = buses & 0xFF; child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; @@ -1316,6 +1322,9 @@ pci_write_config_word(dev, PCI_STATUS, 0xffff); child = pci_add_new_bus(bus, dev, ++max); + if (!child) + return max; + buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) @@ -2214,7 +2223,6 @@ EXPORT_SYMBOL(isa_dma_bridge_buggy); EXPORT_SYMBOL(pci_pci_problems); -EXPORT_SYMBOL(pciehp_msi_quirk); /* Pool allocator */ diff -urN linux-2.4.27/drivers/pci/quirks.c linux-2.4.28/drivers/pci/quirks.c --- linux-2.4.27/drivers/pci/quirks.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/pci/quirks.c 2004-11-17 03:54:21.476392878 -0800 @@ -719,13 +719,6 @@ } } -int pciehp_msi_quirk; - -static void __devinit quirk_pciehp_msi(struct pci_dev *pdev) -{ - pciehp_msi_quirk = 1; -} - /* * The main table of quirks. */ @@ -815,8 +808,6 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi }, - { 0 } }; diff -urN linux-2.4.27/drivers/pcmcia/bulkmem.c linux-2.4.28/drivers/pcmcia/bulkmem.c --- linux-2.4.27/drivers/pcmcia/bulkmem.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/pcmcia/bulkmem.c 2004-11-17 03:54:21.477392919 -0800 @@ -301,7 +301,7 @@ { window_handle_t w; int ret = pcmcia_request_window(a1, a2, &w); - (window_handle_t *)a1 = w; + a1 = w; return ret; } break; diff -urN linux-2.4.27/drivers/pcmcia/i82365.c linux-2.4.28/drivers/pcmcia/i82365.c --- linux-2.4.27/drivers/pcmcia/i82365.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/pcmcia/i82365.c 2004-11-17 03:54:21.478392960 -0800 @@ -63,7 +63,6 @@ #include "cirrus.h" #include "vg468.h" #include "ricoh.h" -#include "o2micro.h" #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; diff -urN linux-2.4.27/drivers/pcmcia/o2micro.h linux-2.4.28/drivers/pcmcia/o2micro.h --- linux-2.4.27/drivers/pcmcia/o2micro.h 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/pcmcia/o2micro.h 2004-11-17 03:54:21.479393001 -0800 @@ -120,4 +120,36 @@ #define O2_MODE_E_LED_OUT 0x08 #define O2_MODE_E_SKTA_ACTV 0x10 +static int o2micro_open(pci_socket_t *socket) +{ + /* + * 'reserved' register at 0x94/D4. chaning it to 0xCA (8 bit) enables + * read prefetching which for example makes the RME Hammerfall DSP + * working. for some bridges it is at 0x94, for others at 0xD4. it's + * ok to write to both registers on all O2 bridges. + * from Eric Still, 02Micro. + */ + if (PCI_FUNC(socket->dev->devfn) == 0) { + config_writeb(socket, 0x94, 0xCA); + config_writeb(socket, 0xD4, 0xCA); + } + + return 0; +} + +static struct pci_socket_ops o2micro_ops = { + o2micro_open, + yenta_close, + yenta_init, + yenta_suspend, + yenta_get_status, + yenta_get_socket, + yenta_set_socket, + yenta_get_io_map, + yenta_set_io_map, + yenta_get_mem_map, + yenta_set_mem_map, + yenta_proc_setup +}; + #endif /* _LINUX_O2MICRO_H */ diff -urN linux-2.4.27/drivers/pcmcia/ti113x.h linux-2.4.28/drivers/pcmcia/ti113x.h --- linux-2.4.27/drivers/pcmcia/ti113x.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/pcmcia/ti113x.h 2004-11-17 03:54:21.479393001 -0800 @@ -134,6 +134,10 @@ /* ExCA IO offset registers */ #define TI113X_IO_OFFSET(map) (0x36+((map)<<1)) +/* EnE test register */ +#define ENE_TEST_C9 0xc9 /* 8bit */ +#define ENE_TEST_C9_TLTENABLE 0x02 + #ifdef CONFIG_CARDBUS /* @@ -155,6 +159,17 @@ new = reg & ~I365_INTR_ENA; if (new != reg) exca_writeb(socket, I365_INTCTL, new); + + /* + * for EnE bridges only: clear testbit TLTEnable. this makes the + * RME Hammerfall DSP sound card working. + */ + if (socket->dev->vendor == PCI_VENDOR_ID_ENE) { + u8 test_c9 = config_readb(socket, ENE_TEST_C9); + test_c9 &= ~ENE_TEST_C9_TLTENABLE; + config_writeb(socket, ENE_TEST_C9, test_c9); + } + return 0; } diff -urN linux-2.4.27/drivers/pcmcia/yenta.c linux-2.4.28/drivers/pcmcia/yenta.c --- linux-2.4.27/drivers/pcmcia/yenta.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/pcmcia/yenta.c 2004-11-17 03:54:21.480393042 -0800 @@ -845,6 +845,7 @@ #include "ti113x.h" #include "ricoh.h" +#include "o2micro.h" /* * Different cardbus controllers have slightly different @@ -880,6 +881,8 @@ { PD(ENE,1410), &ti_ops }, { PD(ENE,1420), &ti_ops }, + { PCI_VENDOR_ID_O2, PCI_ANY_ID, &o2micro_ops }, + { PD(RICOH,RL5C465), &ricoh_ops }, { PD(RICOH,RL5C466), &ricoh_ops }, { PD(RICOH,RL5C475), &ricoh_ops }, diff -urN linux-2.4.27/drivers/s390/Config.in linux-2.4.28/drivers/s390/Config.in --- linux-2.4.27/drivers/s390/Config.in 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/Config.in 2004-11-17 03:54:21.481393083 -0800 @@ -88,6 +88,23 @@ define_bool CONFIG_HOTPLUG y fi + if [ "$CONFIG_QDIO" != "n" -a "$CONFIG_CHANDEV" = "y" -a "$CONFIG_IP_MULTICAST" = "y" ]; then + dep_tristate 'Support for Gigabit Ethernet' CONFIG_QETH $CONFIG_QDIO + if [ "$CONFIG_QETH" != "n" ]; then + comment 'Gigabit Ethernet default settings' + if [ "$CONFIG_IPV6" = "y" -o "$CONFIG_IPV6" = "$CONFIG_QETH" ]; then + bool ' IPv6 support for qeth' CONFIG_QETH_IPV6 + else + define_bool CONFIG_QETH_IPV6 n + fi + if [ "$CONFIG_VLAN_8021Q" = "y" -o "$CONFIG_VLAN_8021Q" = "$CONFIG_QETH" ]; then + bool ' VLAN support for qeth' CONFIG_QETH_VLAN + else + define_bool CONFIG_QETH_VLAN n + fi + bool ' Performance statistics in /proc' CONFIG_QETH_PERF_STATS + fi + fi tristate 'CTC device support' CONFIG_CTC tristate 'IUCV device support (VM only)' CONFIG_IUCV fi diff -urN linux-2.4.27/drivers/s390/Makefile linux-2.4.28/drivers/s390/Makefile --- linux-2.4.27/drivers/s390/Makefile 2003-06-13 07:51:35.000000000 -0700 +++ linux-2.4.28/drivers/s390/Makefile 2004-11-17 03:54:21.481393083 -0800 @@ -9,6 +9,8 @@ obj-y := s390io.o s390mach.o s390dyn.o ccwcache.o sysinfo.o export-objs += ccwcache.o s390dyn.o s390io.o +obj-$(CONFIG_QDIO) += qdio.o +export-objs += qdio.o obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o) diff -urN linux-2.4.27/drivers/s390/block/dasd.c linux-2.4.28/drivers/s390/block/dasd.c --- linux-2.4.27/drivers/s390/block/dasd.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/s390/block/dasd.c 2004-11-17 03:54:21.487393330 -0800 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.311 $ + * $Revision: 1.298.2.11 $ * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review @@ -311,7 +311,7 @@ /* and add the remaining subranges */ for (start = index = from, end = -EINVAL; index <= to; index++) { - if (dasd_devindex_from_devno(index) > 0) { + if (dasd_devindex_from_devno(index) >= 0) { /* current device is already in range */ MESSAGE (KERN_DEBUG, "dasd_add_range %04x-%04x: " @@ -3815,7 +3815,7 @@ } if (device && - device->level >= DASD_STATE_READY) { + device->level >= DASD_STATE_NEW) { s390irq_spin_lock_irqsave (device->devinfo.irq, flags); DEV_MESSAGE (KERN_DEBUG, device, "%s", @@ -5188,6 +5188,7 @@ "/proc/dasd/statistics: only 'set' and " "'reset' are supported verbs"); + vfree (buffer); return -EINVAL; } @@ -5243,6 +5244,7 @@ #endif /* DASD_PROFILE */ + vfree (buffer); return user_len; } diff -urN linux-2.4.27/drivers/s390/block/dasd_3990_erp.c linux-2.4.28/drivers/s390/block/dasd_3990_erp.c --- linux-2.4.27/drivers/s390/block/dasd_3990_erp.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/s390/block/dasd_3990_erp.c 2004-11-17 03:54:21.489393412 -0800 @@ -5,7 +5,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * - * $Revision: 1.52 $ + * $Revision: 1.52.2.3 $ * * History of changes: * 05/14/01 fixed PL030160GTO (BUG() in erp_action_5) @@ -585,9 +585,8 @@ ioinfo[irq]->opm); /* reset status to queued to handle the request again... */ - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); + if (erp->status > CQR_STATUS_QUEUED) + erp->status = CQR_STATUS_QUEUED; erp->retries = 1; @@ -598,12 +597,10 @@ "opm=%x) -> permanent error", erp->dstat->lpum, ioinfo[irq]->opm); - - /* post request with permanent error */ - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + /* post request with permanent error */ + if (erp->status > CQR_STATUS_QUEUED) + erp->status = CQR_STATUS_FAILED; } } /* end dasd_3990_erp_alternate_path */ @@ -768,7 +765,6 @@ CQR_STATUS_QUEUED); } } - return erp; } /* end dasd_3990_erp_action_4 */ @@ -2386,7 +2382,7 @@ switch (sense[28]) { case 0x17: /* issue a Diagnostic Control command with an - * Inhibit Write subcommand and controler modifier */ + * Inhibit Write subcommand and controler modifier */ erp = dasd_3990_erp_DCTL (erp, 0x20); break; @@ -2699,7 +2695,8 @@ if (!erp) { if (cqr->retries <= 0) { DEV_MESSAGE (KERN_ERR, device, "%s", - "Unable to allocate ERP request (NO retries left)"); + "Unable to allocate ERP request " + "(NO retries left)"); check_then_set (&cqr->status, CQR_STATUS_ERROR, @@ -2709,7 +2706,8 @@ } else { DEV_MESSAGE (KERN_ERR, device, - "Unable to allocate ERP request (%i retries left)", + "Unable to allocate ERP request " + "(%i retries left)", cqr->retries); if (!timer_pending(&device->timer)) { @@ -3169,8 +3167,9 @@ dasd_chanq_enq_head (&device->queue, erp); } else { - if ((erp->status == CQR_STATUS_FILLED ) || (erp != device->queue.head)) { - /* something strange happened - log the error and panic */ + if ((erp->status == CQR_STATUS_FILLED ) || + (erp != device->queue.head)) { + /* something strange happened - log error and panic */ /* print current erp_chain */ DEV_MESSAGE (KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION"); @@ -3188,7 +3187,8 @@ temp_erp->refers); } } - panic ("Problems with ERP chain!!! Please report to linux390@de.ibm.com"); + panic ("Problems with ERP chain!!! " + "Please report to linux390@de.ibm.com"); } } diff -urN linux-2.4.27/drivers/s390/char/ctrlchar.c linux-2.4.28/drivers/s390/char/ctrlchar.c --- linux-2.4.27/drivers/s390/char/ctrlchar.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/char/ctrlchar.c 2004-11-17 03:54:21.490393453 -0800 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff -urN linux-2.4.27/drivers/s390/net/c7000.c linux-2.4.28/drivers/s390/net/c7000.c --- linux-2.4.27/drivers/s390/net/c7000.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/c7000.c 2004-11-17 03:54:21.494393618 -0800 @@ -3,6 +3,20 @@ Author: Bob Scardapane (UTS Global LLC). Version: 3. + 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. + To use this driver, run the LINUX command: insmod c7000 base0=0xYYYY lhost0=s1 uhost0=s2 lappl0=s3 uappl0=s4 dbg=x @@ -409,16 +423,7 @@ One device structure per controller. */ -/* RBH Try out the new code for 2.4.0 */ -#define NEWSTUFF - -#ifdef NEWSTUFF -#define STRUCT_NET_DEVICE struct net_device -#else -#define STRUCT_NET_DEVICE struct device -#endif - -STRUCT_NET_DEVICE c7000_devices[MAX_C7000]; +struct net_device c7000_devices[MAX_C7000]; /* Scratch variable filled in with controller name. @@ -432,6 +437,7 @@ MODULE_AUTHOR("Robert Scardapane (UTS Global)"); MODULE_DESCRIPTION("Network module for Cisco 7000 box."); +MODULE_LICENSE("GPL"); MODULE_PARM(base0, "1i"); MODULE_PARM_DESC(base0, "Base unit address for 1st C7000 box."); @@ -521,16 +527,12 @@ ccw1_t ccws[5]; /* control ccws */ int devno; /* device number */ int irq; /* subchannel number */ - int IO_active; /* IO activity flag */ + unsigned long IO_active; /* IO activity flag */ int state; /* fsm state */ int retries; /* retry counter */ unsigned long flag_a; /* bh activity flag */ devstat_t devstat; /* device status */ -#ifdef NEWSTUFF wait_queue_head_t wait; /* sleep q head */ -#else - struct wait_queue *wait; /* sleep q pointer */ -#endif struct c7000_controller *cntlp; /* controller pointer */ struct c7000_buffer *free; /* free buffer anchor */ struct c7000_buffer *proc_head; /* proc head */ @@ -551,7 +553,7 @@ struct c7000_controller { struct net_device_stats stats; /* statistics */ - STRUCT_NET_DEVICE *dev; /* -> device struct */ + struct net_device *dev; /* -> device struct */ unsigned int base_addr; /* base address */ char lappl[NAMLEN]; /* local appl */ char lhost[NAMLEN]; /* local host */ @@ -560,9 +562,7 @@ unsigned char version; /* version = 2 */ unsigned char linkid; /* link id */ struct c7000_unit cunits[NUNITS]; /* embedded units */ -#ifdef NEWSTUFF - int tbusy; -#endif + unsigned long tbusy; }; /* @@ -579,62 +579,29 @@ Set the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_set_busy(dev) netif_stop_queue(dev) -#else -static __inline__ void -c7000_set_busy(STRUCT_NET_DEVICE *dev) -{ - dev->tbusy = 1; - eieio(); - return; -} -#endif /* Clear the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_clear_busy(dev) netif_wake_queue(dev) -#else -static __inline__ void -c7000_clear_busy(STRUCT_NET_DEVICE *dev) -{ - dev->tbusy = 0; - eieio(); - return; -} -#endif /* Extract the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_check_busy(dev) netif_queue_stopped(dev) -#else -static __inline__ int -c7000_check_busy(STRUCT_NET_DEVICE *dev) -{ - eieio(); - return(dev->tbusy); -} -#endif /* Set a bit in the device structure transmission busy flag. */ static __inline__ void -c7000_setbit_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_setbit_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF netif_stop_queue(dev); test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); -#else - set_bit(nr, (void *)&dev->tbusy); -#endif return; } @@ -643,14 +610,10 @@ */ static __inline__ void -c7000_clearbit_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_clearbit_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF clear_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); netif_wake_queue(dev); -#else - clear_bit(nr, (void *)&dev->tbusy); -#endif return; } @@ -659,14 +622,10 @@ */ static __inline__ int -c7000_ts_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_ts_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF netif_stop_queue(dev); return test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); -#else - return(test_and_set_bit(nr, (void *)&dev->tbusy)); -#endif } /* @@ -678,7 +637,7 @@ { int i; struct c7000_unit *cup; - STRUCT_NET_DEVICE *dev = ccp->dev; + struct net_device *dev = ccp->dev; for (i = 0; i < NUNITS; i++) { cup = &ccp->cunits[i]; @@ -686,12 +645,8 @@ } if (dev != NULL) -#ifdef NEWSTUFF /* RBH XXX Should we be doing this? */ dev->state &= ~__LINK_STATE_START; -#else - dev->flags &= ~IFF_RUNNING; -#endif CPrintk(0, "c7000: c7000_error: base unit 0x%x is down\n", ccp->base_addr); return; @@ -759,9 +714,9 @@ static int c7000_haltio(struct c7000_unit *cup) { - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; DECLARE_WAITQUEUE(wait, current); int rc; @@ -792,9 +747,9 @@ static int c7000_doio(struct c7000_unit *cup) { - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; DECLARE_WAITQUEUE(wait, current); int rc; @@ -1013,7 +968,7 @@ */ static int -c7000_alloc_buffers(STRUCT_NET_DEVICE *dev) +c7000_alloc_buffers(struct net_device *dev) { int i; int j; @@ -1030,9 +985,10 @@ bufptr = kmalloc(sizeof(struct c7000_buffer), GFP_KERNEL); data = kmalloc(C7000_BUFSIZE, GFP_KERNEL); - if (bufptr == NULL) - { - if(data) + if (bufptr == NULL || data == NULL) { + if (bufptr) + kfree(bufptr); + if (data) kfree(data); return(-1); } @@ -1088,7 +1044,7 @@ */ static void -c7000_free_buffers(STRUCT_NET_DEVICE *dev) +c7000_free_buffers(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *) dev->priv; @@ -1328,12 +1284,12 @@ struct c7000_rd_header *head; struct sk_buff *skb; struct c7000_controller *ccp; - STRUCT_NET_DEVICE *dev; + struct net_device *dev; int rc; __u16 data_length; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; ccp = cup->cntlp; dev = ccp->dev; @@ -1385,6 +1341,7 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); ccp->stats.rx_packets++; + ccp->stats.rx_bytes += skb->len; } else { CPrintk(0, "c7000: c7000_irq_bh: can not allocate a skb for unit 0x%x\n", cup->devno); ccp->stats.rx_dropped++; @@ -1403,6 +1360,7 @@ Rechain the buffer on the running channel program. */ + buf->ccws[3].cda = buf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[6]); if (pbuf != NULL) pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]); @@ -1422,7 +1380,7 @@ return; } - parm = (__u32)cup; + parm = (unsigned long)cup; cup->state = C7000_READ; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -1979,7 +1937,7 @@ */ struct net_device_stats * -c7000_stats(STRUCT_NET_DEVICE *dev) +c7000_stats(struct net_device *dev) { struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; @@ -1991,13 +1949,13 @@ */ static int -c7000_open(STRUCT_NET_DEVICE *dev) +c7000_open(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; c7000_set_busy(dev); @@ -2025,16 +1983,11 @@ half routine. */ -#ifndef NEWSTUFF - cup->tq.next = NULL; -#endif cup->tq.sync = 0; cup->tq.routine = (void *)(void *)c7000_irq_bh; cup->tq.data = cup; cup->state = C7000_HALT; -#ifdef NEWSTUFF init_waitqueue_head(&cup->wait); -#endif CPrintk(1, "c7000: c7000_open: issuing halt to unit 0x%x\n", cup->devno); /* @@ -2154,7 +2107,7 @@ */ cup->state = C7000_READ; - parm = (__u32) cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2165,11 +2118,7 @@ return(-EIO); } -#ifdef NEWSTUFF netif_start_queue(dev); -#else - dev->start = 1; -#endif CPrintk(0, "c7000: c7000_open: base unit 0x%lx is opened\n", dev->base_addr); c7000_clear_busy(dev); MOD_INC_USE_COUNT; /* increment module usage count */ @@ -2181,18 +2130,13 @@ */ static int -c7000_stop(STRUCT_NET_DEVICE *dev) +c7000_stop(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; -#ifdef NEWSTUFF -/* nothing? */ -#else - dev->start = 0; -#endif c7000_set_busy(dev); /* @@ -2236,7 +2180,7 @@ */ static int -c7000_config(STRUCT_NET_DEVICE *dev, struct ifmap *map) +c7000_config(struct net_device *dev, struct ifmap *map) { CPrintk(1, "c7000: c7000_config: entered for base unit 0x%lx\n", dev->base_addr); return(0); @@ -2247,12 +2191,12 @@ */ static int -c7000_xmit(struct sk_buff *skb, STRUCT_NET_DEVICE *dev) +c7000_xmit(struct sk_buff *skb, struct net_device *dev) { struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; - __u32 saveflags; - __u32 parm; + unsigned long saveflags; + unsigned long parm; __u8 flags = 0x00; struct c7000_buffer *buf, *pbuf; int rc; @@ -2350,7 +2294,7 @@ if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) { CPrintk(1, "c7000: c7000_xmit: start IO for unit 0x%x\n", cup->devno); c7000_bld_wrt_chain(cup); - parm = (__u32) cup; + parm = (unsigned long)cup; cup->state = C7000_WRITE; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2385,7 +2329,7 @@ */ static int -c7000_ioctl(STRUCT_NET_DEVICE *dev, struct ifreq *ifr, int cmd) +c7000_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { CPrintk(1, "c7000: c7000_ioctl: entered for base unit 0x%lx with cmd %d\n", dev->base_addr, cmd); return(0); @@ -2461,7 +2405,7 @@ c7000_retry_io(struct c7000_unit *cup) { int rc; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; ccw1_t *ccwp; @@ -2472,7 +2416,7 @@ } set_bit(0, (void *)&cup->IO_active); - parm = (__u32)cup; + parm = (unsigned long)cup; if (cup->state == C7000_READ || cup->state == C7000_WRITE) ccwp = &cup->proc_head->ccws[0]; @@ -2560,14 +2504,10 @@ */ buf = c7000_dequeue_buffer(cup); + ccp->stats.tx_bytes += buf->len; + ccp->stats.tx_packets++; c7000_release_buffer(cup, buf); num_write++; - - /* - Update transmitted packets statistic. - */ - - ccp->stats.tx_packets++; } CPrintk(1, "c7000: c7000_proc_wintr: %d buffers written for unit 0x%x\n", num_write, cup->devno); @@ -2584,8 +2524,8 @@ devstat_t *devstat = ((devstat_t *) initparm); struct c7000_unit *cup = NULL; struct c7000_controller *ccp = NULL; - STRUCT_NET_DEVICE *dev = NULL; - __u32 parm; + struct net_device *dev = NULL; + unsigned long parm; __u8 flags = 0x00; int rc; @@ -2618,14 +2558,14 @@ ccp = cup->cntlp; if (ccp == NULL) { - CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure 0x%x for unit 0x%x\n", (int)cup, cup->devno); + CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure %p for unit 0x%x\n", cup, cup->devno); return; } dev = ccp->dev; if (dev == NULL) { - CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure 0x%x for unit 0x%x\n", (int)ccp, cup->devno); + CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure %p for unit 0x%x\n", ccp, cup->devno); return; } @@ -2777,7 +2717,7 @@ if ((devstat->flag & DEVSTAT_FINAL_STATUS) && (cup->free != NULL)) { c7000_bld_read_chain(cup); - parm = (__u32)cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2834,7 +2774,7 @@ if (cup->proc_head != NULL) { c7000_bld_wrt_chain(cup); - parm = (__u32)cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2932,7 +2872,7 @@ */ static int -c7000_init(STRUCT_NET_DEVICE *dev) +c7000_init(struct net_device *dev) { struct c7000_controller *ccp; int i; @@ -2970,7 +2910,7 @@ dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = C7000_TXQUEUE_LEN; - dev->flags = IFF_NOARP; + dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP; dev->open = c7000_open; dev->stop = c7000_stop; dev->set_config = c7000_config; @@ -2987,7 +2927,7 @@ return(-ENOMEM); } - CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address 0x%x\n", (int)ccp); + CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address %p\n", ccp); memset(ccp, '\0', sizeof(struct c7000_controller)); ccp->dev = dev; ccp->base_addr = dev->base_addr; @@ -3217,12 +3157,8 @@ Initialize the device structure. */ - memset(&c7000_devices[i], '\0', sizeof(STRUCT_NET_DEVICE)); -#ifdef NEWSTUFF + memset(&c7000_devices[i], '\0', sizeof(struct net_device)); strcpy(c7000_devices[i].name, ifnames[i]); -#else - c7000_devices[i].name = &ifnames[i][0]; -#endif c7000_devices[i].base_addr = bases[i]; c7000_devices[i].init = c7000_init; @@ -3278,7 +3214,7 @@ free_irq(ccp->cunits[j].irq, &ccp->cunits[j].devstat); } - CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address 0x%x\n", (int)ccp); + CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address %p\n", ccp); kfree(ccp); } diff -urN linux-2.4.27/drivers/s390/net/ctcmain.c linux-2.4.28/drivers/s390/net/ctcmain.c --- linux-2.4.27/drivers/s390/net/ctcmain.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/ctcmain.c 2004-11-17 03:54:21.496393700 -0800 @@ -3096,7 +3096,7 @@ privptr = (ctc_priv *)dev->priv; - if (!*sbus || pos == 0) + if (!*sbuf || pos == 0) sprintf(sbuf, "0x%02x\n", loglevel); l = strlen(sbuf); @@ -3169,7 +3169,7 @@ privptr = (ctc_priv *)dev->priv; - if (!*sbus || pos == 0) { + if (!*sbuf || pos == 0) { p += sprintf(p, "Device FSM state: %s\n", fsm_getstate_str(privptr->fsm)); p += sprintf(p, "RX channel FSM state: %s\n", diff -urN linux-2.4.27/drivers/s390/net/iucv.c linux-2.4.28/drivers/s390/net/iucv.c --- linux-2.4.27/drivers/s390/net/iucv.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/iucv.c 2004-11-17 03:54:21.499393823 -0800 @@ -1,5 +1,5 @@ /* - * $Id: iucv.c,v 1.41 2003/06/24 16:05:32 felfert Exp $ + * $Id: iucv.c,v 1.40.2.5 2004/06/29 07:37:33 braunu Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.41 $ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.40.2.5 $ * */ @@ -320,7 +320,7 @@ #define iucv_debug(lvl, fmt, args...) \ do { \ if (debuglevel >= lvl) \ - printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n", ## args); \ + printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__, ## args); \ } while (0) #else @@ -334,13 +334,15 @@ * Internal functions *******************************************************************************/ +static int iucv_retrieve_buffer(void); + /** * print start banner */ static void iucv_banner(void) { - char vbuf[] = "$Revision: 1.41 $"; + char vbuf[] = "$Revision: 1.40.2.5 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -418,6 +420,7 @@ static void iucv_exit(void) { + iucv_retrieve_buffer(); if (iucv_external_int_buffer) kfree(iucv_external_int_buffer); if (iucv_param_pool) @@ -438,17 +441,19 @@ static __inline__ iucv_param * grab_param(void) { - iucv_param *ret; - int i = 0; + iucv_param *ptr; + static int hint = 0; + + ptr = iucv_param_pool + hint; + do { + ptr++; + if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) + ptr = iucv_param_pool; + } while (atomic_compare_and_swap(0, 1, &ptr->in_use)); + hint = ptr - iucv_param_pool; - while (atomic_compare_and_swap(0, 1, &iucv_param_pool[i].in_use)) { - i++; - if (i >= PARAM_POOL_SIZE) - i = 0; - } - ret = &iucv_param_pool[i]; - memset(&ret->param, 0, sizeof(ret->param)); - return ret; + memset(&ptr->param, 0, sizeof(ptr->param)); + return ptr; } /** @@ -549,10 +554,8 @@ * - ENOMEM - storage allocation for a new pathid table failed */ static int -iucv_add_pathid(__u16 pathid, handler *handler) +__iucv_add_pathid(__u16 pathid, handler *handler) { - ulong flags; - iucv_debug(1, "entering"); iucv_debug(1, "handler is pointing to %p", handler); @@ -560,21 +563,30 @@ if (pathid > (max_connections - 1)) return -EINVAL; - spin_lock_irqsave (&iucv_lock, flags); if (iucv_pathid_table[pathid]) { - spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); printk(KERN_WARNING "%s: Pathid being used, error.\n", __FUNCTION__); return -EINVAL; } iucv_pathid_table[pathid] = handler; - spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug(1, "exiting"); return 0; } /* end of add_pathid function */ +static int +iucv_add_pathid(__u16 pathid, handler *handler) +{ + ulong flags; + int rc; + + spin_lock_irqsave (&iucv_lock, flags); + rc = __iucv_add_pathid(pathid, handler); + spin_unlock_irqrestore (&iucv_lock, flags); + return rc; +} + static void iucv_remove_pathid(__u16 pathid) { @@ -688,7 +700,6 @@ spin_lock_irqsave (&iucv_lock, flags); list_del(&handler->list); if (list_empty(&iucv_handler_table)) { - iucv_retrieve_buffer(); if (register_flag) { unregister_external_interrupt(0x4000, iucv_irq_handler); register_flag = 0; @@ -764,6 +775,7 @@ if (iucv_pathid_table == NULL) { printk(KERN_WARNING "%s: iucv_pathid_table storage " "allocation failed\n", __FUNCTION__); + kfree(new_handler); return NULL; } memset (iucv_pathid_table, 0, max_connections * sizeof(handler *)); @@ -1002,6 +1014,8 @@ b2f0_result = b2f0(ACCEPT, parm); if (b2f0_result == 0) { + if (msglim) + *msglim = parm->ipmsglim; if (pgm_data) h->pgm_data = pgm_data; if (flags1_out) @@ -1133,11 +1147,15 @@ iucv_setmask(~(AllInterrupts)); messagesDisabled = 1; + spin_lock_irqsave (&iucv_lock, flags); parm->ipflags1 = (__u8)flags1; b2f0_result = b2f0(CONNECT, parm); memcpy(&local_parm, parm, sizeof(local_parm)); release_param(parm); parm = &local_parm; + if (b2f0_result == 0) + add_pathid_result = __iucv_add_pathid(parm->ippathid, h); + spin_unlock_irqrestore (&iucv_lock, flags); if (b2f0_result) { iucv_setmask(~0); @@ -1145,7 +1163,6 @@ return b2f0_result; } - add_pathid_result = iucv_add_pathid(parm->ippathid, h); *pathid = parm->ippathid; /* Enable everything again */ @@ -1884,6 +1901,7 @@ { iparml_dpl *parm; ulong b2f0_result; + iucv_param save_param; iucv_debug(2, "entering"); @@ -1896,7 +1914,13 @@ parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); + memcpy((void *)&save_param, (void *)parm, sizeof(iucv_param)); b2f0_result = b2f0(SEND, parm); + if (b2f0_result != 0) { + printk("b2f0 call returned %lx\n", b2f0_result); + iucv_dumpit("PL before:", &save_param, sizeof(iucv_param)); + iucv_dumpit("PL after:", parm, sizeof(iucv_param)); + } if ((b2f0_result == 0) && (msgid)) *msgid = parm->ipmsgid; @@ -2333,7 +2357,8 @@ iucv_debug(2, "found a matching handler"); break; - } + } else + h = NULL; } spin_unlock_irqrestore (&iucv_lock, flags); if (h) { diff -urN linux-2.4.27/drivers/s390/net/netiucv.c linux-2.4.28/drivers/s390/net/netiucv.c --- linux-2.4.27/drivers/s390/net/netiucv.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/netiucv.c 2004-11-17 03:54:21.502393947 -0800 @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.23 2003/06/24 16:05:32 felfert Exp $ + * $Id: netiucv.c,v 1.21.8.6 2004/06/29 07:37:33 braunu Exp $ * * IUCV network driver * @@ -28,7 +28,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.23 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.21.8.6 $ * */ @@ -114,17 +114,13 @@ spinlock_t collect_lock; int collect_len; int max_buffsize; - int flags; fsm_timer timer; - int retry; fsm_instance *fsm; net_device *netdev; connection_profile prof; char userid[9]; } iucv_connection; -#define CONN_FLAGS_BUFSIZE_CHANGED 1 - /** * Linked list of all connection structs. */ @@ -435,6 +431,10 @@ iucv_connection *conn = (iucv_connection *)pgm_data; iucv_event ev; +#ifdef DEBUG + printk(KERN_DEBUG "%s() called\n", __FUNCTION__); +#endif + ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); @@ -590,7 +590,7 @@ iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; netiucv_priv *privptr = (netiucv_priv *)conn->netdev->priv; - __u16 msglen = eib->ln1msg2.ipbfln1f; + __u32 msglen = eib->ln1msg2.ipbfln1f; int rc; #ifdef DEBUG @@ -613,6 +613,7 @@ conn->rx_buff->data, msglen, NULL, NULL, NULL); if (rc != 0 || msglen < 5) { privptr->stats.rx_errors++; + printk(KERN_INFO "iucv_receive returned %08x\n", rc); return; } netiucv_unpack_skb(conn, conn->rx_buff); @@ -637,7 +638,6 @@ #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); #endif - fsm_deltimer(&conn->timer); if (conn && conn->netdev && conn->netdev->priv) privptr = (netiucv_priv *)conn->netdev->priv; conn->prof.tx_pending--; @@ -645,11 +645,12 @@ if ((skb = skb_dequeue(&conn->commit_queue))) { atomic_dec(&skb->users); dev_kfree_skb_any(skb); - } - if (privptr) { - privptr->stats.tx_packets++; - privptr->stats.tx_bytes += - (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); + if (privptr) { + privptr->stats.tx_packets++; + privptr->stats.tx_bytes += + (skb->len - NETIUCV_HDRLEN + - NETIUCV_HDRLEN); + } } } conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; @@ -677,8 +678,6 @@ memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); conn->prof.send_stamp = xtime; rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, conn->tx_buff->data, conn->tx_buff->len); @@ -688,12 +687,11 @@ if (conn->prof.tx_pending > conn->prof.tx_max_pending) conn->prof.tx_max_pending = conn->prof.tx_pending; if (rc != 0) { - fsm_deltimer(&conn->timer); conn->prof.tx_pending--; fsm_newstate(fi, CONN_STATE_IDLE); if (privptr) privptr->stats.tx_errors += txpackets; - printk(KERN_DEBUG "iucv_send returned %08x\n", + printk(KERN_INFO "iucv_send returned %08x\n", rc); } else { if (privptr) { @@ -762,6 +760,7 @@ #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); #endif + fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); conn->pathid = eib->ippathid; netdev->tx_queue_len = eib->ipmsglim; @@ -769,6 +768,19 @@ } static void +conn_action_conntimsev(fsm_instance *fi, int event, void *arg) +{ + iucv_connection *conn = (iucv_connection *)arg; + __u8 udata[16]; + + pr_debug("%s() called\n", __FUNCTION__); + + fsm_deltimer(&conn->timer); + iucv_sever(conn->pathid, udata); + fsm_newstate(fi, CONN_STATE_STARTWAIT); +} + +static void conn_action_connsever(fsm_instance *fi, int event, void *arg) { iucv_event *ev = (iucv_event *)arg; @@ -776,30 +788,17 @@ // iucv_ConnectionSevered *eib = (iucv_ConnectionSevered *)ev->data; net_device *netdev = conn->netdev; netiucv_priv *privptr = (netiucv_priv *)netdev->priv; - int state = fsm_getstate(fi); + __u8 udata[16]; #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); #endif - switch (state) { - case CONN_STATE_SETUPWAIT: - printk(KERN_INFO "%s: Remote dropped connection\n", - netdev->name); - conn->handle = 0; - fsm_newstate(fi, CONN_STATE_STOPPED); - fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); - break; - case CONN_STATE_IDLE: - case CONN_STATE_TX: - printk(KERN_INFO "%s: Remote dropped connection\n", - netdev->name); - if (conn->handle) - iucv_unregister_program(conn->handle); - conn->handle = 0; - fsm_newstate(fi, CONN_STATE_STOPPED); - fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); - break; - } + fsm_deltimer(&conn->timer); + iucv_sever(conn->pathid, udata); + printk(KERN_INFO "%s: Remote dropped connection\n", + netdev->name); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } static void @@ -807,7 +806,7 @@ { iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; - + __u16 msglimit; int rc; #ifdef DEBUG @@ -839,10 +838,13 @@ fsm_newstate(fi, CONN_STATE_SETUPWAIT); rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, NULL, conn->handle, + conn->userid, iucv_host, 0, NULL, &msglimit, conn->handle, conn); switch (rc) { case 0: + conn->netdev->tx_queue_len = msglimit; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); return; case 11: printk(KERN_NOTICE @@ -910,6 +912,7 @@ #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); #endif + fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); if (conn->handle) @@ -934,8 +937,8 @@ static const fsm_node conn_fsm[] = { { CONN_STATE_INVALID, CONN_EVENT_START, conn_action_inval }, { CONN_STATE_STOPPED, CONN_EVENT_START, conn_action_start }, - { CONN_STATE_STARTWAIT, CONN_EVENT_START, conn_action_start }, + { CONN_STATE_STOPPED, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_STARTWAIT, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_SETUPWAIT, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_IDLE, CONN_EVENT_STOP, conn_action_stop }, @@ -950,6 +953,7 @@ { CONN_STATE_TX, CONN_EVENT_CONN_REQ, conn_action_connreject }, { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_ACK, conn_action_connack }, + { CONN_STATE_SETUPWAIT, CONN_EVENT_TIMER, conn_action_conntimsev }, { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REJ, conn_action_connsever }, { CONN_STATE_IDLE, CONN_EVENT_CONN_REJ, conn_action_connsever }, @@ -1026,6 +1030,7 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) { net_device *dev = (net_device *)arg; + netiucv_priv *privptr = (netiucv_priv *)dev->priv; #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); @@ -1034,8 +1039,8 @@ case DEV_STATE_STARTWAIT: fsm_newstate(fi, DEV_STATE_RUNNING); printk(KERN_INFO - "%s: connected with remote side\n", - dev->name); + "%s: connected with remote side %s\n", + dev->name, privptr->conn->userid); break; case DEV_STATE_STOPWAIT: printk(KERN_INFO @@ -1056,9 +1061,6 @@ static void dev_action_conndown(fsm_instance *fi, int event, void *arg) { - net_device *dev = (net_device *)arg; - netiucv_priv *privptr = dev->priv; - iucv_event ev; #ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__); @@ -1066,10 +1068,6 @@ switch (fsm_getstate(fi)) { case DEV_STATE_RUNNING: fsm_newstate(fi, DEV_STATE_STARTWAIT); - ev.conn = privptr->conn; - fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); - break; - case DEV_STATE_STARTWAIT: break; case DEV_STATE_STOPWAIT: fsm_newstate(fi, DEV_STATE_STOPPED); @@ -1085,7 +1083,6 @@ { DEV_STATE_STARTWAIT, DEV_EVENT_STOP, dev_action_stop }, { DEV_STATE_STARTWAIT, DEV_EVENT_CONUP, dev_action_connup }, - { DEV_STATE_STARTWAIT, DEV_EVENT_CONDOWN, dev_action_conndown }, { DEV_STATE_RUNNING, DEV_EVENT_STOP, dev_action_stop }, { DEV_STATE_RUNNING, DEV_EVENT_CONDOWN, dev_action_conndown }, @@ -1141,6 +1138,7 @@ "%s: Could not allocate tx_skb\n", conn->netdev->name); rc = -ENOMEM; + return rc; } else { skb_reserve(nskb, NETIUCV_HDRLEN); memcpy(skb_put(nskb, skb->len), @@ -1156,10 +1154,7 @@ header.next = 0; memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); - conn->retry = 0; fsm_newstate(conn->fsm, CONN_STATE_TX); - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); conn->prof.send_stamp = xtime; rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, @@ -1171,7 +1166,6 @@ conn->prof.tx_max_pending = conn->prof.tx_pending; if (rc != 0) { netiucv_priv *privptr; - fsm_deltimer(&conn->timer); fsm_newstate(conn->fsm, CONN_STATE_IDLE); conn->prof.tx_pending--; privptr = (netiucv_priv *)conn->netdev->priv; @@ -1276,7 +1270,6 @@ */ if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) { fsm_event(privptr->fsm, DEV_EVENT_START, dev); - dst_link_failure(skb); dev_kfree_skb(skb); privptr->stats.tx_dropped++; privptr->stats.tx_errors++; @@ -1390,7 +1383,7 @@ static ssize_t netiucv_buffer_write(struct file *file, const char *buf, size_t count, - loff_t *off) + loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; net_device *dev; @@ -1401,7 +1394,7 @@ if (!(dev = find_netdev_by_ino(ino))) return -ENODEV; - if (off != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; privptr = (netiucv_priv *)dev->priv; @@ -1427,13 +1420,12 @@ privptr->conn->max_buffsize = bs1; if (!(dev->flags & IFF_RUNNING)) dev->mtu = bs1 - NETIUCV_HDRLEN - NETIUCV_HDRLEN; - privptr->conn->flags |= CONN_FLAGS_BUFSIZE_CHANGED; return count; } static ssize_t -netiucv_buffer_read(struct file *file, char *buf, size_t count, loff_t *off) +netiucv_buffer_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; char *sbuf = (char *)file->private_data; @@ -1446,7 +1438,7 @@ if (!(dev = find_netdev_by_ino(ino))) return -ENODEV; - if (off != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; privptr = (netiucv_priv *)dev->priv; @@ -1489,7 +1481,7 @@ static ssize_t netiucv_user_write(struct file *file, const char *buf, size_t count, - loff_t *off) + loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; net_device *dev; @@ -1501,7 +1493,7 @@ if (!(dev = find_netdev_by_ino(ino))) return -ENODEV; - if (off != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; privptr = (netiucv_priv *)dev->priv; @@ -1531,7 +1523,7 @@ } static ssize_t -netiucv_user_read(struct file *file, char *buf, size_t count, loff_t *off) +netiucv_user_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; char *sbuf = (char *)file->private_data; @@ -1544,7 +1536,7 @@ if (!(dev = find_netdev_by_ino(ino))) return -ENODEV; - if (off != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; privptr = (netiucv_priv *)dev->priv; @@ -1589,7 +1581,7 @@ } static ssize_t -netiucv_stat_write(struct file *file, const char *buf, size_t count, loff_t *off) +netiucv_stat_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; net_device *dev; @@ -1603,7 +1595,7 @@ } static ssize_t -netiucv_stat_read(struct file *file, char *buf, size_t count, loff_t *off) +netiucv_stat_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int ino = ((struct inode *)file->f_dentry->d_inode)->i_ino; loff_t pos = *ppos; @@ -1616,7 +1608,7 @@ if (!(dev = find_netdev_by_ino(ino))) return -ENODEV; - if (off != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; privptr = (netiucv_priv *)dev->priv; @@ -1799,7 +1791,7 @@ proc_net_unregister(netiucv_dir.low_ino); #endif } -#endif MODULE +#endif /** * Create a device specific subdirectory in /proc/net/iucv/ with the @@ -2059,7 +2051,7 @@ static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.23 $"; + char vbuf[] = "$Revision: 1.21.8.6 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff -urN linux-2.4.27/drivers/s390/net/qeth.c linux-2.4.28/drivers/s390/net/qeth.c --- linux-2.4.27/drivers/s390/net/qeth.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/qeth.c 2004-11-17 03:54:21.514394440 -0800 @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth.c ($Revision: 1.337 $) + * linux/drivers/s390/net/qeth.c ($Revision: 1.337.4.24 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -28,9 +28,6 @@ */ /* - * The driver supports in general all QDIO driven network devices on the - * Hydra card. - * * For all devices, three channels must be available to the driver. One * channel is the read channel, one is the write channel and the third * one is the channel used to control QDIO. @@ -156,6 +153,7 @@ #include #include #include +#include #include @@ -171,7 +169,7 @@ static int global_stay_in_mem=0; /****************** MODULE STUFF **********************************/ -#define VERSION_QETH_C "$Revision: 1.337 $" +#define VERSION_QETH_C "$Revision: 1.337.4.24 $" static const char *version="qeth S/390 OSA-Express driver (" \ VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; @@ -183,10 +181,8 @@ /******************** HERE WE GO ***********************************/ -#define PROCFILE_SLEEP_SEM_MAX_VALUE 0 -#define PROCFILE_IOCTL_SEM_MAX_VALUE 3 -static struct semaphore qeth_procfile_ioctl_lock; -static struct semaphore qeth_procfile_ioctl_sem; + + static qeth_card_t *firstcard=NULL; static sparebufs_t sparebufs[MAX_SPARE_BUFFERS]; @@ -224,9 +220,12 @@ /* thought I could get along without forward declarations... * just lazyness here */ static int qeth_reinit_thread(void*); -static void qeth_schedule_recovery(qeth_card_t *card); +static inline void qeth_schedule_recovery(qeth_card_t *card); +static int qeth_fake_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); -inline static int QETH_IP_VERSION(struct sk_buff *skb) +static inline int QETH_IP_VERSION(struct sk_buff *skb) { switch (skb->protocol) { case ETH_P_IPV6: return 6; @@ -243,6 +242,21 @@ return b; } +/* + * This is our local skb_unshare, only with pskb_copy instead of skb_copy. + * We place our headers whare Ethernet MAC was, so we do not need + * full skb_copy. + */ +static inline struct sk_buff *qeth_pskb_unshare(struct sk_buff *skb, int pri) +{ + struct sk_buff *nskb; + if (!skb_cloned(skb)) + return skb; + nskb = skb_copy(skb, pri); + kfree_skb(skb); /* free our shared copy */ + return nskb; +} + static inline unsigned int qeth_get_millis(void) { __u64 time; @@ -291,7 +305,8 @@ set_task_state(current,TASK_RUNNING); } -static void qeth_get_mac_for_ipm(__u32 ipm,char *mac,struct net_device *dev) { +static inline void qeth_get_mac_for_ipm(__u32 ipm,char *mac, + struct net_device *dev) { if (dev->type==ARPHRD_IEEE802_TR) ip_tr_mc_map(ipm,mac); else @@ -403,7 +418,7 @@ #define QETH_GET_ADDR(x) ((__u32)x) #endif /* CONFIG_ARCH_S390X */ -static int qeth_does_card_exist(qeth_card_t *card) +static inline int qeth_does_card_exist(qeth_card_t *card) { qeth_card_t *c=firstcard; int rc=0; @@ -718,7 +733,9 @@ static int qeth_is_multicast_skb_at_all(struct sk_buff *skb,int version) { - int i; + int i=RTN_UNSPEC; + qeth_card_t *card = (qeth_card_t *)skb->dev->priv; + if (skb->dst && skb->dst->neighbour) { i=skb->dst->neighbour->type; return ((i==RTN_BROADCAST)|| @@ -731,13 +748,37 @@ } else if (version==6) { return (skb->nh.raw[24]==0xff)?RTN_MULTICAST:0; } - return 0; + if (!memcmp(skb->nh.raw,skb->dev->broadcast,6)) { + i=RTN_BROADCAST; + } else { + __u16 hdr_mac; + hdr_mac=*((__u16*)skb->nh.raw); + /* tr multicast? */ + switch (card->link_type) { + case QETH_MPC_LINK_TYPE_HSTR: + case QETH_MPC_LINK_TYPE_LANE_TR: + if ( (hdr_mac==QETH_TR_MAC_NC) || + (hdr_mac==QETH_TR_MAC_C) ) + i = RTN_MULTICAST; + break; + /* eth or so multicast? */ + default: + if ( (hdr_mac==QETH_ETH_MAC_V4) || + (hdr_mac==QETH_ETH_MAC_V6) ) + i = RTN_MULTICAST; + } + } + return ((i==RTN_BROADCAST)|| + (i==RTN_MULTICAST)|| + (i==RTN_ANYCAST))?i:0; } static int qeth_get_prioqueue(qeth_card_t *card,struct sk_buff *skb, int multicast,int version) { - if (!version) return QETH_DEFAULT_QUEUE; + if (!version && + (card->type==QETH_CARD_TYPE_OSAE)) + return QETH_DEFAULT_QUEUE; switch (card->no_queues) { case 1: return 0; @@ -1046,7 +1087,7 @@ return retval; } -static int qeth_get_spare_buf(void) +static inline int qeth_get_spare_buf(void) { int i=0; char dbf_text[15]; @@ -1131,8 +1172,8 @@ } } -static void qeth_queue_input_buffer(qeth_card_t *card,int bufno, - unsigned int under_int) +static inline void qeth_queue_input_buffer(qeth_card_t *card,int bufno, + unsigned int under_int) { int count=0,start=0,stop=0,pos; int result; @@ -1283,10 +1324,11 @@ return skb; } -static struct sk_buff *qeth_get_next_skb(qeth_card_t *card, - int *element_ptr,int *pos_in_el_ptr, - void **hdr_ptr, - qdio_buffer_t *buffer) +static inline struct sk_buff *qeth_get_next_skb(qeth_card_t *card, + int *element_ptr, + int *pos_in_el_ptr, + void **hdr_ptr, + qdio_buffer_t *buffer) { int length; char *data_ptr; @@ -1394,10 +1436,6 @@ skb=qeth_get_skb(length+QETH_FAKE_LL_LEN); if (!skb) goto nomem; skb_pull(skb,QETH_FAKE_LL_LEN); - if (!skb) { - dev_kfree_skb_irq(skb); - goto nomem; - } } else { skb=qeth_get_skb(length); if (!skb) goto nomem; @@ -1472,8 +1510,8 @@ return NULL; } -static void qeth_transform_outbound_addrs(qeth_card_t *card, - qdio_buffer_t *buffer) +static inline void qeth_transform_outbound_addrs(qeth_card_t *card, + qdio_buffer_t *buffer) { int i; void *ptr; @@ -1485,7 +1523,8 @@ } } } -static void qeth_get_linux_addrs_for_buffer(qeth_card_t *card,int buffer_no) +static inline void qeth_get_linux_addrs_for_buffer(qeth_card_t *card, + int buffer_no) { int i; void *ptr; @@ -1501,7 +1540,7 @@ } } -static void qeth_read_in_buffer(qeth_card_t *card,int buffer_no) +static inline void qeth_read_in_buffer(qeth_card_t *card,int buffer_no) { struct sk_buff *skb; void *hdr_ptr; @@ -1643,7 +1682,7 @@ } else { /* clear source MAC for security reasons */ memset(skb->mac.raw+ - QETH_FAKE_LL_DEST_MAC_POS,0, + QETH_FAKE_LL_SRC_MAC_POS,0, QETH_FAKE_LL_ADDR_LEN); } memcpy(skb->mac.raw+ @@ -1654,34 +1693,47 @@ skb->mac.raw=skb->data; } - skb->ip_summed=card->options.checksum_type; if (card->options.checksum_type==HW_CHECKSUMMING) { /* do we have a checksummed packet? */ - if (*(__u8*)(hdr_ptr+11)& - QETH_EXT_HEADER_CSUM_TRANSP_REQ) { - /* skb->ip_summed is set already */ - /* vlan is not an issue here, it's still in + /* we only check for TCP/UDP checksums when the + * pseudo header was also checked sucessfully -- for + * the rest of the packets, it's not clear, whether + * the upper layer csum is alright. And they + * shouldn't occur too often anyway in real life */ + if ( (*(__u8*)(hdr_ptr+11)& + (QETH_EXT_HEADER_CSUM_HDR_REQ| + QETH_EXT_HEADER_CSUM_TRANSP_REQ)) == + (QETH_EXT_HEADER_CSUM_HDR_REQ| + QETH_EXT_HEADER_CSUM_TRANSP_REQ) ) { + /* csum does not need to be set + * inbound anyway + * + * vlan is not an issue here, it's still in * the QDIO header, not pushed in the - * skb yet */ + * skb yet * int ip_len=(skb->data[0]&0x0f)<<2; if (*(__u8*)(hdr_ptr+11)& QETH_EXT_HEADER_CSUM_TRANSP_FRAME_TYPE) { - /* get the UDP checksum */ + * get the UDP checksum * skb->csum=*(__u16*) (&skb->data[ip_len+ QETH_UDP_CSUM_OFFSET]); } else { - /* get the TCP checksum */ + * get the TCP checksum * skb->csum=*(__u16*) (&skb->data[ip_len+ QETH_TCP_CSUM_OFFSET]); } + */ + skb->ip_summed=CHECKSUM_UNNECESSARY; } else { /* make the stack check it */ - skb->ip_summed=SW_CHECKSUMMING; + skb->ip_summed=CHECKSUM_NONE; } + } else { + skb->ip_summed=card->options.checksum_type; } #ifdef QETH_VLAN @@ -1735,8 +1787,8 @@ buffer_no]); } -static void qeth_fill_header(qeth_hdr_t *hdr,struct sk_buff *skb, - int version,int multicast) +static inline void qeth_fill_header(qeth_hdr_t *hdr,struct sk_buff *skb, + int version,int multicast) { #ifdef QETH_DBF_LIKE_HELL char dbf_text[15]; @@ -1750,14 +1802,17 @@ #ifdef QETH_VLAN /* before we're going to overwrite - this location with next hop ip - */ + * this location with next hop ip. + * v6 uses passthrough, v4 sets the tag in the QDIO header */ card = (qeth_card_t *)skb->dev->priv; if ((card->vlangrp != NULL) && - (version == 4) && vlan_tx_tag_present(skb)) { - hdr->ext_flags = QETH_EXT_HEADER_VLAN_FRAME; + if (version == 4) { + hdr->ext_flags = QETH_EXT_HEADER_VLAN_FRAME; + } else { + hdr->ext_flags = QETH_EXT_HEADER_INCLUDE_VLAN_TAG; + } hdr->vlan_id = vlan_tx_tag_get(skb); } #endif @@ -1820,7 +1875,13 @@ skb->dev->broadcast,6)) { /* broadcast? */ hdr->flags=QETH_CAST_BROADCAST|QETH_HEADER_PASSTHRU; } else { - hdr->flags=QETH_CAST_UNICAST|QETH_HEADER_PASSTHRU; + if (multicast==RTN_MULTICAST) { + hdr->flags=QETH_CAST_MULTICAST| + QETH_HEADER_PASSTHRU; + } else { + hdr->flags=QETH_CAST_UNICAST| + QETH_HEADER_PASSTHRU; + } } } #ifdef QETH_DBF_LIKE_HELL @@ -1836,7 +1897,7 @@ #endif /* QETH_DBF_LIKE_HELL */ } -static int inline qeth_fill_buffer(qdio_buffer_t *buffer,char *dataptr, +static inline int qeth_fill_buffer(qdio_buffer_t *buffer,char *dataptr, int length,int element) { int length_here; @@ -1891,8 +1952,8 @@ return element; } -static void qeth_flush_packed_packets(qeth_card_t *card,int queue, - int under_int) +static inline void qeth_flush_packed_packets(qeth_card_t *card,int queue, + int under_int) { qdio_buffer_t *buffer; int result; @@ -1951,8 +2012,23 @@ * adapter honors it or not */ switch (card->send_state[queue]) { case SEND_STATE_DONT_PACK: + /* only request a PCI, if the fill level of the queue + * is close to the high watermark, so that we don't + * loose initiative during packing */ if (atomic_read(&card->outbound_used_buffers[queue]) last_pci_pos[queue]); + /* compensate queues that wrapped around */ + if (position_for_do_qdiooutbound_ringbuffer[queue]-> buffer[position_for_do_qdio].element[0].flags|=0x40; @@ -1966,13 +2042,13 @@ * last_pci is the position of the last pci we've set * position_for_do_qdio is the position we will send out now * outbound_used_buffers is the number of buffers used (means - * all buffers hydra has, inclusive position_for_do_qdio) + * all buffers OSA has, inclusive position_for_do_qdio) * * we have to request a pci, if we have got the buffer of the * last_pci position back. * * position_for_do_qdio-outbound_used_buffers is the newest - * buffer that we got back from hydra + * buffer that we got back from OSA * * if this is greater or equal than the last_pci position, * we should request a pci, as no pci request is @@ -2055,8 +2131,8 @@ return ERROR_LINK_FAILURE; /* should never happen */ } -static void qeth_free_buffer(qeth_card_t *card,int queue,int bufno, - int qdio_error,int siga_error) +static inline void qeth_free_buffer(qeth_card_t *card,int queue,int bufno, + int qdio_error,int siga_error) { struct sk_buff *skb; int error; @@ -2139,7 +2215,8 @@ case ERROR_LINK_FAILURE: case ERROR_KICK_THAT_PUPPY: QETH_DBF_TEXT4(0,trace,"endeglnd"); - dst_link_failure(skb); + card->stats->tx_dropped++; + card->stats->tx_errors++; atomic_dec(&skb->users); dev_kfree_skb_irq(skb); break; @@ -2164,7 +2241,7 @@ card->send_retries[queue][bufno]=0; } -static void qeth_free_all_skbs(qeth_card_t *card) +static inline void qeth_free_all_skbs(qeth_card_t *card) { int q,b; @@ -2199,7 +2276,7 @@ } #ifdef QETH_VLAN -void qeth_insert_ipv6_vlan_tag(struct sk_buff *__skb) +static inline void qeth_insert_ipv6_vlan_tag(struct sk_buff *__skb) { /* Move the mac addresses to the beginning of the new header. @@ -2230,9 +2307,9 @@ -static void qeth_send_packet_fast(qeth_card_t *card,struct sk_buff *skb, - struct net_device *dev, - int queue,int version,int multicast) +static inline void qeth_send_packet_fast(qeth_card_t *card,struct sk_buff *skb, + struct net_device *dev, + int queue,int version,int multicast) { qeth_ringbuffer_element_t *mybuffer; int position; @@ -2250,8 +2327,8 @@ if ((version)&&(!card->realloc_message)) { card->realloc_message=1; PRINT_WARN("%s: not enough headroom in skb. " \ - "Try increasing the " \ - "add_hhlen parameter by %i.\n", + "Increasing the " \ + "add_hhlen parameter by %i may help.\n", card->dev_name, QETH_HEADER_SIZE-skb_headroom(skb)); } @@ -2327,9 +2404,11 @@ /* no checks, if all elements are used, as then we would not be here (at most 127 buffers are enqueued) */ -static void qeth_send_packet_packed(qeth_card_t *card,struct sk_buff *skb, - struct net_device *dev, - int queue,int version,int multicast) +static inline void qeth_send_packet_packed(qeth_card_t *card, + struct sk_buff *skb, + struct net_device *dev, + int queue,int version, + int multicast) { qeth_ringbuffer_element_t *mybuffer; int elements_needed; @@ -2490,8 +2569,8 @@ return old_val; } -static int qeth_do_send_packet(qeth_card_t *card,struct sk_buff *skb, - struct net_device *dev) +static inline int qeth_do_send_packet(qeth_card_t *card,struct sk_buff *skb, + struct net_device *dev) { int queue,result=0; int multicast,version; @@ -2610,12 +2689,32 @@ qeth_card_t *card; char dbf_text[15]; int result; + unsigned long stackptr; card=(qeth_card_t*)(dev->priv); if (skb==NULL) return 0; +#ifdef CONFIG_ARCH_S390X + asm volatile ("lgr %0,15" : "=d" (stackptr)); +#else /* CONFIG_ARCH_S390X */ + asm volatile ("lr %0,15" : "=d" (stackptr)); +#endif /* CONFIG_ARCH_S390X */ + /* prevent stack overflows */ + /* normal and async stack is both 8k on s390 and 16k on s390x, + * so it doesn't matter whether we're in an interrupt */ + if ( (stackptr & STACK_PTR_MASK)< + (sizeof(struct task_struct) + WORST_CASE_STACK_USAGE) ) { + PRINT_ERR("delaying packet transmission " \ + "due to potential stack overflow\n"); + sprintf(dbf_text,"STOF%4x",card->irq0); + QETH_DBF_TEXT1(1,trace,dbf_text); + PRINT_ERR("Backtrace follows:\n"); + show_trace((unsigned long *)stackptr); + return -EBUSY; + } + #ifdef QETH_DBF_LIKE_HELL QETH_DBF_HEX4(0,data,skb->data,__max(QETH_DBF_DATA_LEN,skb->len)); #endif /* QETH_DBF_LIKE_HELL */ @@ -2624,7 +2723,8 @@ if (!card) { QETH_DBF_TEXT2(0,trace,"XMNSNOCD"); - dst_link_failure(skb); + card->stats->tx_dropped++; + card->stats->tx_errors++; dev_kfree_skb_irq(skb); return 0; } @@ -2637,11 +2737,29 @@ card->stats->tx_carrier_errors++; sprintf(dbf_text,"XMNS%4x",card->irq0); QETH_DBF_TEXT2(0,trace,dbf_text); - dst_link_failure(skb); + card->stats->tx_dropped++; + card->stats->tx_errors++; dev_kfree_skb_irq(skb); return 0; } + if (dev->hard_header == qeth_fake_header) { + /* + * in theory, if we run in undef-ed QETH_IPV6, we should + * always unshare, because we do skb_push, then overwrite + * that place with OSA header in qeth_send_packet_fast(). + * But it is only visible to one application - tcpdump. + * Nobody else cares if (fake) MAC header gets smashed. + * So, we only do it if fake_ll is in effect. + */ + if ((skb = qeth_pskb_unshare(skb, GFP_ATOMIC)) == NULL) { + card->stats->tx_dropped++; + dev_kfree_skb_irq(skb); + return 0; + } + skb_pull(skb, QETH_FAKE_LL_LEN); + } + result=qeth_do_send_packet(card,skb,dev); if (!result) @@ -2650,6 +2768,36 @@ return result; } +/* + * This function is needed to tell af_packet.c to process headers. + * It is not called from there, but only from the transmit path, + * when we do not need any actual header. + * + * N.B. Why do we insist on kludging here instead of fixing tcpdump? + * Because tcpdump is shared among gazillions of platforms, and + * there is a) no reliable way to identify qeth or its packets + * in pcap-linux.c (sll->sll_halen is the only hope); b) no easy + * way to pass this information from libpcap to tcpdump proper. + * + * XXX This fails with TR: traffic flows ok, but tcpdump remains confused. + */ +int qeth_fake_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + unsigned char *hdr; + + hdr = skb_push(skb, QETH_FAKE_LL_LEN); + memcpy(hdr, "FAKELLFAKELL", ETH_ALEN*2); + if (type != ETH_P_802_3) + *(u16 *)(hdr + ETH_ALEN*2) = htons(type); + else + *(u16 *)(hdr + ETH_ALEN*2) = htons(len); + + /* XXX Maybe dev->hard_header_len here? Then skb_pull by same size. */ + return QETH_FAKE_LL_LEN; +} + static struct net_device_stats* qeth_get_stats(struct net_device *dev) { qeth_card_t *card; @@ -2803,23 +2951,19 @@ return retval; } -static void qeth_wakeup_procfile(void) -{ - QETH_DBF_TEXT5(0,trace,"procwkup"); - if (atomic_read(&qeth_procfile_ioctl_sem.count)< - PROCFILE_SLEEP_SEM_MAX_VALUE) - up(&qeth_procfile_ioctl_sem); -} - - -static int qeth_sleepon_procfile(void) +static void qeth_snmp_notify(void) { - QETH_DBF_TEXT5(0,trace,"procslp"); - if (down_interruptible(&qeth_procfile_ioctl_sem)) { - up(&qeth_procfile_ioctl_sem); - return -ERESTARTSYS; + /*notify all registered processes */ + struct list_head *l; + struct qeth_notify_list *n_entry; + + QETH_DBF_TEXT5(0,trace,"snmpnoti"); + spin_lock(¬ify_lock); + list_for_each(l, ¬ify_list) { + n_entry = list_entry(l, struct qeth_notify_list, list); + send_sig(n_entry->signum, n_entry->task, 1); } - return 0; + spin_unlock(¬ify_lock); } static char* qeth_send_control_data(qeth_card_t *card,unsigned char *buffer, @@ -2889,17 +3033,19 @@ QETH_DBF_TEXT2(0,trace,"scd:doio"); sprintf(dbf_text,"%4x",(__s16)result); QETH_DBF_TEXT2(0,trace,dbf_text); + /* re-enable qeth_send_control_data again */ + atomic_set(&card->write_busy,0); return NULL; } if (intparam==IPA_IOCTL_STATE) { if (qeth_sleepon_ioctl(card,QETH_IPA_TIMEOUT)) { - QETH_DBF_TEXT2(0,trace,"scd:ioctime"); + QETH_DBF_TEXT2(0,trace,"scd:ioct"); /* re-enable qeth_send_control_data again */ atomic_set(&card->write_busy,0); return NULL; } - rec_buf=card->ipa_buf; + rec_buf=card->dma_stuff->recbuf; sprintf(dbf_text,"scro%4x",card->irq0); } else { if (qeth_sleepon(card,(setip)?QETH_IPA_TIMEOUT: @@ -2963,6 +3109,15 @@ if ((ipa_cmd==IPA_CMD_SETADAPTERPARMS)&&(result==0)) { result=reply->data.setadapterparms.return_code; } + if ( (ipa_cmd==IPA_CMD_SETASSPARMS) && + (result==0) && + (reply->data.setassparms.assist_no== + IPA_INBOUND_CHECKSUM) && + (reply->data.setassparms.command_code== + IPA_CMD_ASS_START) ) { + card->csum_enable_mask= + reply->data.setassparms.data.flags_32bit; + } } return result; } @@ -3183,6 +3338,18 @@ static int qeth_ioctl_handle_arp_data(qeth_card_t *card, arp_cmd_t *reply) { + if ( (reply->data.setassparms.command_code== + IPA_CMD_ASS_ARP_SET_NO_ENTRIES) || + (reply->data.setassparms.command_code== + IPA_CMD_ASS_ARP_ADD_ENTRY) || + (reply->data.setassparms.command_code== + IPA_CMD_ASS_ARP_REMOVE_ENTRY) ) { + if (reply->data.setassparms.return_code) { + return ARP_RETURNCODE_ERROR; + } else { + return ARP_RETURNCODE_LASTREPLY; + } + } if (reply->data.setassparms.seq_no == 1) { if (card->ioctl_buffersize <= (sizeof(__u16) + sizeof(int) + reply->data. @@ -3229,6 +3396,21 @@ } return card->ioctl_returncode; } +static int qeth_is_arp_command(int cmd) +{ + switch (cmd) { + case IPA_CMD_ASS_ARP_SET_NO_ENTRIES: + case IPA_CMD_ASS_ARP_QUERY_CACHE: + case IPA_CMD_ASS_ARP_ADD_ENTRY: + case IPA_CMD_ASS_ARP_REMOVE_ENTRY: + case IPA_CMD_ASS_ARP_FLUSH_CACHE: + case IPA_CMD_ASS_ARP_QUERY_INFO: + case IPA_CMD_ASS_ARP_QUERY_STATS: + return 1; + default: + return 0; + } +} static int qeth_look_for_arp_data(qeth_card_t *card) { @@ -3245,9 +3427,7 @@ result=ARP_FLUSH; } else if ( (reply->command == IPA_CMD_SETASSPARMS) && (reply->data.setassparms.assist_no == IPA_ARP_PROCESSING) && - (reply->data.setassparms.command_code == - IPA_CMD_ASS_ARP_QUERY_INFO) && - (card->ioctl_returncode == ARP_RETURNCODE_SUCCESS)) { + (qeth_is_arp_command(reply->data.setassparms.command_code)) ) { result = qeth_ioctl_handle_arp_data(card,reply); } else if ( (reply->command == IPA_CMD_SETADAPTERPARMS) && (reply->data.setadapterparms.command_code == @@ -3305,8 +3485,9 @@ result = IPA_REPLY_SUCCESS; memcpy(((char *)(card->ioctl_data_buffer)) + sizeof(__u16), &(card->number_of_entries),sizeof(int)); - copy_to_user(req->ifr_ifru.ifru_data, - card->ioctl_data_buffer,data_size); + if (copy_to_user(req->ifr_ifru.ifru_data, + card->ioctl_data_buffer,data_size)) + result =-EFAULT; } card->ioctl_buffer_pointer = NULL; vfree(card->ioctl_data_buffer); @@ -3373,16 +3554,14 @@ result = IPA_REPLY_FAILED; goto snmp_out; } - if (result == ARP_RETURNCODE_ERROR ) { - copy_to_user(req->ifr_ifru.ifru_data+SNMP_REQUEST_DATA_OFFSET, - card->ioctl_data_buffer,card->ioctl_buffersize); + if (result == ARP_RETURNCODE_ERROR ) result = IPA_REPLY_FAILED; - } - else { - copy_to_user(req->ifr_ifru.ifru_data+SNMP_REQUEST_DATA_OFFSET, - card->ioctl_data_buffer,card->ioctl_buffersize); + else result = IPA_REPLY_SUCCESS; - } + + if (copy_to_user(req->ifr_ifru.ifru_data + SNMP_REQUEST_DATA_OFFSET, + card->ioctl_data_buffer, card->ioctl_buffersize)) + result = -EFAULT; snmp_out: card->number_of_entries = 0; card->ioctl_buffersize = 0; @@ -3571,6 +3750,11 @@ (result==0xe00e)?"unsupported arp assist cmd": \ (result==0xe00f)?"arp assist not enabled": \ (result==0xe080)?"startlan disabled": \ + (result==0xf012)?"unicast IP address invalid": \ + (result==0xf013)?"multicast router limit reached": \ + (result==0xf014)?"stop assist not supported": \ + (result==0xf015)?"multicast assist not set": \ + (result==0xf080)?"VM: startlan disabled": \ (result==-1)?"IPA communication timeout": \ "unknown return code") @@ -3612,7 +3796,8 @@ QETH_DBF_TEXT2(0,trace,dbf_text); } - if (((result==-1)||(result==0xe080))&&(retries--)) { + if ( ((result==-1)||(result==0xe080)||(result==0xf080))&& + (retries--) ) { sprintf(dbf_text,"sipr%4x",card->irq0); QETH_DBF_TEXT2(0,trace,dbf_text); if (ip_vers==4) { @@ -3771,8 +3956,8 @@ le is last entry */ char dbf_text[15]; int result; - __u8 netmask[16]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; + __u8 netmask[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; qeth_vipa_entry_t *priv_add_list=NULL; qeth_vipa_entry_t *priv_del_list=NULL; @@ -3790,6 +3975,7 @@ GFP_KERNEL); if (ne) { ne->version=e->version; + ne->flag=e->flag; memcpy(ne->ip,e->ip,16); ne->next=priv_add_list; priv_add_list=ne; @@ -3821,6 +4007,7 @@ GFP_KERNEL); if (ne) { ne->version=e->version; + ne->flag=e->flag; memcpy(ne->ip,e->ip,16); ne->next=priv_del_list; priv_del_list=ne; @@ -3852,7 +4039,7 @@ sprintf(dbf_text,"%4x%4x",card->irq0,result); QETH_DBF_TEXT2(0,trace,dbf_text); if (priv_add_list->version==4) { - PRINT_ERR("going to leave vipa/rxip %08x" \ + PRINT_ERR("going to leave vipa/rxip x%08x " \ "unset...\n", *((__u32*)&priv_add_list->ip[0])); sprintf(dbf_text,"%08x", @@ -4404,9 +4591,12 @@ } #endif /* QETH_IPV6 */ + + #define QETH_STANDARD_RETVALS \ ret_val=-EIO; \ if (result==IPA_REPLY_SUCCESS) ret_val=0; \ + if (result==-EFAULT) ret_val=-EFAULT; \ if (result==IPA_REPLY_FAILED) ret_val=-EIO; \ if (result==IPA_REPLY_OPNOTSUPP) ret_val=-EOPNOTSUPP @@ -4429,7 +4619,14 @@ if ((cmdSIOCDEVPRIVATE+5)) return -EOPNOTSUPP; - copy_from_user(buff,rq->ifr_ifru.ifru_data,sizeof(buff)); + if (copy_from_user(buff,rq->ifr_ifru.ifru_data,sizeof(buff))) + return -EFAULT; + data=buff; + + if ((cmdSIOCDEVPRIVATE+5)) + return -EOPNOTSUPP; + if (copy_from_user(buff,rq->ifr_ifru.ifru_data,sizeof(buff))) + return -EFAULT; data=buff; if ( (!atomic_read(&card->is_registered))|| @@ -4438,9 +4635,14 @@ if (atomic_read(&card->shutdown_phase)) return -ENODEV; - my_spin_lock(&card->ioctl_lock); + if (down_interruptible ( &card->ioctl_sem ) ) + return -ERESTARTSYS; + + if (atomic_read(&card->shutdown_phase)) { + ret_val=-ENODEV; + goto out; + } - if (atomic_read(&card->shutdown_phase)) return -ENODEV; if ( (!atomic_read(&card->is_registered))|| (!atomic_read(&card->is_hardsetup))|| (atomic_read(&card->is_gone)) ) { @@ -4486,7 +4688,7 @@ ret_val=-EPERM; break; } - for (i=4;i<12;i++) if (data[i]) version=6; + for (i=12;i<24;i++) if (data[i]) version=6; result=qeth_send_setassparms(card,version,IPA_ARP_PROCESSING, IPA_CMD_ASS_ARP_REMOVE_ENTRY, (long)data,16); @@ -4503,17 +4705,26 @@ QETH_STANDARD_RETVALS; break; case SIOCDEVPRIVATE+5: - result=qeth_send_snmp_control(card,rq,IPA_CMD_SETADAPTERPARMS, + result=qeth_send_snmp_control(card,rq, + IPA_CMD_SETADAPTERPARMS, IPA_SETADP_SET_SNMP_CONTROL, data,4); QETH_STANDARD_RETVALS; break; + case SIOCDEVPRIVATE+6: + if (!card->is_guest_lan && + (card->type == QETH_CARD_TYPE_OSAE)) + ret_val = 1; + else + ret_val = 0; + break; default: - return -EOPNOTSUPP; + ret_val=-EOPNOTSUPP; + goto out; } out: - my_spin_unlock(&card->ioctl_lock); + up (&card->ioctl_sem); sprintf(dbf_text,"ret=%4x",ret_val); QETH_DBF_TEXT2(0,trace,dbf_text); @@ -5240,13 +5451,17 @@ "failure -- please check the " \ "network, plug in the cable or " \ "enable the OSA port": + (result==0xf080)? + "startlan disabled (VM: LAN " \ + "is offline for functions " \ + "requiring LAN access.": "unknown return code"); sprintf(dbf_text,"stln%4x",result); QETH_DBF_TEXT2(0,trace,dbf_text); atomic_set(&card->is_softsetup,0); atomic_set(&card->is_startlaned,0); /* do not return an error */ - if (result==0xe080) { + if ((result==0xe080)||(result==0xf080)) { result=0; } goto out; @@ -5372,7 +5587,8 @@ QETH_DBF_TEXT2(0,trace,dbf_text); atomic_set(&card->is_softsetup,0); /* do not return an error */ - if (result==0xe080) { + if ((result==0xe080)|| + (result==0xf080)) { result=0; } goto out; @@ -5390,8 +5606,9 @@ goto out; } - sprintf(dbf_text,"%4x%4x",card->ipa6_supported, - card->ipa6_enabled); + sprintf(dbf_text,"%8x",card->ipa6_supported); + QETH_DBF_TEXT2(0,trace,dbf_text); + sprintf(dbf_text,"%8x",card->ipa6_enabled); QETH_DBF_TEXT2(0,trace,dbf_text); QETH_DBF_TEXT2(0,trace,"enaipv46"); result=qeth_send_setassparms_simple_with_data( @@ -5461,8 +5678,19 @@ goto go_on_filt; } card->dev->flags|=IFF_BROADCAST; - card->broadcast_capable=1; + card->broadcast_capable=BROADCAST_WITH_ECHO; + result=qeth_send_setassparms_simple_with_data( + card,IPA_FILTERING,IPA_CMD_ASS_ENABLE,1); + sprintf(dbf_text,"Flt3%4x",result); + QETH_DBF_TEXT2(0,trace,dbf_text); + QETH_DBF_TEXT2(0,setup,dbf_text); + if (!result) { + PRINT_INFO("Broadcast packets will not be " \ + "echoed back on %s.\n", + card->dev_name); + card->broadcast_capable=BROADCAST_WITHOUT_ECHO; + } } go_on_filt: if (card->options.checksum_type==HW_CHECKSUMMING) { @@ -5494,7 +5722,7 @@ result=qeth_send_setassparms_simple_with_data( card,IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_ENABLE, - IPA_CHECKSUM_ENABLE_MASK); + card->csum_enable_mask); if (result) { PRINT_WARN("Could not enable inbound " \ "checksumming on %s: " \ @@ -5571,7 +5799,14 @@ #ifdef QETH_IPV6 if (atomic_read(&card->enable_routing_attempts6)) { - if (card->options.routing_type6) { + /* for OSAs that can't do v6 multicast routing, we don't try */ + if ( (card->type==QETH_CARD_TYPE_OSAE) && + ( (card->options.routing_type6&ROUTER_MASK) == + MULTICAST_ROUTER) && + (!qeth_is_supported6(IPA_OSA_MC_ROUTER_AVAIL)) ) { + atomic_set(&card->enable_routing_attempts6,0); + atomic_set(&card->rt6fld,0); + } else if (card->options.routing_type6) { sprintf(dbf_text,"strtg6%2x", card->options.routing_type6); QETH_DBF_TEXT2(0,trace,dbf_text); @@ -5753,9 +5988,12 @@ sprintf(dbf_text,"PROB%4x",i); QETH_DBF_TEXT2(0,trace,dbf_text); - PRINT_WARN("recovery was scheduled on irq 0x%x (%s) with " \ - "problem 0x%x\n", - card->irq0,card->dev_name,i); + if (i!=PROBLEM_TX_TIMEOUT) { + PRINT_WARN("recovery was scheduled on irq 0x%x (%s) with " \ + "problem 0x%x\n", + card->irq0,card->dev_name,i); + } + switch (i) { case PROBLEM_RECEIVED_IDX_TERMINATE: if (atomic_read(&card->in_recovery)) @@ -5802,7 +6040,7 @@ } } -static void qeth_schedule_recovery(qeth_card_t *card) +static inline void qeth_schedule_recovery(qeth_card_t *card) { if (card) { INIT_LIST_HEAD(&card->tqueue.list); @@ -5920,6 +6158,9 @@ card=(qeth_card_t *)card_ptr; if (status&QDIO_STATUS_LOOK_FOR_ERROR) { + sbalf15=(card->outbound_ringbuffer[queue]->buffer[ + (first_element+count-1)& + QDIO_MAX_BUFFERS_PER_Q].element[15].flags)&0xff; if (status&QDIO_STATUS_ACTIVATE_CHECK_CONDITION) { problem=PROBLEM_ACTIVATE_CHECK_CONDITION; PRINT_WARN("activate queues on irq 0x%x: " \ @@ -5937,9 +6178,29 @@ qeth_schedule_recovery(card); goto out; } - sbalf15=(card->outbound_ringbuffer[queue]->buffer[ - (first_element+count-1)& - QDIO_MAX_BUFFERS_PER_Q].element[15].flags)&0xff; + if ( (siga_error==0x01) || + (siga_error==(0x02|QDIO_SIGA_ERROR_B_BIT_SET)) || + (siga_error==0x03) ) { + sprintf(dbf_text,"BS%4x%2x",card->irq0,queue); + QETH_DBF_TEXT2(0,trace,dbf_text); + QETH_DBF_TEXT2(0,qerr,dbf_text); + QETH_DBF_TEXT2(1,setup,dbf_text); + sprintf(dbf_text,"%2x%2x%2x%2x", + first_element+count-1, + siga_error,qdio_error,sbalf15); + QETH_DBF_TEXT2(1,trace,dbf_text); + QETH_DBF_TEXT2(1,qerr,dbf_text); + PRINT_ERR("Outbound queue x%x on irq x%x (%s); " \ + "errs: siga: x%x, qdio: x%x, flags15: " \ + "x%x. The device will be taken down.\n", + queue,card->irq0,card->dev_name, + siga_error,qdio_error,sbalf15); + netif_stop_queue(card->dev); + qeth_set_dev_flag_norunning(card); + atomic_set(&card->problem,PROBLEM_BAD_SIGA_RESULT); + qeth_schedule_recovery(card); + goto out; + } PRINT_STUPID("outbound qdio transfer error on irq %04x, " \ "queue=%i. qdio_error=0x%x (more than one: %c)," \ " siga_error=0x%x (more than one: %c), " \ @@ -5988,7 +6249,7 @@ (&card->outbound_used_buffers[queue])<= LOW_WATERMARK_PACK); /* first_element is the last buffer that we got back - * from hydra */ + * from OSA */ if (switch_state||last_pci_hit) { *((__u16*)(&dbf_text2[6]))=card->irq0; QETH_DBF_HEX3(0,trace,dbf_text2,QETH_DBF_TRACE_LEN); @@ -6010,6 +6271,14 @@ if (switch_state) card->send_state[queue]= SEND_STATE_DONT_PACK; + + /* reset the last_pci position to avoid + * races, when we get close to packing again + * immediately (in order to never loose + * a PCI) */ + atomic_set(&card->last_pci_pos[queue], + (-2*QDIO_MAX_BUFFERS_PER_Q)); + netif_wake_queue(card->dev); atomic_set(&card->outbound_ringbuffer_lock[ queue],QETH_LOCK_UNLOCKED); @@ -6137,8 +6406,9 @@ goto wakeup_out; } - if (!IS_IPA(card->dma_stuff->recbuf)|| - IS_IPA_REPLY(card->dma_stuff->recbuf)) { + if ( (!IS_IPA(card->dma_stuff->recbuf))|| + (IS_IPA(card->dma_stuff->recbuf)&& + IS_IPA_REPLY(card->dma_stuff->recbuf)) ) { /* setup or unknown data */ result = qeth_look_for_arp_data(card); switch (result) { @@ -6870,6 +7140,10 @@ card->portname_required= ((!QETH_IDX_NO_PORTNAME_REQUIRED(card->dma_stuff->recbuf))&& (card->type==QETH_CARD_TYPE_OSAE)); + /* however, as the portname indication of OSA is wrong, we have to + * do this: */ + card->portname_required=(card->type==QETH_CARD_TYPE_OSAE); + memcpy(&temp,QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->recbuf),2); if (temp!=qeth_peer_func_level(card->func_level)) { @@ -7220,12 +7494,17 @@ static int qeth_qdio_establish(qeth_card_t *card) { int result; - char adapter_area[15]; + char *adapter_area; char dbf_text[15]; void **input_array,**output_array,**ptr; int i,j; qdio_initialize_t init_data; + adapter_area=vmalloc(QDIO_MAX_BUFFERS_PER_Q*sizeof(char)); + if (!adapter_area) return -ENOMEM; + + memset(adapter_area,0,QDIO_MAX_BUFFERS_PER_Q*sizeof(char)); + adapter_area[0]=_ascebc['P']; adapter_area[1]=_ascebc['C']; adapter_area[2]=_ascebc['I']; @@ -7235,7 +7514,10 @@ *((unsigned int*)(&adapter_area[12]))=PCI_TIMER_VALUE; input_array=vmalloc(QDIO_MAX_BUFFERS_PER_Q*sizeof(void*)); - if (!input_array) return -ENOMEM; + if (!input_array) { + vfree(adapter_area); + return -ENOMEM; + } ptr=input_array; for (j=0;jno_queues); if (!output_array) { vfree(input_array); + vfree(adapter_area); return -ENOMEM; } ptr=output_array; @@ -7285,6 +7568,7 @@ vfree(input_array); vfree(output_array); + vfree(adapter_area); sprintf(dbf_text,"qde=%4i",result); QETH_DBF_TEXT3(0,trace,dbf_text); @@ -7388,6 +7672,51 @@ return result; } +static void qeth_correct_routing_status(qeth_card_t *card) +{ + if (card->type==QETH_CARD_TYPE_IQD) { + /* if it's not a mc router, it's no router */ + if ( (card->options.routing_type4 == PRIMARY_ROUTER) || + (card->options.routing_type4 == SECONDARY_ROUTER) +#ifdef QETH_IPV6 + || + (card->options.routing_type6 == PRIMARY_ROUTER) || + (card->options.routing_type6 == SECONDARY_ROUTER) +#endif /* QETH_IPV6 */ + ) { + PRINT_WARN("routing not applicable, reset " \ + "routing status.\n"); + card->options.routing_type4=NO_ROUTER; +#ifdef QETH_IPV6 + card->options.routing_type6=NO_ROUTER; +#endif /* QETH_IPV6 */ + } + card->options.do_prio_queueing=NO_PRIO_QUEUEING; + } else { + /* if it's a mc router, it's no router */ + if ( (((!qeth_is_supported(IPA_OSA_MC_ROUTER_AVAIL))&& + card->options.routing_type4 == MULTICAST_ROUTER)) || + (card->options.routing_type4 == PRIMARY_CONNECTOR) || + (card->options.routing_type4 == SECONDARY_CONNECTOR) +#ifdef QETH_IPV6 + || + (((!qeth_is_supported(IPA_OSA_MC_ROUTER_AVAIL))&& + card->options.routing_type6 == MULTICAST_ROUTER)) || + (card->options.routing_type6 == PRIMARY_CONNECTOR) || + (card->options.routing_type6 == SECONDARY_CONNECTOR) +#endif /* QETH_IPV6 */ + ) { + PRINT_WARN("routing not applicable, reset " \ + "routing status. (Did you mean " \ + "primary_router or secondary_router?)\n"); + card->options.routing_type4=NO_ROUTER; +#ifdef QETH_IPV6 + card->options.routing_type6=NO_ROUTER; +#endif /* QETH_IPV6 */ + } + } +} + #ifdef QETH_IPV6 extern struct neigh_table arp_tbl; int (*qeth_old_arp_constructor)(struct neighbour *); @@ -7567,6 +7896,8 @@ (!(qeth_get_additional_dev_flags(card->type)&IFF_NOARP))? (qeth_get_hard_header(card->link_type)? qeth_hard_header:NULL): +#else /* QETH_IPV6 */ + (card->options.fake_ll==FAKE_LL)?qeth_fake_header: #endif /* QETH_IPV6 */ NULL; dev->header_cache_update= @@ -7600,7 +7931,7 @@ qeth_send_qipassist(card,4);*/ /* that was the old place. one id. we need to make sure, that - * hydra knows about us going to use the same id again, so we + * OSA knows about us going to use the same id again, so we * do that in hardsetup_card every time qeth_get_unique_id(card);*/ @@ -7650,8 +7981,9 @@ card->unit_addr2 = prcd[31]; card->cula = prcd[63]; /* Don't build queues with diag98 for VM guest lan. */ - card->do_pfix = (MACHINE_HAS_PFIX) ? ((prcd[0x10]!=_ascebc['V']) || - (prcd[0x11]!=_ascebc['M'])):0; + card->is_guest_lan= ((prcd[0x10]==_ascebc['V']) && + (prcd[0x11]==_ascebc['M'])); + card->do_pfix = (MACHINE_HAS_PFIX) ? (!(card->is_guest_lan)):0; sprintf(dbf_text,"chpid:%02x",card->chpid); QETH_DBF_TEXT2(0,trace,dbf_text); @@ -8041,8 +8373,12 @@ QETH_DBF_TEXT2(0,trace,dbf_text); } - sprintf(dbf_text,"%4x%4x",card->ipa_supported,card->ipa_enabled); + sprintf(dbf_text,"%8x",card->ipa_supported); QETH_DBF_TEXT2(0,trace,dbf_text); + sprintf(dbf_text,"%8x",card->ipa_enabled); + QETH_DBF_TEXT2(0,trace,dbf_text); + + qeth_correct_routing_status(card); qeth_get_unique_id(card); @@ -8094,7 +8430,8 @@ "card%s%s%s\n" \ "with link type %s (portname: %s)\n", card->devno0,card->devno1,card->devno2, - qeth_get_cardname(card->type), + qeth_get_cardname(card->type, + card->is_guest_lan), (card->level[0])?" (level: ":"", (card->level[0])?card->level:"", (card->level[0])?")":"", @@ -8102,16 +8439,32 @@ card->link_type), dbf_text); } else { - printk("qeth: Device 0x%X/0x%X/0x%X is a%s " \ - "card%s%s%s\nwith link type %s " \ - "(no portname needed by interface)\n", - card->devno0,card->devno1,card->devno2, - qeth_get_cardname(card->type), - (card->level[0])?" (level: ":"", - (card->level[0])?card->level:"", - (card->level[0])?")":"", - qeth_get_link_type_name(card->type, - card->link_type)); + if (card->options.portname[0]) { + printk("qeth: Device 0x%X/0x%X/0x%X is a%s " \ + "card%s%s%s\nwith link type %s " \ + "(no portname needed by interface)\n", + card->devno0,card->devno1,card->devno2, + qeth_get_cardname(card->type, + card->is_guest_lan), + (card->level[0])?" (level: ":"", + (card->level[0])?card->level:"", + (card->level[0])?")":"", + qeth_get_link_type_name(card->type, + card-> + link_type)); + } else { + printk("qeth: Device 0x%X/0x%X/0x%X is a%s " \ + "card%s%s%s\nwith link type %s\n", + card->devno0,card->devno1,card->devno2, + qeth_get_cardname(card->type, + card->is_guest_lan), + (card->level[0])?" (level: ":"", + (card->level[0])?card->level:"", + (card->level[0])?")":"", + qeth_get_link_type_name(card->type, + card-> + link_type)); + } } } @@ -8210,7 +8563,7 @@ atomic_set(&card->is_startlaned,0); /* show status in /proc/qeth */ atomic_set(&card->is_gone,1); - qeth_wakeup_procfile(); + qeth_snmp_notify(); } else { QETH_DBF_TEXT1(0,trace,"ri-sftst"); qeth_softsetup_card(card,QETH_LOCK_ALREADY_HELD); @@ -8223,7 +8576,7 @@ qeth_restore_dev_flag_state(card); atomic_set(&card->is_gone,0); netif_wake_queue(card->dev); - qeth_wakeup_procfile(); + qeth_snmp_notify(); } my_spin_unlock(&setup_lock); } @@ -8324,7 +8677,8 @@ spin_lock_init(&card->wait_q_lock); spin_lock_init(&card->softsetup_lock); spin_lock_init(&card->hardsetup_lock); - spin_lock_init(&card->ioctl_lock); + sema_init(&card->ioctl_sem, 1); + #ifdef QETH_VLAN spin_lock_init(&card->vlan_lock); card->vlangrp = NULL; @@ -8346,6 +8700,8 @@ card->ip_mc_new_state.ipm6_ifa=NULL; #endif /* QETH_IPV6 */ + card->csum_enable_mask=IPA_CHECKSUM_DEFAULT_ENABLE_MASK; + /* setup net_device stuff */ card->dev->priv=card; @@ -8819,7 +9175,7 @@ if ((card=qeth_get_card_by_irq(irq))) { qeth_remove_card(card,remove_method); } - qeth_wakeup_procfile(); + qeth_snmp_notify(); my_spin_unlock(&setup_lock); } @@ -8905,49 +9261,6 @@ return cnt; } -static void qeth_correct_routing_status(qeth_card_t *card) -{ - if (card->type==QETH_CARD_TYPE_IQD) { - /* if it's not a mc router, it's no router */ - if ( (card->options.routing_type4 == PRIMARY_ROUTER) || - (card->options.routing_type4 == SECONDARY_ROUTER) -#ifdef QETH_IPV6 - || - (card->options.routing_type6 == PRIMARY_ROUTER) || - (card->options.routing_type6 == SECONDARY_ROUTER) -#endif /* QETH_IPV6 */ - ) { - PRINT_WARN("routing not applicable, reset " \ - "routing status.\n"); - card->options.routing_type4=NO_ROUTER; -#ifdef QETH_IPV6 - card->options.routing_type6=NO_ROUTER; -#endif /* QETH_IPV6 */ - } - card->options.do_prio_queueing=NO_PRIO_QUEUEING; - } else { - /* if it's a mc router, it's no router */ - if ( (card->options.routing_type4 == MULTICAST_ROUTER) || - (card->options.routing_type4 == PRIMARY_CONNECTOR) || - (card->options.routing_type4 == SECONDARY_CONNECTOR) -#ifdef QETH_IPV6 - || - (card->options.routing_type6 == MULTICAST_ROUTER) || - (card->options.routing_type6 == PRIMARY_CONNECTOR) || - (card->options.routing_type6 == SECONDARY_CONNECTOR) -#endif /* QETH_IPV6 */ - ) { - PRINT_WARN("routing not applicable, reset " \ - "routing status. (Did you mean " \ - "primary_router or secondary_router?)\n"); - card->options.routing_type4=NO_ROUTER; -#ifdef QETH_IPV6 - card->options.routing_type6=NO_ROUTER; -#endif /* QETH_IPV6 */ - } - } -} - static int qeth_attach_handler(int irq_to_scan,chandev_probeinfo *probeinfo) { int result = 0; @@ -9102,7 +9415,6 @@ goto endloop; } - qeth_correct_routing_status(card); qeth_insert_card_into_list(card); QETH_DBF_TEXT3(0,trace,"request0"); @@ -9247,7 +9559,7 @@ /* means, we prevent looping in * qeth_send_control_data */ atomic_set(&card->write_busy,0); - qeth_wakeup_procfile(); + qeth_snmp_notify(); } my_read_unlock(&list_lock); } @@ -9297,7 +9609,7 @@ card->tqueue_sst.sync=0; schedule_task(&card->tqueue_sst); out: - qeth_wakeup_procfile(); + qeth_snmp_notify(); return dev; } @@ -9385,11 +9697,10 @@ sprintf(dbf_text,"ipevent"); QETH_DBF_TEXT3(0,trace,dbf_text); QETH_DBF_HEX3(0,trace,&event,sizeof(unsigned long)); - QETH_DBF_HEX3(0,trace,&dev,sizeof(void*)); - sprintf(dbf_text,"%08x",ifa->ifa_address); - QETH_DBF_TEXT3(0,trace,dbf_text); - sprintf(dbf_text,"%08x",ifa->ifa_mask); - QETH_DBF_TEXT3(0,trace,dbf_text); + sprintf(dbf_text,"%08x",ifa->ifa_address); + QETH_DBF_TEXT3(0,trace,dbf_text); + sprintf(dbf_text,"%08x",ifa->ifa_mask); + QETH_DBF_TEXT3(0,trace,dbf_text); #ifdef QETH_VLAN if (qeth_verify_dev(dev)==QETH_VERIFY_IS_VLAN_DEV) @@ -9418,10 +9729,9 @@ sprintf(dbf_text,"ip6event"); QETH_DBF_TEXT3(0,trace,dbf_text); QETH_DBF_HEX3(0,trace,&event,sizeof(unsigned long)); - QETH_DBF_HEX3(0,trace,&dev,sizeof(void*)); - QETH_DBF_HEX3(0,trace,ifa->addr.s6_addr,QETH_DBF_TRACE_LEN); - QETH_DBF_HEX3(0,trace,ifa->addr.s6_addr+QETH_DBF_TRACE_LEN, - QETH_DBF_TRACE_LEN); + QETH_DBF_HEX3(0,trace,ifa->addr.s6_addr,QETH_DBF_TRACE_LEN); + QETH_DBF_HEX3(0,trace,ifa->addr.s6_addr+QETH_DBF_TRACE_LEN, + QETH_DBF_TRACE_LEN); #ifdef QETH_VLAN if (qeth_verify_dev(dev)==QETH_VERIFY_IS_VLAN_DEV) @@ -9438,8 +9748,63 @@ return NOTIFY_DONE; } + +static int +qeth_multicast6_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + qeth_card_t *card; + struct ifmcaddr6 *mc = (struct ifmcaddr6 *) ptr; + struct net_device *dev = mc->idev->dev; + char dbf_text[15]; + + sprintf(dbf_text,"mc6event"); + QETH_DBF_TEXT3(0,trace,dbf_text); + QETH_DBF_HEX3(0,trace,&event,sizeof(unsigned long)); +#ifdef QETH_VLAN + if (qeth_verify_dev(dev)==QETH_VERIFY_IS_VLAN_DEV) + card = (qeth_card_t *)VLAN_DEV_INFO(dev)->real_dev->priv; + else +#endif + card=(qeth_card_t *)dev->priv; + if (qeth_does_card_exist(card)) { + QETH_DBF_HEX3(0,trace,&card,sizeof(void*)); + qeth_save_dev_flag_state(card); + qeth_start_softsetup_thread(card); + } + + return NOTIFY_DONE; +} + #endif /* QETH_IPV6 */ +static int +qeth_multicast_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + qeth_card_t *card; + struct ip_mc_list *mc = (struct ip_mc_list *) ptr; + struct net_device *dev = mc->interface->dev; + char dbf_text[15]; + + sprintf(dbf_text,"mc4event"); + QETH_DBF_TEXT3(0,trace,dbf_text); + QETH_DBF_HEX3(0,trace,&event,sizeof(unsigned long)); +#ifdef QETH_VLAN + if (qeth_verify_dev(dev)==QETH_VERIFY_IS_VLAN_DEV) + card = (qeth_card_t *)VLAN_DEV_INFO(dev)->real_dev->priv; + else +#endif + card=(qeth_card_t *)dev->priv; + if (qeth_does_card_exist(card)) { + QETH_DBF_HEX3(0,trace,&card,sizeof(void*)); + qeth_save_dev_flag_state(card); + qeth_start_softsetup_thread(card); + } + + return NOTIFY_DONE; +} + static int qeth_reboot_event(struct notifier_block *this, unsigned long event,void *ptr) { @@ -9533,9 +9898,11 @@ int size; tempinfo_t *info; + MOD_INC_USE_COUNT; info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { PRINT_WARN("No memory available for data\n"); + MOD_DEC_USE_COUNT; return -ENOMEM; } else { file->private_data = (void *) info; @@ -9556,6 +9923,7 @@ PRINT_WARN("No memory available for data\n"); vfree (info); rc=-ENOMEM; + MOD_DEC_USE_COUNT; goto out; } @@ -9583,23 +9951,23 @@ "by_ToS"); } + /* a '+' in the routing indicator means, that broadcast + * packets are not echoed back to the sender */ #ifdef QETH_IPV6 - if (atomic_read(&card->rt4fld) && - atomic_read(&card->rt6fld)) - strcpy(router_str, "no"); - else if (atomic_read(&card->rt4fld) || - atomic_read(&card->rt6fld)) - strcpy(router_str, "mix"); + if (atomic_read(&card->rt4fld) || + atomic_read(&card->rt6fld)) + strcpy(router_str, "FLD"); #else /* QETH_IPV6 */ if (atomic_read(&card->rt4fld)) - strcpy(router_str, "no"); + strcpy(router_str, "FLD"); #endif /* QETH_IPV6 */ else if ( ((card->options.routing_type4&ROUTER_MASK)== PRIMARY_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - PRIMARY_ROUTER) + ( ((card->options.routing_type6&ROUTER_MASK)== + PRIMARY_ROUTER)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { strcpy(router_str,"pri"); @@ -9608,8 +9976,9 @@ SECONDARY_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - SECONDARY_ROUTER) + ( ((card->options.routing_type6&ROUTER_MASK)== + SECONDARY_ROUTER)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { strcpy(router_str,"sec"); @@ -9618,38 +9987,51 @@ MULTICAST_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - MULTICAST_ROUTER) + ( ((card->options.routing_type6&ROUTER_MASK)== + MULTICAST_ROUTER)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { - strcpy(router_str,"mc"); + if (card->broadcast_capable==BROADCAST_WITHOUT_ECHO) + strcpy(router_str,"mc+"); + else + strcpy(router_str,"mc"); } else if ( ((card->options.routing_type4&ROUTER_MASK)== PRIMARY_CONNECTOR) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - PRIMARY_CONNECTOR) + ( ((card->options.routing_type6&ROUTER_MASK)== + PRIMARY_CONNECTOR)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { - strcpy(router_str,"p.c"); + if (card->broadcast_capable==BROADCAST_WITHOUT_ECHO) + strcpy(router_str,"p+c"); + else + strcpy(router_str,"p.c"); } else if ( ((card->options.routing_type4&ROUTER_MASK)== SECONDARY_CONNECTOR) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - SECONDARY_CONNECTOR) + ( ((card->options.routing_type6&ROUTER_MASK)== + SECONDARY_CONNECTOR)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { - strcpy(router_str,"s.c"); + if (card->broadcast_capable==BROADCAST_WITHOUT_ECHO) + strcpy(router_str,"s+c"); + else + strcpy(router_str,"s.c"); } else if ( ((card->options.routing_type4&ROUTER_MASK)== NO_ROUTER) #ifdef QETH_IPV6 && - ((card->options.routing_type6&ROUTER_MASK)== - NO_ROUTER) + ( ((card->options.routing_type6&ROUTER_MASK)== + NO_ROUTER)|| + (!qeth_is_supported(IPA_IPv6)) ) #endif /* QETH_IPV6 */ ) { strcpy(router_str,"no"); @@ -9670,7 +10052,8 @@ card->chpid, card->dev_name, qeth_get_cardname_short - (card->type,card->link_type), + (card->type,card->link_type, + card->is_guest_lan), card->options.portno); } else if (!atomic_read(&card->is_startlaned)) { length+=sprintf(buffer+length, @@ -9680,7 +10063,8 @@ card->chpid, card->dev_name, qeth_get_cardname_short - (card->type,card->link_type), + (card->type,card->link_type, + card->is_guest_lan), card->options.portno); } else { length+=sprintf(buffer+length, @@ -9689,7 +10073,8 @@ card->devno0,card->devno1,card->devno2, card->chpid,card->dev_name, qeth_get_cardname_short - (card->type,card->link_type), + (card->type,card->link_type, + card->is_guest_lan), card->options.portno, checksum_str, queueing_str,router_str,bufsize_str, @@ -10174,6 +10559,7 @@ int size; char entry_type[5]; + MOD_INC_USE_COUNT; info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { PRINT_WARN("No memory available for data\n"); @@ -10327,13 +10713,25 @@ static int qeth_procfile_release(struct inode *inode,struct file *file) { tempinfo_t *p_info = (tempinfo_t *) file->private_data; + struct list_head *l,*n; + struct qeth_notify_list *n_entry; if (p_info) { if (p_info->data) vfree (p_info->data); vfree (p_info); } - +/*remove task-entry to notify from list */ + spin_lock(¬ify_lock); + list_for_each_safe(l, n, ¬ify_list) { + n_entry = list_entry(l, struct qeth_notify_list, list); + if (n_entry->task == current) { + list_del(&n_entry->list); + kfree(n_entry); + } + } + spin_unlock(¬ify_lock); + MOD_DEC_USE_COUNT; return 0; } @@ -10481,118 +10879,35 @@ return user_len; } -static int qeth_procfile_getinterfaces(unsigned long arg) +static int qeth_snmp_register(struct task_struct *p, unsigned long arg) { - qeth_card_t *card; + struct qeth_notify_list *n_entry; + struct list_head *l; + QETH_DBF_TEXT5(0,trace,"snmpreg"); - char parms[16]; - char *buffer; - char *buffer_pointer; - __u32 version,valid_fields,qeth_version,number_of_devices,if_index; - __u32 data_size,data_len; - unsigned long ioctl_flags; - int result=0; + /*check first if entry already exists*/ - /* the struct of version 0 is: -typedef struct dev_list -{ - char device_name[IFNAME_MAXLEN]; // OSA-Exp device name (e.g. eth0) - __u32 if_index; // interface index from kernel - __u32 flags; // device charateristics -} __attribute__((packed)) DEV_LIST; - -typedef struct osaexp_dev_ver0 -{ - __u32 version; // structure version - __u32 valid_fields; // bitmask of fields that are really filled - __u32 qeth_version; // qeth driver version - __u32 number_of_devices; // number of OSA Express devices - struct dev_list devices[0]; // list of OSA Express devices -} __attribute__((packed)) OSAEXP_DEV_VER0; - */ - - version = 0; - valid_fields = 0; - qeth_version = 0; - number_of_devices= 0; - - copy_from_user((void*)parms,(void*)arg,sizeof(parms)); - memcpy(&data_size,parms,sizeof(__u32)); - - if ( !(data_size > 0) ) - return -EFAULT; - if ( data_size > IOCTL_MAX_TRANSFER_SIZE ) - return -EFAULT; - if ( !access_ok(VERIFY_WRITE, (void *)arg, data_size) ) - return -EFAULT; - - my_read_lock(&list_lock); - card = firstcard; -#define IOCTL_USER_STRUCT_SIZE (DEV_NAME_LEN*sizeof(char)) + \ - sizeof(__u32) + sizeof(__u32) - while (card) { - if (card->type == QETH_CARD_TYPE_OSAE) - number_of_devices=number_of_devices + IOCTL_USER_STRUCT_SIZE; - card = card->next; - } -#undef IOCTL_USER_STRUCT_SIZE - if ((number_of_devices + 4*sizeof(__u32)) >= data_size) { - result=-ENOMEM; - goto out; - } + spin_lock(¬ify_lock); + list_for_each(l, ¬ify_list) { + n_entry = list_entry(l, struct qeth_notify_list, list); + if (n_entry->task == p) { + n_entry->signum = (int) arg; + goto reg_out; + } - number_of_devices=0; - card = firstcard; - buffer = (char *)vmalloc(data_size); - if (!buffer) { - result=-EFAULT; - goto out; } - buffer_pointer = ((char *)(buffer)) + (4*sizeof(__u32)) ; - while (card) { - if ((card->type == QETH_CARD_TYPE_OSAE)&& - (!atomic_read(&card->is_gone))&& - (atomic_read(&card->is_hardsetup))&& - (atomic_read(&card->is_registered))) { - - memcpy(buffer_pointer,card->dev_name,DEV_NAME_LEN); - buffer_pointer = buffer_pointer + DEV_NAME_LEN; - if_index=card->dev->ifindex; - memcpy(buffer_pointer,&if_index,sizeof(__u32)); - buffer_pointer = buffer_pointer + sizeof(__u32); - memcpy(buffer_pointer,&ioctl_flags,sizeof(__u32)); - buffer_pointer = buffer_pointer + sizeof(__u32); - number_of_devices=number_of_devices+1; - } - card = card->next; - } - - /* we copy the real size */ - data_len=buffer_pointer-buffer; - - buffer_pointer = buffer; - /* copy the header information at the beginning of the buffer */ - memcpy(buffer_pointer,&version,sizeof(__u32)); - memcpy(((char *)buffer_pointer)+sizeof(__u32),&valid_fields, - sizeof(__u32)); - memcpy(((char *)buffer_pointer)+(2*sizeof(__u32)),&qeth_version, - sizeof(__u32)); - memcpy(((char *)buffer_pointer)+(3*sizeof(__u32)),&number_of_devices, - sizeof(__u32)); - copy_to_user((char *)arg,buffer,data_len); - vfree(buffer); -out: - my_read_unlock(&list_lock); - return result; - -#undef PARMS_BUFFERLENGTH - -}; - -static int qeth_procfile_interfacechanges(unsigned long arg) -{ - return qeth_sleepon_procfile(); - + spin_unlock(¬ify_lock); + n_entry = (struct qeth_notify_list *) + kmalloc(sizeof(struct qeth_notify_list),GFP_KERNEL); + if (!n_entry) + return -ENOMEM; + n_entry->task = p; + n_entry->signum = (int) arg; + spin_lock(¬ify_lock); + list_add(&n_entry->list,¬ify_list); +reg_out: + spin_unlock(¬ify_lock); + return 0; } static int qeth_procfile_ioctl(struct inode *inode, struct file *file, @@ -10600,19 +10915,17 @@ { int result; - down_interruptible(&qeth_procfile_ioctl_lock); - switch (cmd) { - case QETH_IOCPROC_OSAEINTERFACES: - result = qeth_procfile_getinterfaces(arg); - break; - case QETH_IOCPROC_INTERFACECHANGES: - result = qeth_procfile_interfacechanges(arg); + switch (cmd) { + case QETH_IOCPROC_REGISTER: + if ( (arg > 0) && (arg < 32) ) + result = qeth_snmp_register(current,arg); + else + result = -EINVAL; break; default: result = -EOPNOTSUPP; } - up(&qeth_procfile_ioctl_lock); return result; }; @@ -10644,10 +10957,6 @@ S_IFREG|0644,&proc_root); if (qeth_proc_file) { qeth_proc_file->proc_fops = &qeth_procfile_fops; - sema_init(&qeth_procfile_ioctl_sem, - PROCFILE_SLEEP_SEM_MAX_VALUE); - sema_init(&qeth_procfile_ioctl_lock, - PROCFILE_IOCTL_SEM_MAX_VALUE); } else proc_file_registration=-1; if (proc_file_registration) @@ -10796,7 +11105,11 @@ global_stay_in_mem = chandev_persist(chandev_type_qeth); #endif /* MODULE */ - spin_lock_init(&setup_lock); +/*SNMP init stuff*/ + spin_lock_init(¬ify_lock); + INIT_LIST_HEAD(¬ify_list); + + spin_lock_init(&setup_lock); spin_lock_init(&ipato_list_lock); diff -urN linux-2.4.27/drivers/s390/net/qeth.h linux-2.4.28/drivers/s390/net/qeth.h --- linux-2.4.27/drivers/s390/net/qeth.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/qeth.h 2004-11-17 03:54:21.516394522 -0800 @@ -15,7 +15,7 @@ #define QETH_NAME " qeth" -#define VERSION_QETH_H "$Revision: 1.113 $" +#define VERSION_QETH_H "$Revision: 1.113.4.8 $" /******************** CONFIG STUFF ***********************/ //#define QETH_DBF_LIKE_HELL @@ -47,7 +47,7 @@ /********************* TUNING STUFF **************************/ #define HIGH_WATERMARK_PACK 5 #define LOW_WATERMARK_PACK 2 -#define WATERMARK_FUZZ 2 +#define WATERMARK_FUZZ 1 #define QETH_MAX_INPUT_THRESHOLD 500 #define QETH_MAX_OUTPUT_THRESHOLD 300 /* ? */ @@ -85,6 +85,22 @@ #define QETH_HARDSETUP_CLEAR_LAPS 3 #define QETH_RECOVERY_HARDSETUP_RETRY 2 +/* the worst case stack usage is: + * qeth_hard_start_xmit + * do_QDIO + * qeth_qdio_output_handler + * do_QDIO + * qeth_qdio_output_handler + * (no more recursion as we have called netif_stop_queue) + */ +#ifdef CONFIG_ARCH_S390X +#define STACK_PTR_MASK 0x3fff +#define WORST_CASE_STACK_USAGE 1100 +#else /* CONFIG_ARCH_S390X */ +#define STACK_PTR_MASK 0x1fff +#define WORST_CASE_STACK_USAGE 800 +#endif /* CONFIG_ARCH_S390X */ + /************************* DEBUG FACILITY STUFF *********************/ #define QETH_DBF_HEX(ex,name,level,addr,len) \ @@ -253,6 +269,12 @@ #define QETH_HEADER_PASSTHRU 0x10 #define QETH_HEADER_IPV6 0x80 +#define QETH_ETH_MAC_V4 0x0100 /* like v4 */ +#define QETH_ETH_MAC_V6 0x3333 /* like v6 */ +/* tr mc mac is longer, but that will be enough to detect mc frames */ +#define QETH_TR_MAC_NC 0xc000 /* non-canonical */ +#define QETH_TR_MAC_C 0x0300 /* canonical */ + #define QETH_CAST_FLAGS 0x07 #define QETH_CAST_UNICAST 6 #define QETH_CAST_MULTICAST 4 @@ -529,7 +551,7 @@ #define QETH_FAKE_LL_ADDR_LEN ETH_ALEN /* 6 */ #define QETH_FAKE_LL_DEST_MAC_POS 0 #define QETH_FAKE_LL_SRC_MAC_POS 6 -#define QETH_FAKE_LL_SRC_MAC_POS_IN_QDIO_HDR 6 +#define QETH_FAKE_LL_SRC_MAC_POS_IN_QDIO_HDR 18 #define QETH_FAKE_LL_PROT_POS 12 #define QETH_FAKE_LL_V4_ADDR_POS 16 #define QETH_FAKE_LL_V6_ADDR_POS 24 @@ -603,7 +625,7 @@ #define MULTICAST_ROUTER 3 #define PRIMARY_CONNECTOR 4 #define SECONDARY_CONNECTOR 5 -#define ROUTER_MASK 0xf /* used to remove SET_ROUTING_FLAG +#define ROUTER_MASK 0xf /* used to remove RESET_ROUTING_FLAG from routing_type */ #define RESET_ROUTING_FLAG 0x10 /* used to indicate, that setting the routing type is desired */ @@ -629,6 +651,9 @@ #define QETH_DONT_WAIT_FOR_LOCK 1 #define QETH_LOCK_ALREADY_HELD 2 +#define BROADCAST_WITH_ECHO 1 +#define BROADCAST_WITHOUT_ECHO 2 + #define PROBLEM_CARD_HAS_STARTLANED 1 #define PROBLEM_RECEIVED_IDX_TERMINATE 2 #define PROBLEM_ACTIVATE_CHECK_CONDITION 3 @@ -782,6 +807,7 @@ __u8 link_type; + int is_guest_lan; int do_pfix; /* to avoid doing diag98 for vm guest lan devices */ /* inbound buffer management */ @@ -852,7 +878,7 @@ /* prevents deadlocks :-O */ spinlock_t softsetup_lock; spinlock_t hardsetup_lock; - spinlock_t ioctl_lock; + struct semaphore ioctl_sem; atomic_t softsetup_thread_is_running; struct semaphore softsetup_thread_sem; struct tq_struct tqueue_sst; @@ -907,6 +933,8 @@ __u32 ipa6_enabled; __u32 adp_supported; + __u32 csum_enable_mask; + atomic_t startlan_attempts; atomic_t enable_routing_attempts4; atomic_t rt4fld; @@ -1004,6 +1032,15 @@ struct mydevreg_t *prev; } mydevreg_t; +/*user process notification stuff */ +spinlock_t notify_lock; +struct list_head notify_list; +struct qeth_notify_list { + struct list_head list; + struct task_struct *task; + int signum; +}; + inline static int qeth_get_arphrd_type(int cardtype,int linktype) { switch (cardtype) { @@ -1011,7 +1048,7 @@ case QETH_MPC_LINK_TYPE_LANE_TR: /* fallthrough */ case QETH_MPC_LINK_TYPE_HSTR: - return ARPHRD_IEEE802; + return ARPHRD_IEEE802_TR; default: return ARPHRD_ETHER; } case QETH_CARD_TYPE_IQD: return ARPHRD_ETHER; @@ -1036,22 +1073,33 @@ } } -inline static const char *qeth_get_cardname(int cardtype) +inline static const char *qeth_get_cardname(int cardtype,int is_guest_lan) { - switch (cardtype) { - case QETH_CARD_TYPE_UNKNOWN: return "n unknown"; - case QETH_CARD_TYPE_OSAE: return "n OSD Express"; - case QETH_CARD_TYPE_IQD: return " HiperSockets"; - default: return " strange"; + if (is_guest_lan) { + switch (cardtype) { + case QETH_CARD_TYPE_UNKNOWN: return "n unknown"; + case QETH_CARD_TYPE_OSAE: return " Guest LAN QDIO"; + case QETH_CARD_TYPE_IQD: return " Guest LAN Hiper"; + default: return " strange"; + } + } else { + switch (cardtype) { + case QETH_CARD_TYPE_UNKNOWN: return "n unknown"; + case QETH_CARD_TYPE_OSAE: return "n OSD Express"; + case QETH_CARD_TYPE_IQD: return " HiperSockets"; + default: return " strange"; + } } } /* max length to be returned: 14 */ -inline static const char *qeth_get_cardname_short(int cardtype,__u8 link_type) +inline static const char *qeth_get_cardname_short(int cardtype,__u8 link_type,int is_guest_lan) { switch (cardtype) { case QETH_CARD_TYPE_UNKNOWN: return "unknown"; - case QETH_CARD_TYPE_OSAE: switch (link_type) { + case QETH_CARD_TYPE_OSAE: if (is_guest_lan) + return "GuestLAN QDIO"; + switch (link_type) { case QETH_MPC_LINK_TYPE_FAST_ETHERNET: return "OSD_100"; case QETH_MPC_LINK_TYPE_HSTR: @@ -1068,7 +1116,7 @@ return "OSD_ATM_LANE"; default: return "OSD_Express"; } - case QETH_CARD_TYPE_IQD: return "HiperSockets"; + case QETH_CARD_TYPE_IQD: return (is_guest_lan)?"GuestLAN Hiper":"HiperSockets"; default: return " strange"; } } diff -urN linux-2.4.27/drivers/s390/net/qeth_mpc.h linux-2.4.28/drivers/s390/net/qeth_mpc.h --- linux-2.4.27/drivers/s390/net/qeth_mpc.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/net/qeth_mpc.h 2004-11-17 03:54:21.517394564 -0800 @@ -11,7 +11,7 @@ #ifndef __QETH_MPC_H__ #define __QETH_MPC_H__ -#define VERSION_QETH_MPC_H "$Revision: 1.42 $" +#define VERSION_QETH_MPC_H "$Revision: 1.42.4.4 $" #define QETH_IPA_TIMEOUT (card->ipa_timeout) #define QETH_MPC_TIMEOUT 2000 @@ -288,6 +288,7 @@ #define IPA_PASSTHRU 0x00001000L #define IPA_FULL_VLAN 0x00004000L #define IPA_SOURCE_MAC_AVAIL 0x00010000L +#define IPA_OSA_MC_ROUTER_AVAIL 0x00020000L #define IPA_SETADP_QUERY_COMMANDS_SUPPORTED 0x01 #define IPA_SETADP_ALTER_MAC_ADDRESS 0x02 @@ -331,7 +332,7 @@ #define IPA_CMD_ASS_ARP_QUERY_INFO 0x0104 #define IPA_CMD_ASS_ARP_QUERY_STATS 0x0204 -#define IPA_CHECKSUM_ENABLE_MASK 0x001f +#define IPA_CHECKSUM_DEFAULT_ENABLE_MASK 0x001a #define IPA_CMD_ASS_FILTER_SET_TYPES 0x0003 @@ -462,11 +463,10 @@ } ipa_cmd_t __attribute__ ((packed)); #define QETH_IOC_MAGIC 0x22 -#define QETH_IOCPROC_OSAEINTERFACES _IOWR(QETH_IOC_MAGIC, 1, arg) -#define QETH_IOCPROC_INTERFACECHANGES _IOWR(QETH_IOC_MAGIC, 2, arg) +#define QETH_IOCPROC_REGISTER _IOWR(QETH_IOC_MAGIC, 1, int) #define SNMP_QUERY_CARD_INFO 0x00000002L -#define SNMP_REGISETER_MIB 0x00000004L +#define SNMP_REGISTER_MIB 0x00000004L #define SNMP_GET_OID 0x00000010L #define SNMP_SET_OID 0x00000011L #define SNMP_GET_NEXT_OID 0x00000012L diff -urN linux-2.4.27/drivers/s390/qdio.c linux-2.4.28/drivers/s390/qdio.c --- linux-2.4.27/drivers/s390/qdio.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/s390/qdio.c 2004-11-17 03:54:21.521394728 -0800 @@ -57,7 +57,7 @@ #include -#define VERSION_QDIO_C "$Revision: 1.145 $" +#define VERSION_QDIO_C "$Revision: 1.145.4.9 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -97,10 +97,12 @@ #endif /* QDIO_PERFORMANCE_STATS */ static int hydra_thinints=0; +static int omit_svs=0; static int indicator_used[INDICATORS_PER_CACHELINE]; static __u32 * volatile indicators; static __u32 volatile spare_indicator; +static atomic_t spare_indicator_usecount; static debug_info_t *qdio_dbf_setup=NULL; static debug_info_t *qdio_dbf_sbal=NULL; @@ -121,6 +123,7 @@ static struct semaphore init_sema; static qdio_chsc_area_t *chsc_area; +static spinlock_t chsc_area_lock=SPIN_LOCK_UNLOCKED; /* iQDIO stuff: */ static volatile qdio_q_t *tiq_list=NULL; /* volatile as it could change during a while loop */ @@ -198,7 +201,7 @@ } static inline unsigned long qdio_get_millis(void) { - return (unsigned long)(qdio_get_micros()>>12); + return (unsigned long)(qdio_get_micros()>>10); } static __inline__ int atomic_return_add (int i, atomic_t *v) @@ -518,8 +521,10 @@ if (found) return indicators+i; - else + else { + atomic_inc(&spare_indicator_usecount); return (__u32 * volatile) &spare_indicator; + } } /* locked by the locks in qdio_activate and qdio_cleanup */ @@ -531,6 +536,9 @@ i=addr-indicators; indicator_used[i]=0; } + if (addr==&spare_indicator) { + atomic_dec(&spare_indicator_usecount); + } } static inline volatile void tiqdio_clear_summary_bit(__u32 *location) @@ -621,8 +629,8 @@ set_slsb(&q->slsb.acc.val[(gsf+QDIO_MAX_BUFFERS_PER_Q-1)& (QDIO_MAX_BUFFERS_PER_Q-1)],SLSB_P_INPUT_NOT_INIT); /* we don't issue this SYNC_MEMORY, as we trust Rick T and - * moreover will not use the PROCESSING state, so q->polling - * was 0 + * moreover will not use the PROCESSING state under VM, + * so q->polling was 0 anyway. SYNC_MEMORY;*/ if (q->slsb.acc.val[gsf]==SLSB_P_INPUT_PRIMED) { /* set our summary bit again, as otherwise there is a @@ -655,6 +663,11 @@ if ((q->is_thinint_q)&&(q->is_input_q)) { /* iQDIO */ spin_lock_irqsave(&ttiq_list_lock,flags); + /* in case cleanup has done this already and simultanously + * qdio_unmark_q is called from the interrupt handler, we've + * got to check this in this specific case again */ + if ((!q->list_prev)||(!q->list_next)) + goto out; if (q->list_next==q) { /* q was the only interesting q */ tiq_list=NULL; @@ -667,6 +680,7 @@ q->list_next=NULL; q->list_prev=NULL; } +out: spin_unlock_irqrestore(&ttiq_list_lock,flags); } } @@ -710,7 +724,7 @@ (void*)q->sbal[bufno],SBAL_SIZE); } -inline static int qdio_get_outbound_buffer_frontier(qdio_q_t *q) +static inline int qdio_get_outbound_buffer_frontier(qdio_q_t *q) { int f,f_mod_no; volatile char *slsb; @@ -739,7 +753,7 @@ if (f==first_not_to_check) goto out; slsbyte=slsb[f_mod_no]; - /* the hydra has not fetched the output yet */ + /* the card has not fetched the output yet */ if (slsbyte==SLSB_CU_OUTPUT_PRIMED) { #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_TEXT5(0,trace,"outpprim"); @@ -747,7 +761,7 @@ goto out; } - /* the hydra got it */ + /* the card got it */ if (slsbyte==SLSB_P_OUTPUT_EMPTY) { atomic_dec(&q->number_of_buffers_used); f++; @@ -797,7 +811,7 @@ } /* all buffers are processed */ -inline static int qdio_is_outbound_q_done(qdio_q_t *q) +static inline int qdio_is_outbound_q_done(qdio_q_t *q) { int no_used; #ifdef QDIO_DBF_LIKE_HELL @@ -818,7 +832,7 @@ return (no_used==0); } -inline static int qdio_has_outbound_q_moved(qdio_q_t *q) +static inline int qdio_has_outbound_q_moved(qdio_q_t *q) { int i; @@ -827,7 +841,6 @@ if ( (i!=GET_SAVED_FRONTIER(q)) || (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) { SAVE_FRONTIER(q,i); - SAVE_TIMESTAMP(q); #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_TEXT4(0,trace,"oqhasmvd"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -842,9 +855,10 @@ } } -inline static void qdio_kick_outbound_q(qdio_q_t *q) +static inline void qdio_kick_outbound_q(qdio_q_t *q) { int result; + char dbf_text[15]; #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_TEXT4(0,trace,"kickoutq"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -852,9 +866,66 @@ if (!q->siga_out) return; + /* here's the story with cc=2 and busy bit set (thanks, Rick): + * VM's CP could present us cc=2 and busy bit set on SIGA-write + * during reconfiguration of their Guest LAN (only in HIPERS mode, + * QDIO mode is asynchronous -- cc=2 and busy bit there will take + * the queues down immediately; and not being under VM we have a + * problem on cc=2 and busy bit set right away). + * + * Therefore qdio_siga_output will try for a short time constantly, + * if such a condition occurs. If it doesn't change, it will + * increase the busy_siga_counter and save the timestamp, and + * schedule the queue for later processing (via mark_q, using the + * queue tasklet). __qdio_outbound_processing will check out the + * counter. If non-zero, it will call qdio_kick_outbound_q as often + * as the value of the counter. This will attempt further SIGA + * instructions. + * Every successful SIGA instruction will decrease the counter. + * After some time of no movement, qdio_kick_outbound_q will + * finally fail and reflect corresponding error codes to call + * the upper layer module and have it take the queues down. + * + * Note that this is a change from the original HiperSockets design + * (saying cc=2 and busy bit means take the queues down), but in + * these days Guest LAN didn't exist... excessive cc=2 with busy bit + * conditions will still take the queues down, but the threshold is + * higher due to the Guest LAN environment. + */ + result=qdio_siga_output(q); - if (result) { + switch (result) { + case 0: + /* went smooth this time, reset timestamp */ + QDIO_DBF_TEXT3(0,trace,"cc2reslv"); + sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no, + atomic_read(&q->busy_siga_counter)); + QDIO_DBF_TEXT3(0,trace,dbf_text); + q->timing.busy_start=0; + break; + case (2|QDIO_SIGA_ERROR_B_BIT_SET): + /* cc=2 and busy bit: */ + atomic_inc(&q->busy_siga_counter); + + /* if the last siga was successful, save + * timestamp here */ + if (!q->timing.busy_start) + q->timing.busy_start=NOW; + + /* if we're in time, don't touch error_status_flags + * and siga_error */ + if (NOW-q->timing.busy_startirq,q->q_no, + atomic_read(&q->busy_siga_counter)); + QDIO_DBF_TEXT3(0,trace,dbf_text); + /* else fallthrough and report error */ + default: + /* for plain cc=1, 2 or 3: */ if (q->siga_error) q->error_status_flags|= QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR; @@ -864,7 +935,7 @@ } } -inline static void qdio_kick_outbound_handler(qdio_q_t *q) +static inline void qdio_kick_outbound_handler(qdio_q_t *q) { #ifdef QDIO_DBF_LIKE_HELL char dbf_text[15]; @@ -901,8 +972,9 @@ q->error_status_flags=0; } -static void qdio_outbound_processing(qdio_q_t *q) +static inline void __qdio_outbound_processing(qdio_q_t *q) { + int siga_attempts; #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_TEXT4(0,trace,"qoutproc"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -926,6 +998,14 @@ o_p_nc++; #endif /* QDIO_PERFORMANCE_STATS */ + /* see comment in qdio_kick_outbound_q */ + siga_attempts=atomic_read(&q->busy_siga_counter); + while (siga_attempts) { + atomic_dec(&q->busy_siga_counter); + qdio_kick_outbound_q(q); + siga_attempts--; + } + #ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs++; #endif /* QDIO_PERFORMANCE_STATS */ @@ -936,7 +1016,8 @@ if (q->is_iqdio_q) { /* for asynchronous queues, we better check, if the fill - * level is too high */ + * level is too high. for synchronous queues, the fill + * level will never be that high. */ if (atomic_read(&q->number_of_buffers_used)> IQDIO_FILL_LEVEL_TO_POLL) { qdio_mark_q(q); @@ -950,16 +1031,24 @@ qdio_release_q(q); } +static void qdio_outbound_processing(qdio_q_t *q) +{ + __qdio_outbound_processing(q); +} + /************************* INBOUND ROUTINES *******************************/ -inline static int qdio_get_inbound_buffer_frontier(qdio_q_t *q) +static inline int qdio_get_inbound_buffer_frontier(qdio_q_t *q) { int f,f_mod_no; volatile char *slsb; char slsbyte; int first_not_to_check; char dbf_text[15]; +#ifdef QDIO_USE_PROCESSING_STATE + int last_position=-1; +#endif /* QDIO_USE_PROCESSING_STATE */ #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_TEXT4(0,trace,"getibfro"); @@ -1002,8 +1091,14 @@ if (q->siga_sync) { set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT); } else { - set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_PROCESSING); + /* set the previous buffer to NOT_INIT. The current + * buffer will be set to PROCESSING at the end of + * this function to avoid further interrupts. */ + if (last_position>=0) + set_slsb(&slsb[last_position], + SLSB_P_INPUT_NOT_INIT); atomic_set(&q->polling,1); + last_position=f_mod_no; } #else /* QDIO_USE_PROCESSING_STATE */ set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT); @@ -1044,6 +1139,10 @@ f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1); atomic_dec(&q->number_of_buffers_used); +#ifdef QDIO_USE_PROCESSING_STATE + last_position=-1; +#endif /* QDIO_USE_PROCESSING_STATE */ + goto out; } @@ -1051,6 +1150,11 @@ out: q->first_to_check=f_mod_no; +#ifdef QDIO_USE_PROCESSING_STATE + if (last_position>=0) + set_slsb(&slsb[last_position],SLSB_P_INPUT_PROCESSING); +#endif /* QDIO_USE_PROCESSING_STATE */ + #ifdef QDIO_DBF_LIKE_HELL QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int)); #endif /* QDIO_DBF_LIKE_HELL */ @@ -1058,7 +1162,7 @@ return q->first_to_check; } -inline static int qdio_has_inbound_q_moved(qdio_q_t *q) +static inline int qdio_has_inbound_q_moved(qdio_q_t *q) { int i; @@ -1095,7 +1199,7 @@ } /* means, no more buffers to be filled */ -inline static int iqdio_is_inbound_q_done(qdio_q_t *q) +static inline int iqdio_is_inbound_q_done(qdio_q_t *q) { int no_used; #ifdef QDIO_DBF_LIKE_HELL @@ -1148,7 +1252,7 @@ return 0; } -inline static int qdio_is_inbound_q_done(qdio_q_t *q) +static inline int qdio_is_inbound_q_done(qdio_q_t *q) { int no_used; #ifdef QDIO_DBF_LIKE_HELL @@ -1157,7 +1261,7 @@ no_used=atomic_read(&q->number_of_buffers_used); - /* we need that one for synchronization with Hydra, as Hydra + /* we need that one for synchronization with the OSA/FCP card, as it * does a kind of PCI avoidance */ SYNC_MEMORY; @@ -1204,7 +1308,7 @@ } } -inline static void qdio_kick_inbound_handler(qdio_q_t *q) +static inline void qdio_kick_inbound_handler(qdio_q_t *q) { int count=0; int start,end,real_end,i; @@ -1250,7 +1354,8 @@ #endif /* QDIO_PERFORMANCE_STATS */ } -static inline void tiqdio_inbound_processing(qdio_q_t *q) +static inline void __tiqdio_inbound_processing(qdio_q_t *q, + int spare_ind_was_set) { qdio_irq_t *irq_ptr; qdio_q_t *oq; @@ -1282,8 +1387,18 @@ goto out; } - if (*(q->dev_st_chg_ind)) { - tiqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind); + /* we reset spare_ind_was_set, when the queue does not use the + * spare indicator */ + if (spare_ind_was_set) { + spare_ind_was_set==(q->dev_st_chg_ind==&spare_indicator); + } + + if ( (*(q->dev_st_chg_ind)) || (spare_ind_was_set) ) { + /* q->dev_st_chg_ind is the indicator, be it shared or not. + * only clear it, if indicator is non-shared */ + if (!spare_ind_was_set) { + tiqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind); + } if (q->hydra_gives_outbound_pcis) { if (!q->siga_sync_done_on_thinints) { @@ -1297,7 +1412,7 @@ } /* maybe we have to do work on our outbound queues... at least - * we have to check Hydra outbound-int-capable thinint-capable + * we have to check for outbound-int-capable thinint-capable * queues */ if (q->hydra_gives_outbound_pcis) { irq_ptr=(qdio_irq_t*)q->irq_ptr; @@ -1307,7 +1422,7 @@ perf_stats.tl_runs--; #endif /* QDIO_PERFORMANCE_STATS */ if (!qdio_is_outbound_q_done(oq)) { - qdio_outbound_processing(oq); + __qdio_outbound_processing(oq); } } } @@ -1330,7 +1445,12 @@ qdio_release_q(q); } -static void qdio_inbound_processing(qdio_q_t *q) +static void tiqdio_inbound_processing(qdio_q_t *q) +{ + __tiqdio_inbound_processing(q,atomic_read(&spare_indicator_usecount)); +} + +static inline void __qdio_inbound_processing(qdio_q_t *q) { int q_laps=0; @@ -1375,11 +1495,17 @@ qdio_release_q(q); } +static void qdio_inbound_processing(qdio_q_t *q) +{ + __qdio_inbound_processing(q); +} + /************************* MAIN ROUTINES *******************************/ static inline void tiqdio_inbound_checks(void) { qdio_q_t *q; + int spare_ind_was_set=0; #ifdef QDIO_USE_PROCESSING_STATE int q_laps=0; #endif /* QDIO_USE_PROCESSING_STATE */ @@ -1398,15 +1524,22 @@ again: #endif /* QDIO_USE_PROCESSING_STATE */ + /* when the spare indicator is used and set, save that and clear it */ + if ( (atomic_read(&spare_indicator_usecount)) && (spare_indicator) ) { + spare_ind_was_set=1; + tiqdio_clear_summary_bit((__u32*)&spare_indicator); + } + q=(qdio_q_t*)tiq_list; /* switch all active queues to processing state */ do { if (!q) break; - tiqdio_inbound_processing(q); + __tiqdio_inbound_processing(q,spare_ind_was_set); q=(qdio_q_t*)q->list_next; } while (q!=(qdio_q_t*)tiq_list); - /* switch off all queues' processing state */ + /* switch off all queues' processing state, see comments in + * qdio_get_inbound_buffer_frontier */ #ifdef QDIO_USE_PROCESSING_STATE q=(qdio_q_t*)tiq_list; do { @@ -1589,7 +1722,7 @@ kfree(irq_ptr->output_qs[i]); } - if (irq_ptr->qdr) kfree(irq_ptr->qdr); + kfree(irq_ptr->qdr); kfree(irq_ptr); } @@ -1758,6 +1891,10 @@ ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: &qdio_inbound_processing); + /* actually this is not used for inbound queues. yet. */ + atomic_set(&q->busy_siga_counter,0); + q->timing.busy_start=0; + /* for (j=0;jtiming.last_transfer_times[j]=(qdio_get_micros()/ QDIO_STATS_NUMBER)*j; @@ -1849,6 +1986,9 @@ q->tasklet.func=(void(*)(unsigned long)) &qdio_outbound_processing; + atomic_set(&q->busy_siga_counter,0); + q->timing.busy_start=0; + /* fill in slib */ if (i>0) irq_ptr->output_qs[i-1]->slib->nsliba= QDIO_PFIX_GET_ADDR(q->slib); @@ -1928,9 +2068,10 @@ perf_stats.start_time_inbound=NOW; #endif /* QDIO_PERFORMANCE_STATS */ - /* VM will do the SVS for us - * issue SVS to benefit from iqdio interrupt avoidance (SVS clears AISOI)*/ - if (!MACHINE_IS_VM) { + /* SVS only when needed: + * issue SVS to benefit from iqdio interrupt avoidance + * (SVS clears AISOI)*/ + if (!omit_svs) { tiqdio_clear_global_summary(); } @@ -2014,7 +2155,7 @@ #ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs--; #endif /* QDIO_PERFORMANCE_STATS */ - qdio_inbound_processing(q); + __qdio_inbound_processing(q); } } if (irq_ptr->hydra_gives_outbound_pcis) { @@ -2027,7 +2168,7 @@ if (!irq_ptr->sync_done_on_outb_pcis) { SYNC_MEMORY; } - qdio_outbound_processing(q); + __qdio_outbound_processing(q); } } } @@ -2206,6 +2347,9 @@ static unsigned char qdio_check_siga_needs(int sch) { int resp_code,result; + unsigned long flags; + + spin_lock_irqsave(&chsc_area_lock,flags); memset(chsc_area,0,sizeof(qdio_chsc_area_t)); chsc_area->request_block.command_code1=0x0010; /* length */ @@ -2219,7 +2363,8 @@ QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ "SIGAs for sch x%x.\n", result,sch); - return -1; /* all flags set */ + result=-1; /* all flags set */ + goto out; } resp_code=chsc_area->request_block.operation_data_area. @@ -2228,7 +2373,8 @@ QDIO_PRINT_WARN("response upon checking SIGA needs " \ "is 0x%x. Using all SIGAs for sch x%x.\n", resp_code,sch); - return -1; /* all flags set */ + result=-1; /* all flags set */ + goto out; } if ( (!(chsc_area->request_block.operation_data_area. @@ -2240,18 +2386,25 @@ ) { QDIO_PRINT_WARN("huh? problems checking out sch x%x... " \ "using all SIGAs.\n",sch); - return CHSC_FLAG_SIGA_INPUT_NECESSARY | + result=CHSC_FLAG_SIGA_INPUT_NECESSARY | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ + goto out; } - return chsc_area->request_block.operation_data_area. + result=chsc_area->request_block.operation_data_area. store_qdio_data_response.qdioac; +out: + spin_unlock_irqrestore(&chsc_area_lock,flags); + return result; } -static int qdio_check_for_hydra_thinints(void) +static void qdio_check_for_machine_features(void) { int i,result; + unsigned long flags; + + spin_lock_irqsave(&chsc_area_lock,flags); memset(chsc_area,0,sizeof(qdio_chsc_area_t)); chsc_area->request_block.command_code1=0x0010; @@ -2260,16 +2413,19 @@ if (result) { QDIO_PRINT_WARN("CHSC returned cc %i. Won't use adapter " \ - "interrupts for any Hydra.\n",result); - return 0; + "interrupts for any QDIO device.\n",result); + result=0; + goto out; } i=chsc_area->request_block.operation_data_area. store_qdio_data_response.response_code; if (i!=1) { QDIO_PRINT_WARN("Was not able to determine general " \ - "characteristics of all Hydras aboard.\n"); - return 0; + "characteristics of all QDIO devices " \ + "aboard.\n"); + result=0; + goto out; } /* 4: request block @@ -2277,16 +2433,29 @@ * 512: chsc char */ /* check for bit 67 */ if ( (*(((unsigned int*)(chsc_area))+4+2+2)&0x10000000)!=0x10000000) { - return 0; + hydra_thinints=0; } else { - return 1; + hydra_thinints=1; } + + /* check for bit 56: if aif time delay disablement fac installed, + * omit svs even under lpar (good point by rick again) */ + if ( (*(((unsigned int*)(chsc_area))+4+2+1)&0x00000080)!=0x00000080) { + omit_svs=1; + } else { + omit_svs=0; + } +out: + spin_unlock_irqrestore(&chsc_area_lock,flags); } /* the chsc_area is locked by the lock in qdio_activate */ static unsigned int tiqdio_check_chsc_availability(void) { int result; int i; + unsigned long flags; + + spin_lock_irqsave(&chsc_area_lock,flags); memset(chsc_area,0,sizeof(qdio_chsc_area_t)); chsc_area->request_block.command_code1=0x0010; @@ -2327,6 +2496,7 @@ goto exit; } exit: + spin_unlock_irqrestore(&chsc_area_lock,flags); return result; } @@ -2337,6 +2507,7 @@ unsigned long real_addr_local_summary_bit; unsigned long real_addr_dev_st_chg_ind; void *ptr; + unsigned long flags; char dbf_text[15]; unsigned int resp_code; @@ -2354,6 +2525,8 @@ virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); } + spin_lock_irqsave(&chsc_area_lock,flags); + memset(chsc_area,0,sizeof(qdio_chsc_area_t)); chsc_area->request_block.command_code1=0x0fe0; chsc_area->request_block.command_code2=0x0021; @@ -2377,7 +2550,8 @@ if (result) { QDIO_PRINT_WARN("could not set indicators on irq x%x, " \ "cc=%i.\n",irq_ptr->irq,result); - return -EIO; + result=-EIO; + goto out; } resp_code=chsc_area->response_block.response_code; @@ -2389,14 +2563,18 @@ QDIO_DBF_TEXT1(0,setup,dbf_text); ptr=&chsc_area->response_block; QDIO_DBF_HEX2(1,setup,&ptr,QDIO_DBF_SETUP_LEN); - return -EIO; + result=-EIO; + goto out; } QDIO_DBF_TEXT2(0,setup,"setscind"); QDIO_DBF_HEX2(0,setup,&real_addr_local_summary_bit, sizeof(unsigned long)); QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); - return 0; + result=0; +out: + spin_unlock_irqrestore(&chsc_area_lock,flags); + return result; } /* chsc_area would have to be locked if called from outside qdio_activate */ @@ -2406,10 +2584,13 @@ unsigned int resp_code; int result; void *ptr; + unsigned long flags; char dbf_text[15]; if (!irq_ptr->is_thinint_irq) return -ENODEV; + spin_lock_irqsave(&chsc_area_lock,flags); + memset(chsc_area,0,sizeof(qdio_chsc_area_t)); chsc_area->request_block.command_code1=0x0fe0; chsc_area->request_block.command_code2=0x1027; @@ -2420,7 +2601,8 @@ if (result) { QDIO_PRINT_WARN("could not set delay target on irq x%x, " \ "cc=%i. Continuing.\n",irq_ptr->irq,result); - return -EIO; + result=-EIO; + goto out; } resp_code=chsc_area->response_block.response_code; @@ -2435,7 +2617,10 @@ } QDIO_DBF_TEXT2(0,trace,"delytrgt"); QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); - return 0; + result=0; +out: + spin_unlock_irqrestore(&chsc_area_lock,flags); + return result; } int qdio_cleanup(int irq,int how) @@ -2445,7 +2630,7 @@ int do_an_irqrestore=0; unsigned long flags; int timeout; - char dbf_text[15]="12345678"; + char dbf_text[15]; result=0; sprintf(dbf_text,"qcln%4x",irq); @@ -2455,7 +2640,7 @@ irq_ptr=qdio_get_irq_ptr(irq); if (!irq_ptr) return -ENODEV; - spin_lock(&irq_ptr->setting_up_lock); + down(&irq_ptr->setting_up_lock); /* mark all qs as uninteresting */ for (i=0;ino_input_qs;i++) { @@ -2527,7 +2712,7 @@ if (do_an_irqrestore) s390irq_spin_unlock_irqrestore(irq,flags); - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); qdio_remove_irq_ptr(irq_ptr); qdio_release_irq_memory(irq_ptr); @@ -2574,16 +2759,15 @@ int result,result2; int found; unsigned long flags; - char dbf_text[20]; /* if a printf would print out more than 8 chars */ + char dbf_text[20]; /* if a printf printed out more than 8 chars */ - down_interruptible(&init_sema); + down(&init_sema); sprintf(dbf_text,"qini%4x",init_data->irq); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); sprintf(dbf_text,"qfmt:%x",init_data->q_format); QDIO_DBF_TEXT0(0,setup,dbf_text); - QDIO_DBF_TEXT0(0,setup,init_data->adapter_name); QDIO_DBF_HEX0(0,setup,init_data->adapter_name,8); sprintf(dbf_text,"qpff%4x",init_data->qib_param_field_format); QDIO_DBF_TEXT0(0,setup,dbf_text); @@ -2672,7 +2856,6 @@ irq_ptr->qdr=kmalloc(sizeof(qdr_t),GFP_DMA); if (!(irq_ptr->qdr)) { - kfree(irq_ptr->qdr); kfree(irq_ptr); QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); result=-ENOMEM; @@ -2736,12 +2919,12 @@ qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE); - irq_ptr->setting_up_lock=SPIN_LOCK_UNLOCKED; + sema_init(&irq_ptr->setting_up_lock,1); MOD_INC_USE_COUNT; QDIO_DBF_TEXT3(0,setup,"MOD_INC_"); - spin_lock(&irq_ptr->setting_up_lock); + down(&irq_ptr->setting_up_lock); qdio_insert_irq_ptr(irq_ptr); @@ -2867,10 +3050,10 @@ } result=tiqdio_set_subchannel_ind(irq_ptr,0); if (result) { - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); qdio_cleanup(irq_ptr->irq, QDIO_FLAG_CLEANUP_USING_CLEAR); - goto out2; + goto out; } tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET); } @@ -2906,9 +3089,9 @@ s390irq_spin_unlock_irqrestore(irq_ptr->irq,saveflags); if (result) { - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR); - goto out2; + goto out; } result=qdio_sleepon(&irq_ptr->interrupt_has_arrived, @@ -2918,9 +3101,9 @@ QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n", irq_ptr->irq); QDIO_DBF_TEXT2(1,setup,"eq:timeo"); - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR); - goto out2; + goto out; } if (!(irq_ptr->io_result_dstat & DEV_STAT_DEV_END)) { @@ -2937,10 +3120,10 @@ irq_ptr->irq,irq_ptr->io_result_dstat, irq_ptr->io_result_cstat, irq_ptr->io_result_flags); - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR); result=-EIO; - goto out2; + goto out; } if (irq_ptr->io_result_dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) { @@ -2958,18 +3141,19 @@ irq_ptr->io_result_cstat, irq_ptr->io_result_flags); result=-EIO; + up(&irq_ptr->setting_up_lock); goto out; } - if (MACHINE_IS_VM) irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq); - else { - irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY - | CHSC_FLAG_SIGA_OUTPUT_NECESSARY; - } sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac); QDIO_DBF_TEXT2(0,setup,dbf_text); + /* if this gets set once, we're running under VM and can omit SVSes */ + if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY) { + omit_svs=1; + } + sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac); QDIO_DBF_TEXT2(0,setup,dbf_text); @@ -3026,11 +3210,10 @@ qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); - out: if (irq_ptr) { - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); } - out2: + out: up(&init_sema); return result; @@ -3046,7 +3229,7 @@ irq_ptr=qdio_get_irq_ptr(irq); if (!irq_ptr) return -ENODEV; - spin_lock(&irq_ptr->setting_up_lock); + down(&irq_ptr->setting_up_lock); if (irq_ptr->state==QDIO_IRQ_STATE_INACTIVE) { result=-EBUSY; goto out; @@ -3141,14 +3324,15 @@ qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ACTIVE); out: - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_lock); return result; } /* buffers filled forwards again to make Rick happy */ -static void qdio_do_qdio_fill_input(qdio_q_t *q,unsigned int qidx, - unsigned int count,qdio_buffer_t *buffers) +static inline void qdio_do_qdio_fill_input(qdio_q_t *q,unsigned int qidx, + unsigned int count, + qdio_buffer_t *buffers) { for (;;) { if (!q->is_0copy_sbals_q) { @@ -3281,7 +3465,7 @@ qdio_kick_outbound_q(q); } - qdio_outbound_processing(q); + __qdio_outbound_processing(q); } else { /* under VM, we do a SIGA sync * unconditionally */ @@ -3309,7 +3493,7 @@ * too long, the upper layer * module could do a lot of * traffic in that time */ - qdio_outbound_processing(q); + __qdio_outbound_processing(q); } } @@ -3349,7 +3533,7 @@ perf_stats.siga_ins); _OUTP_IT("Number of SIGA out's issued : %u\n", perf_stats.siga_outs); - _OUTP_IT("Number of PCI's caught : %u\n", + _OUTP_IT("Number of PCIs caught : %u\n", perf_stats.pcis); _OUTP_IT("Number of adapter interrupts caught : %u\n", perf_stats.thinints); @@ -3576,10 +3760,12 @@ qdio_add_procfs_entry(); - hydra_thinints=qdio_check_for_hydra_thinints(); + qdio_check_for_machine_features(); sprintf(dbf_text,"hydrati%1x",hydra_thinints); QDIO_DBF_TEXT0(0,setup,dbf_text); + sprintf(dbf_text,"omitsvs%1x",omit_svs); + QDIO_DBF_TEXT0(0,setup,dbf_text); tiqdio_register_thinints(); diff -urN linux-2.4.27/drivers/s390/s390io.c linux-2.4.28/drivers/s390/s390io.c --- linux-2.4.27/drivers/s390/s390io.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/s390/s390io.c 2004-11-17 03:54:21.526394934 -0800 @@ -1,7 +1,7 @@ /* * drivers/s390/s390io.c * S/390 common I/O routines - * $Revision: 1.258 $ + * $Revision: 1.247.4.4 $ * * S390 version * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, @@ -3043,7 +3043,16 @@ if (!ioinfo[irq]->ui.flags.ready) return (ending_status); - memcpy (udp, &(ioinfo[irq]->devstat), sdevstat); + /* + * Special case: We got a deferred cc 3 on a basic sense. + * We have to notify the device driver of the former unit + * check, but must not confuse it by calling it with the status + * for the failed basic sense. + */ + if (ioinfo[irq]->ui.flags.w4sense) + ioinfo[irq]->ui.flags.w4sense = 0; + else + memcpy (udp, &(ioinfo[irq]->devstat), sdevstat); ioinfo[irq]->devstat.intparm = 0; diff -urN linux-2.4.27/drivers/sbus/char/bpp.c linux-2.4.28/drivers/sbus/char/bpp.c --- linux-2.4.27/drivers/sbus/char/bpp.c 2001-10-11 09:43:29.000000000 -0700 +++ linux-2.4.28/drivers/sbus/char/bpp.c 2004-11-17 03:54:21.528395016 -0800 @@ -1073,3 +1073,5 @@ module_init(bpp_init); module_exit(bpp_cleanup); + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/sbus/char/vfc_dev.c linux-2.4.28/drivers/sbus/char/vfc_dev.c --- linux-2.4.27/drivers/sbus/char/vfc_dev.c 2001-08-12 10:38:48.000000000 -0700 +++ linux-2.4.28/drivers/sbus/char/vfc_dev.c 2004-11-17 03:54:21.528395016 -0800 @@ -743,4 +743,4 @@ } #endif - +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/scsi/53c7,8xx.c linux-2.4.28/drivers/scsi/53c7,8xx.c --- linux-2.4.27/drivers/scsi/53c7,8xx.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/scsi/53c7,8xx.c 2004-11-17 03:54:21.568396660 -0800 @@ -3926,7 +3926,7 @@ restore_flags (flags); cmd->result = le32_to_cpu(0xffff); /* The NCR will overwrite message and status with valid data */ - cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd); + cmd->host_scribble = (unsigned char *) create_cmd (cmd); } cli(); /* diff -urN linux-2.4.27/drivers/scsi/53c700.h linux-2.4.28/drivers/scsi/53c700.h --- linux-2.4.27/drivers/scsi/53c700.h 2002-02-25 11:38:04.000000000 -0800 +++ linux-2.4.28/drivers/scsi/53c700.h 2004-11-17 03:54:21.569396702 -0800 @@ -109,8 +109,11 @@ static inline void NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer) { - ((unsigned long)SDp->hostdata) &= 0xffffff00; - ((unsigned long)SDp->hostdata) |= sxfer & 0xff; + long l = (long)SDp->hostdata; + + l &= 0xffffff00; + l |= sxfer & 0xff; + SDp->hostdata = (void *)l; } static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp) { @@ -119,8 +122,11 @@ static inline void NCR_700_set_depth(Scsi_Device *SDp, __u8 depth) { - ((unsigned long)SDp->hostdata) &= 0xffff00ff; - ((unsigned long)SDp->hostdata) |= (0xff00 & (depth << 8)); + long l = (long)SDp->hostdata; + + l &= 0xffff00ff; + l |= 0xff00 & (depth << 8); + SDp->hostdata = (void *)l; } static inline __u8 NCR_700_get_depth(Scsi_Device *SDp) @@ -140,12 +146,12 @@ static inline void NCR_700_set_flag(Scsi_Device *SDp, __u32 flag) { - ((unsigned long)SDp->hostdata) |= (flag & 0xffff0000); + SDp->hostdata = (void *)((long)SDp->hostdata | (flag & 0xffff0000)); } static inline void NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag) { - ((unsigned long)SDp->hostdata) &= ~(flag & 0xffff0000); + SDp->hostdata = (void *)((long)SDp->hostdata & ~(flag & 0xffff0000)); } /* These represent the Nexus hashing functions. A Nexus in SCSI terms diff -urN linux-2.4.27/drivers/scsi/AM53C974.c linux-2.4.28/drivers/scsi/AM53C974.c --- linux-2.4.27/drivers/scsi/AM53C974.c 2001-09-30 12:26:07.000000000 -0700 +++ linux-2.4.28/drivers/scsi/AM53C974.c 2004-11-17 03:54:21.593397688 -0800 @@ -1027,6 +1027,78 @@ spin_unlock_irqrestore(&io_request_lock, flags); } +/************************************************************************** +* Function : AM53C974_set_async(struct Scsi_Host *instance, int target) +* +* Purpose : put controller into async. mode +* +* Inputs : instance -- which AM53C974 +* target -- which SCSI target to deal with +* +* Returns : nothing +**************************************************************************/ +static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target) +{ + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + + AM53C974_write_8(STPREG, hostdata->sync_per[target]); + AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); +} + +/************************************************************************** +* Function : AM53C974_set_sync(struct Scsi_Host *instance, int target) +* +* Purpose : put controller into sync. mode +* +* Inputs : instance -- which AM53C974 +* target -- which SCSI target to deal with +* +* Returns : nothing +**************************************************************************/ +static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target) +{ + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + + AM53C974_write_8(STPREG, hostdata->sync_per[target]); + AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) | + (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); +} + +/************************************************************************** +* Function : AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, +* unsigned long length, char *data) +* +* Purpose : setup DMA transfer +* +* Inputs : instance -- which AM53C974 +* dir -- direction flag, 0: write to device, read from memory; +* 1: read from device, write to memory +* length -- number of bytes to transfer to from buffer +* data -- pointer to data buffer +* +* Returns : nothing +**************************************************************************/ +static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, + unsigned long length, char *data) +{ + AM53C974_local_declare(); + AM53C974_setio(instance); + + AM53C974_write_8(CMDREG, CMDREG_NOP); + AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D); /* idle command */ + AM53C974_write_8(STCLREG, (unsigned char) (length & 0xff)); + AM53C974_write_8(STCMREG, (unsigned char) ((length & 0xff00) >> 8)); + AM53C974_write_8(STCHREG, (unsigned char) ((length & 0xff0000) >> 16)); + AM53C974_write_32(DMASTC, length & 0xffffff); + AM53C974_write_32(DMASPA, virt_to_bus(data)); + AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA); + AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START); +} + /************************************************************************ * Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) * * * @@ -1464,47 +1536,6 @@ return (0); } -/************************************************************************** -* Function : AM53C974_set_async(struct Scsi_Host *instance, int target) -* -* Purpose : put controller into async. mode -* -* Inputs : instance -- which AM53C974 -* target -- which SCSI target to deal with -* -* Returns : nothing -**************************************************************************/ -static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target) -{ - AM53C974_local_declare(); - struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; - AM53C974_setio(instance); - - AM53C974_write_8(STPREG, hostdata->sync_per[target]); - AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); -} - -/************************************************************************** -* Function : AM53C974_set_sync(struct Scsi_Host *instance, int target) -* -* Purpose : put controller into sync. mode -* -* Inputs : instance -- which AM53C974 -* target -- which SCSI target to deal with -* -* Returns : nothing -**************************************************************************/ -static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target) -{ - AM53C974_local_declare(); - struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; - AM53C974_setio(instance); - - AM53C974_write_8(STPREG, hostdata->sync_per[target]); - AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) | - (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); -} - /*********************************************************************** * Function : AM53C974_information_transfer(struct Scsi_Host *instance, * * unsigned char statreg, unsigned char isreg, * @@ -2157,37 +2188,6 @@ } /************************************************************************** -* Function : AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, -* unsigned long length, char *data) -* -* Purpose : setup DMA transfer -* -* Inputs : instance -- which AM53C974 -* dir -- direction flag, 0: write to device, read from memory; -* 1: read from device, write to memory -* length -- number of bytes to transfer to from buffer -* data -- pointer to data buffer -* -* Returns : nothing -**************************************************************************/ -static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, - unsigned long length, char *data) -{ - AM53C974_local_declare(); - AM53C974_setio(instance); - - AM53C974_write_8(CMDREG, CMDREG_NOP); - AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D); /* idle command */ - AM53C974_write_8(STCLREG, (unsigned char) (length & 0xff)); - AM53C974_write_8(STCMREG, (unsigned char) ((length & 0xff00) >> 8)); - AM53C974_write_8(STCHREG, (unsigned char) ((length & 0xff0000) >> 16)); - AM53C974_write_32(DMASTC, length & 0xffffff); - AM53C974_write_32(DMASPA, virt_to_bus(data)); - AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA); - AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START); -} - -/************************************************************************** * Function : AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus, * unsigned char statreg) * diff -urN linux-2.4.27/drivers/scsi/Config.in linux-2.4.28/drivers/scsi/Config.in --- linux-2.4.27/drivers/scsi/Config.in 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/Config.in 2004-11-17 03:54:21.594397729 -0800 @@ -70,10 +70,13 @@ dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI dep_mbool 'Serial ATA (SATA) support' CONFIG_SCSI_SATA $CONFIG_SCSI dep_tristate ' ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL +dep_tristate ' Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI +dep_tristate ' NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI dep_tristate ' Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' SiS 964/180 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIS $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL +dep_tristate ' ULi Electronics SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_ULI $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' VIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_VIA $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Vitesse VSC-7174 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_VITESSE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL diff -urN linux-2.4.27/drivers/scsi/Makefile linux-2.4.28/drivers/scsi/Makefile --- linux-2.4.27/drivers/scsi/Makefile 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/Makefile 2004-11-17 03:54:21.594397729 -0800 @@ -131,12 +131,15 @@ obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o +obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o +obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o +obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o subdir-$(CONFIG_ARCH_ACORN) += ../acorn/scsi obj-$(CONFIG_ARCH_ACORN) += ../acorn/scsi/acorn-scsi.o diff -urN linux-2.4.27/drivers/scsi/advansys.c linux-2.4.28/drivers/scsi/advansys.c --- linux-2.4.27/drivers/scsi/advansys.c 2004-04-14 06:05:31.000000000 -0700 +++ linux-2.4.28/drivers/scsi/advansys.c 2004-11-17 03:54:21.622398881 -0800 @@ -6118,8 +6118,8 @@ } 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); + last_scp->host_scribble = (unsigned char *)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)) { @@ -6141,8 +6141,8 @@ } 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); + last_scp->host_scribble = (unsigned char *)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)) { @@ -6394,8 +6394,8 @@ ASC_TID_ALL); } else { ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done, - &new_last_scp, ASC_TID_ALL); + last_scp->host_scribble = (unsigned char *)asc_dequeue_list( + &boardp->done, &new_last_scp, ASC_TID_ALL); if (new_last_scp != NULL) { ASC_ASSERT(REQPNEXT(last_scp) != NULL); last_scp = new_last_scp; @@ -6466,7 +6466,7 @@ while (scp != NULL) { ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp); tscp = REQPNEXT(scp); - REQPNEXT(scp) = NULL; + scp->host_scribble = NULL; ASC_STATS(scp->host, done); ASC_ASSERT(scp->scsi_done != NULL); scp->scsi_done(scp); @@ -7511,7 +7511,7 @@ tid = REQPTID(reqp); ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if (flag == ASC_FRONT) { - REQPNEXT(reqp) = ascq->q_first[tid]; + reqp->host_scribble = (unsigned char *)ascq->q_first[tid]; ascq->q_first[tid] = reqp; /* If the queue was empty, set the last pointer. */ if (ascq->q_last[tid] == NULL) { @@ -7519,10 +7519,10 @@ } } else { /* ASC_BACK */ if (ascq->q_last[tid] != NULL) { - REQPNEXT(ascq->q_last[tid]) = reqp; + ascq->q_last[tid]->host_scribble = (unsigned char *)reqp; } ascq->q_last[tid] = reqp; - REQPNEXT(reqp) = NULL; + reqp->host_scribble = NULL; /* If the queue was empty, set the first pointer. */ if (ascq->q_first[tid] == NULL) { ascq->q_first[tid] = reqp; @@ -7643,7 +7643,7 @@ lastp = ascq->q_last[i]; } else { ASC_ASSERT(lastp != NULL); - REQPNEXT(lastp) = ascq->q_first[i]; + lastp->host_scribble = (unsigned char *)ascq->q_first[i]; lastp = ascq->q_last[i]; } ascq->q_first[i] = ascq->q_last[i] = NULL; @@ -7721,8 +7721,8 @@ currp; prevp = currp, currp = REQPNEXT(currp)) { if (currp == reqp) { ret = ASC_TRUE; - REQPNEXT(prevp) = REQPNEXT(currp); - REQPNEXT(reqp) = NULL; + prevp->host_scribble = (unsigned char *)REQPNEXT(currp); + reqp->host_scribble = NULL; if (ascq->q_last[tid] == reqp) { ascq->q_last[tid] = prevp; } diff -urN linux-2.4.27/drivers/scsi/aic7xxx/aic79xx_osm.c linux-2.4.28/drivers/scsi/aic7xxx/aic79xx_osm.c --- linux-2.4.27/drivers/scsi/aic7xxx/aic79xx_osm.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/scsi/aic7xxx/aic79xx_osm.c 2004-11-17 03:54:21.627399086 -0800 @@ -2931,6 +2931,19 @@ ahd_unlock(ahd, &s); } +static __inline int +ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) +{ + u_long s; + int retval; + + ahd_lock(ahd, &s); + retval = ahd_linux_fallback(ahd, devinfo); + ahd_unlock(ahd, &s); + + return (retval); +} + static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, @@ -3567,19 +3580,6 @@ cmd->cmnd[4] = le | SSS_START; } -static __inline int -ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_long s; - int retval; - - ahd_lock(ahd, &s); - retval = ahd_linux_fallback(ahd, devinfo); - ahd_unlock(ahd, &s); - - return (retval); -} - static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { diff -urN linux-2.4.27/drivers/scsi/aic7xxx/aic79xx_osm_pci.c linux-2.4.28/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- linux-2.4.27/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2004-11-17 03:54:21.628399127 -0800 @@ -52,9 +52,12 @@ const struct pci_device_id *ent); static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, u_long *base2); +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, uint8_t **maddr); +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); @@ -271,6 +274,7 @@ return (0); } +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, @@ -318,6 +322,7 @@ error = ENOMEM; return (error); } +#endif int ahd_pci_map_registers(struct ahd_softc *ahd) diff -urN linux-2.4.27/drivers/scsi/ata_piix.c linux-2.4.28/drivers/scsi/ata_piix.c --- linux-2.4.27/drivers/scsi/ata_piix.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/scsi/ata_piix.c 2004-11-17 03:54:21.629399169 -0800 @@ -0,0 +1,682 @@ +/* + + ata_piix.c - Intel PATA/SATA controllers + + Maintained by: Jeff Garzik + Please ALWAYS copy linux-ide@vger.kernel.org + on emails. + + + Copyright 2003-2004 Red Hat Inc + Copyright 2003-2004 Jeff Garzik + + + Copyright header from piix.c: + + Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + Copyright (C) 1998-2000 Andre Hedrick + Copyright (C) 2003 Red Hat Inc + + May be copied or modified under the terms of the GNU General Public License + + */ + +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "ata_piix" +#define DRV_VERSION "1.02" + +enum { + PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ + ICH5_PMR = 0x90, /* port mapping register */ + ICH5_PCS = 0x92, /* port control and status */ + + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ + PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ + PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ + + /* combined mode. if set, PATA is channel 0. + * if clear, PATA is channel 1. + */ + PIIX_COMB_PATA_P0 = (1 << 1), + PIIX_COMB = (1 << 2), /* combined mode enabled? */ + + PIIX_PORT_PRESENT = (1 << 0), + PIIX_PORT_ENABLED = (1 << 4), + + PIIX_80C_PRI = (1 << 5) | (1 << 4), + PIIX_80C_SEC = (1 << 7) | (1 << 6), + + ich5_pata = 0, + ich5_sata = 1, + piix4_pata = 2, + ich6_sata = 3, + ich6_sata_rm = 4, +}; + +static int piix_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); + +static void piix_pata_phy_reset(struct ata_port *ap); +static void piix_sata_phy_reset(struct ata_port *ap); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); + +static unsigned int in_module_init = 1; + +static struct pci_device_id piix_pci_tbl[] = { +#ifdef ATA_ENABLE_PATA + { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, + { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, + { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, +#endif + + /* NOTE: The following PCI ids must be kept in sync with the + * list in drivers/pci/quirks.c. + */ + + { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + + { } /* terminate list */ +}; + +static struct pci_driver piix_pci_driver = { + .name = DRV_NAME, + .id_table = piix_pci_tbl, + .probe = piix_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template piix_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .use_new_eh_code = ATA_SHT_NEW_EH_CODE, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations piix_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = piix_set_piomode, + .set_dmamode = piix_set_dmamode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .phy_reset = piix_pata_phy_reset, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static struct ata_port_operations piix_sata_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .phy_reset = piix_sata_phy_reset, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static struct ata_port_info piix_port_info[] = { + /* ich5_pata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + PIIX_FLAG_CHECKINTR, + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &piix_pata_ops, + }, + + /* ich5_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* piix4_pata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif + .udma_mask = ATA_UDMA_MASK_40C, + .port_ops = &piix_pata_ops, + }, + + /* ich6_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, +}; + +static struct pci_bits piix_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ +}; + +MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik"); +MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, piix_pci_tbl); + +/** + * piix_pata_cbl_detect - Probe host controller cable detect info + * @ap: Port for which cable detect info is desired + * + * Read 80c cable indicator from ATA PCI device's PCI config + * register. This register is normally set by firmware (BIOS). + * + * LOCKING: + * None (inherited from caller). + */ +static void piix_pata_cbl_detect(struct ata_port *ap) +{ + struct pci_dev *pdev = ap->host_set->pdev; + u8 tmp, mask; + + /* no 80c support in host controller? */ + if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) + goto cbl40; + + /* check BIOS cable detect results */ + mask = ap->hard_port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; + pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); + if ((tmp & mask) == 0) + goto cbl40; + + ap->cbl = ATA_CBL_PATA80; + return; + +cbl40: + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; +} + +/** + * piix_pata_phy_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * Probe PATA phy. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_pata_phy_reset(struct ata_port *ap) +{ + if (!pci_test_config_bits(ap->host_set->pdev, + &piix_enable_bits[ap->hard_port_no])) { + ata_port_disable(ap); + printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + return; + } + + piix_pata_cbl_detect(ap); + + ata_port_probe(ap); + + ata_bus_reset(ap); +} + +/** + * piix_sata_probe - Probe PCI device for present SATA devices + * @ap: Port associated with the PCI device we wish to probe + * + * Reads SATA PCI device's PCI config register Port Configuration + * and Status (PCS) to determine port and device availability. + * + * LOCKING: + * None (inherited from caller). + * + * RETURNS: + * Non-zero if device detected, zero otherwise. + */ +static int piix_sata_probe (struct ata_port *ap) +{ + struct pci_dev *pdev = ap->host_set->pdev; + int combined = (ap->flags & ATA_FLAG_SLAVE_POSS); + int orig_mask, mask, i; + u8 pcs; + + mask = (PIIX_PORT_PRESENT << ap->hard_port_no) | + (PIIX_PORT_ENABLED << ap->hard_port_no); + + pci_read_config_byte(pdev, ICH5_PCS, &pcs); + orig_mask = (int) pcs & 0xff; + + /* TODO: this is vaguely wrong for ICH6 combined mode, + * where only two of the four SATA ports are mapped + * onto a single ATA channel. It is also vaguely inaccurate + * for ICH5, which has only two ports. However, this is ok, + * as further device presence detection code will handle + * any false positives produced here. + */ + + for (i = 0; i < 4; i++) { + mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i); + + if ((orig_mask & mask) == mask) + if (combined || (i == ap->hard_port_no)) + return 1; + } + + return 0; +} + +/** + * piix_sata_phy_reset - Probe specified port on SATA host controller + * @ap: Port to probe + * + * Probe SATA phy. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_sata_phy_reset(struct ata_port *ap) +{ + if (!piix_sata_probe(ap)) { + ata_port_disable(ap); + printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); + return; + } + + ap->cbl = ATA_CBL_SATA; + + ata_port_probe(ap); + + ata_bus_reset(ap); +} + +/** + * piix_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * @pio: PIO mode, 0 - 4 + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = ap->host_set->pdev; + unsigned int is_slave = (adev->devno != 0); + unsigned int master_port= ap->hard_port_no ? 0x42 : 0x40; + unsigned int slave_port = 0x44; + u16 master_data; + u8 slave_data; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + if (is_slave) { + master_data |= 0x4000; + /* enable PPE, IE and TIME */ + master_data |= 0x0070; + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= (ap->hard_port_no ? 0x0f : 0xf0); + slave_data |= + (timings[pio][0] << 2) | + (timings[pio][1] << (ap->hard_port_no ? 4 : 0)); + } else { + master_data &= 0xccf8; + /* enable PPE, IE and TIME */ + master_data |= 0x0007; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); +} + +/** + * piix_set_dmamode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * @udma: udma mode, 0 - 6 + * + * Set UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ + struct pci_dev *dev = ap->host_set->pdev; + u8 maslave = ap->hard_port_no ? 0x42 : 0x40; + u8 speed = udma; + unsigned int drive_dn = (ap->hard_port_no ? 2 : 0) + adev->devno; + int a_speed = 3 << (drive_dn * 4); + int u_flag = 1 << drive_dn; + int v_flag = 0x01 << drive_dn; + int w_flag = 0x10 << drive_dn; + int u_speed = 0; + int sitre; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + + pci_read_config_word(dev, maslave, ®4042); + DPRINTK("reg4042 = 0x%04x\n", reg4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break; + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; + default: + BUG(); + return; + } + + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + } else { + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } +} + +/* move to PCI layer, integrate w/ MSI stuff */ +static void pci_enable_intx(struct pci_dev *pdev) +{ + u16 pci_command; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_INTX_DISABLE) { + pci_command &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } +} + +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + +/** + * piix_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in piix_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_port_info *port_info[2]; + unsigned int combined = 0, n_ports = 1; + unsigned int pata_chan = 0, sata_chan = 0; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + /* no hotplugging support (FIXME) */ + if (!in_module_init) + return -ENODEV; + + port_info[0] = &piix_port_info[ent->driver_data]; + port_info[1] = NULL; + + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } + + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { + u8 tmp; + pci_read_config_byte(pdev, ICH5_PMR, &tmp); + + if (tmp & PIIX_COMB) { + combined = 1; + if (tmp & PIIX_COMB_PATA_P0) + sata_chan = 1; + else + pata_chan = 1; + } + } + + /* On ICH5, some BIOSen disable the interrupt using the + * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. + * On ICH6, this bit has the same effect, but only when + * MSI is disabled (and it is disabled, as we don't use + * message-signalled interrupts currently). + */ + if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR) + pci_enable_intx(pdev); + + if (combined) { + port_info[sata_chan] = &piix_port_info[ent->driver_data]; + port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS; + port_info[pata_chan] = &piix_port_info[ich5_pata]; + n_ports++; + + printk(KERN_ERR DRV_NAME ": combined mode not supported\n"); + return -ENODEV; + } + + return ata_pci_init_one(pdev, port_info, n_ports); +} + +/** + * piix_init - + * + * LOCKING: + * + * RETURNS: + * + */ + +static int __init piix_init(void) +{ + int rc; + + DPRINTK("pci_module_init\n"); + rc = pci_module_init(&piix_pci_driver); + if (rc) + return rc; + + in_module_init = 0; + + DPRINTK("scsi_register_host\n"); + rc = scsi_register_module(MODULE_SCSI_HA, &piix_sht); + if (rc) { + rc = -ENODEV; + goto err_out; + } + + DPRINTK("done\n"); + return 0; + +err_out: + pci_unregister_driver(&piix_pci_driver); + return rc; +} + +/** + * piix_exit - + * + * LOCKING: + * + */ + +static void __exit piix_exit(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &piix_sht); + pci_unregister_driver(&piix_pci_driver); +} + +module_init(piix_init); +module_exit(piix_exit); + diff -urN linux-2.4.27/drivers/scsi/dpt_i2o.c linux-2.4.28/drivers/scsi/dpt_i2o.c --- linux-2.4.27/drivers/scsi/dpt_i2o.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/scsi/dpt_i2o.c 2004-11-17 03:54:21.631399251 -0800 @@ -434,7 +434,7 @@ cmd->scsi_done(cmd); return 0; } - (struct adpt_device*)(cmd->device->hostdata) = pDev; + cmd->device->hostdata = pDev; } pDev->pScsi_dev = cmd->device; @@ -2194,7 +2194,7 @@ printk ("%s: scsi_register returned NULL\n",pHba->name); return -1; } - (adpt_hba*)(host->hostdata[0]) = pHba; + host->hostdata[0] = (unsigned long)pHba; pHba->host = host; host->irq = pHba->pDev->irq;; diff -urN linux-2.4.27/drivers/scsi/esp.c linux-2.4.28/drivers/scsi/esp.c --- linux-2.4.27/drivers/scsi/esp.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/scsi/esp.c 2004-11-17 03:54:21.634399374 -0800 @@ -4368,4 +4368,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/scsi/fcal.c linux-2.4.28/drivers/scsi/fcal.c --- linux-2.4.27/drivers/scsi/fcal.c 2001-02-09 11:30:23.000000000 -0800 +++ linux-2.4.28/drivers/scsi/fcal.c 2004-11-17 03:54:21.635399415 -0800 @@ -300,4 +300,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/scsi/gdth.c linux-2.4.28/drivers/scsi/gdth.c --- linux-2.4.27/drivers/scsi/gdth.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/scsi/gdth.c 2004-11-17 03:54:21.649399991 -0800 @@ -4,11 +4,14 @@ * Intel Corporation: Storage RAID Controllers * * * * gdth.c * - * Copyright (C) 1995-02 ICP vortex, an Intel company, Achim Leubner * - * * + * Copyright (C) 1995-04 ICP vortex GmbH, Achim Leubner * + * Copyright (C) 2002-03 Intel Corporation * + * Copyright (C) 2003-04 Adaptec Inc. * + * * * * - * Additions/Fixes: Boji Tony Kannanthanam * - * * + * Additions/Fixes: * + * Boji Tony Kannanthanam * + * Johannes Dinner * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published * @@ -24,11 +27,57 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Tested with Linux 1.2.13, ..., 2.2.20, ..., 2.4.18 * + * Linux kernel 2.2.x, 2.4.x, 2.6.x supported * * * * $Log: gdth.c,v $ - * Revision 1.61 2002/10/03 09:35:22 boji - * Fixed SCREENSERVICE intialisation in SMP cases. + * Revision 1.73 2004/03/31 13:33:03 achim + * Special command 0xfd implemented to detect 64-bit DMA support + * + * Revision 1.72 2004/03/17 08:56:04 achim + * 64-bit DMA only enabled if FW >= x.43 + * + * Revision 1.71 2004/03/05 15:51:29 achim + * Screen service: separate message buffer, bugfixes + * + * Revision 1.70 2004/02/27 12:19:07 achim + * Bugfix: Reset bit in config (0xfe) call removed + * + * Revision 1.69 2004/02/20 09:50:24 achim + * Compatibility changes for kernels < 2.4.20 + * Bugfix screen service command size + * pci_set_dma_mask() error handling added + * + * Revision 1.68 2004/02/19 15:46:54 achim + * 64-bit DMA bugfixes + * Drive size bugfix for drives > 1TB + * + * Revision 1.67 2004/01/14 13:11:57 achim + * Tool access over /proc no longer supported + * Bugfixes IOCTLs + * + * Revision 1.66 2003/12/19 15:04:06 achim + * Bugfixes support for drives > 2TB + * + * Revision 1.65 2003/12/15 11:21:56 achim + * 64-bit DMA support added + * Support for drives > 2 TB implemented + * Kernels 2.2.x, 2.4.x, 2.6.x supported + * + * Revision 1.64 2003/09/17 08:30:26 achim + * EISA/ISA controller scan disabled + * Command line switch probe_eisa_isa added + * + * Revision 1.63 2003/07/12 14:01:00 Daniele Bellucci + * Minor cleanups in gdth_ioctl. + * + * Revision 1.62 2003/02/27 15:01:59 achim + * Dynamic DMA mapping implemented + * New (character device) IOCTL interface added + * Other controller related changes made + * + * Revision 1.61 2002/11/08 13:09:52 boji + * Added support for XSCALE based RAID Controllers + * Fixed SCREENSERVICE initialization in SMP cases * Added checks for gdth_polling before GDTH_HA_LOCK * * Revision 1.60 2002/02/05 09:35:22 achim @@ -216,7 +265,7 @@ * * Revision 1.9 1997/09/04 10:07:25 achim * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ... - * register_reboot_notifier() to get a notify on shutdown used + * register_reboot_notifier() to get a notify on shutown used * * Revision 1.8 1997/04/02 12:14:30 achim * Version 1.00 (see gdth.h), tested with kernel 2.0.29 @@ -248,7 +297,6 @@ * Initial revision * ************************************************************************/ -#ident "$Id: gdth.c,v 1.60 2002/02/05 09:35:22 achim Exp $" /* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the @@ -282,10 +330,14 @@ * access a shared resource from several nodes, * appropiate controller firmware required * shared_access:N enable driver reserve/release protocol + * probe_eisa_isa:Y scan for EISA/ISA controllers + * probe_eisa_isa:N do not scan for EISA/ISA controllers + * force_dma32:Y use only 32 bit DMA mode + * force_dma32:N use 64 bit DMA mode, if supported * * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, * max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0, - * shared_access:Y". + * shared_access:Y,probe_eisa_isa:N,force_dma32:N". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". * * When loading the gdth driver as a module, the same options are available. @@ -295,22 +347,31 @@ * '1' in place of 'Y' and '0' in place of 'N'. * * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 - * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0" + * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 + * probe_eisa_isa=0 force_dma32=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". */ /* The meaning of the Scsi_Pointer members in this driver is as follows: - * ptr: Chaining - * this_residual: Command priority - * buffer: Unused - * buffers_residual: Timeout value - * Status: Command status (gdth_do_cmd()) - * Message: Additional info (gdth_do_cmd()) - * have_data_in: Flag for gdth_wait_completion() - * sent_command: Opcode special command - * phase: Service/parameter/return code special command + * ptr: Chaining + * this_residual: Command priority + * buffer: phys. DMA sense buffer + * dma_handle: phys. DMA buffer (kernel >= 2.4.0) + * buffers_residual: Timeout value + * Status: Command status (gdth_do_cmd()), DMA mem. mappings + * Message: Additional info (gdth_do_cmd()), DMA direction + * have_data_in: Flag for gdth_wait_completion() + * sent_command: Opcode special command + * phase: Service/parameter/return code special command */ + +/* interrupt coalescing */ +/* #define INT_COAL */ + +/* statistics */ +#define GDTH_STATISTICS + #include #include @@ -322,6 +383,7 @@ #include #include #include +#include #include #include #include @@ -329,38 +391,34 @@ #ifdef GDTH_RTC #include #endif -#if LINUX_VERSION_CODE >= 0x020100 #include -#else -#include -#endif #include #include #include -#if LINUX_VERSION_CODE >= 0x020322 +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include -#elif LINUX_VERSION_CODE >= 0x02015F +#else #include #endif - -#if LINUX_VERSION_CODE >= 0x010300 -#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#include #else -#include "../block/blk.h" +#include +#include "sd.h" #endif + #include "scsi.h" #include "hosts.h" -#include "sd.h" - #include "gdth.h" static void gdth_delay(int milliseconds); -static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs); -#if LINUX_VERSION_CODE >= 0x010346 -static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs); +static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs); #else -static void gdth_interrupt(int irq,struct pt_regs *regs); +static void gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs); #endif static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp); static int gdth_async_event(int hanum); @@ -377,7 +435,8 @@ gdth_evt_str *estr); static void gdth_clear_events(void); -static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count); +static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp, + char *buffer,ushort count); static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp); static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive); @@ -398,24 +457,19 @@ static void gdth_release_event(int hanum); static int gdth_wait(int hanum,int index,ulong32 time); static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, - ulong32 p2,ulong32 p3); + ulong64 p2,ulong64 p3); static int gdth_search_drives(int hanum); static int gdth_analyse_hdrive(int hanum, ushort hdrive); -static void *gdth_mmap(ulong paddr, ulong size); -static void gdth_munmap(void *addr); - static const char *gdth_ctr_name(int hanum); -#if LINUX_VERSION_CODE >= 0x010300 +static int gdth_open(struct inode *inode, struct file *filep); +static int gdth_close(struct inode *inode, struct file *filep); +static int gdth_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg); + static void gdth_flush(int hanum); -#if LINUX_VERSION_CODE >= 0x020100 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); -#else -static int halt_called = FALSE; -void gdth_halt(void); -#endif -#endif #ifdef DEBUG_GDTH static unchar DebugState = DEBUG_GDTH; @@ -500,6 +554,9 @@ #ifdef GDTH_STATISTICS static ulong32 max_rq=0, max_index=0, max_sg=0; +#ifdef INT_COAL +static ulong32 max_int_coal=0; +#endif static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; static struct timer_list gdth_timer; #endif @@ -514,80 +571,12 @@ #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) -#if LINUX_VERSION_CODE < 0x010300 -static void *gdth_mmap(ulong paddr, ulong size) -{ - if (paddr >= high_memory) - return NULL; - else - return (void *)paddr; -} -static void gdth_munmap(void *addr) -{ -} -inline ulong32 virt_to_phys(volatile void *addr) -{ - return (ulong32)addr; -} -inline void *phys_to_virt(ulong32 addr) -{ - return (void *)addr; -} -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt -#define gdth_readb(addr) (*(volatile unchar *)(addr)) -#define gdth_readw(addr) (*(volatile ushort *)(addr)) -#define gdth_readl(addr) (*(volatile ulong32 *)(addr)) -#define gdth_writeb(b,addr) (*(volatile unchar *)(addr) = (b)) -#define gdth_writew(b,addr) (*(volatile ushort *)(addr) = (b)) -#define gdth_writel(b,addr) (*(volatile ulong32 *)(addr) = (b)) -#define memset_io(a,b,c) memset((void *)(a),(b),(c)) -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -#define PCI_SLOT(devfn) ((devfn >> 3) & 0x1f) - -#elif LINUX_VERSION_CODE < 0x020100 -static int remapped = FALSE; -static void *gdth_mmap(ulong paddr, ulong size) -{ - if ( paddr >= high_memory) { - remapped = TRUE; - return vremap(paddr, size); - } else { - return (void *)paddr; - } -} -static void gdth_munmap(void *addr) -{ - if (remapped) - vfree(addr); - remapped = FALSE; -} -#define gdth_readb(addr) readb((ulong)(addr)) -#define gdth_readw(addr) readw((ulong)(addr)) -#define gdth_readl(addr) (ulong32)readl((ulong)(addr)) -#define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) -#define gdth_writew(b,addr) writew((b),(ulong)(addr)) -#define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) - -#else -static void *gdth_mmap(ulong paddr, ulong size) -{ - return ioremap(paddr, size); -} -static void gdth_munmap(void *addr) -{ - return iounmap(addr); -} #define gdth_readb(addr) readb((ulong)(addr)) #define gdth_readw(addr) readw((ulong)(addr)) #define gdth_readl(addr) (ulong32)readl((ulong)(addr)) #define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) #define gdth_writew(b,addr) writew((b),(ulong)(addr)) #define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) -#endif - static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ @@ -603,6 +592,7 @@ static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ static int elastidx; static int eoldidx; +static int major; #define DIN 1 /* IN data direction */ #define DOU 2 /* OUT data direction */ @@ -617,8 +607,8 @@ DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN, DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU, DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, @@ -628,36 +618,32 @@ }; /* __initfunc, __initdata macros */ -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define __devinitdata +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define GDTH_INITFUNC(type, func) type __init func #include -#elif LINUX_VERSION_CODE >= 0x020126 +#else #define GDTH_INITFUNC(type, func) __initfunc(type func) #include -#else -#define GDTH_INITFUNC(type, func) type func -#define __initdata -#define __init #endif -#if LINUX_VERSION_CODE >= 0x02015F +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define GDTH_INIT_LOCK_HA(ha) spin_lock_init(&(ha)->smp_lock) +#define GDTH_LOCK_HA(ha,flags) spin_lock_irqsave(&(ha)->smp_lock,flags) +#define GDTH_UNLOCK_HA(ha,flags) spin_unlock_irqrestore(&(ha)->smp_lock,flags) + +#define GDTH_LOCK_SCSI_DONE(dev, flags) spin_lock_irqsave(dev->host_lock,flags) +#define GDTH_UNLOCK_SCSI_DONE(dev, flags) spin_unlock_irqrestore(dev->host_lock,flags) + +#else #define GDTH_INIT_LOCK_HA(ha) spin_lock_init(&(ha)->smp_lock) #define GDTH_LOCK_HA(ha,flags) spin_lock_irqsave(&(ha)->smp_lock,flags) #define GDTH_UNLOCK_HA(ha,flags) spin_unlock_irqrestore(&(ha)->smp_lock,flags) #define GDTH_LOCK_SCSI_DONE(flags) spin_lock_irqsave(&io_request_lock,flags) #define GDTH_UNLOCK_SCSI_DONE(flags) spin_unlock_irqrestore(&io_request_lock,flags) -#define GDTH_LOCK_SCSI_DOCMD() spin_lock_irq(&io_request_lock) -#define GDTH_UNLOCK_SCSI_DOCMD() spin_unlock_irq(&io_request_lock) -#else -#define GDTH_INIT_LOCK_HA(ha) do {} while (0) -#define GDTH_LOCK_HA(ha,flags) do {save_flags(flags); cli();} while (0) -#define GDTH_UNLOCK_HA(ha,flags) do {restore_flags(flags);} while (0) - -#define GDTH_LOCK_SCSI_DONE(flags) do {} while (0) -#define GDTH_UNLOCK_SCSI_DONE(flags) do {} while (0) -#define GDTH_LOCK_SCSI_DOCMD() do {} while (0) -#define GDTH_UNLOCK_SCSI_DOCMD() do {} while (0) #endif /* LILO and modprobe/insmod parameters */ @@ -686,9 +672,12 @@ static int virt_ctr = 0; /* shared access */ static int shared_access = 1; +/* enable support for EISA and ISA controllers */ +static int probe_eisa_isa = 0; +/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */ +static int force_dma32 = 0; #ifdef MODULE -#if LINUX_VERSION_CODE >= 0x02011A /* parameters for modprobe/insmod */ MODULE_PARM(irq, "i"); MODULE_PARM(disable, "i"); @@ -700,32 +689,43 @@ MODULE_PARM(rescan, "i"); MODULE_PARM(virt_ctr, "i"); MODULE_PARM(shared_access, "i"); +MODULE_PARM(probe_eisa_isa, "i"); +MODULE_PARM(force_dma32, "i"); MODULE_AUTHOR("Achim Leubner"); -#endif -#if LINUX_VERSION_CODE >= 0x02040B +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,11) MODULE_LICENSE("GPL"); #endif #endif +/* ioctl interface */ +static struct file_operations gdth_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .ioctl = gdth_ioctl, + .open = gdth_open, + .release = gdth_close, +#else + ioctl:gdth_ioctl, + open:gdth_open, + release:gdth_close, +#endif +}; + /* /proc support */ -#if LINUX_VERSION_CODE >= 0x010300 #include -#if LINUX_VERSION_CODE < 0x020322 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) struct proc_dir_entry proc_scsi_gdth = { PROC_SCSI_GDTH, 4, "gdth", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #endif + #include "gdth_proc.h" #include "gdth_proc.c" -#endif -#if LINUX_VERSION_CODE >= 0x020100 /* notifier block to get a notify on system shutdown/halt/reboot */ static struct notifier_block gdth_notifier = { gdth_halt, NULL, 0 }; -#endif static void gdth_delay(int milliseconds) @@ -733,17 +733,11 @@ if (milliseconds == 0) { udelay(1); } else { -#if LINUX_VERSION_CODE >= 0x020168 mdelay(milliseconds); -#else - int i; - for (i = 0; i < milliseconds; ++i) - udelay(1000); -#endif } } -static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs) +static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs) { *cyls = size /HEADS/SECS; if (*cyls <= MAXCYLS) { @@ -788,9 +782,9 @@ ulong32 id; TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); - if ((addr = gdth_mmap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) { + if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) { id = gdth_readl(addr); - gdth_munmap(addr); + iounmap(addr); if (id == GDT2_ID) /* GDT2000 */ return 1; } @@ -812,19 +806,24 @@ gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device); gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, PCI_DEVICE_ID_VORTEX_GDTNEWRX); + gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, + PCI_DEVICE_ID_VORTEX_GDTNEWRX2); gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SRC); + gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_SRC_XSCALE); return cnt; } -#if LINUX_VERSION_CODE >= 0x20363 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Vortex only makes RAID controllers. * We do not really want to specify all 550 ids here, so wildcard match. */ -static struct pci_device_id gdthtable[] = { - {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID }, - {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID }, - {0} +static struct pci_device_id gdthtable[] __devinitdata = { + {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID}, + {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID}, + {0} }; MODULE_DEVICE_TABLE(pci,gdthtable); #endif @@ -833,17 +832,12 @@ ushort vendor, ushort device)) { ulong base0, base1, base2; -#if LINUX_VERSION_CODE >= 0x2015C struct pci_dev *pdev; -#else - int error; - ushort idx; -#endif TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n", *cnt, vendor, device)); -#if LINUX_VERSION_CODE >= 0x20363 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdev = NULL; while ((pdev = pci_find_device(vendor, device, pdev)) != NULL) { @@ -881,7 +875,7 @@ pcistr[*cnt].irq, pcistr[*cnt].dpmem)); (*cnt)++; } -#elif LINUX_VERSION_CODE >= 0x2015C +#else pdev = NULL; while ((pdev = pci_find_device(vendor, device, pdev)) != NULL) { @@ -922,66 +916,6 @@ pcistr[*cnt].irq, pcistr[*cnt].dpmem)); (*cnt)++; } -#else - idx = 0; - while (!pcibios_find_device(vendor, device, idx++, - &pcistr[*cnt].bus,&pcistr[*cnt].device_fn)) { - if (*cnt >= MAXHA) - return; - /* GDT PCI ctr. found, now read resources from config space */ -#if LINUX_VERSION_CODE >= 0x010300 -#define GDTH_BASEP (int *) -#else -#define GDTH_BASEP -#endif - if ((error = pcibios_read_config_dword(pcistr[*cnt].bus, - pcistr[*cnt].device_fn, - PCI_BASE_ADDRESS_0, - GDTH_BASEP&base0)) || - (error = pcibios_read_config_dword(pcistr[*cnt].bus, - pcistr[*cnt].device_fn, - PCI_BASE_ADDRESS_1, - GDTH_BASEP&base1)) || - (error = pcibios_read_config_dword(pcistr[*cnt].bus, - pcistr[*cnt].device_fn, - PCI_BASE_ADDRESS_2, - GDTH_BASEP&base2)) || - (error = pcibios_read_config_word(pcistr[*cnt].bus, - pcistr[*cnt].device_fn, - PCI_SUBSYSTEM_ID, - &pcistr[*cnt].subdevice_id)) || - (error = pcibios_read_config_byte(pcistr[*cnt].bus, - pcistr[*cnt].device_fn, - PCI_INTERRUPT_LINE, - &pcistr[*cnt].irq))) { - printk("GDT-PCI: error %d reading configuration space", error); - continue; - } - pcistr[*cnt].vendor_id = vendor; - pcistr[*cnt].device_id = device; - if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ - device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ - if ((base0 & PCI_BASE_ADDRESS_SPACE) != - PCI_BASE_ADDRESS_SPACE_MEMORY) - continue; - pcistr[*cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK; - } else { /* GDT6110, GDT6120, .. */ - if ((base0 & PCI_BASE_ADDRESS_SPACE) != - PCI_BASE_ADDRESS_SPACE_MEMORY || - (base2 & PCI_BASE_ADDRESS_SPACE) != - PCI_BASE_ADDRESS_SPACE_MEMORY || - (base1 & PCI_BASE_ADDRESS_SPACE) != - PCI_BASE_ADDRESS_SPACE_IO) - continue; - pcistr[*cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK; - pcistr[*cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK; - pcistr[*cnt].io = base1 & PCI_BASE_ADDRESS_IO_MASK; - } - TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", - pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn), - pcistr[*cnt].irq, pcistr[*cnt].dpmem)); - (*cnt)++; - } #endif } @@ -1111,6 +1045,8 @@ ha->type = GDT_EISA; ha->stype = id; } + + ha->dma64_support = 0; return 1; } @@ -1124,7 +1060,7 @@ TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr)); - ha->brd = gdth_mmap(bios_adr, sizeof(gdt2_dpram_str)); + ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str)); if (ha->brd == NULL) { printk("GDT-ISA: Initialization error (DPMEM remap error)\n"); return 0; @@ -1134,8 +1070,8 @@ /* reset interface area */ memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u)); if (gdth_readl(&dp2_ptr->u) != 0) { - printk("GDT-PCI: Initialization error (DPMEM write error)\n"); - gdth_munmap(ha->brd); + printk("GDT-ISA: Initialization error (DPMEM write error)\n"); + iounmap(ha->brd); return 0; } @@ -1170,7 +1106,7 @@ while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-ISA: Initialization error (DEINIT failed)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); @@ -1180,7 +1116,7 @@ gdth_writeb(0xff, &dp2_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-ISA: Illegal protocol version\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } @@ -1202,13 +1138,15 @@ while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-ISA: Initialization error\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); } gdth_writeb(0, &dp2_ptr->u.ic.Status); gdth_writeb(0xff, &dp2_ptr->io.irqdel); + + ha->dma64_support = 0; return 1; } @@ -1222,9 +1160,6 @@ unchar prot_ver; ushort command; int i, found = FALSE; -#if LINUX_VERSION_CODE < 0x2015C - int rom_addr; -#endif TRACE(("gdth_init_pci()\n")); @@ -1236,10 +1171,13 @@ ha->stype = (ulong32)pcistr->device_id; ha->subdevice_id = pcistr->subdevice_id; ha->irq = pcistr->irq; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + ha->pdev = pcistr->pdev; +#endif if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */ TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); - ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6_dpram_str)); + ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1252,8 +1190,8 @@ pcistr->dpmem); found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - gdth_munmap(ha->brd); - ha->brd = gdth_mmap(i, sizeof(ushort)); + iounmap(ha->brd); + ha->brd = ioremap(i, sizeof(ushort)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1262,15 +1200,10 @@ TRACE2(("init_pci_old() address 0x%x busy\n", i)); continue; } - gdth_munmap(ha->brd); -#if LINUX_VERSION_CODE >= 0x2015C + iounmap(ha->brd); pci_write_config_dword(pcistr->pdev, PCI_BASE_ADDRESS_0, i); -#else - pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, - PCI_BASE_ADDRESS_0, i); -#endif - ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); + ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1285,20 +1218,20 @@ } if (!found) { printk("GDT-PCI: No free address found!\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } } memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u)); if (gdth_readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } /* disable board interrupts, deinit services */ gdth_writeb(0xff, &dp6_ptr->io.irqdel); - gdth_writeb(0x00, &dp6_ptr->io.irqen);; + gdth_writeb(0x00, &dp6_ptr->io.irqen); gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status); gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); @@ -1310,7 +1243,7 @@ while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); @@ -1320,7 +1253,7 @@ gdth_writeb(0xff, &dp6_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } @@ -1330,7 +1263,7 @@ /* special command to controller BIOS */ gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]); gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]); - gdth_writel(0x01, &dp6_ptr->u.ic.S_Info[2]); + gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]); gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]); gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); gdth_writeb(0, &dp6_ptr->io.event); @@ -1339,7 +1272,7 @@ while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); @@ -1347,14 +1280,16 @@ gdth_writeb(0, &dp6_ptr->u.ic.S_Status); gdth_writeb(0xff, &dp6_ptr->io.irqdel); + ha->dma64_support = 0; + } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */ ha->plx = (gdt6c_plx_regs *)pcistr->io; TRACE2(("init_pci_new() dpmem %lx irq %d\n", pcistr->dpmem,ha->irq)); - ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6c_dpram_str)); + ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } /* check and reset interface area */ @@ -1365,8 +1300,8 @@ pcistr->dpmem); found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - gdth_munmap(ha->brd); - ha->brd = gdth_mmap(i, sizeof(ushort)); + iounmap(ha->brd); + ha->brd = ioremap(i, sizeof(ushort)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1375,15 +1310,10 @@ TRACE2(("init_pci_plx() address 0x%x busy\n", i)); continue; } - gdth_munmap(ha->brd); -#if LINUX_VERSION_CODE >= 0x2015C + iounmap(ha->brd); pci_write_config_dword(pcistr->pdev, PCI_BASE_ADDRESS_2, i); -#else - pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, - PCI_BASE_ADDRESS_2, i); -#endif - ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); + ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1398,14 +1328,14 @@ } if (!found) { printk("GDT-PCI: No free address found!\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } } memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u)); if (gdth_readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } @@ -1426,7 +1356,7 @@ while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); @@ -1435,7 +1365,7 @@ gdth_writeb(0, &dp6c_ptr->u.ic.Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } @@ -1445,7 +1375,7 @@ /* special command to controller BIOS */ gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); - gdth_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]); + gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]); gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); @@ -1456,23 +1386,25 @@ while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); } gdth_writeb(0, &dp6c_ptr->u.ic.S_Status); + ha->dma64_support = 0; + } else { /* MPR */ TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); - ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6m_dpram_str)); + ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } /* manipulate config. space to enable DPMEM, start RP controller */ -#if LINUX_VERSION_CODE >= 0x20363 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); command |= 6; pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); @@ -1483,7 +1415,7 @@ gdth_delay(1); pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, pci_resource_start(pcistr->pdev, 8)); -#elif LINUX_VERSION_CODE >= 0x2015C +#else pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); command |= 6; pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); @@ -1494,24 +1426,13 @@ gdth_delay(1); pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, pcistr->pdev->rom_address); -#else - pcibios_read_config_word(pcistr->bus, pcistr->device_fn, - PCI_COMMAND, &command); - command |= 6; - pcibios_write_config_word(pcistr->bus, pcistr->device_fn, - PCI_COMMAND, command); - pcibios_read_config_dword(pcistr->bus, pcistr->device_fn, - PCI_ROM_ADDRESS, &rom_addr); - if (rom_addr == 1UL) - rom_addr = 0UL; - i = 0xFEFF0001UL; - pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, - PCI_ROM_ADDRESS, i); - gdth_delay(1); - pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, - PCI_ROM_ADDRESS, rom_addr); #endif + /* Ensure that it is safe to access the non HW portions of DPMEM. + * Aditional check needed for Xscale based RAID controllers */ + while( ((int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg) ) & 3 ) + gdth_delay(1); + /* check and reset interface area */ dp6m_ptr = (gdt6m_dpram_str *)ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); @@ -1520,8 +1441,8 @@ pcistr->dpmem); found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - gdth_munmap(ha->brd); - ha->brd = gdth_mmap(i, sizeof(ushort)); + iounmap(ha->brd); + ha->brd = ioremap(i, sizeof(ushort)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1530,15 +1451,10 @@ TRACE2(("init_pci_mpr() address 0x%x busy\n", i)); continue; } - gdth_munmap(ha->brd); -#if LINUX_VERSION_CODE >= 0x2015C + iounmap(ha->brd); pci_write_config_dword(pcistr->pdev, PCI_BASE_ADDRESS_0, i); -#else - pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, - PCI_BASE_ADDRESS_0, i); -#endif - ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); + ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1553,7 +1469,7 @@ } if (!found) { printk("GDT-PCI: No free address found!\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } } @@ -1574,7 +1490,7 @@ while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } gdth_delay(1); @@ -1583,7 +1499,7 @@ gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); return 0; } @@ -1593,7 +1509,7 @@ /* special command to controller BIOS */ gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]); gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]); - gdth_writel(0x01, &dp6m_ptr->u.ic.S_Info[2]); + gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]); gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]); gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx); gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg); @@ -1602,12 +1518,32 @@ while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); - gdth_munmap(ha->brd); + iounmap(ha->brd); + return 0; + } + gdth_delay(1); + } + gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); + + /* read FW version to detect 64-bit DMA support */ + gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx); + gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg); + retries = INIT_RETRIES; + gdth_delay(20); + while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) { + if (--retries == 0) { + printk("GDT-PCI: Initialization error (DEINIT failed)\n"); + iounmap(ha->brd); return 0; } gdth_delay(1); } + prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); + if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ + ha->dma64_support = 0; + else + ha->dma64_support = 1; } return 1; @@ -1841,7 +1777,7 @@ if (ha->type == GDT_EISA) { if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */ - outl(virt_to_bus(ha->pccb), ha->bmic + MAILBOXREG); + outl(ha->ccb_phys, ha->bmic + MAILBOXREG); outb(ha->pccb->Service, ha->bmic + LDOORREG); } else if (ha->type == GDT_ISA) { gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event); @@ -1868,11 +1804,7 @@ gdth_from_wait = TRUE; do { -#if LINUX_VERSION_CODE >= 0x010346 gdth_interrupt((int)ha->irq,ha,NULL); -#else - gdth_interrupt((int)ha->irq,NULL); -#endif if (wait_hanum==hanum && wait_index==index) { answer_found = TRUE; break; @@ -1889,7 +1821,7 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, - ulong32 p2,ulong32 p3) + ulong64 p2,ulong64 p3) { register gdth_ha_str *ha; register gdth_cmd_str *cmd_ptr; @@ -1915,23 +1847,35 @@ if (service == CACHESERVICE) { if (opcode == GDT_IOCTL) { cmd_ptr->u.ioctl.subfunc = p1; - cmd_ptr->u.ioctl.channel = p2; + cmd_ptr->u.ioctl.channel = (ulong32)p2; cmd_ptr->u.ioctl.param_size = (ushort)p3; - cmd_ptr->u.ioctl.p_param = virt_to_bus(ha->pscratch); + cmd_ptr->u.ioctl.p_param = ha->scratch_phys; } else { - cmd_ptr->u.cache.DeviceNo = (ushort)p1; - cmd_ptr->u.cache.BlockNo = p2; + if (ha->cache_feat & GDT_64BIT) { + cmd_ptr->u.cache64.DeviceNo = (ushort)p1; + cmd_ptr->u.cache64.BlockNo = p2; + } else { + cmd_ptr->u.cache.DeviceNo = (ushort)p1; + cmd_ptr->u.cache.BlockNo = (ulong32)p2; + } } } else if (service == SCSIRAWSERVICE) { - cmd_ptr->u.raw.direction = p1; - cmd_ptr->u.raw.bus = (unchar)p2; - cmd_ptr->u.raw.target = (unchar)p3; - cmd_ptr->u.raw.lun = (unchar)(p3 >> 8); + if (ha->raw_feat & GDT_64BIT) { + cmd_ptr->u.raw64.direction = p1; + cmd_ptr->u.raw64.bus = (unchar)p2; + cmd_ptr->u.raw64.target = (unchar)p3; + cmd_ptr->u.raw64.lun = (unchar)(p3 >> 8); + } else { + cmd_ptr->u.raw.direction = p1; + cmd_ptr->u.raw.bus = (unchar)p2; + cmd_ptr->u.raw.target = (unchar)p3; + cmd_ptr->u.raw.lun = (unchar)(p3 >> 8); + } } else if (service == SCREENSERVICE) { if (opcode == GDT_REALTIME) { *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1; - *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2; - *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3; + *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2; + *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3; } } ha->cmd_len = sizeof(gdth_cmd_str); @@ -1959,6 +1903,7 @@ { register gdth_ha_str *ha; ushort cdev_cnt, i; + int ok; ulong32 bus_no, drv_cnt, drv_no, j; gdth_getch_str *chn; gdth_drlist_str *drl; @@ -1966,6 +1911,11 @@ gdth_raw_iochan_str *iocr; gdth_arcdl_str *alst; gdth_alist_str *alst2; + gdth_oem_str_ioctl *oemstr; +#ifdef INT_COAL + gdth_perf_modes *pmod; +#endif + #ifdef GDTH_RTC unchar rtc[12]; ulong flags; @@ -1973,11 +1923,20 @@ TRACE(("gdth_search_drives() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); + ok = 0; /* initialize controller services, at first: screen service */ - if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) { - printk("GDT: Initialization error screen service (code %d)\n", - ha->status); + ha->screen_feat = 0; + if (!force_dma32) { + ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0); + if (ok) + ha->screen_feat = GDT_64BIT; + } + if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0); + if (!ok) { + printk("GDT-HA %d: Initialization error screen service (code %d)\n", + hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); @@ -2009,15 +1968,52 @@ gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0); /* initialize cache service */ - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) { - printk("GDT: Initialization error cache service (code %d)\n", - ha->status); + ha->cache_feat = 0; + if (!force_dma32) { + ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0); + if (ok) + ha->cache_feat = GDT_64BIT; + } + if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0); + if (!ok) { + printk("GDT-HA %d: Initialization error cache service (code %d)\n", + hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); cdev_cnt = (ushort)ha->info; ha->fw_vers = ha->service; +#ifdef INT_COAL + if (ha->type == GDT_PCIMPR) { + /* set perf. modes */ + pmod = (gdth_perf_modes *)ha->pscratch; + pmod->version = 1; + pmod->st_mode = 1; /* enable one status buffer */ + *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; + pmod->st_buff_indx1 = COALINDEX; + pmod->st_buff_addr2 = 0; + pmod->st_buff_u_addr2 = 0; + pmod->st_buff_indx2 = 0; + pmod->st_buff_size = sizeof(gdth_coal_status) * MAXOFFSETS; + pmod->cmd_mode = 0; // disable all cmd buffers + pmod->cmd_buff_addr1 = 0; + pmod->cmd_buff_u_addr1 = 0; + pmod->cmd_buff_indx1 = 0; + pmod->cmd_buff_addr2 = 0; + pmod->cmd_buff_u_addr2 = 0; + pmod->cmd_buff_indx2 = 0; + pmod->cmd_buff_size = 0; + pmod->reserved1 = 0; + pmod->reserved2 = 0; + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES, + INVALID_CHANNEL,sizeof(gdth_perf_modes))) { + printk("GDT-HA %d: Interrupt coalescing activated\n", hanum); + } + } +#endif + /* detect number of buses - try new IOCTL */ iocr = (gdth_raw_iochan_str *)ha->pscratch; iocr->hdr.version = 0xffffffff; @@ -2045,8 +2041,8 @@ IO_CHANNEL | INVALID_CHANNEL, sizeof(gdth_getch_str))) { if (bus_no == 0) { - printk("GDT: Error detecting channel count (0x%x)\n", - ha->status); + printk("GDT-HA %d: Error detecting channel count (0x%x)\n", + hanum, ha->status); return 0; } break; @@ -2063,8 +2059,8 @@ /* read cache configuration */ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO, INVALID_CHANNEL,sizeof(gdth_cinfo_str))) { - printk("GDT: Initialization error cache service (code %d)\n", - ha->status); + printk("GDT-HA %d: Initialization error cache service (code %d)\n", + hanum, ha->status); return 0; } ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar; @@ -2183,9 +2179,17 @@ } /* initialize raw service */ - if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) { - printk("GDT: Initialization error raw service (code %d)\n", - ha->status); + ha->raw_feat = 0; + if (!force_dma32) { + ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0); + if (ok) + ha->raw_feat = GDT_64BIT; + } + if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0); + if (!ok) { + printk("GDT-HA %d: Initialization error raw service (code %d)\n", + hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); @@ -2197,7 +2201,7 @@ if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) { TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", ha->info)); - ha->raw_feat = (ushort)ha->info; + ha->raw_feat |= (ushort)ha->info; } } @@ -2208,7 +2212,7 @@ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) { TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", ha->info)); - ha->cache_feat = (ushort)ha->info; + ha->cache_feat |= (ushort)ha->info; } } @@ -2228,12 +2232,48 @@ if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0, reserve_list[i+1], reserve_list[i+2] | (reserve_list[i+3] << 8))) { - printk("GDT: Error raw service (RESERVE, code %d)\n", - ha->status); + printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n", + hanum, ha->status); } } } + /* Determine OEM string using IOCTL */ + oemstr = (gdth_oem_str_ioctl *)ha->pscratch; + oemstr->params.ctl_version = 0x01; + oemstr->params.buffer_size = sizeof(oemstr->text); + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL, + sizeof(gdth_oem_str_ioctl))) { + TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n")); + printk("GDT-HA %d: Vendor: %s Name: %s\n", + hanum,oemstr->text.oem_company_name,ha->binfo.type_string); + /* Save the Host Drive inquiry data */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id, + sizeof(ha->oem_name)); +#else + strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7); + ha->oem_name[7] = '\0'; +#endif + } else { + /* Old method, based on PCI ID */ + TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n")); + printk("GDT-HA %d: Name: %s\n", + hanum,ha->binfo.type_string); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + if (ha->oem_id == OEM_ID_INTEL) + strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name)); + else + strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name)); +#else + if (ha->oem_id == OEM_ID_INTEL) + strcpy(ha->oem_name,"Intel "); + else + strcpy(ha->oem_name,"ICP "); +#endif + } + /* scanning for host drives */ for (i = 0; i < cdev_cnt; ++i) gdth_analyse_hdrive(hanum,i); @@ -2245,7 +2285,8 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive) { register gdth_ha_str *ha; - int drv_cyls, drv_hds, drv_secs; + ulong32 drv_cyls; + int drv_hds, drv_secs; TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive)); if (hdrive >= MAX_HDRIVES) @@ -2256,7 +2297,7 @@ return 0; ha->hdr[hdrive].present = TRUE; ha->hdr[hdrive].size = ha->info; - + /* evaluate mapping (sectors per head, heads per cylinder) */ ha->hdr[hdrive].size &= ~SECS32; if (ha->info2 == 0) { @@ -2264,15 +2305,22 @@ } else { drv_hds = ha->info2 & 0xff; drv_secs = (ha->info2 >> 8) & 0xff; - drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs; + drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs; } ha->hdr[hdrive].heads = (unchar)drv_hds; ha->hdr[hdrive].secs = (unchar)drv_secs; /* round size */ ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; + + if (ha->cache_feat & GDT_64BIT) { + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0) + && ha->info2 != 0) { + ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info; + } + } TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs)); - + /* get informations about device */ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) { TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", @@ -2314,9 +2362,13 @@ GDTH_LOCK_HA(ha, flags); scp->SCp.this_residual = (int)priority; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + t = scp->device->id; +#else b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; t = scp->target; -#if LINUX_VERSION_CODE >= 0x010300 +#endif if (priority >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { @@ -2324,7 +2376,6 @@ scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); } } -#endif if (ha->req_first==NULL) { ha->req_first = scp; /* queue was empty */ @@ -2358,7 +2409,7 @@ register gdth_ha_str *ha; register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; - unchar b, t, firsttime; + unchar b, t, l, firsttime; unchar this_cmd, next_cmd; ulong flags = 0; int cmd_index; @@ -2366,7 +2417,7 @@ TRACE(("gdth_next() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); if (!gdth_polling) - GDTH_LOCK_HA(ha, flags); + GDTH_LOCK_HA(ha, flags); ha->cmd_cnt = ha->cmd_offs_dpmem = 0; this_cmd = firsttime = TRUE; @@ -2376,8 +2427,15 @@ for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) { if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr) pscp = (Scsi_Cmnd *)pscp->SCp.ptr; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(nscp->device->host)->busnum : nscp->device->channel; + t = nscp->device->id; + l = nscp->device->lun; +#else b = virt_ctr ? NUMDATA(nscp->host)->busnum : nscp->channel; t = nscp->target; + l = nscp->lun; +#endif if (nscp->SCp.this_residual >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) @@ -2397,24 +2455,21 @@ firsttime = FALSE; } -#if LINUX_VERSION_CODE >= 0x010300 - if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) -#endif - { + if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) { if (nscp->SCp.phase == -1) { nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */ if (nscp->cmnd[0] == TEST_UNIT_READY) { TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", - b, t, nscp->lun)); + b, t, l)); /* TEST_UNIT_READY -> set scan mode */ if ((ha->scan_mode & 0x0f) == 0) { - if (b == 0 && t == 0 && nscp->lun == 0) { + if (b == 0 && t == 0 && l == 0) { ha->scan_mode |= 1; TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); } } else if ((ha->scan_mode & 0x0f) == 1) { - if (b == 0 && ((t == 0 && nscp->lun == 1) || - (t == 1 && nscp->lun == 0))) { + if (b == 0 && ((t == 0 && l == 1) || + (t == 1 && l == 0))) { nscp->SCp.sent_command = GDT_SCAN_START; nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) | SCSIRAWSERVICE; @@ -2466,37 +2521,32 @@ /* io_request_lock already active ! */ nscp->scsi_done(nscp); if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + GDTH_LOCK_HA(ha,flags); } } - } else - -#if LINUX_VERSION_CODE >= 0x010300 - if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) { + } else if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) { if (!(cmd_index=gdth_special_cmd(hanum,nscp))) this_cmd = FALSE; next_cmd = FALSE; - } else -#endif - if (b != ha->virt_bus) { + } else if (b != ha->virt_bus) { if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) this_cmd = FALSE; else ha->raw[BUS_L2P(ha,b)].io_cnt[t]++; - } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || nscp->lun != 0) { + } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || l != 0) { TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", - nscp->cmnd[0], b, t, nscp->lun)); + nscp->cmnd[0], b, t, l)); nscp->result = DID_BAD_TARGET << 16; if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + GDTH_LOCK_HA(ha,flags); } } else { switch (nscp->cmnd[0]) { @@ -2507,6 +2557,9 @@ case VERIFY: case START_STOP: case MODE_SENSE: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + case SERVICE_ACTION_IN: +#endif TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], nscp->cmnd[4],nscp->cmnd[5])); @@ -2522,20 +2575,20 @@ if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { - if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); - if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_LOCK_HA(ha,flags); } } else if (gdth_internal_cache_cmd(hanum,nscp)) { if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + GDTH_LOCK_HA(ha,flags); } break; @@ -2550,12 +2603,12 @@ if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { - if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); - if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_LOCK_HA(ha,flags); } } else { nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0; @@ -2578,6 +2631,10 @@ case WRITE_6: case READ_10: case WRITE_10: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + case READ_16: + case WRITE_16: +#endif if (ha->hdr[t].media_changed) { /* return UNIT_ATTENTION */ TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", @@ -2590,12 +2647,12 @@ if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { - if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); - if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + if (!gdth_polling) + GDTH_LOCK_HA(ha,flags); } } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) this_cmd = FALSE; @@ -2605,18 +2662,18 @@ TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0], nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], nscp->cmnd[4],nscp->cmnd[5])); - printk("GDT: Unknown SCSI command 0x%x to cache service !\n", - nscp->cmnd[0]); + printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n", + hanum, nscp->cmnd[0]); nscp->result = DID_ABORT << 16; if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { if (!gdth_polling) - GDTH_UNLOCK_HA(ha,flags); + GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); if (!gdth_polling) - GDTH_LOCK_HA(ha,flags); + GDTH_LOCK_HA(ha,flags); } break; } @@ -2637,36 +2694,68 @@ } if (!gdth_polling) - GDTH_UNLOCK_HA(ha, flags); + GDTH_UNLOCK_HA(ha, flags); if (gdth_polling && ha->cmd_cnt > 0) { if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT)) - printk("GDT: Controller %d: Command %d timed out !\n", + printk("GDT-HA %d: Command %d timed out !\n", hanum,cmd_index); } } - -static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count) + +static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp, + char *buffer,ushort count) { ushort cpcount,i; ushort cpsum,cpnow; struct scatterlist *sl; + gdth_ha_str *ha; + int sgcnt; + char *address; cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen; + ha = HADATA(gdth_ctr_tab[hanum]); + if (scp->use_sg) { sl = (struct scatterlist *)scp->request_buffer; - for (i=0,cpsum=0; iuse_sg; ++i,++sl) { - cpnow = (ushort)sl->length; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,PCI_DMA_FROMDEVICE); + for (i=0,cpsum=0; ibufflen)); if (cpsum+cpnow > cpcount) cpnow = cpcount - cpsum; cpsum += cpnow; - memcpy((char*)sl->address,buffer,cpnow); + if (!sl->page) { + printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n", + hanum); + return; + } + address = (char *)(page_address(sl->page) + sl->offset); + memcpy(address,buffer,cpnow); + if (cpsum == cpcount) + break; + buffer += cpnow; + } + pci_unmap_sg(ha->pdev,scp->request_buffer, + scp->use_sg,PCI_DMA_FROMDEVICE); +#else + sgcnt = scp->use_sg; + for (i=0,cpsum=0; ilength; + TRACE(("copy_internal() now %d sum %d count %d %d\n", + cpnow,cpsum,cpcount,(ushort)scp->bufflen)); + if (cpsum+cpnow > cpcount) + cpnow = cpcount - cpsum; + cpsum += cpnow; + address = (char *)sl->address; + memcpy(address,buffer,cpnow); if (cpsum == cpcount) break; buffer += cpnow; } +#endif } else { TRACE(("copy_internal() count %d\n",cpcount)); memcpy((char*)scp->request_buffer,buffer,cpcount); @@ -2683,10 +2772,17 @@ gdth_modep_data mpd; ha = HADATA(gdth_ctr_tab[hanum]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + t = scp->device->id; +#else t = scp->target; +#endif TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n", scp->cmnd[0],t)); + scp->result = DID_OK << 16; + scp->sense_buffer[0] = 0; + switch (scp->cmnd[0]) { case TEST_UNIT_READY: case VERIFY: @@ -2707,13 +2803,10 @@ inq.version = 2; inq.resp_aenc = 2; inq.add_length= 32; - if (ha->oem_id == OEM_ID_INTEL) - strcpy(inq.vendor,"Intel "); - else - strcpy(inq.vendor,"ICP "); + strcpy(inq.vendor,ha->oem_name); sprintf(inq.product,"Host Drive #%02d",t); strcpy(inq.revision," "); - gdth_copy_internal_data(scp,(char*)&inq,sizeof(gdth_inq_data)); + gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data)); break; case REQUEST_SENSE: @@ -2723,7 +2816,7 @@ sd.key = NO_SENSE; sd.info = 0; sd.add_length= 0; - gdth_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data)); + gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data)); break; case MODE_SENSE: @@ -2735,24 +2828,40 @@ mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); - gdth_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data)); + gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data)); break; case READ_CAPACITY: TRACE2(("Read capacity hdrive %d\n",t)); - rdc.last_block_no = ntohl(ha->hdr[t].size-1); - rdc.block_length = ntohl(SECTOR_SIZE); - gdth_copy_internal_data(scp,(char*)&rdc,sizeof(gdth_rdcap_data)); + if (ha->hdr[t].size > (ulong64)0xffffffff) + rdc.last_block_no = 0xffffffff; + else + rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); + rdc.block_length = cpu_to_be32(SECTOR_SIZE); + gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data)); + break; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + case SERVICE_ACTION_IN: + if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 && + (ha->cache_feat & GDT_64BIT)) { + gdth_rdcap16_data rdc16; + + TRACE2(("Read capacity (16) hdrive %d\n",t)); + rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); + rdc16.block_length = cpu_to_be32(SECTOR_SIZE); + gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data)); + } else { + scp->result = DID_ABORT << 16; + } break; +#endif default: TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0])); break; } - scp->result = DID_OK << 16; - scp->sense_buffer[0] = 0; - if (!scp->SCp.have_data_in) scp->SCp.have_data_in++; else @@ -2766,9 +2875,14 @@ register gdth_ha_str *ha; register gdth_cmd_str *cmdp; struct scatterlist *sl; - ushort i, cnt; - ulong32 no; - int cmd_index, read_write; + ulong32 cnt, blockcnt; + ulong64 no, blockno; + dma_addr_t phys_addr; + int i, cmd_index, read_write, sgcnt, mode64; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + struct page *page; + ulong offset; +#endif ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; @@ -2778,6 +2892,11 @@ if (ha->type==GDT_EISA && ha->cmd_cnt>0) return 0; + mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE; + /* test for READ_16, WRITE_16 if !mode64 ? --- + not required, should not occur due to error return on + READ_CAPACITY_16 */ + cmdp->Service = CACHESERVICE; cmdp->RequestBuffer = scp; /* search free command index */ @@ -2790,7 +2909,7 @@ gdth_set_sema0(hanum); /* fill command */ - read_write = FALSE; + read_write = 0; if (scp->SCp.sent_command != -1) cmdp->OpCode = scp->SCp.sent_command; /* special cache cmd. */ else if (scp->cmnd[0] == RESERVE) @@ -2804,76 +2923,173 @@ cmdp->OpCode = GDT_UNMOUNT; else cmdp->OpCode = GDT_FLUSH; - } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) { - read_write = TRUE; + } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 || + scp->cmnd[0] == WRITE_12 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + || scp->cmnd[0] == WRITE_16 +#endif + ) { + read_write = 1; if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && (ha->cache_feat & GDT_WR_THROUGH))) cmdp->OpCode = GDT_WRITE_THR; else cmdp->OpCode = GDT_WRITE; } else { - read_write = TRUE; + read_write = 2; cmdp->OpCode = GDT_READ; } - - cmdp->BoardNode = LOCALBOARD; - cmdp->u.cache.DeviceNo = hdrive; - cmdp->u.cache.BlockNo = 1; - cmdp->u.cache.sg_canz = 0; + + cmdp->BoardNode = LOCALBOARD; + if (mode64) { + cmdp->u.cache64.DeviceNo = hdrive; + cmdp->u.cache64.BlockNo = 1; + cmdp->u.cache64.sg_canz = 0; + } else { + cmdp->u.cache.DeviceNo = hdrive; + cmdp->u.cache.BlockNo = 1; + cmdp->u.cache.sg_canz = 0; + } if (read_write) { - if (scp->cmd_len != 6) { + if (scp->cmd_len == 16) { + memcpy(&no, &scp->cmnd[2], sizeof(ulong64)); + blockno = be64_to_cpu(no); + memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32)); + blockcnt = be32_to_cpu(cnt); + } else if (scp->cmd_len == 10) { memcpy(&no, &scp->cmnd[2], sizeof(ulong32)); - cmdp->u.cache.BlockNo = ntohl(no); + blockno = be32_to_cpu(no); memcpy(&cnt, &scp->cmnd[7], sizeof(ushort)); - cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt); + blockcnt = be16_to_cpu(cnt); } else { memcpy(&no, &scp->cmnd[0], sizeof(ulong32)); - cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL; - cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; + blockno = be32_to_cpu(no) & 0x001fffffUL; + blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; + } + if (mode64) { + cmdp->u.cache64.BlockNo = blockno; + cmdp->u.cache64.BlockCnt = blockcnt; + } else { + cmdp->u.cache.BlockNo = (ulong32)blockno; + cmdp->u.cache.BlockCnt = blockcnt; } if (scp->use_sg) { - cmdp->u.cache.DestAddr= 0xffffffff; sl = (struct scatterlist *)scp->request_buffer; - for (i=0; iuse_sg; ++i,++sl) { - cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address); - cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length; + sgcnt = scp->use_sg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + scp->SCp.Status = GDTH_MAP_SG; + scp->SCp.Message = (read_write == 1 ? + PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message); + if (mode64) { + cmdp->u.cache64.DestAddr= (ulong64)-1; + cmdp->u.cache64.sg_canz = sgcnt; + for (i=0; iu.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); +#ifdef GDTH_DMA_STATISTICS + if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + ha->dma64_cnt++; + else + ha->dma32_cnt++; +#endif + cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl); + } + } else { + cmdp->u.cache.DestAddr= 0xffffffff; + cmdp->u.cache.sg_canz = sgcnt; + for (i=0; iu.cache.sg_lst[i].sg_ptr = sg_dma_address(sl); +#ifdef GDTH_DMA_STATISTICS + ha->dma32_cnt++; +#endif + cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl); + } + } +#else + if (mode64) { + cmdp->u.cache64.DestAddr= (ulong64)-1; + cmdp->u.cache64.sg_canz = sgcnt; + for (i=0; iu.cache64.sg_lst[i].sg_ptr = virt_to_bus(sl->address); + cmdp->u.cache64.sg_lst[i].sg_len = (ulong32)sl->length; + } + } else { + cmdp->u.cache.DestAddr= 0xffffffff; + cmdp->u.cache.sg_canz = sgcnt; + for (i=0; iu.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address); + cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length; + } } - cmdp->u.cache.sg_canz = (ulong32)i; +#endif #ifdef GDTH_STATISTICS - if (max_sg < (ulong32)i) { - max_sg = (ulong32)i; - TRACE3(("GDT: max_sg = %d\n",i)); + if (max_sg < (ulong32)sgcnt) { + max_sg = (ulong32)sgcnt; + TRACE3(("GDT: max_sg = %d\n",max_sg)); } #endif - if (iu.cache.sg_lst[i].sg_len = 0; + } else { - if (ha->cache_feat & SCATTER_GATHER) { - cmdp->u.cache.DestAddr = 0xffffffff; - cmdp->u.cache.sg_canz = 1; - cmdp->u.cache.sg_lst[0].sg_ptr = - virt_to_bus(scp->request_buffer); - cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.cache.sg_lst[1].sg_len = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + scp->SCp.Status = GDTH_MAP_SINGLE; + scp->SCp.Message = (read_write == 1 ? + PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + page = virt_to_page(scp->request_buffer); + offset = (ulong)scp->request_buffer & ~PAGE_MASK; + phys_addr = pci_map_page(ha->pdev,page,offset, + scp->request_bufflen,scp->SCp.Message); + scp->SCp.dma_handle = phys_addr; +#else + phys_addr = virt_to_bus(scp->request_buffer); +#endif + if (mode64) { + if (ha->cache_feat & SCATTER_GATHER) { + cmdp->u.cache64.DestAddr = (ulong64)-1; + cmdp->u.cache64.sg_canz = 1; + cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr; + cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen; + cmdp->u.cache64.sg_lst[1].sg_len = 0; + } else { + cmdp->u.cache64.DestAddr = phys_addr; + cmdp->u.cache64.sg_canz= 0; + } } else { - cmdp->u.cache.DestAddr = virt_to_bus(scp->request_buffer); - cmdp->u.cache.sg_canz= 0; + if (ha->cache_feat & SCATTER_GATHER) { + cmdp->u.cache.DestAddr = 0xffffffff; + cmdp->u.cache.sg_canz = 1; + cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr; + cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen; + cmdp->u.cache.sg_lst[1].sg_len = 0; + } else { + cmdp->u.cache.DestAddr = phys_addr; + cmdp->u.cache.sg_canz= 0; + } } } } - TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, - cmdp->u.cache.sg_lst[0].sg_ptr, - cmdp->u.cache.sg_lst[0].sg_len)); - TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", - cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); - /* evaluate command size, check space */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + - (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); + if (mode64) { + TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", + cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz, + cmdp->u.cache64.sg_lst[0].sg_ptr, + cmdp->u.cache64.sg_lst[0].sg_len)); + TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", + cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt)); + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + + (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); + } else { + TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", + cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, + cmdp->u.cache.sg_lst[0].sg_ptr, + cmdp->u.cache.sg_lst[0].sg_len)); + TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", + cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + + (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); + } if (ha->cmd_len & 3) ha->cmd_len += (4 - (ha->cmd_len & 3)); @@ -2897,12 +3113,22 @@ register gdth_cmd_str *cmdp; struct scatterlist *sl; ushort i; - int cmd_index; + dma_addr_t phys_addr, sense_paddr; + int cmd_index, sgcnt, mode64; unchar t,l; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + struct page *page; + ulong offset; +#endif ha = HADATA(gdth_ctr_tab[hanum]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + t = scp->device->id; + l = scp->device->lun; +#else t = scp->target; l = scp->lun; +#endif cmdp = ha->pccb; TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n", scp->cmnd[0],b,t,l)); @@ -2910,6 +3136,8 @@ if (ha->type==GDT_EISA && ha->cmd_cnt>0) return 0; + mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE; + cmdp->Service = SCSIRAWSERVICE; cmdp->RequestBuffer = scp; /* search free command index */ @@ -2925,68 +3153,176 @@ if (scp->SCp.sent_command != -1) { cmdp->OpCode = scp->SCp.sent_command; /* special raw cmd. */ cmdp->BoardNode = LOCALBOARD; - cmdp->u.raw.direction = (scp->SCp.phase >> 8); - TRACE2(("special raw cmd 0x%x param 0x%x\n", - cmdp->OpCode, cmdp->u.raw.direction)); + if (mode64) { + cmdp->u.raw64.direction = (scp->SCp.phase >> 8); + TRACE2(("special raw cmd 0x%x param 0x%x\n", + cmdp->OpCode, cmdp->u.raw64.direction)); + /* evaluate command size */ + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst); + } else { + cmdp->u.raw.direction = (scp->SCp.phase >> 8); + TRACE2(("special raw cmd 0x%x param 0x%x\n", + cmdp->OpCode, cmdp->u.raw.direction)); + /* evaluate command size */ + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst); + } - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst); } else { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + page = virt_to_page(scp->sense_buffer); + offset = (ulong)scp->sense_buffer & ~PAGE_MASK; + sense_paddr = pci_map_page(ha->pdev,page,offset, + 16,PCI_DMA_FROMDEVICE); + scp->SCp.buffer = (struct scatterlist *)((ulong32)sense_paddr); + /* high part, if 64bit */ + scp->host_scribble = (char *)(ulong32)((ulong64)sense_paddr >> 32); +#else + sense_paddr = virt_to_bus(scp->sense_buffer); +#endif cmdp->OpCode = GDT_WRITE; /* always */ cmdp->BoardNode = LOCALBOARD; - cmdp->u.raw.reserved = 0; - cmdp->u.raw.mdisc_time = 0; - cmdp->u.raw.mcon_time = 0; - cmdp->u.raw.clen = scp->cmd_len; - cmdp->u.raw.target = t; - cmdp->u.raw.lun = l; - cmdp->u.raw.bus = b; - cmdp->u.raw.priority = 0; - cmdp->u.raw.link_p = 0; - cmdp->u.raw.sdlen = scp->request_bufflen; - cmdp->u.raw.sense_len = 16; - cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer); - cmdp->u.raw.direction = - gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; - memcpy(cmdp->u.raw.cmd,scp->cmnd,12); + if (mode64) { + cmdp->u.raw64.reserved = 0; + cmdp->u.raw64.mdisc_time = 0; + cmdp->u.raw64.mcon_time = 0; + cmdp->u.raw64.clen = scp->cmd_len; + cmdp->u.raw64.target = t; + cmdp->u.raw64.lun = l; + cmdp->u.raw64.bus = b; + cmdp->u.raw64.priority = 0; + cmdp->u.raw64.sdlen = scp->request_bufflen; + cmdp->u.raw64.sense_len = 16; + cmdp->u.raw64.sense_data = sense_paddr; + cmdp->u.raw64.direction = + gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; + memcpy(cmdp->u.raw64.cmd,scp->cmnd,16); + } else { + cmdp->u.raw.reserved = 0; + cmdp->u.raw.mdisc_time = 0; + cmdp->u.raw.mcon_time = 0; + cmdp->u.raw.clen = scp->cmd_len; + cmdp->u.raw.target = t; + cmdp->u.raw.lun = l; + cmdp->u.raw.bus = b; + cmdp->u.raw.priority = 0; + cmdp->u.raw.link_p = 0; + cmdp->u.raw.sdlen = scp->request_bufflen; + cmdp->u.raw.sense_len = 16; + cmdp->u.raw.sense_data = sense_paddr; + cmdp->u.raw.direction = + gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; + memcpy(cmdp->u.raw.cmd,scp->cmnd,12); + } if (scp->use_sg) { - cmdp->u.raw.sdata = 0xffffffff; sl = (struct scatterlist *)scp->request_buffer; - for (i=0; iuse_sg; ++i,++sl) { - cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address); - cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length; - } - cmdp->u.raw.sg_ranz = (ulong32)i; - + sgcnt = scp->use_sg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + scp->SCp.Status = GDTH_MAP_SG; + scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; + sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message); + if (mode64) { + cmdp->u.raw64.sdata = (ulong64)-1; + cmdp->u.raw64.sg_ranz = sgcnt; + for (i=0; iu.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); +#ifdef GDTH_DMA_STATISTICS + if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + ha->dma64_cnt++; + else + ha->dma32_cnt++; +#endif + cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl); + } + } else { + cmdp->u.raw.sdata = 0xffffffff; + cmdp->u.raw.sg_ranz = sgcnt; + for (i=0; iu.raw.sg_lst[i].sg_ptr = sg_dma_address(sl); +#ifdef GDTH_DMA_STATISTICS + ha->dma32_cnt++; +#endif + cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl); + } + } +#else + if (mode64) { + cmdp->u.raw64.sdata = (ulong64)-1; + cmdp->u.raw64.sg_ranz = sgcnt; + for (i=0; iu.raw64.sg_lst[i].sg_ptr = virt_to_bus(sl->address); + cmdp->u.raw64.sg_lst[i].sg_len = (ulong32)sl->length; + } + } else { + cmdp->u.raw.sdata = 0xffffffff; + cmdp->u.raw.sg_ranz = sgcnt; + for (i=0; iu.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address); + cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length; + } + } +#endif + #ifdef GDTH_STATISTICS - if (max_sg < (ulong32)i) { - max_sg = (ulong32)i; - TRACE3(("GDT: max_sg = %d\n",i)); + if (max_sg < sgcnt) { + max_sg = sgcnt; + TRACE3(("GDT: max_sg = %d\n",sgcnt)); } #endif - if (iu.raw.sg_lst[i].sg_len = 0; + } else { - if (ha->raw_feat & SCATTER_GATHER) { - cmdp->u.raw.sdata = 0xffffffff; - cmdp->u.raw.sg_ranz= 1; - cmdp->u.raw.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer); - cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.raw.sg_lst[1].sg_len = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + scp->SCp.Status = GDTH_MAP_SINGLE; + scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; + page = virt_to_page(scp->request_buffer); + offset = (ulong)scp->request_buffer & ~PAGE_MASK; + phys_addr = pci_map_page(ha->pdev,page,offset, + scp->request_bufflen,scp->SCp.Message); + scp->SCp.dma_handle = phys_addr; +#else + phys_addr = virt_to_bus(scp->request_buffer); +#endif + if (mode64) { + if (ha->raw_feat & SCATTER_GATHER) { + cmdp->u.raw64.sdata = (ulong64)-1; + cmdp->u.raw64.sg_ranz= 1; + cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr; + cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen; + cmdp->u.raw64.sg_lst[1].sg_len = 0; + } else { + cmdp->u.raw64.sdata = phys_addr; + cmdp->u.raw64.sg_ranz= 0; + } } else { - cmdp->u.raw.sdata = virt_to_bus(scp->request_buffer); - cmdp->u.raw.sg_ranz= 0; + if (ha->raw_feat & SCATTER_GATHER) { + cmdp->u.raw.sdata = 0xffffffff; + cmdp->u.raw.sg_ranz= 1; + cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr; + cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen; + cmdp->u.raw.sg_lst[1].sg_len = 0; + } else { + cmdp->u.raw.sdata = phys_addr; + cmdp->u.raw.sg_ranz= 0; + } } } - TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, - cmdp->u.raw.sg_lst[0].sg_ptr, - cmdp->u.raw.sg_lst[0].sg_len)); - - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + - (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); + if (mode64) { + TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", + cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz, + cmdp->u.raw64.sg_lst[0].sg_ptr, + cmdp->u.raw64.sg_lst[0].sg_len)); + /* evaluate command size */ + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + + (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); + } else { + TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", + cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, + cmdp->u.raw.sg_lst[0].sg_ptr, + cmdp->u.raw.sg_lst[0].sg_len)); + /* evaluate command size */ + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + + (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); + } } /* check space */ if (ha->cmd_len & 3) @@ -3036,15 +3372,23 @@ if (cmdp->OpCode == GDT_IOCTL) { TRACE2(("IOCTL\n")); ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong32); + GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64); } else if (cmdp->Service == CACHESERVICE) { TRACE2(("cache command %d\n",cmdp->OpCode)); - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str); + if (ha->cache_feat & GDT_64BIT) + ha->cmd_len = + GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str); + else + ha->cmd_len = + GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str); } else if (cmdp->Service == SCSIRAWSERVICE) { - TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0])); - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str); + TRACE2(("raw command %d\n",cmdp->OpCode)); + if (ha->raw_feat & GDT_64BIT) + ha->cmd_len = + GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str); + else + ha->cmd_len = + GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str); } if (ha->cmd_len & 3) @@ -3187,14 +3531,14 @@ /* SCSI interface functions */ -#if LINUX_VERSION_CODE >= 0x010346 -static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) #else -static void gdth_interrupt(int irq,struct pt_regs *regs) +static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) #endif { register gdth_ha_str *ha; - gdt6m_dpram_str *dp6m_ptr; + gdt6m_dpram_str *dp6m_ptr = NULL; gdt6_dpram_str *dp6_ptr; gdt2_dpram_str *dp2_ptr; Scsi_Cmnd *scp; @@ -3202,13 +3546,23 @@ unchar IStatus; ushort Service; ulong flags = 0; +#ifdef INT_COAL + int coalesced = FALSE; + int next = FALSE; + gdth_coal_status *pcs = NULL; + int act_int_coal = 0; +#endif TRACE(("gdth_interrupt() IRQ %d\n",irq)); /* if polling and not from gdth_wait() -> return */ if (gdth_polling) { if (!gdth_from_wait) { - return; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif } } @@ -3221,163 +3575,261 @@ /* spurious interrupt */ if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - return; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif } + ha = HADATA(gdth_ctr_tab[hanum]); #ifdef GDTH_STATISTICS ++act_ints; #endif - - ha = HADATA(gdth_ctr_tab[hanum]); - if (ha->type == GDT_EISA) { - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = inw(ha->bmic + MAILBOXREG+8); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = inl(ha->bmic + MAILBOXREG+12); - ha->service = inw(ha->bmic + MAILBOXREG+10); - ha->info2 = inl(ha->bmic + MAILBOXREG+4); - - outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ - outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ - } else if (ha->type == GDT_ISA) { - dp2_ptr = (gdt2_dpram_str *)ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = gdth_readw(&dp2_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]); - ha->service = gdth_readw(&dp2_ptr->u.ic.Service); - ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); - - gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ - gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index); /* reset command index */ - gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ - } else if (ha->type == GDT_PCI) { - dp6_ptr = (gdt6_dpram_str *)ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = gdth_readw(&dp6_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]); - ha->service = gdth_readw(&dp6_ptr->u.ic.Service); - ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); - - gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ - gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index); /* reset command index */ - gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ - } else if (ha->type == GDT_PCINEW) { - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = inw(PTR2USHORT(&ha->plx->status)); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else - ha->status = S_OK; - ha->info = inl(PTR2USHORT(&ha->plx->info[0])); - ha->service = inw(PTR2USHORT(&ha->plx->service)); - ha->info2 = inl(PTR2USHORT(&ha->plx->info[1])); - outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); - outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); - } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = (gdt6m_dpram_str *)ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = gdth_readw(&dp6m_ptr->i960r.status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]); - ha->service = gdth_readw(&dp6m_ptr->i960r.service); - ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]); +#ifdef INT_COAL + /* See if the fw is returning coalesced status */ + if (IStatus == COALINDEX) { + /* Coalesced status. Setup the initial status + buffer pointer and flags */ + pcs = ha->coal_stat; + coalesced = TRUE; + next = TRUE; + } - /* event string */ - if (IStatus == ASYNCINDEX) { - if (ha->service != SCREENSERVICE && - (ha->fw_vers & 0xff) >= 0x1a) { - ha->dvr.severity = - gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity); - for (i = 0; i < 256; ++i) { - ha->dvr.event_string[i] = gdth_readb - (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]); - if (ha->dvr.event_string[i] == 0) - break; + do { + if (coalesced) { + /* For coalesced requests all status + information is found in the status buffer */ + IStatus = (unchar)(pcs->status & 0xff); + } +#endif + + if (ha->type == GDT_EISA) { + if (IStatus & 0x80) { /* error flag */ + IStatus &= ~0x80; + ha->status = inw(ha->bmic + MAILBOXREG+8); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); + } else /* no error */ + ha->status = S_OK; + ha->info = inl(ha->bmic + MAILBOXREG+12); + ha->service = inw(ha->bmic + MAILBOXREG+10); + ha->info2 = inl(ha->bmic + MAILBOXREG+4); + + outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ + outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ + } else if (ha->type == GDT_ISA) { + dp2_ptr = (gdt2_dpram_str *)ha->brd; + if (IStatus & 0x80) { /* error flag */ + IStatus &= ~0x80; + ha->status = gdth_readw(&dp2_ptr->u.ic.Status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); + } else /* no error */ + ha->status = S_OK; + ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]); + ha->service = gdth_readw(&dp2_ptr->u.ic.Service); + ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); + + gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ + gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ + gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ + } else if (ha->type == GDT_PCI) { + dp6_ptr = (gdt6_dpram_str *)ha->brd; + if (IStatus & 0x80) { /* error flag */ + IStatus &= ~0x80; + ha->status = gdth_readw(&dp6_ptr->u.ic.Status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); + } else /* no error */ + ha->status = S_OK; + ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]); + ha->service = gdth_readw(&dp6_ptr->u.ic.Service); + ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); + + gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ + gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */ + gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ + } else if (ha->type == GDT_PCINEW) { + if (IStatus & 0x80) { /* error flag */ + IStatus &= ~0x80; + ha->status = inw(PTR2USHORT(&ha->plx->status)); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); + } else + ha->status = S_OK; + ha->info = inl(PTR2USHORT(&ha->plx->info[0])); + ha->service = inw(PTR2USHORT(&ha->plx->service)); + ha->info2 = inl(PTR2USHORT(&ha->plx->info[1])); + + outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); + outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); + } else if (ha->type == GDT_PCIMPR) { + dp6m_ptr = (gdt6m_dpram_str *)ha->brd; + if (IStatus & 0x80) { /* error flag */ + IStatus &= ~0x80; +#ifdef INT_COAL + if (coalesced) + ha->status = pcs->ext_status && 0xffff; + else +#endif + ha->status = gdth_readw(&dp6m_ptr->i960r.status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); + } else /* no error */ + ha->status = S_OK; +#ifdef INT_COAL + /* get information */ + if (coalesced) { + ha->info = pcs->info0; + ha->info2 = pcs->info1; + ha->service = (pcs->ext_status >> 16) && 0xffff; + } else +#endif + { + ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]); + ha->service = gdth_readw(&dp6m_ptr->i960r.service); + ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]); + } + /* event string */ + if (IStatus == ASYNCINDEX) { + if (ha->service != SCREENSERVICE && + (ha->fw_vers & 0xff) >= 0x1a) { + ha->dvr.severity = gdth_readb + (&((gdt6m_dpram_str *)ha->brd)->i960r.severity); + for (i = 0; i < 256; ++i) { + ha->dvr.event_string[i] = gdth_readb + (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]); + if (ha->dvr.event_string[i] == 0) + break; + } } } +#ifdef INT_COAL + /* Make sure that non coalesced interrupts get cleared + before being handled by gdth_async_event/gdth_sync_event */ + if (!coalesced) +#endif + { + gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); + } + } else { + TRACE2(("gdth_interrupt() unknown controller type\n")); + if (!gdth_polling) + GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif } - gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); - } else { - TRACE2(("gdth_interrupt() unknown controller type\n")); - if (!gdth_polling) - GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - return; - } - TRACE(("gdth_interrupt() index %d stat %d info %d\n", - IStatus,ha->status,ha->info)); + TRACE(("gdth_interrupt() index %d stat %d info %d\n", + IStatus,ha->status,ha->info)); - if (gdth_from_wait) { - wait_hanum = hanum; - wait_index = (int)IStatus; - } + if (gdth_from_wait) { + wait_hanum = hanum; + wait_index = (int)IStatus; + } - if (IStatus == ASYNCINDEX) { - TRACE2(("gdth_interrupt() async. event\n")); - gdth_async_event(hanum); - if (!gdth_polling) - GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - gdth_next(hanum); - return; - } + if (IStatus == ASYNCINDEX) { + TRACE2(("gdth_interrupt() async. event\n")); + gdth_async_event(hanum); + if (!gdth_polling) + GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); + gdth_next(hanum); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif + } + + if (IStatus == SPEZINDEX) { + TRACE2(("Service unknown or not initialized !\n")); + ha->dvr.size = sizeof(ha->dvr.eu.driver); + ha->dvr.eu.driver.ionode = hanum; + gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); + if (!gdth_polling) + GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif + } + scp = ha->cmd_tab[IStatus-2].cmnd; + Service = ha->cmd_tab[IStatus-2].service; + ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND; + if (scp == UNUSED_CMND) { + TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); + ha->dvr.size = sizeof(ha->dvr.eu.driver); + ha->dvr.eu.driver.ionode = hanum; + ha->dvr.eu.driver.index = IStatus; + gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); + if (!gdth_polling) + GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif + } + if (scp == INTERNAL_CMND) { + TRACE(("gdth_interrupt() answer to internal command\n")); + if (!gdth_polling) + GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#else + return; +#endif + } - if (IStatus == SPEZINDEX) { - TRACE2(("Service unknown or not initialized !\n")); - ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = hanum; - gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); - if (!gdth_polling) - GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - return; - } - scp = ha->cmd_tab[IStatus-2].cmnd; - Service = ha->cmd_tab[IStatus-2].service; - ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND; - if (scp == UNUSED_CMND) { - TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); - ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = hanum; - ha->dvr.eu.driver.index = IStatus; - gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); - if (!gdth_polling) - GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - return; - } - if (scp == INTERNAL_CMND) { - TRACE(("gdth_interrupt() answer to internal command\n")); + TRACE(("gdth_interrupt() sync. status\n")); + rval = gdth_sync_event(hanum,Service,IStatus,scp); if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - return; - } + if (rval == 2) { + gdth_putq(hanum,scp,scp->SCp.this_residual); + } else if (rval == 1) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + GDTH_LOCK_SCSI_DONE(scp->device->host, flags); + scp->scsi_done(scp); + GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags); +#else + GDTH_LOCK_SCSI_DONE(flags); + scp->scsi_done(scp); + GDTH_UNLOCK_SCSI_DONE(flags); +#endif + } - TRACE(("gdth_interrupt() sync. status\n")); - rval = gdth_sync_event(hanum,Service,IStatus,scp); - if (!gdth_polling) - GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); - if (rval == 2) { - gdth_putq(hanum,scp,scp->SCp.this_residual); - } else if (rval == 1) { - GDTH_LOCK_SCSI_DONE(flags); - scp->scsi_done(scp); - GDTH_UNLOCK_SCSI_DONE(flags); +#ifdef INT_COAL + if (coalesced) { + /* go to the next status in the status buffer */ + ++pcs; +#ifdef GDTH_STATISTICS + ++act_int_coal; + if (act_int_coal > max_int_coal) { + max_int_coal = act_int_coal; + printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal); + } +#endif + /* see if there is another status */ + if (pcs->status == 0) + /* Stop the coalesce loop */ + next = FALSE; + } + } while (next); + + /* coalescing only for new GDT_PCIMPR controllers available */ + if (ha->type == GDT_PCIMPR && coalesced) { + gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); } +#endif + gdth_next(hanum); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + return IRQ_HANDLED; +#endif } static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) @@ -3385,7 +3837,7 @@ register gdth_ha_str *ha; gdth_msg_str *msg; gdth_cmd_str *cmdp; - unchar b; + unchar b, t; ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; @@ -3393,10 +3845,11 @@ service,ha->status)); if (service == SCREENSERVICE) { - msg = (gdth_msg_str *)ha->pscratch; - ha->scratch_busy = FALSE; + msg = ha->pmsg; TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n", msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen)); + if (msg->msg_len > MSGLEN+1) + msg->msg_len = MSGLEN+1; if (msg->msg_len) if (!(msg->msg_answer && msg->msg_ext)) { msg->msg_text[msg->msg_len] = '\0'; @@ -3414,11 +3867,10 @@ cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; - cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); - ha->scratch_busy = TRUE; + cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong32); + + sizeof(ulong64); ha->cmd_cnt = 0; gdth_copy_command(hanum); gdth_release_event(hanum); @@ -3449,11 +3901,10 @@ cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; - cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); - ha->scratch_busy = TRUE; + cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong32); + + sizeof(ulong64); ha->cmd_cnt = 0; gdth_copy_command(hanum); gdth_release_event(hanum); @@ -3462,11 +3913,39 @@ printk("\n"); } else { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + t = scp->device->id; +#else b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; + t = scp->target; +#endif if (scp->SCp.sent_command == -1 && b != ha->virt_bus) { - ha->raw[BUS_L2P(ha,b)].io_cnt[scp->target]--; + ha->raw[BUS_L2P(ha,b)].io_cnt[t]--; } /* cache or raw service */ + if (ha->status == S_BSY) { + TRACE2(("Controller busy -> retry !\n")); + if (scp->SCp.sent_command == GDT_MOUNT) + scp->SCp.sent_command = GDT_CLUST_INFO; + /* retry */ + return 2; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13) + if (scp->SCp.Status == GDTH_MAP_SG) + pci_unmap_sg(ha->pdev,scp->request_buffer, + scp->use_sg,scp->SCp.Message); + else if (scp->SCp.Status == GDTH_MAP_SINGLE) + pci_unmap_page(ha->pdev,scp->SCp.dma_handle, + scp->request_bufflen,scp->SCp.Message); + if (scp->SCp.buffer) { + dma_addr_t addr; + addr = (dma_addr_t)(ulong32)scp->SCp.buffer; + if (scp->host_scribble) + addr += (dma_addr_t)((ulong64)(ulong32)scp->host_scribble << 32); + pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE); + } +#endif if (ha->status == S_OK) { scp->SCp.Status = S_OK; scp->SCp.Message = ha->info; @@ -3475,12 +3954,12 @@ scp->SCp.sent_command)); /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ if (scp->SCp.sent_command == GDT_CLUST_INFO) { - ha->hdr[scp->target].cluster_type = (unchar)ha->info; - if (!(ha->hdr[scp->target].cluster_type & + ha->hdr[t].cluster_type = (unchar)ha->info; + if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) { /* NOT MOUNTED -> MOUNT */ scp->SCp.sent_command = GDT_MOUNT; - if (ha->hdr[scp->target].cluster_type & + if (ha->hdr[t].cluster_type & CLUSTER_RESERVED) { /* cluster drive RESERVED (on the other node) */ scp->SCp.phase = -2; /* reservation conflict */ @@ -3490,11 +3969,11 @@ } } else { if (scp->SCp.sent_command == GDT_MOUNT) { - ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED; - ha->hdr[scp->target].media_changed = TRUE; + ha->hdr[t].cluster_type |= CLUSTER_MOUNTED; + ha->hdr[t].media_changed = TRUE; } else if (scp->SCp.sent_command == GDT_UNMOUNT) { - ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED; - ha->hdr[scp->target].media_changed = TRUE; + ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED; + ha->hdr[t].media_changed = TRUE; } scp->SCp.sent_command = -1; } @@ -3504,21 +3983,13 @@ } else { /* RESERVE/RELEASE ? */ if (scp->cmnd[0] == RESERVE) { - ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED; + ha->hdr[t].cluster_type |= CLUSTER_RESERVED; } else if (scp->cmnd[0] == RELEASE) { - ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; } scp->result = DID_OK << 16; scp->sense_buffer[0] = 0; } - } else if (ha->status == S_BSY) { - TRACE2(("Controller busy -> retry !\n")); - scp->SCp.Status = S_BSY; - scp->SCp.Message = ha->info; - if (scp->SCp.sent_command == GDT_MOUNT) - scp->SCp.sent_command = GDT_CLUST_INFO; - /* retry */ - return 2; } else { scp->SCp.Status = ha->status; scp->SCp.Message = ha->info; @@ -3539,10 +4010,10 @@ scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } else if (service == CACHESERVICE) { if (ha->status == S_CACHE_UNKNOWN && - (ha->hdr[scp->target].cluster_type & + (ha->hdr[t].cluster_type & CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) { /* bus reset -> force GDT_CLUST_INFO */ - ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; } memset((char*)scp->sense_buffer,0,16); if (ha->status == (ushort)S_CACHE_RESERV) { @@ -3552,16 +4023,13 @@ scp->sense_buffer[2] = NOT_READY; scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } -#if LINUX_VERSION_CODE >= 0x010300 - if (scp->done != gdth_scsi_done) -#endif - { + if (scp->done != gdth_scsi_done) { ha->dvr.size = sizeof(ha->dvr.eu.sync); ha->dvr.eu.sync.ionode = hanum; ha->dvr.eu.sync.service = service; ha->dvr.eu.sync.status = ha->status; ha->dvr.eu.sync.info = ha->info; - ha->dvr.eu.sync.hostdrive = scp->target; + ha->dvr.eu.sync.hostdrive = t; if (ha->status >= 0x8000) gdth_store_event(ha, ES_SYNC, 0, &ha->dvr); else @@ -3651,9 +4119,9 @@ /*31*/ "\007\000\002\012\001\013\001" "GDT HA %u, Fault bus %u, ID %u: old disk detected", /*32*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is illegal", + "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is invalid", /*33*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: illegal device detected", + "GDT HA %u, Fault bus %u, ID %u: invalid device detected", /*34*/ "\011\000\002\012\001\013\001\006\004" "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)", /*35*/ "\007\000\002\012\001\013\001" @@ -3744,13 +4212,11 @@ static int gdth_async_event(int hanum) { gdth_ha_str *ha; - gdth_msg_str *msg; gdth_cmd_str *cmdp; int cmd_index; ha = HADATA(gdth_ctr_tab[hanum]); cmdp= ha->pccb; - msg = (gdth_msg_str *)ha->pscratch; TRACE2(("gdth_async_event() ha %d serv %d\n", hanum,ha->service)); @@ -3766,11 +4232,10 @@ cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE; - cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); - ha->scratch_busy = TRUE; + cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong32); + + sizeof(ulong64); ha->cmd_cnt = 0; gdth_copy_command(hanum); if (ha->type == GDT_EISA) @@ -3943,6 +4408,8 @@ virt_ctr = val; else if (!strncmp(argv, "shared_access:", 14)) shared_access = val; + else if (!strncmp(argv, "probe_eisa_isa:", 15)) + probe_eisa_isa = val; else if (!strncmp(argv, "reserve_list:", 13)) { reserve_list[0] = val; for (i = 1; i < MAX_RES_ARGS; i++) { @@ -3988,10 +4455,11 @@ GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp)) { struct Scsi_Host *shp; + gdth_pci_str pcistr[MAXHA]; gdth_ha_str *ha; ulong32 isa_bios; ushort eisa_slot; - int i,hanum,cnt,ctr; + int i,hanum,cnt,ctr,err; unchar b; @@ -4014,347 +4482,493 @@ TRACE(("gdth_detect()\n")); if (disable) { - printk("GDT: Controller driver disabled from command line !\n"); + printk("GDT-HA: Controller driver disabled from command line !\n"); return 0; } - printk("GDT: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR); + printk("GDT-HA: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR); /* initializations */ gdth_polling = TRUE; b = 0; gdth_clear_events(); - /* scanning for controllers, at first: ISA controller */ - for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) { - if (gdth_ctr_count >= MAXHA) - break; - if (gdth_search_isa(isa_bios)) { /* controller found */ - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; - ha = HADATA(shp); - if (!gdth_init_isa(isa_bios,ha)) { - scsi_unregister(shp); - continue; - } -#ifdef __ia64__ - break; -#else - /* controller found and initialized */ - printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", - isa_bios,ha->irq,ha->drq); + /* As default we do not probe for EISA or ISA controllers */ + if (probe_eisa_isa) { + /* scanning for controllers, at first: ISA controller */ + for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) { + dma_addr_t scratch_dma_handle; + scratch_dma_handle = 0; -#if LINUX_VERSION_CODE >= 0x010346 - if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) -#else - if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) -#endif - { - printk("GDT-ISA: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - if (request_dma(ha->drq,"gdth")) { - printk("GDT-ISA: Unable to allocate DMA channel\n"); -#if LINUX_VERSION_CODE >= 0x010346 - free_irq(ha->irq,ha); -#else - free_irq(ha->irq); -#endif - scsi_unregister(shp); - continue; - } - set_dma_mode(ha->drq,DMA_MODE_CASCADE); - enable_dma(ha->drq); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - - ha->pccb = CMDDATA(shp); -#if LINUX_VERSION_CODE >= 0x020322 - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - GDTH_SCRATCH_ORD); -#else - ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); -#endif - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (ha->pscratch == NULL || !gdth_search_drives(hanum)) { - printk("GDT-ISA: Error during device scan\n"); - --gdth_ctr_count; - --gdth_ctr_vcount; - if (ha->pscratch != NULL) -#if LINUX_VERSION_CODE >= 0x020322 - free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); -#else - scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); -#endif -#if LINUX_VERSION_CODE >= 0x010346 - free_irq(ha->irq,ha); + if (gdth_ctr_count >= MAXHA) + break; + if (gdth_search_isa(isa_bios)) { /* controller found */ + shp = scsi_register(shtp,sizeof(gdth_ext_str)); + if (shp == NULL) + continue; + + ha = HADATA(shp); + if (!gdth_init_isa(isa_bios,ha)) { + scsi_unregister(shp); + continue; + } +#ifdef __ia64__ + break; #else - free_irq(ha->irq); + /* controller found and initialized */ + printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", + isa_bios,ha->irq,ha->drq); + + if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) { + printk("GDT-ISA: Unable to allocate IRQ\n"); + scsi_unregister(shp); + continue; + } + if (request_dma(ha->drq,"gdth")) { + printk("GDT-ISA: Unable to allocate DMA channel\n"); + free_irq(ha->irq,ha); + scsi_unregister(shp); + continue; + } + set_dma_mode(ha->drq,DMA_MODE_CASCADE); + enable_dma(ha->drq); + shp->unchecked_isa_dma = 1; + shp->irq = ha->irq; + shp->dma_channel = ha->drq; + hanum = gdth_ctr_count; + gdth_ctr_tab[gdth_ctr_count++] = shp; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum= 0; + + ha->pccb = CMDDATA(shp); + ha->ccb_phys = 0L; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + ha->pdev = NULL; + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + ha->scratch_phys = scratch_dma_handle; + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + ha->msg_phys = scratch_dma_handle; +#ifdef INT_COAL + ha->coal_stat = (gdth_coal_status *) + pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, &scratch_dma_handle); + ha->coal_stat_phys = scratch_dma_handle; +#endif +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); + if (ha->pscratch) + ha->scratch_phys = virt_to_bus(ha->pscratch); + ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA); + if (ha->pmsg) + ha->msg_phys = virt_to_bus(ha->pmsg); +#ifdef INT_COAL + ha->coal_stat = + scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, + GFP_ATOMIC | GFP_DMA); + if (ha->coal_stat) + ha->coal_stat_phys = virt_to_bus(ha->coal_stat); +#endif +#endif + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + if (ha->pscratch == NULL || ha->pmsg == NULL || + !gdth_search_drives(hanum)) { + printk("GDT-ISA: Error during device scan\n"); + --gdth_ctr_count; + --gdth_ctr_vcount; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#ifdef INT_COAL + if (ha->coal_stat) + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, ha->coal_stat, + ha->coal_stat_phys); +#endif + if (ha->pscratch) + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + if (ha->pmsg) + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); +#else +#ifdef INT_COAL + if (ha->coal_stat) + scsi_init_free((void *)ha->coal_stat, + sizeof(gdth_coal_status) * MAXOFFSETS); +#endif + if (ha->pscratch) + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); + if (ha->pmsg) + scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str)); #endif - scsi_unregister(shp); - continue; + free_irq(ha->irq,ha); + scsi_unregister(shp); + continue; + } + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + shp->highmem_io = 0; +#endif + if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) + shp->max_cmd_len = 16; +#endif + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 1; + shp->irq = ha->irq; + shp->dma_channel = ha->drq; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; + } + } + + GDTH_INIT_LOCK_HA(ha); + gdth_enable_int(hanum); +#endif /* !__ia64__ */ } - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; + } -#if LINUX_VERSION_CODE >= 0x020000 - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) + /* scanning for EISA controllers */ + for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) { + dma_addr_t scratch_dma_handle; + scratch_dma_handle = 0; + + if (gdth_ctr_count >= MAXHA) + break; + if (gdth_search_eisa(eisa_slot)) { /* controller found */ + shp = scsi_register(shtp,sizeof(gdth_ext_str)); + if (shp == NULL) + continue; + + ha = HADATA(shp); + if (!gdth_init_eisa(eisa_slot,ha)) { + scsi_unregister(shp); + continue; + } + /* controller found and initialized */ + printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", + eisa_slot>>12,ha->irq); + + if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) { + printk("GDT-EISA: Unable to allocate IRQ\n"); + scsi_unregister(shp); + continue; + } + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + hanum = gdth_ctr_count; + gdth_ctr_tab[gdth_ctr_count++] = shp; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum= 0; + TRACE2(("EISA detect Bus 0: hanum %d\n", + NUMDATA(shp)->hanum)); + + ha->pccb = CMDDATA(shp); + ha->ccb_phys = 0L; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + ha->pdev = NULL; + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + ha->scratch_phys = scratch_dma_handle; + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + ha->msg_phys = scratch_dma_handle; +#ifdef INT_COAL + ha->coal_stat = (gdth_coal_status *) + pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, &scratch_dma_handle); + ha->coal_stat_phys = scratch_dma_handle; +#endif + ha->ccb_phys = + pci_map_single(ha->pdev,ha->pccb, + sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); + if (ha->pscratch) + ha->scratch_phys = virt_to_bus(ha->pscratch); + ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA); + if (ha->pmsg) + ha->msg_phys = virt_to_bus(ha->pmsg); +#ifdef INT_COAL + ha->coal_stat = + scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, + GFP_ATOMIC | GFP_DMA); + if (ha->coal_stat) + ha->coal_stat_phys = virt_to_bus(ha->coal_stat); +#endif + ha->ccb_phys = virt_to_bus(ha->pccb); +#endif + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + if (ha->pscratch == NULL || ha->pmsg == NULL || + !gdth_search_drives(hanum)) { + printk("GDT-EISA: Error during device scan\n"); + --gdth_ctr_count; + --gdth_ctr_vcount; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#ifdef INT_COAL + if (ha->coal_stat) + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, ha->coal_stat, + ha->coal_stat_phys); +#endif + if (ha->pscratch) + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + if (ha->pmsg) + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + if (ha->ccb_phys) + pci_unmap_single(ha->pdev,ha->ccb_phys, + sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); +#else +#ifdef INT_COAL + if (ha->coal_stat) + scsi_init_free((void *)ha->coal_stat, + sizeof(gdth_coal_status) * MAXOFFSETS); +#endif + if (ha->pscratch) + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); + if (ha->pmsg) + scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str)); #endif - { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; + free_irq(ha->irq,ha); + scsi_unregister(shp); + continue; } - } + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + shp->highmem_io = 0; +#endif + if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) + shp->max_cmd_len = 16; +#endif + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; + } + } - GDTH_INIT_LOCK_HA(ha); - gdth_enable_int(hanum); -#endif /* !__ia64__ */ + GDTH_INIT_LOCK_HA(ha); + gdth_enable_int(hanum); + } } } - /* scanning for EISA controllers */ - for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) { - if (gdth_ctr_count >= MAXHA) + /* scanning for PCI controllers */ + cnt = gdth_search_pci(pcistr); + printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt); + gdth_sort_pci(pcistr,cnt); + for (ctr = 0; ctr < cnt; ++ctr) { + dma_addr_t scratch_dma_handle; + scratch_dma_handle = 0; + + if (gdth_ctr_count >= MAXHA) break; - if (gdth_search_eisa(eisa_slot)) { /* controller found */ - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; - - ha = HADATA(shp); - if (!gdth_init_eisa(eisa_slot,ha)) { - scsi_unregister(shp); - continue; - } - /* controller found and initialized */ - printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", - eisa_slot>>12,ha->irq); + shp = scsi_register(shtp,sizeof(gdth_ext_str)); + if (shp == NULL) + continue; + + ha = HADATA(shp); + if (!gdth_init_pci(&pcistr[ctr],ha)) { + scsi_unregister(shp); + continue; + } + /* controller found and initialized */ + printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", + pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq); -#if LINUX_VERSION_CODE >= 0x010346 - if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) -#else - if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) + if (request_irq(ha->irq, gdth_interrupt, + SA_INTERRUPT|SA_SHIRQ, "gdth", ha)) + { + printk("GDT-PCI: Unable to allocate IRQ\n"); + scsi_unregister(shp); + continue; + } + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + hanum = gdth_ctr_count; + gdth_ctr_tab[gdth_ctr_count++] = shp; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum= 0; + + ha->pccb = CMDDATA(shp); + ha->ccb_phys = 0L; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + ha->scratch_phys = scratch_dma_handle; + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + ha->msg_phys = scratch_dma_handle; +#ifdef INT_COAL + ha->coal_stat = (gdth_coal_status *) + pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, &scratch_dma_handle); + ha->coal_stat_phys = scratch_dma_handle; +#endif +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); + if (ha->pscratch) + ha->scratch_phys = virt_to_bus(ha->pscratch); + ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA); + if (ha->pmsg) + ha->msg_phys = virt_to_bus(ha->pmsg); +#ifdef INT_COAL + ha->coal_stat = + scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, + GFP_ATOMIC | GFP_DMA); + if (ha->coal_stat) + ha->coal_stat_phys = virt_to_bus(ha->coal_stat); #endif - { - printk("GDT-EISA: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - TRACE2(("EISA detect Bus 0: hanum %d\n", - NUMDATA(shp)->hanum)); - - ha->pccb = CMDDATA(shp); -#if LINUX_VERSION_CODE >= 0x020322 - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - GDTH_SCRATCH_ORD); -#else - ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); -#endif - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (ha->pscratch == NULL || !gdth_search_drives(hanum)) { - printk("GDT-EISA: Error during device scan\n"); - --gdth_ctr_count; - --gdth_ctr_vcount; - if (ha->pscratch != NULL) -#if LINUX_VERSION_CODE >= 0x020322 - free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); -#else - scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); #endif -#if LINUX_VERSION_CODE >= 0x010346 - free_irq(ha->irq,ha); -#else - free_irq(ha->irq); -#endif - scsi_unregister(shp); - continue; - } + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + err = FALSE; + if (ha->pscratch == NULL || ha->pmsg == NULL || + !gdth_search_drives(hanum)) { + err = TRUE; + } else { if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) hdr_channel = ha->bus_cnt; ha->virt_bus = hdr_channel; -#if LINUX_VERSION_CODE >= 0x020000 - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) -#endif - { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_set_device(shp, &pcistr[ctr].pdev->dev); +#else + scsi_set_pci_device(shp, pcistr[ctr].pdev); +#endif + if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)|| + /* 64-bit DMA only supported from FW >= x.43 */ + (!ha->dma64_support)) { + if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) { + printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum); + err = TRUE; } - } - - GDTH_INIT_LOCK_HA(ha); - gdth_enable_int(hanum); + } else { + shp->max_cmd_len = 16; + if (!pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffffffffffffULL)) { + printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum); + } else if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) { + printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum); + err = TRUE; + } + } +#endif } - } - /* scanning for PCI controllers */ -#if LINUX_VERSION_CODE >= 0x2015C - if (pci_present()) -#else - if (pcibios_present()) + if (err) { + printk("GDT-PCI %d: Error during device scan\n", hanum); + --gdth_ctr_count; + --gdth_ctr_vcount; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#ifdef INT_COAL + if (ha->coal_stat) + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, ha->coal_stat, + ha->coal_stat_phys); +#endif + if (ha->pscratch) + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + if (ha->pmsg) + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); +#else +#ifdef INT_COAL + if (ha->coal_stat) + scsi_init_free((void *)ha->coal_stat, + sizeof(gdth_coal_status) * MAXOFFSETS); +#endif + if (ha->pscratch) + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); + if (ha->pmsg) + scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str)); #endif - { - gdth_pci_str pcistr[MAXHA]; + free_irq(ha->irq,ha); + scsi_unregister(shp); + continue; + } - cnt = gdth_search_pci(pcistr); - printk("GDT: Found %d PCI Storage RAID Controllers\n",cnt); - gdth_sort_pci(pcistr,cnt); - for (ctr = 0; ctr < cnt; ++ctr) { - if (gdth_ctr_count >= MAXHA) - break; - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; - - ha = HADATA(shp); - if (!gdth_init_pci(&pcistr[ctr],ha)) { - scsi_unregister(shp); - continue; - } - /* controller found and initialized */ - printk("GDT CTR%d: Configuring GDT-PCI HA at %d/%d IRQ %u\n", - ctr,pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq); - -#if LINUX_VERSION_CODE >= 0x010346 - if (request_irq(ha->irq, gdth_interrupt, - SA_INTERRUPT|SA_SHIRQ, "gdth", ha)) -#else - if (request_irq(ha->irq, gdth_interrupt, - SA_INTERRUPT|SA_SHIRQ, "gdth")) -#endif - { - printk("GDT-PCI: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - - ha->pccb = CMDDATA(shp); -#if LINUX_VERSION_CODE >= 0x020322 - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - GDTH_SCRATCH_ORD); -#else - ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); -#endif - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; icmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (ha->pscratch == NULL || !gdth_search_drives(hanum)) { - printk("GDT-PCI: Error during device scan\n"); - --gdth_ctr_count; - --gdth_ctr_vcount; - if (ha->pscratch != NULL) -#if LINUX_VERSION_CODE >= 0x020322 - free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); -#else - scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); -#endif -#if LINUX_VERSION_CODE >= 0x010346 - free_irq(ha->irq,ha); -#else - free_irq(ha->irq); -#endif - scsi_unregister(shp); - continue; + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; } - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; + } -#if LINUX_VERSION_CODE >= 0x020000 - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) -#endif - { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; - } - } - GDTH_INIT_LOCK_HA(ha); - gdth_enable_int(hanum); - } + GDTH_INIT_LOCK_HA(ha); + gdth_enable_int(hanum); } - + TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count)); if (gdth_ctr_count > 0) { #ifdef GDTH_STATISTICS @@ -4365,9 +4979,8 @@ gdth_timer.function = gdth_timeout; add_timer(&gdth_timer); #endif -#if LINUX_VERSION_CODE >= 0x020100 + major = register_chrdev(0,"gdth",&gdth_fops); register_reboot_notifier(&gdth_notifier); -#endif } gdth_polling = FALSE; return gdth_ctr_vcount; @@ -4383,26 +4996,47 @@ if (NUMDATA(shp)->busnum == 0) { hanum = NUMDATA(shp)->hanum; ha = HADATA(gdth_ctr_tab[hanum]); -#if LINUX_VERSION_CODE >= 0x010300 - gdth_flush(hanum); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (ha->sdev) { + scsi_free_host_dev(ha->sdev); + ha->sdev = NULL; + } #endif + gdth_flush(hanum); if (shp->irq) { -#if LINUX_VERSION_CODE >= 0x010346 free_irq(shp->irq,ha); -#else - free_irq(shp->irq); -#endif } #ifndef __ia64__ if (shp->dma_channel != 0xff) { free_dma(shp->dma_channel); } #endif -#if LINUX_VERSION_CODE >= 0x020322 - free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); -#else - scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#ifdef INT_COAL + if (ha->coal_stat) + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys); +#endif + if (ha->pscratch) + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + if (ha->pmsg) + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + if (ha->ccb_phys) + pci_unmap_single(ha->pdev,ha->ccb_phys, + sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); +#else +#ifdef INT_COAL + if (ha->coal_stat) + scsi_init_free((void *)ha->coal_stat, + sizeof(gdth_coal_status) * MAXOFFSETS); +#endif + if (ha->pscratch) + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); + if (ha->pmsg) + scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str)); #endif gdth_ctr_released++; TRACE2(("gdth_release(): HA %d of %d\n", @@ -4412,9 +5046,8 @@ #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif -#if LINUX_VERSION_CODE >= 0x020100 + unregister_chrdev(major,"gdth"); unregister_reboot_notifier(&gdth_notifier); -#endif } } @@ -4467,6 +5100,7 @@ return ((const char *)ha->binfo.type_string); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* old error handling */ int gdth_abort(Scsi_Cmnd *scp) { @@ -4474,17 +5108,13 @@ return SCSI_ABORT_SNOOZE; } -#if LINUX_VERSION_CODE >= 0x010346 int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags) -#else -int gdth_reset(Scsi_Cmnd *scp) -#endif { TRACE2(("gdth_reset()\n")); return SCSI_RESET_PUNT; } +#endif -#if LINUX_VERSION_CODE >= 0x02015F /* new error handling */ int gdth_eh_abort(Scsi_Cmnd *scp) { @@ -4507,15 +5137,24 @@ unchar b; TRACE2(("gdth_eh_bus_reset()\n")); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + hanum = NUMDATA(scp->device->host)->hanum; + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; +#else hanum = NUMDATA(scp->host)->hanum; b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; +#endif ha = HADATA(gdth_ctr_tab[hanum]); /* clear command tab */ GDTH_LOCK_HA(ha, flags); for (i = 0; i < GDTH_MAXCMDS; ++i) { cmnd = ha->cmd_tab[i].cmnd; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b) +#else if (!SPECIAL_SCP(cmnd) && cmnd->channel == b) +#endif ha->cmd_tab[i].cmnd = UNUSED_CMND; } GDTH_UNLOCK_HA(ha, flags); @@ -4556,32 +5195,41 @@ TRACE2(("gdth_eh_host_reset()\n")); return FAILED; } -#endif -#if LINUX_VERSION_CODE >= 0x010300 -int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) #else -int gdth_bios_param(Disk *disk,int dev,int *ip) +int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) #endif { unchar b, t; int hanum; gdth_ha_str *ha; + struct scsi_device *sd; + unsigned capacity; - hanum = NUMDATA(disk->device->host)->hanum; - b = virt_ctr ? NUMDATA(disk->device->host)->busnum : disk->device->channel; - t = disk->device->id; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sd = sdev; + capacity = cap; +#else + sd = disk->device; + capacity = disk->capacity; +#endif + hanum = NUMDATA(sd->host)->hanum; + b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel; + t = sd->id; TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); ha = HADATA(gdth_ctr_tab[hanum]); if (b != ha->virt_bus || ha->hdr[t].heads == 0) { /* raw device or host drive without mapping information */ TRACE2(("Evaluate mapping\n")); - gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); + gdth_eval_mapping(capacity,&ip[2],&ip[0],&ip[1]); } else { ip[0] = ha->hdr[t].heads; ip[1] = ha->hdr[t].secs; - ip[2] = disk->capacity / ip[0] / ip[1]; + ip[2] = capacity / ip[0] / ip[1]; } TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", @@ -4595,37 +5243,813 @@ int hanum; int priority; - TRACE(("gdth_queuecommand() cmd 0x%x id %d lun %d\n", - scp->cmnd[0],scp->target,scp->lun)); + TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0])); scp->scsi_done = (void *)done; scp->SCp.have_data_in = 1; scp->SCp.phase = -1; scp->SCp.sent_command = -1; + scp->SCp.Status = GDTH_MAP_NONE; + scp->SCp.buffer = (struct scatterlist *)NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + hanum = NUMDATA(scp->device->host)->hanum; +#else hanum = NUMDATA(scp->host)->hanum; +#endif #ifdef GDTH_STATISTICS ++act_ios; #endif priority = DEFAULT_PRI; -#if LINUX_VERSION_CODE >= 0x010300 if (scp->done == gdth_scsi_done) priority = scp->SCp.this_residual; -#endif gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6); gdth_putq( hanum, scp, priority ); gdth_next( hanum ); return 0; } -#if LINUX_VERSION_CODE >= 0x010300 + +static int gdth_open(struct inode *inode, struct file *filep) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_ha_str *ha; + int i; + + for (i = 0; i < gdth_ctr_count; i++) { + ha = HADATA(gdth_ctr_tab[i]); + if (!ha->sdev) + ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]); + } +#endif + + TRACE(("gdth_open()\n")); + return 0; +} + +static int gdth_close(struct inode *inode, struct file *filep) +{ + TRACE(("gdth_close()\n")); + return 0; +} + +static int ioc_event(unsigned long arg) +{ + gdth_ioctl_event evt; + gdth_ha_str *ha; + ulong flags; + + if (copy_from_user(&evt, (char *)arg, sizeof(gdth_ioctl_event)) || + evt.ionode >= gdth_ctr_count) + return -EFAULT; + ha = HADATA(gdth_ctr_tab[evt.ionode]); + + if (evt.erase == 0xff) { + if (evt.event.event_source == ES_TEST) + evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); + else if (evt.event.event_source == ES_DRIVER) + evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); + else if (evt.event.event_source == ES_SYNC) + evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); + else + evt.event.event_data.size=sizeof(evt.event.event_data.eu.async); + GDTH_LOCK_HA(ha, flags); + gdth_store_event(ha, evt.event.event_source, evt.event.event_idx, + &evt.event.event_data); + GDTH_UNLOCK_HA(ha, flags); + } else if (evt.erase == 0xfe) { + gdth_clear_events(); + } else if (evt.erase == 0) { + evt.handle = gdth_read_event(ha, evt.handle, &evt.event); + } else { + gdth_readapp_event(ha, evt.erase, &evt.event); + } + if (copy_to_user((char *)arg, &evt, sizeof(gdth_ioctl_event))) + return -EFAULT; + return 0; +} + +static int ioc_lockdrv(unsigned long arg) +{ + gdth_ioctl_lockdrv ldrv; + unchar i, j; + ulong flags; + gdth_ha_str *ha; + + if (copy_from_user(&ldrv, (char *)arg, sizeof(gdth_ioctl_lockdrv)) || + ldrv.ionode >= gdth_ctr_count) + return -EFAULT; + ha = HADATA(gdth_ctr_tab[ldrv.ionode]); + + for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) { + j = ldrv.drives[i]; + if (j >= MAX_HDRIVES || !ha->hdr[j].present) + continue; + if (ldrv.lock) { + GDTH_LOCK_HA(ha, flags); + ha->hdr[j].lock = 1; + GDTH_UNLOCK_HA(ha, flags); + gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); + gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); + } else { + GDTH_LOCK_HA(ha, flags); + ha->hdr[j].lock = 0; + GDTH_UNLOCK_HA(ha, flags); + gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); + gdth_next(ldrv.ionode); + } + } + return 0; +} + +static int ioc_resetdrv(unsigned long arg, char *cmnd) +{ + gdth_ioctl_reset res; + gdth_cmd_str cmd; + int hanum; + gdth_ha_str *ha; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Cmnd *scp; +#else + Scsi_Cmnd scp; +#endif + + if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) || + res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES) + return -EFAULT; + hanum = res.ionode; + ha = HADATA(gdth_ctr_tab[hanum]); + + if (!ha->hdr[res.number].present) + return 0; + memset(&cmd, 0, sizeof(gdth_cmd_str)); + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_CLUST_RESET; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = res.number; + else + cmd.u.cache.DeviceNo = res.number; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + srp = scsi_allocate_request(ha->sdev, GFP_KERNEL); + if (!srp) + return -ENOMEM; + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; + gdth_do_req(srp, &cmd, cmnd, 30); + res.status = (ushort)srp->sr_command->SCp.Status; + scsi_release_request(srp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scp = scsi_allocate_device(ha->sdev, 1, FALSE); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; + gdth_do_cmd(scp, &cmd, cmnd, 30); + res.status = (ushort)scp->SCp.Status; + scsi_release_command(scp); +#else + memset(&ha->sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + ha->sdev.host = scp.host = gdth_ctr_tab[hanum]; + ha->sdev.id = scp.target = ha->sdev.host->this_id; + scp.device = &ha->sdev; + gdth_do_cmd(&scp, &cmd, cmnd, 30); + res.status = (ushort)scp.SCp.Status; +#endif + if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset))) + return -EFAULT; + return 0; +} + +static int ioc_general(unsigned long arg, char *cmnd) +{ + gdth_ioctl_general gen; + char *buf = NULL; + ulong64 paddr; + int hanum; + gdth_ha_str *ha; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Cmnd *scp; +#else + Scsi_Cmnd scp; +#endif + + if (copy_from_user(&gen, (char *)arg, sizeof(gdth_ioctl_general)) || + gen.ionode >= gdth_ctr_count) + return -EFAULT; + hanum = gen.ionode; + ha = HADATA(gdth_ctr_tab[hanum]); + if (gen.data_len + gen.sense_len != 0) { + if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, + FALSE, &paddr))) + return -EFAULT; + if (copy_from_user(buf, (char *)arg + sizeof(gdth_ioctl_general), + gen.data_len + gen.sense_len)) { + gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + return -EFAULT; + } + + if (gen.command.OpCode == GDT_IOCTL) { + gen.command.u.ioctl.p_param = paddr; + } else if (gen.command.Service == CACHESERVICE) { + if (ha->cache_feat & GDT_64BIT) { + /* copy elements from 32-bit IOCTL structure */ + gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt; + gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo; + gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo; + /* addresses */ + if (ha->cache_feat & SCATTER_GATHER) { + gen.command.u.cache64.DestAddr = (ulong64)-1; + gen.command.u.cache64.sg_canz = 1; + gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; + gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len; + gen.command.u.cache64.sg_lst[1].sg_len = 0; + } else { + gen.command.u.cache64.DestAddr = paddr; + gen.command.u.cache64.sg_canz = 0; + } + } else { + if (ha->cache_feat & SCATTER_GATHER) { + gen.command.u.cache.DestAddr = 0xffffffff; + gen.command.u.cache.sg_canz = 1; + gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; + gen.command.u.cache.sg_lst[1].sg_len = 0; + } else { + gen.command.u.cache.DestAddr = paddr; + gen.command.u.cache.sg_canz = 0; + } + } + } else if (gen.command.Service == SCSIRAWSERVICE) { + if (ha->raw_feat & GDT_64BIT) { + /* copy elements from 32-bit IOCTL structure */ + char cmd[16]; + gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len; + gen.command.u.raw64.bus = gen.command.u.raw.bus; + gen.command.u.raw64.lun = gen.command.u.raw.lun; + gen.command.u.raw64.target = gen.command.u.raw.target; + memcpy(cmd, gen.command.u.raw.cmd, 16); + memcpy(gen.command.u.raw64.cmd, cmd, 16); + gen.command.u.raw64.clen = gen.command.u.raw.clen; + gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen; + gen.command.u.raw64.direction = gen.command.u.raw.direction; + /* addresses */ + if (ha->raw_feat & SCATTER_GATHER) { + gen.command.u.raw64.sdata = (ulong64)-1; + gen.command.u.raw64.sg_ranz = 1; + gen.command.u.raw64.sg_lst[0].sg_ptr = paddr; + gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len; + gen.command.u.raw64.sg_lst[1].sg_len = 0; + } else { + gen.command.u.raw64.sdata = paddr; + gen.command.u.raw64.sg_ranz = 0; + } + gen.command.u.raw64.sense_data = paddr + gen.data_len; + } else { + if (ha->raw_feat & SCATTER_GATHER) { + gen.command.u.raw.sdata = 0xffffffff; + gen.command.u.raw.sg_ranz = 1; + gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.raw.sg_lst[0].sg_len = gen.data_len; + gen.command.u.raw.sg_lst[1].sg_len = 0; + } else { + gen.command.u.raw.sdata = paddr; + gen.command.u.raw.sg_ranz = 0; + } + gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len; + } + } else { + gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + return -EFAULT; + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + srp = scsi_allocate_request(ha->sdev, GFP_KERNEL); + if (!srp) + return -ENOMEM; + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; + gdth_do_req(srp, &gen.command, cmnd, gen.timeout); + gen.status = srp->sr_command->SCp.Status; + gen.info = srp->sr_command->SCp.Message; + scsi_release_request(srp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scp = scsi_allocate_device(ha->sdev, 1, FALSE); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; + gdth_do_cmd(scp, &gen.command, cmnd, gen.timeout); + gen.status = scp->SCp.Status; + gen.info = scp->SCp.Message; + scsi_release_command(scp); +#else + memset(&ha->sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + ha->sdev.host = scp.host = gdth_ctr_tab[hanum]; + ha->sdev.id = scp.target = ha->sdev.host->this_id; + scp.device = &ha->sdev; + gdth_do_cmd(&scp, &gen.command, cmnd, gen.timeout); + gen.status = scp.SCp.Status; + gen.info = scp.SCp.Message; +#endif + + if (copy_to_user((char *)arg + sizeof(gdth_ioctl_general), buf, + gen.data_len + gen.sense_len)) { + gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + return -EFAULT; + } + if (copy_to_user((char *)arg, &gen, + sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) { + gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + return -EFAULT; + } + gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + return 0; +} + +static int ioc_hdrlist(unsigned long arg, char *cmnd) +{ + gdth_ioctl_rescan rsc; + gdth_cmd_str cmd; + gdth_ha_str *ha; + unchar i; + int hanum; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Cmnd *scp; +#else + Scsi_Cmnd scp; +#endif + + if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) || + rsc.ionode >= gdth_ctr_count) + return -EFAULT; + hanum = rsc.ionode; + ha = HADATA(gdth_ctr_tab[hanum]); + memset(&cmd, 0, sizeof(gdth_cmd_str)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + srp = scsi_allocate_request(ha->sdev, GFP_KERNEL); + if (!srp) + return -ENOMEM; + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scp = scsi_allocate_device(ha->sdev, 1, FALSE); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; +#else + memset(&ha->sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + ha->sdev.host = scp.host = gdth_ctr_tab[hanum]; + ha->sdev.id = scp.target = ha->sdev.host->this_id; + scp.device = &ha->sdev; +#endif + + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!ha->hdr[i].present) { + rsc.hdr_list[i].bus = 0xff; + continue; + } + rsc.hdr_list[i].bus = ha->virt_bus; + rsc.hdr_list[i].target = i; + rsc.hdr_list[i].lun = 0; + rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; + if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_CLUST_INFO; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = i; + else + cmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + if (srp->sr_command->SCp.Status == S_OK) + rsc.hdr_list[i].cluster_type = srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + if (scp->SCp.Status == S_OK) + rsc.hdr_list[i].cluster_type = scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + if (scp.SCp.Status == S_OK) + rsc.hdr_list[i].cluster_type = scp.SCp.Message; +#endif + } + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_release_request(srp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scsi_release_command(scp); +#endif + + if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan))) + return -EFAULT; + return 0; +} + +static int ioc_rescan(unsigned long arg, char *cmnd) +{ + gdth_ioctl_rescan rsc; + gdth_cmd_str cmd; + ushort i, status, hdr_cnt; + ulong32 info; + int hanum, cyls, hds, secs; + ulong flags; + gdth_ha_str *ha; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Cmnd *scp; +#else + Scsi_Cmnd scp; +#endif + + if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) || + rsc.ionode >= gdth_ctr_count) + return -EFAULT; + hanum = rsc.ionode; + ha = HADATA(gdth_ctr_tab[hanum]); + memset(&cmd, 0, sizeof(gdth_cmd_str)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + srp = scsi_allocate_request(ha->sdev, GFP_KERNEL); + if (!srp) + return -ENOMEM; + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scp = scsi_allocate_device(ha->sdev, 1, FALSE); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; +#else + memset(&ha->sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + ha->sdev.host = scp.host = gdth_ctr_tab[hanum]; + ha->sdev.id = scp.target = ha->sdev.host->this_id; + scp.device = &ha->sdev; +#endif + + if (rsc.flag == 0) { + /* old method: re-init. cache service */ + cmd.Service = CACHESERVICE; + if (ha->cache_feat & GDT_64BIT) { + cmd.OpCode = GDT_X_INIT_HOST; + cmd.u.cache64.DeviceNo = LINUX_OS; + } else { + cmd.OpCode = GDT_INIT; + cmd.u.cache.DeviceNo = LINUX_OS; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + status = (ushort)srp->sr_command->SCp.Status; + info = (ulong32)srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + i = 0; + hdr_cnt = (status == S_OK ? (ushort)info : 0); + } else { + i = rsc.hdr_no; + hdr_cnt = i + 1; + } + for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) { + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_INFO; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = i; + else + cmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + status = (ushort)srp->sr_command->SCp.Status; + info = (ulong32)srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + rsc.hdr_list[i].bus = ha->virt_bus; + rsc.hdr_list[i].target = i; + rsc.hdr_list[i].lun = 0; + if (status != S_OK) { + ha->hdr[i].present = FALSE; + } else { + ha->hdr[i].present = TRUE; + ha->hdr[i].size = info; + /* evaluate mapping */ + ha->hdr[i].size &= ~SECS32; + gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); + ha->hdr[i].heads = hds; + ha->hdr[i].secs = secs; + /* round size */ + ha->hdr[i].size = cyls * hds * secs; + } + GDTH_UNLOCK_HA(ha, flags); + if (status != S_OK) + continue; + + /* extended info, if GDT_64BIT, for drives > 2 TB */ + /* but we need ha->info2, not yet stored in scp->SCp */ + + /* devtype, cluster info, R/W attribs */ + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_DEVTYPE; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = i; + else + cmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + status = (ushort)srp->sr_command->SCp.Status; + info = (ulong32)srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0); + GDTH_UNLOCK_HA(ha, flags); + + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_CLUST_INFO; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = i; + else + cmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + status = (ushort)srp->sr_command->SCp.Status; + info = (ulong32)srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[i].cluster_type = + ((status == S_OK && !shared_access) ? (ushort)info : 0); + GDTH_UNLOCK_HA(ha, flags); + rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; + + cmd.Service = CACHESERVICE; + cmd.OpCode = GDT_RW_ATTRIBS; + if (ha->cache_feat & GDT_64BIT) + cmd.u.cache64.DeviceNo = i; + else + cmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &cmd, cmnd, 30); + status = (ushort)srp->sr_command->SCp.Status; + info = (ulong32)srp->sr_command->SCp.Message; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &cmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &cmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0); + GDTH_UNLOCK_HA(ha, flags); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_release_request(srp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scsi_release_command(scp); +#endif + + if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan))) + return -EFAULT; + return 0; +} + +static int gdth_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + gdth_ha_str *ha; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Cmnd *scp; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Cmnd *scp; +#else + Scsi_Cmnd scp; +#endif + ulong flags; + char cmnd[MAX_COMMAND_SIZE]; + + memset(cmnd, 0xff, 12); + + TRACE(("gdth_ioctl() cmd 0x%x\n", cmd)); + + switch (cmd) { + case GDTIOCTL_CTRCNT: + { + int cnt = gdth_ctr_count; + if (put_user(cnt, (int *)arg)) + return -EFAULT; + break; + } + + case GDTIOCTL_DRVERS: + { + int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION; + if (put_user(ver, (int *)arg)) + return -EFAULT; + break; + } + + case GDTIOCTL_OSVERS: + { + gdth_ioctl_osvers osv; + + osv.version = (unchar)(LINUX_VERSION_CODE >> 16); + osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8); + osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff); + if (copy_to_user((char *)arg, &osv, sizeof(gdth_ioctl_osvers))) + return -EFAULT; + break; + } + + case GDTIOCTL_CTRTYPE: + { + gdth_ioctl_ctrtype ctrt; + + if (copy_from_user(&ctrt, (char *)arg, sizeof(gdth_ioctl_ctrtype)) || + ctrt.ionode >= gdth_ctr_count) + return -EFAULT; + ha = HADATA(gdth_ctr_tab[ctrt.ionode]); + if (ha->type == GDT_ISA || ha->type == GDT_EISA) { + ctrt.type = (unchar)((ha->stype>>20) - 0x10); + } else { + if (ha->type != GDT_PCIMPR) { + ctrt.type = (unchar)((ha->stype<<4) + 6); + } else { + ctrt.type = + (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); + if (ha->stype >= 0x300) + ctrt.ext_type = 0x6000 | ha->subdevice_id; + else + ctrt.ext_type = 0x6000 | ha->stype; + } + ctrt.device_id = ha->stype; + ctrt.sub_device_id = ha->subdevice_id; + } + ctrt.info = ha->brd_phys; + ctrt.oem_id = ha->oem_id; + if (copy_to_user((char *)arg, &ctrt, sizeof(gdth_ioctl_ctrtype))) + return -EFAULT; + break; + } + + case GDTIOCTL_GENERAL: + return ioc_general(arg, cmnd); + + case GDTIOCTL_EVENT: + return ioc_event(arg); + + case GDTIOCTL_LOCKDRV: + return ioc_lockdrv(arg); + + case GDTIOCTL_LOCKCHN: + { + gdth_ioctl_lockchn lchn; + unchar i, j; + + if (copy_from_user(&lchn, (char *)arg, sizeof(gdth_ioctl_lockchn)) || + lchn.ionode >= gdth_ctr_count) + return -EFAULT; + ha = HADATA(gdth_ctr_tab[lchn.ionode]); + + i = lchn.channel; + if (i < ha->bus_cnt) { + if (lchn.lock) { + GDTH_LOCK_HA(ha, flags); + ha->raw[i].lock = 1; + GDTH_UNLOCK_HA(ha, flags); + for (j = 0; j < ha->tid_cnt; ++j) { + gdth_wait_completion(lchn.ionode, i, j); + gdth_stop_timeout(lchn.ionode, i, j); + } + } else { + GDTH_LOCK_HA(ha, flags); + ha->raw[i].lock = 0; + GDTH_UNLOCK_HA(ha, flags); + for (j = 0; j < ha->tid_cnt; ++j) { + gdth_start_timeout(lchn.ionode, i, j); + gdth_next(lchn.ionode); + } + } + } + break; + } + + case GDTIOCTL_RESCAN: + return ioc_rescan(arg, cmnd); + + case GDTIOCTL_HDRLIST: + return ioc_hdrlist(arg, cmnd); + + case GDTIOCTL_RESET_BUS: + { + gdth_ioctl_reset res; + int hanum, rval; + + if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) || + res.ionode >= gdth_ctr_count) + return -EFAULT; + hanum = res.ionode; + ha = HADATA(gdth_ctr_tab[hanum]); + + /* Because we need a Scsi_Cmnd struct., we make a scsi_allocate device also for kernels >=2.6.x */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scp = scsi_get_command(ha->sdev, GFP_KERNEL); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; + scp->device->channel = virt_ctr ? 0 : res.number; + rval = gdth_eh_bus_reset(scp); + res.status = (rval == SUCCESS ? S_OK : S_GENERR); + scsi_put_command(scp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scp = scsi_allocate_device(ha->sdev, 1, FALSE); + if (!scp) + return -ENOMEM; + scp->cmd_len = 12; + scp->use_sg = 0; + scp->channel = virt_ctr ? 0 : res.number; + rval = gdth_eh_bus_reset(scp); + res.status = (rval == SUCCESS ? S_OK : S_GENERR); + scsi_release_command(scp); +#else + memset(&ha->sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + ha->sdev.host = scp.host = gdth_ctr_tab[hanum]; + ha->sdev.id = scp.target = ha->sdev.host->this_id; + scp.device = &ha->sdev; + scp.channel = virt_ctr ? 0 : res.number; + rval = gdth_eh_bus_reset(&scp); + res.status = (rval == SUCCESS ? S_OK : S_GENERR); +#endif + if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset))) + return -EFAULT; + break; + } + + case GDTIOCTL_RESET_DRV: + return ioc_resetdrv(arg, cmnd); + + default: + break; + } + return 0; +} + + /* flush routine */ static void gdth_flush(int hanum) { int i; gdth_ha_str *ha; gdth_cmd_str gdtcmd; -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; + Scsi_Device *sdev; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) Scsi_Cmnd *scp; Scsi_Device *sdev; #else @@ -4638,9 +6062,18 @@ TRACE2(("gdth_flush() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); + srp = scsi_allocate_request(sdev, GFP_KERNEL); + if (!srp) + return; + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); scp = scsi_allocate_device(sdev, 1, FALSE); + if (!scp) + return; scp->cmd_len = 12; scp->use_sg = 0; #else @@ -4656,34 +6089,44 @@ gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_FLUSH; - gdtcmd.u.cache.DeviceNo = i; - gdtcmd.u.cache.BlockNo = 1; - gdtcmd.u.cache.sg_canz = 0; + if (ha->cache_feat & GDT_64BIT) { + gdtcmd.u.cache64.DeviceNo = i; + gdtcmd.u.cache64.BlockNo = 1; + gdtcmd.u.cache64.sg_canz = 0; + } else { + gdtcmd.u.cache.DeviceNo = i; + gdtcmd.u.cache.BlockNo = 1; + gdtcmd.u.cache.sg_canz = 0; + } TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(srp, &gdtcmd, cmnd, 30); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); #endif } } -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_release_request(srp); + scsi_free_host_dev(sdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsi_release_command(scp); scsi_free_host_dev(sdev); #endif } /* shutdown routine */ -#if LINUX_VERSION_CODE >= 0x020100 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) -#else -void gdth_halt(void) -#endif { int hanum; #ifndef __alpha__ gdth_cmd_str gdtcmd; -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *srp; + Scsi_Device *sdev; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) Scsi_Cmnd *scp; Scsi_Device *sdev; #else @@ -4693,47 +6136,51 @@ char cmnd[MAX_COMMAND_SIZE]; #endif -#if LINUX_VERSION_CODE >= 0x020100 TRACE2(("gdth_halt() event %d\n",(int)event)); if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) return NOTIFY_DONE; -#else - TRACE2(("gdth_halt()\n")); - if (halt_called) { - TRACE2(("already called\n")); - return; - } - halt_called = TRUE; -#endif - printk("GDT: Flushing all host drives .. "); + + printk("GDT-HA: Flushing all host drives .. "); for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { gdth_flush(hanum); #ifndef __alpha__ /* controller reset */ memset(cmnd, 0xff, MAX_COMMAND_SIZE); -#if LINUX_VERSION_CODE >= 0x020322 + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_RESET; + TRACE2(("gdth_halt(): reset controller %d\n", hanum)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); + srp = scsi_allocate_request(sdev, GFP_KERNEL); + if (!srp) { + unregister_reboot_notifier(&gdth_notifier); + return NOTIFY_OK; + } + srp->sr_cmd_len = 12; + srp->sr_use_sg = 0; + gdth_do_req(srp, &gdtcmd, cmnd, 10); + scsi_release_request(srp); + scsi_free_host_dev(sdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); scp = scsi_allocate_device(sdev, 1, FALSE); + if (!scp) { + unregister_reboot_notifier(&gdth_notifier); + return NOTIFY_OK; + } scp->cmd_len = 12; scp->use_sg = 0; + gdth_do_cmd(scp, &gdtcmd, cmnd, 10); + scsi_release_command(scp); + scsi_free_host_dev(sdev); #else memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); sdev.host = scp.host = gdth_ctr_tab[hanum]; sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; -#endif - - gdtcmd.BoardNode = LOCALBOARD; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_RESET; - TRACE2(("gdth_halt(): reset controller %d\n", hanum)); -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 10); - scsi_release_command(scp); - scsi_free_host_dev(sdev); -#else gdth_do_cmd(&scp, &gdtcmd, cmnd, 10); #endif #endif @@ -4743,15 +6190,12 @@ #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif -#if LINUX_VERSION_CODE >= 0x020100 unregister_reboot_notifier(&gdth_notifier); return NOTIFY_OK; -#endif } -#endif -#if LINUX_VERSION_CODE < 0x020400 && !defined(MODULE) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) && !defined(MODULE) GDTH_INITFUNC(void, gdth_setup(char *str,int *ints)) { @@ -4762,7 +6206,37 @@ #else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static Scsi_Host_Template driver_template = { + .proc_name = "gdth", + .proc_info = gdth_proc_info, + .name = "GDT SCSI Disk Array Controller", + .detect = gdth_detect, + .release = gdth_release, + .info = gdth_info, + .queuecommand = gdth_queuecommand, + .eh_abort_handler = gdth_eh_abort, + .eh_device_reset_handler = gdth_eh_device_reset, + .eh_bus_reset_handler = gdth_eh_bus_reset, + .eh_host_reset_handler = gdth_eh_host_reset, + .bios_param = gdth_bios_param, + .can_queue = GDTH_MAXCMDS, + .this_id = -1, + .sg_tablesize = GDTH_MAXSG, + .cmd_per_lun = GDTH_MAXC_P_L, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + .use_new_eh_code = 1, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) + .highmem_io = 1, +#endif +#endif +}; +#else static Scsi_Host_Template driver_template = GDTH; +#endif + #include "scsi_module.c" #ifndef MODULE __setup("gdth=", option_setup); diff -urN linux-2.4.27/drivers/scsi/gdth.h linux-2.4.28/drivers/scsi/gdth.h --- linux-2.4.27/drivers/scsi/gdth.h 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/scsi/gdth.h 2004-11-17 03:54:21.652400114 -0800 @@ -4,21 +4,18 @@ /* * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux * - * gdth.h Copyright (C) 1995-02 ICP vortex, an Intel company, Achim Leubner + * gdth.h Copyright (C) 1995-03 ICP vortex, Achim Leubner * See gdth.c for further informations and * below for supported controller types * - * + * * - * $Id: gdth.h,v 1.46 2002/02/05 09:39:53 achim Exp $ + * $Id: gdth.h,v 1.57 2004/03/31 11:52:09 achim Exp $ */ #include #include -#ifndef NULL -#define NULL 0 -#endif #ifndef TRUE #define TRUE 1 #endif @@ -29,16 +26,16 @@ /* defines, macros */ /* driver version */ -#define GDTH_VERSION_STR "2.05" -#define GDTH_VERSION 2 -#define GDTH_SUBVERSION 5 +#define GDTH_VERSION_STR "3.04" +#define GDTH_VERSION 3 +#define GDTH_SUBVERSION 4 /* protocol version */ #define PROTOCOL_VERSION 1 /* OEM IDs */ -#define OEM_ID_ICP 0x941c -#define OEM_ID_INTEL 0x8000 +#define OEM_ID_ICP 0x941c +#define OEM_ID_INTEL 0x8000 /* controller classes */ #define GDT_ISA 0x01 /* ISA controller */ @@ -134,18 +131,27 @@ #ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX /* new GDT Rx Controller */ -#define PCI_DEVICE_ID_VORTEX_GDTNEWRX 0x300 +#define PCI_DEVICE_ID_VORTEX_GDTNEWRX 0x300 #endif - + +#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX2 +/* new(2) GDT Rx Controller */ +#define PCI_DEVICE_ID_VORTEX_GDTNEWRX2 0x301 +#endif + #ifndef PCI_DEVICE_ID_INTEL_SRC /* Intel Storage RAID Controller */ -#define PCI_DEVICE_ID_INTEL_SRC 0x600 +#define PCI_DEVICE_ID_INTEL_SRC 0x600 +#endif + +#ifndef PCI_DEVICE_ID_INTEL_SRC_XSCALE +/* Intel Storage RAID Controller */ +#define PCI_DEVICE_ID_INTEL_SRC_XSCALE 0x601 #endif /* limits */ #define GDTH_SCRATCH PAGE_SIZE /* 4KB scratch buffer */ -#define GDTH_SCRATCH_ORD 0 /* order 0 means 1 page */ -#define GDTH_MAXCMDS 124 +#define GDTH_MAXCMDS 120 #define GDTH_MAXC_P_L 16 /* max. cmds per lun */ #define GDTH_MAX_RAW 2 /* max. cmds per raw device */ #define MAXOFFSETS 128 @@ -153,8 +159,6 @@ #define MAXID 127 #define MAXLUN 8 #define MAXBUS 6 -#define MAX_HDRIVES 100 /* max. host drive count */ -#define MAX_LDRIVES 255 /* max. log. drive count */ #define MAX_EVENTS 100 /* event buffer count */ #define MAX_RES_ARGS 40 /* device reservation, must be a multiple of 4 */ @@ -221,6 +225,8 @@ #define GDT_CLUST_RESET 24 /* releases the cluster drives*/ #define GDT_FREEZE_IO 25 /* freezes all IOs */ #define GDT_UNFREEZE_IO 26 /* unfreezes all IOs */ +#define GDT_X_INIT_HOST 29 /* ext. init: 64 bit support */ +#define GDT_X_INFO 30 /* ext. info for drives>2TB */ /* raw service commands */ #define GDT_RESERVE 14 /* reserve dev. to raw serv. */ @@ -230,9 +236,11 @@ #define GDT_RESET_BUS 18 /* reset bus */ #define GDT_SCAN_START 19 /* start device scan */ #define GDT_SCAN_END 20 /* stop device scan */ +#define GDT_X_INIT_RAW 21 /* ext. init: 64 bit support */ /* screen service commands */ #define GDT_REALTIME 3 /* realtime clock to screens. */ +#define GDT_X_INIT_SCR 4 /* ext. init: 64 bit support */ /* IOCTL command defines */ #define SCSI_DR_INFO 0x00 /* SCSI drive info */ @@ -254,6 +262,9 @@ #define CACHE_DRV_INFO 0x07 /* cache drive info */ #define BOARD_FEATURES 0x15 /* controller features */ #define BOARD_INFO 0x28 /* controller info */ +#define SET_PERF_MODES 0x82 /* set mode (coalescing,..) */ +#define GET_PERF_MODES 0x83 /* get mode */ +#define CACHE_READ_OEM_STRING_RECORD 0x84 /* read OEM string record */ #define HOST_GET 0x10001L /* get host drive list */ #define IO_CHANNEL 0x00020000L /* default IO channel */ #define INVALID_CHANNEL 0x0000ffffL /* invalid channel */ @@ -265,7 +276,8 @@ #define S_CACHE_UNKNOWN 12 /* cache serv.: drive unknown */ #define S_RAW_SCSI 12 /* raw serv.: target error */ #define S_RAW_ILL 0xff /* raw serv.: illegal */ -#define S_CACHE_RESERV -24 /* cache: reserv. conflict */ +#define S_NOFUNC -2 /* unknown function */ +#define S_CACHE_RESERV -24 /* cache: reserv. conflict */ /* timeout values */ #define INIT_RETRIES 100000 /* 100000 * 1ms = 100s */ @@ -292,21 +304,28 @@ #define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */ #define EISAREG 0x0cc0 /* EISA configuration */ +/* DMA memory mappings */ +#define GDTH_MAP_NONE 0 +#define GDTH_MAP_SINGLE 1 +#define GDTH_MAP_SG 2 +#define GDTH_MAP_IOCTL 3 + /* other defines */ #define LINUX_OS 8 /* used for cache optim. */ #define SCATTER_GATHER 1 /* s/g feature */ -#define GDTH_MAXSG 32 /* max. s/g elements */ #define SECS32 0x1f /* round capacity */ #define BIOS_ID_OFFS 0x10 /* offset contr-ID in ISABIOS */ #define LOCALBOARD 0 /* board node always 0 */ #define ASYNCINDEX 0 /* cmd index async. event */ #define SPEZINDEX 1 /* cmd index unknown service */ -#define GDT_WR_THROUGH 0x100 /* WRITE_THROUGH supported */ +#define COALINDEX (GDTH_MAXCMDS + 2) +/* features */ +#define SCATTER_GATHER 1 /* s/g feature */ +#define GDT_WR_THROUGH 0x100 /* WRITE_THROUGH supported */ +#define GDT_64BIT 0x200 /* 64bit / drv>2TB support */ -/* typedefs */ -typedef u32 ulong32; -#define PACKED __attribute__((packed)) +#include "gdth_ioctl.h" /* screenservice message */ typedef struct { @@ -319,7 +338,40 @@ char msg_text[MSGLEN+2]; /* the message text */ } PACKED gdth_msg_str; + /* IOCTL data structures */ + +/* Status coalescing buffer for returning multiple requests per interrupt */ +typedef struct { + ulong32 status; + ulong32 ext_status; + ulong32 info0; + ulong32 info1; +} PACKED gdth_coal_status; + +/* performance mode data structure */ +typedef struct { + ulong32 version; /* The version of this IOCTL structure. */ + ulong32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ + ulong32 st_buff_addr1; /* physical address of status buffer 1 */ + ulong32 st_buff_u_addr1; /* reserved for 64 bit addressing */ + ulong32 st_buff_indx1; /* reserved command idx. for this buffer */ + ulong32 st_buff_addr2; /* physical address of status buffer 1 */ + ulong32 st_buff_u_addr2; /* reserved for 64 bit addressing */ + ulong32 st_buff_indx2; /* reserved command idx. for this buffer */ + ulong32 st_buff_size; /* size of each buffer in bytes */ + ulong32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ + ulong32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ + ulong32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ + ulong32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ + ulong32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ + ulong32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ + ulong32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ + ulong32 cmd_buff_size; /* size of each cmd bufer in bytes */ + ulong32 reserved1; + ulong32 reserved2; +} PACKED gdth_perf_modes; + /* SCSI drive info */ typedef struct { unchar vendor[8]; /* vendor string */ @@ -535,6 +587,50 @@ unchar ld_error; /* error */ } PACKED gdth_cdrinfo_str; +/* OEM string */ +typedef struct { + ulong32 ctl_version; + ulong32 file_major_version; + ulong32 file_minor_version; + ulong32 buffer_size; + ulong32 cpy_count; + ulong32 ext_error; + ulong32 oem_id; + ulong32 board_id; +} PACKED gdth_oem_str_params; + +typedef struct { + unchar product_0_1_name[16]; + unchar product_4_5_name[16]; + unchar product_cluster_name[16]; + unchar product_reserved[16]; + unchar scsi_cluster_target_vendor_id[16]; + unchar cluster_raid_fw_name[16]; + unchar oem_brand_name[16]; + unchar oem_raid_type[16]; + unchar bios_type[13]; + unchar bios_title[50]; + unchar oem_company_name[37]; + ulong32 pci_id_1; + ulong32 pci_id_2; + unchar validation_status[80]; + unchar reserved_1[4]; + unchar scsi_host_drive_inquiry_vendor_id[16]; + unchar library_file_template[16]; + unchar reserved_2[16]; + unchar tool_name_1[32]; + unchar tool_name_2[32]; + unchar tool_name_3[32]; + unchar oem_contact_1[84]; + unchar oem_contact_2[84]; + unchar oem_contact_3[84]; +} PACKED gdth_oem_str; + +typedef struct { + gdth_oem_str_params params; + gdth_oem_str text; +} PACKED gdth_oem_str_ioctl; + /* board features */ typedef struct { unchar chaining; /* Chaining supported */ @@ -594,118 +690,6 @@ gdth_hentry_str entry[MAX_HDRIVES]; /* entries */ } PACKED gdth_hget_str; -/* scatter/gather element */ -typedef struct { - ulong32 sg_ptr; /* address */ - ulong32 sg_len; /* length */ -} PACKED gdth_sg_str; - -/* command structure */ -typedef struct { - ulong32 BoardNode; /* board node (always 0) */ - ulong32 CommandIndex; /* command number */ - ushort OpCode; /* the command (READ,..) */ - union { - struct { - ushort DeviceNo; /* number of cache drive */ - ulong32 BlockNo; /* block number */ - ulong32 BlockCnt; /* block count */ - ulong32 DestAddr; /* dest. addr. (if s/g: -1) */ - ulong32 sg_canz; /* s/g element count */ - gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED cache; /* cache service cmd. str. */ - struct { - ushort param_size; /* size of p_param buffer */ - ulong32 subfunc; /* IOCTL function */ - ulong32 channel; /* device */ - ulong32 p_param; /* buffer */ - } PACKED ioctl; /* IOCTL command structure */ - struct { - ushort reserved; - union { - struct { - ulong32 msg_handle; /* message handle */ - ulong32 msg_addr; /* message buffer address */ - } PACKED msg; - unchar data[12]; /* buffer for rtc data, ... */ - } su; - } PACKED screen; /* screen service cmd. str. */ - struct { - ushort reserved; - ulong32 direction; /* data direction */ - ulong32 mdisc_time; /* disc. time (0: no timeout)*/ - ulong32 mcon_time; /* connect time(0: no to.) */ - ulong32 sdata; /* dest. addr. (if s/g: -1) */ - ulong32 sdlen; /* data length (bytes) */ - ulong32 clen; /* SCSI cmd. length(6,10,12) */ - unchar cmd[12]; /* SCSI command */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar bus; /* SCSI bus number */ - unchar priority; /* only 0 used */ - ulong32 sense_len; /* sense data length */ - ulong32 sense_data; /* sense data addr. */ - ulong32 link_p; /* linked cmds (not supp.) */ - ulong32 sg_ranz; /* s/g element count */ - gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED raw; /* raw service cmd. struct. */ - } u; - /* additional variables */ - unchar Service; /* controller service */ - ushort Status; /* command result */ - ulong32 Info; /* additional information */ - Scsi_Cmnd *RequestBuffer; /* request buffer */ -} PACKED gdth_cmd_str; - -/* controller event structure */ -#define ES_ASYNC 1 -#define ES_DRIVER 2 -#define ES_TEST 3 -#define ES_SYNC 4 -typedef struct { - ushort size; /* size of structure */ - union { - char stream[16]; - struct { - ushort ionode; - ushort service; - ulong32 index; - } PACKED driver; - struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - unchar scsi_coord[3]; - } PACKED async; - struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - ushort hostdrive; - unchar scsi_coord[3]; - unchar sense_key; - } PACKED sync; - struct { - ulong32 l1, l2, l3, l4; - } PACKED test; - } eu; - ulong32 severity; - unchar event_string[256]; -} PACKED gdth_evt_data; - -typedef struct { - ulong32 first_stamp; - ulong32 last_stamp; - ushort same_count; - ushort event_source; - ushort event_idx; - unchar application; - unchar reserved; - gdth_evt_data event_data; -} PACKED gdth_evt_str; - /* DPRAM structures */ @@ -860,9 +844,7 @@ /* PCI resources */ typedef struct { -#if LINUX_VERSION_CODE >= 0x02015C struct pci_dev *pdev; -#endif ushort vendor_id; /* vendor (ICP, Intel, ..) */ ushort device_id; /* device ID (0,..,9) */ ushort subdevice_id; /* sub device ID */ @@ -879,18 +861,28 @@ typedef struct { ushort oem_id; /* OEM */ ushort type; /* controller class */ - ushort raw_feat; /* feat. raw service (s/g,..) */ ulong32 stype; /* subtype (PCI: device ID) */ ushort subdevice_id; /* sub device ID (PCI) */ ushort fw_vers; /* firmware version */ - ushort cache_feat; /* feat. cache serv. (s/g,..) */ + ushort cache_feat; /* feat. cache serv. (s/g,..)*/ + ushort raw_feat; /* feat. raw service (s/g,..)*/ + ushort screen_feat; /* feat. raw service (s/g,..)*/ ushort bmic; /* BMIC address (EISA) */ void *brd; /* DPRAM address */ ulong32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ gdth_cmd_str *pccb; /* address command structure */ + ulong32 ccb_phys; /* phys. address */ +#ifdef INT_COAL + gdth_coal_status *coal_stat; /* buffer for coalescing int.*/ + ulong64 coal_stat_phys; /* phys. address */ +#endif char *pscratch; /* scratch (DMA) buffer */ + ulong64 scratch_phys; /* phys. address */ unchar scratch_busy; /* in use? */ + unchar dma64_support; /* 64-bit DMA supported? */ + gdth_msg_str *pmsg; /* message buffer */ + ulong64 msg_phys; /* phys. address */ unchar scan_mode; /* current scan mode */ unchar irq; /* IRQ */ unchar drq; /* DRQ (ISA controllers) */ @@ -911,7 +903,7 @@ unchar heads; /* mapping */ unchar secs; ushort devtype; /* further information */ - ulong32 size; /* capacity */ + ulong64 size; /* capacity */ unchar ldr_no; /* log. drive no. */ unchar rw_attribs; /* r/w attributes */ unchar cluster_type; /* cluster properties */ @@ -943,8 +935,18 @@ gdth_bfeat_str bfeat; /* controller features */ gdth_binfo_str binfo; /* controller info */ gdth_evt_data dvr; /* event structure */ -#if LINUX_VERSION_CODE >= 0x02015F spinlock_t smp_lock; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + struct pci_dev *pdev; +#endif + char oem_name[8]; +#ifdef GDTH_DMA_STATISTICS + ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + Scsi_Device *sdev; +#else + Scsi_Device sdev; #endif } gdth_ha_str; @@ -983,6 +985,12 @@ ulong32 block_length; } PACKED gdth_rdcap_data; +/* READ_CAPACITY (16) data format */ +typedef struct { + ulong64 last_block_no; + ulong32 block_length; +} PACKED gdth_rdcap16_data; + /* REQUEST_SENSE data format */ typedef struct { unchar errorcode; @@ -1024,53 +1032,20 @@ int gdth_detect(Scsi_Host_Template *); int gdth_release(struct Scsi_Host *); int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *)); -int gdth_abort(Scsi_Cmnd *); -#if LINUX_VERSION_CODE >= 0x010346 -int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags); -#else -int gdth_reset(Scsi_Cmnd *); -#endif const char *gdth_info(struct Scsi_Host *); -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *); +int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) int gdth_bios_param(Disk *,kdev_t,int *); int gdth_proc_info(char *,char **,off_t,int,int,int); -int gdth_eh_abort(Scsi_Cmnd *scp); -int gdth_eh_device_reset(Scsi_Cmnd *scp); -int gdth_eh_bus_reset(Scsi_Cmnd *scp); -int gdth_eh_host_reset(Scsi_Cmnd *scp); -#define GDTH { proc_name: "gdth", \ - proc_info: gdth_proc_info, \ - name: "GDT SCSI Disk Array Controller",\ - detect: gdth_detect, \ - release: gdth_release, \ - info: gdth_info, \ - command: NULL, \ - queuecommand: gdth_queuecommand, \ - eh_abort_handler: gdth_eh_abort, \ - eh_device_reset_handler: gdth_eh_device_reset, \ - eh_bus_reset_handler: gdth_eh_bus_reset, \ - eh_host_reset_handler: gdth_eh_host_reset, \ - abort: gdth_abort, \ - reset: gdth_reset, \ - bios_param: gdth_bios_param, \ - can_queue: GDTH_MAXCMDS, \ - this_id: -1, \ - sg_tablesize: GDTH_MAXSG, \ - cmd_per_lun: GDTH_MAXC_P_L, \ - present: 0, \ - unchecked_isa_dma: 1, \ - use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 1 /* use new error code */ } - -#elif LINUX_VERSION_CODE >= 0x02015F +#else int gdth_bios_param(Disk *,kdev_t,int *); extern struct proc_dir_entry proc_scsi_gdth; int gdth_proc_info(char *,char **,off_t,int,int,int); -int gdth_eh_abort(Scsi_Cmnd *scp); -int gdth_eh_device_reset(Scsi_Cmnd *scp); -int gdth_eh_bus_reset(Scsi_Cmnd *scp); -int gdth_eh_host_reset(Scsi_Cmnd *scp); +int gdth_abort(Scsi_Cmnd *); +int gdth_reset(Scsi_Cmnd *,unsigned int); #define GDTH { proc_dir: &proc_scsi_gdth, \ proc_info: gdth_proc_info, \ name: "GDT SCSI Disk Array Controller",\ @@ -1094,53 +1069,11 @@ unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING, \ use_new_eh_code: 1 /* use new error code */ } - -#elif LINUX_VERSION_CODE >= 0x010300 -int gdth_bios_param(Disk *,kdev_t,int *); -extern struct proc_dir_entry proc_scsi_gdth; -int gdth_proc_info(char *,char **,off_t,int,int,int); -#define GDTH { NULL, NULL, \ - &proc_scsi_gdth, \ - gdth_proc_info, \ - "GDT SCSI Disk Array Controller", \ - gdth_detect, \ - gdth_release, \ - gdth_info, \ - NULL, \ - gdth_queuecommand, \ - gdth_abort, \ - gdth_reset, \ - NULL, \ - gdth_bios_param, \ - GDTH_MAXCMDS, \ - -1, \ - GDTH_MAXSG, \ - GDTH_MAXC_P_L, \ - 0, \ - 1, \ - ENABLE_CLUSTERING} - -#else -int gdth_bios_param(Disk *,int,int *); -#define GDTH { NULL, NULL, \ - "GDT SCSI Disk Array Controller", \ - gdth_detect, \ - gdth_release, \ - gdth_info, \ - NULL, \ - gdth_queuecommand, \ - gdth_abort, \ - gdth_reset, \ - NULL, \ - gdth_bios_param, \ - GDTH_MAXCMDS, \ - -1, \ - GDTH_MAXSG, \ - GDTH_MAXC_P_L, \ - 0, \ - 1, \ - ENABLE_CLUSTERING} #endif -#endif +int gdth_eh_abort(Scsi_Cmnd *scp); +int gdth_eh_device_reset(Scsi_Cmnd *scp); +int gdth_eh_bus_reset(Scsi_Cmnd *scp); +int gdth_eh_host_reset(Scsi_Cmnd *scp); +#endif diff -urN linux-2.4.27/drivers/scsi/gdth_ioctl.h linux-2.4.28/drivers/scsi/gdth_ioctl.h --- linux-2.4.27/drivers/scsi/gdth_ioctl.h 2001-09-07 09:28:37.000000000 -0700 +++ linux-2.4.28/drivers/scsi/gdth_ioctl.h 2004-11-17 03:54:21.653400155 -0800 @@ -2,7 +2,7 @@ #define _GDTH_IOCTL_H /* gdth_ioctl.h - * $Id: gdth_ioctl.h,v 1.10 2001/05/22 06:28:59 achim Exp $ + * $Id: gdth_ioctl.h,v 1.14 2004/02/19 15:43:15 achim Exp $ */ /* IOCTLs */ @@ -21,10 +21,172 @@ #define GDTIOCTL_RESCAN (GDTIOCTL_MASK |11) /* rescan host drives */ #define GDTIOCTL_RESET_DRV (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */ -#define GDTIOCTL_MAGIC 0xaffe0004 -#define EVENT_SIZE 294 -#define MAX_HDRIVES 100 +#define GDTIOCTL_MAGIC 0xaffe0004 +#define EVENT_SIZE 294 +#define GDTH_MAXSG 32 /* max. s/g elements */ +#define MAX_LDRIVES 255 /* max. log. drive count */ +#ifdef GDTH_IOCTL_PROC +#define MAX_HDRIVES 100 /* max. host drive count */ +#else +#define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */ +#endif + +/* typedefs */ +#ifdef __KERNEL__ +typedef u32 ulong32; +typedef u64 ulong64; +#endif + +#define PACKED __attribute__((packed)) + +/* scatter/gather element */ +typedef struct { + ulong32 sg_ptr; /* address */ + ulong32 sg_len; /* length */ +} PACKED gdth_sg_str; + +/* scatter/gather element - 64bit addresses */ +typedef struct { + ulong64 sg_ptr; /* address */ + ulong32 sg_len; /* length */ +} PACKED gdth_sg64_str; + +/* command structure */ +typedef struct { + ulong32 BoardNode; /* board node (always 0) */ + ulong32 CommandIndex; /* command number */ + ushort OpCode; /* the command (READ,..) */ + union { + struct { + ushort DeviceNo; /* number of cache drive */ + ulong32 BlockNo; /* block number */ + ulong32 BlockCnt; /* block count */ + ulong32 DestAddr; /* dest. addr. (if s/g: -1) */ + ulong32 sg_canz; /* s/g element count */ + gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ + } PACKED cache; /* cache service cmd. str. */ + struct { + ushort DeviceNo; /* number of cache drive */ + ulong64 BlockNo; /* block number */ + ulong32 BlockCnt; /* block count */ + ulong64 DestAddr; /* dest. addr. (if s/g: -1) */ + ulong32 sg_canz; /* s/g element count */ + gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ + } PACKED cache64; /* cache service cmd. str. */ + struct { + ushort param_size; /* size of p_param buffer */ + ulong32 subfunc; /* IOCTL function */ + ulong32 channel; /* device */ + ulong64 p_param; /* buffer */ + } PACKED ioctl; /* IOCTL command structure */ + struct { + ushort reserved; + union { + struct { + ulong32 msg_handle; /* message handle */ + ulong64 msg_addr; /* message buffer address */ + } PACKED msg; + unchar data[12]; /* buffer for rtc data, ... */ + } su; + } PACKED screen; /* screen service cmd. str. */ + struct { + ushort reserved; + ulong32 direction; /* data direction */ + ulong32 mdisc_time; /* disc. time (0: no timeout)*/ + ulong32 mcon_time; /* connect time(0: no to.) */ + ulong32 sdata; /* dest. addr. (if s/g: -1) */ + ulong32 sdlen; /* data length (bytes) */ + ulong32 clen; /* SCSI cmd. length(6,10,12) */ + unchar cmd[12]; /* SCSI command */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar bus; /* SCSI bus number */ + unchar priority; /* only 0 used */ + ulong32 sense_len; /* sense data length */ + ulong32 sense_data; /* sense data addr. */ + ulong32 link_p; /* linked cmds (not supp.) */ + ulong32 sg_ranz; /* s/g element count */ + gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ + } PACKED raw; /* raw service cmd. struct. */ + struct { + ushort reserved; + ulong32 direction; /* data direction */ + ulong32 mdisc_time; /* disc. time (0: no timeout)*/ + ulong32 mcon_time; /* connect time(0: no to.) */ + ulong64 sdata; /* dest. addr. (if s/g: -1) */ + ulong32 sdlen; /* data length (bytes) */ + ulong32 clen; /* SCSI cmd. length(6,..,16) */ + unchar cmd[16]; /* SCSI command */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar bus; /* SCSI bus number */ + unchar priority; /* only 0 used */ + ulong32 sense_len; /* sense data length */ + ulong64 sense_data; /* sense data addr. */ + ulong32 sg_ranz; /* s/g element count */ + gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ + } PACKED raw64; /* raw service cmd. struct. */ + } u; + /* additional variables */ + unchar Service; /* controller service */ + unchar reserved; + ushort Status; /* command result */ + ulong32 Info; /* additional information */ + void *RequestBuffer; /* request buffer */ +} PACKED gdth_cmd_str; + +/* controller event structure */ +#define ES_ASYNC 1 +#define ES_DRIVER 2 +#define ES_TEST 3 +#define ES_SYNC 4 +typedef struct { + ushort size; /* size of structure */ + union { + char stream[16]; + struct { + ushort ionode; + ushort service; + ulong32 index; + } PACKED driver; + struct { + ushort ionode; + ushort service; + ushort status; + ulong32 info; + unchar scsi_coord[3]; + } PACKED async; + struct { + ushort ionode; + ushort service; + ushort status; + ulong32 info; + ushort hostdrive; + unchar scsi_coord[3]; + unchar sense_key; + } PACKED sync; + struct { + ulong32 l1, l2, l3, l4; + } PACKED test; + } eu; + ulong32 severity; + unchar event_string[256]; +} PACKED gdth_evt_data; + +typedef struct { + ulong32 first_stamp; + ulong32 last_stamp; + ushort same_count; + ushort event_source; + ushort event_idx; + unchar application; + unchar reserved; + gdth_evt_data event_data; +} PACKED gdth_evt_str; + + +#ifdef GDTH_IOCTL_PROC /* IOCTL structure (write) */ typedef struct { ulong32 magic; /* IOCTL magic */ @@ -106,7 +268,80 @@ } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } iu; } gdth_iord_str; +#endif +/* GDTIOCTL_GENERAL */ +typedef struct { + ushort ionode; /* controller number */ + ushort timeout; /* timeout */ + ulong32 info; /* error info */ + ushort status; /* status */ + ulong data_len; /* data buffer size */ + ulong sense_len; /* sense buffer size */ + gdth_cmd_str command; /* command */ +} gdth_ioctl_general; -#endif +/* GDTIOCTL_LOCKDRV */ +typedef struct { + ushort ionode; /* controller number */ + unchar lock; /* lock/unlock */ + unchar drive_cnt; /* drive count */ + ushort drives[MAX_HDRIVES]; /* drives */ +} gdth_ioctl_lockdrv; + +/* GDTIOCTL_LOCKCHN */ +typedef struct { + ushort ionode; /* controller number */ + unchar lock; /* lock/unlock */ + unchar channel; /* channel */ +} gdth_ioctl_lockchn; + +/* GDTIOCTL_OSVERS */ +typedef struct { + unchar version; /* OS version */ + unchar subversion; /* OS subversion */ + ushort revision; /* revision */ +} gdth_ioctl_osvers; +/* GDTIOCTL_CTRTYPE */ +typedef struct { + ushort ionode; /* controller number */ + unchar type; /* controller type */ + ushort info; /* slot etc. */ + ushort oem_id; /* OEM ID */ + ushort bios_ver; /* not used */ + ushort access; /* not used */ + ushort ext_type; /* extended type */ + ushort device_id; /* device ID */ + ushort sub_device_id; /* sub device ID */ +} gdth_ioctl_ctrtype; + +/* GDTIOCTL_EVENT */ +typedef struct { + ushort ionode; + int erase; /* erase event? */ + int handle; /* event handle */ + gdth_evt_str event; +} gdth_ioctl_event; + +/* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */ +typedef struct { + ushort ionode; /* controller number */ + unchar flag; /* add/remove */ + ushort hdr_no; /* drive no. */ + struct { + unchar bus; /* SCSI bus */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar cluster_type; /* cluster properties */ + } hdr_list[MAX_HDRIVES]; /* index is host drive number */ +} gdth_ioctl_rescan; + +/* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */ +typedef struct { + ushort ionode; /* controller number */ + ushort number; /* bus/host drive number */ + ushort status; /* status */ +} gdth_ioctl_reset; + +#endif diff -urN linux-2.4.27/drivers/scsi/gdth_proc.c linux-2.4.28/drivers/scsi/gdth_proc.c --- linux-2.4.27/drivers/scsi/gdth_proc.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/scsi/gdth_proc.c 2004-11-17 03:54:21.658400361 -0800 @@ -1,53 +1,80 @@ /* gdth_proc.c - * $Id: gdth_proc.c,v 1.33 2001/08/10 07:54:39 achim Exp $ + * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $ */ -#include "gdth_ioctl.h" -#if LINUX_VERSION_CODE >= 0x020407 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) #include #endif -int gdth_proc_info(char *buffer,char **start,off_t offset,int length, - int hostno,int inout) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length, + int inout) +{ + int hanum,busnum; + + TRACE2(("gdth_proc_info() length %d offs %d inout %d\n", + length,(int)offset,inout)); + + hanum = NUMDATA(host)->hanum; + busnum= NUMDATA(host)->busnum; + + if (inout) + return(gdth_set_info(buffer,length,host,hanum,busnum)); + else + return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum)); +} +#else +int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno, + int inout) { int hanum,busnum,i; - TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n", - length,hostno,(int)offset,inout)); + TRACE2(("gdth_proc_info() length %d offs %d inout %d\n", + length,(int)offset,inout)); - for (i=0; ihost_no == hostno) break; } - if (i==gdth_ctr_vcount) + if (i == gdth_ctr_vcount) return(-EINVAL); hanum = NUMDATA(gdth_ctr_vtab[i])->hanum; busnum= NUMDATA(gdth_ctr_vtab[i])->busnum; if (inout) - return(gdth_set_info(buffer,length,i,hanum,busnum)); + return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum)); else - return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum)); + return(gdth_get_info(buffer,start,offset,length, + gdth_ctr_vtab[i],hanum,busnum)); } +#endif -static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) +static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, + int hanum,int busnum) { - int ret_val; -#if LINUX_VERSION_CODE >= 0x020322 + int ret_val = -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *scp; + Scsi_Device *sdev; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) Scsi_Cmnd *scp; Scsi_Device *sdev; #else Scsi_Cmnd scp; Scsi_Device sdev; #endif - gdth_iowr_str *piowr; - TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum)); - piowr = (gdth_iowr_str *)buffer; -#if LINUX_VERSION_CODE >= 0x020322 - sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sdev = scsi_get_host_dev(host); + scp = scsi_allocate_request(sdev, GFP_KERNEL); + if (!scp) + return -ENOMEM; + scp->sr_cmd_len = 12; + scp->sr_use_sg = 0; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + sdev = scsi_get_host_dev(host); scp = scsi_allocate_device(sdev, 1, FALSE); if (!scp) return -ENOMEM; @@ -56,7 +83,7 @@ #else memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.host = scp.host = host; sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; #endif @@ -66,28 +93,21 @@ buffer += 5; length -= 5; ret_val = gdth_set_asc_info( buffer, length, hanum, scp ); - } else if (piowr->magic == GDTIOCTL_MAGIC) { - ret_val = gdth_set_bin_info( buffer, length, hanum, scp ); - } else { - printk("GDT: Wrong signature %x (%x required)!\n", - piowr->magic, GDTIOCTL_MAGIC); - if (piowr->magic > GDTIOCTL_MAGIC) - printk("GDT: Please update your driver.\n"); - else - printk("GDT: Please update your tool.\n"); - ret_val = -EINVAL; } - } else { - ret_val = -EINVAL; } -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_release_request(scp); + scsi_free_host_dev(sdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsi_release_command(scp); scsi_free_host_dev(sdev); #endif return ret_val; } -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) #else static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) @@ -98,6 +118,7 @@ gdth_ha_str *ha; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; + ulong64 paddr; char cmnd[MAX_COMMAND_SIZE]; memset(cmnd, 0xff, 12); @@ -131,9 +152,16 @@ found = TRUE; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_FLUSH; - gdtcmd.u.cache.DeviceNo = i; - gdtcmd.u.cache.BlockNo = 1; -#if LINUX_VERSION_CODE >= 0x020322 + if (ha->cache_feat & GDT_64BIT) { + gdtcmd.u.cache64.DeviceNo = i; + gdtcmd.u.cache64.BlockNo = 1; + } else { + gdtcmd.u.cache.DeviceNo = i; + gdtcmd.u.cache.BlockNo = 1; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); @@ -178,23 +206,25 @@ } if (wb_mode) { - if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE)) + if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr)) return(-EBUSY); pcpar = (gdth_cpar_str *)ha->pscratch; memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar); + gdtcmd.u.ioctl.p_param = paddr; gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str); gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; pcpar->write_back = wb_mode==1 ? 0:1; -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); #endif - gdth_ioctl_free(hanum, ha->pscratch); + gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr); printk("Done.\n"); return(orig_length); } @@ -203,489 +233,23 @@ return(-EINVAL); } -#if LINUX_VERSION_CODE >= 0x020322 -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) -#else -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) -#endif -{ - unchar i, j; - ushort k, hdr_cnt, status; - gdth_ha_str *ha; - gdth_iowr_str *piowr; - gdth_iord_str *piord; - gdth_cmd_str *pcmd; - gdth_evt_str *pevt; - ulong32 *ppadd, add_size, *ppadd2, add_size2, info; - ulong flags; - gdth_cmd_str gdtcmd; - int drv_cyls, drv_hds, drv_secs; - - char cmnd[MAX_COMMAND_SIZE]; - memset(cmnd, 0xff, 12); - memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); - - TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); - piowr = (gdth_iowr_str *)buffer; - piord = NULL; - pcmd = NULL; - ppadd = ppadd2 = NULL; - add_size = add_size2 = 0; - - if (length < GDTOFFSOF(gdth_iowr_str,iu)) - return(-EINVAL); - - switch (piowr->ioctl) { - case GDTIOCTL_GENERAL: - if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0])) - return(-EINVAL); - pcmd = (gdth_cmd_str *)piowr->iu.general.command; - pcmd->Service = piowr->service; - if (pcmd->OpCode == GDT_IOCTL) { - ppadd = &pcmd->u.ioctl.p_param; - add_size = pcmd->u.ioctl.param_size; - } else if (piowr->service == CACHESERVICE) { - add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE; - if (ha->cache_feat & SCATTER_GATHER) { - ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr; - pcmd->u.cache.DestAddr = 0xffffffff; - pcmd->u.cache.sg_lst[0].sg_len = add_size; - pcmd->u.cache.sg_canz = 1; - } else { - ppadd = &pcmd->u.cache.DestAddr; - pcmd->u.cache.sg_canz = 0; - } - } else if (piowr->service == SCSIRAWSERVICE) { - add_size = pcmd->u.raw.sdlen; - add_size2 = pcmd->u.raw.sense_len; - if (ha->raw_feat & SCATTER_GATHER) { - ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr; - pcmd->u.raw.sdata = 0xffffffff; - pcmd->u.raw.sg_lst[0].sg_len = add_size; - pcmd->u.raw.sg_ranz = 1; - } else { - ppadd = &pcmd->u.raw.sdata; - pcmd->u.raw.sg_ranz = 0; - } - ppadd2 = &pcmd->u.raw.sense_data; - } else { - return(-EINVAL); - } - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2, - TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - - piord->size = sizeof(gdth_iord_str) + add_size + add_size2; - if (add_size > 0) { - memcpy(piord->iu.general.data, piowr->iu.general.data, add_size); - *ppadd = virt_to_bus(piord->iu.general.data); - } - if (add_size2 > 0) { - memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2); - *ppadd2 = virt_to_bus(piord->iu.general.data+add_size); - } - /* do IOCTL */ -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); - piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; -#else - gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); - piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; -#endif - break; - - case GDTIOCTL_DRVERS: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION; - break; - - case GDTIOCTL_CTRTYPE: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - if (ha->type == GDT_ISA || ha->type == GDT_EISA) { - piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10); - } else { - if (ha->type != GDT_PCIMPR) { - piord->iu.ctrtype.type = (unchar)((ha->stype<<4) + 6); - } else { - piord->iu.ctrtype.type = - (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); - if (ha->stype >= 0x300) - piord->iu.ctrtype.ext_type = 0x6000 | ha->subdevice_id; - else - piord->iu.ctrtype.ext_type = 0x6000 | ha->stype; - } - piord->iu.ctrtype.device_id = ha->stype; - piord->iu.ctrtype.sub_device_id = ha->subdevice_id; - } - piord->iu.ctrtype.info = ha->brd_phys; - piord->iu.ctrtype.oem_id = ha->oem_id; - break; - - case GDTIOCTL_CTRCNT: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - piord->iu.ctrcnt.count = (ushort)gdth_ctr_count; - break; - - case GDTIOCTL_OSVERS: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16); - piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8); - piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff); - break; - - case GDTIOCTL_LOCKDRV: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - for (i = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) { - j = piowr->iu.lockdrv.drives[i]; - if (j >= MAX_HDRIVES || !ha->hdr[j].present) - continue; - if (piowr->iu.lockdrv.lock) { - GDTH_LOCK_HA(ha, flags); - ha->hdr[j].lock = 1; - GDTH_UNLOCK_HA(ha, flags); - gdth_wait_completion( hanum, ha->bus_cnt, j ); - gdth_stop_timeout( hanum, ha->bus_cnt, j ); - } else { - GDTH_LOCK_HA(ha, flags); - ha->hdr[j].lock = 0; - GDTH_UNLOCK_HA(ha, flags); - gdth_start_timeout( hanum, ha->bus_cnt, j ); - gdth_next( hanum ); - } - } - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - break; - - case GDTIOCTL_LOCKCHN: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - i = piowr->iu.lockchn.channel; - if (i < ha->bus_cnt) { - if (piowr->iu.lockchn.lock) { - GDTH_LOCK_HA(ha, flags); - ha->raw[i].lock = 1; - GDTH_UNLOCK_HA(ha, flags); - for (j = 0; j < ha->tid_cnt; ++j) { - gdth_wait_completion( hanum, i, j ); - gdth_stop_timeout( hanum, i, j ); - } - } else { - GDTH_LOCK_HA(ha, flags); - ha->raw[i].lock = 0; - GDTH_UNLOCK_HA(ha, flags); - for (j = 0; j < ha->tid_cnt; ++j) { - gdth_start_timeout( hanum, i, j ); - gdth_next( hanum ); - } - } - } - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - break; - - case GDTIOCTL_EVENT: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - if (piowr->iu.event.erase == 0xff) { - pevt = (gdth_evt_str *)piowr->iu.event.evt; - if (pevt->event_source == ES_TEST) - pevt->event_data.size = sizeof(pevt->event_data.eu.test); - else if (pevt->event_source == ES_DRIVER) - pevt->event_data.size = sizeof(pevt->event_data.eu.driver); - else if (pevt->event_source == ES_SYNC) - pevt->event_data.size = sizeof(pevt->event_data.eu.sync); - else { - pevt->event_data.size = sizeof(pevt->event_data.eu.async); - gdth_log_event(&pevt->event_data, NULL); - } - GDTH_LOCK_HA(ha, flags); - gdth_store_event(ha, pevt->event_source, pevt->event_idx, - &pevt->event_data); - GDTH_UNLOCK_HA(ha, flags); - } else if (piowr->iu.event.erase == 0xfe) { - gdth_clear_events(); - } else if (piowr->iu.event.erase == 0) { - piord->iu.event.handle = - gdth_read_event(ha,piowr->iu.event.handle, - (gdth_evt_str *)piord->iu.event.evt); - } else { - piord->iu.event.handle = piowr->iu.event.handle; - gdth_readapp_event(ha, (unchar)piowr->iu.event.erase, - (gdth_evt_str *)piord->iu.event.evt); - } - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - break; - - case GDTIOCTL_SCSI: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - memcpy(cmnd, piowr->iu.scsi.cmd, 12); -#if LINUX_VERSION_CODE >= 0x020322 - scp->target = piowr->iu.scsi.target; - scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; - scp->cmd_len = piowr->iu.scsi.cmd_len; - gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); - piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; -#else - scp.target = piowr->iu.scsi.target; - scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; - scp.cmd_len = piowr->iu.scsi.cmd_len; - gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); - piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; -#endif - break; - - case GDTIOCTL_RESET_BUS: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); -#if LINUX_VERSION_CODE >= 0x020322 - scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; - piord->status = (ulong32)gdth_eh_bus_reset( scp ); - if (piord->status == SUCCESS) - piord->status = S_OK; - else - piord->status = S_GENERR; -#elif LINUX_VERSION_CODE >= 0x02015F - scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; - piord->status = (ulong32)gdth_eh_bus_reset( &scp ); - if (piord->status == SUCCESS) - piord->status = S_OK; - else - piord->status = S_GENERR; -#else - piord->status = S_OK; -#endif - break; - - case GDTIOCTL_HDRLIST: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - for (i = 0; i < MAX_HDRIVES; ++i) { - if (ha->hdr[i].present) { - piord->iu.hdr_list[i].bus = ha->virt_bus; - piord->iu.hdr_list[i].target = i; - piord->iu.hdr_list[i].lun = 0; - piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; - if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_CLUST_INFO; - gdtcmd.u.cache.DeviceNo = i; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status == S_OK) - piord->iu.hdr_list[i].cluster_type = - (unchar)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status == S_OK) - piord->iu.hdr_list[i].cluster_type = - (unchar)scp.SCp.Message; -#endif - } - } else { - piord->iu.hdr_list[i].bus = 0xff; - } - } - break; - - case GDTIOCTL_RESCAN: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - if (piowr->iu.rescan.flag == 0) { - /* old method: scan all host drives - re-initialize cache service to get host drive count - */ - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_INIT; - gdtcmd.u.cache.DeviceNo = LINUX_OS; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - status = (ushort)scp->SCp.Status; - info = (ulong32)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - status = (ushort)scp.SCp.Status; - info = (ulong32)scp.SCp.Message; -#endif - if (status != S_OK) - break; - k = 0; - hdr_cnt = (ushort)info; - } else { - k = piowr->iu.rescan.hdr_no; - hdr_cnt = k + 1; - } - if (hdr_cnt > MAX_HDRIVES) - hdr_cnt = MAX_HDRIVES; - /* scanning for host drives */ - for (; k < hdr_cnt; ++k) { - /* info about host drive */ - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_INFO; - gdtcmd.u.cache.DeviceNo = k; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - status = (ushort)scp->SCp.Status; - info = (ulong32)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - status = (ushort)scp.SCp.Status; - info = (ulong32)scp.SCp.Message; -#endif - GDTH_LOCK_HA(ha, flags); - piord->iu.hdr_list[k].bus = ha->virt_bus; - piord->iu.hdr_list[k].target = k; - piord->iu.hdr_list[k].lun = 0; - if (status != S_OK) { - ha->hdr[k].present = FALSE; - } else { - ha->hdr[k].present = TRUE; - ha->hdr[k].size = info; - /* evaluate mapping (sectors per head, heads per cylinder) */ - ha->hdr[k].size &= ~SECS32; - gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs); - ha->hdr[k].heads = (unchar)drv_hds; - ha->hdr[k].secs = (unchar)drv_secs; - /* round size */ - ha->hdr[k].size = drv_cyls * drv_hds * drv_secs; - } - GDTH_UNLOCK_HA(ha, flags); - if (status != S_OK) - continue; /* next host drive */ - - /* devtype, cluster info, R/W attributes */ - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_DEVTYPE; - gdtcmd.u.cache.DeviceNo = k; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - status = (ushort)scp->SCp.Status; - info = (ulong32)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - status = (ushort)scp.SCp.Status; - info = (ulong32)scp.SCp.Message; -#endif - GDTH_LOCK_HA(ha, flags); - ha->hdr[k].devtype = 0; - if (status == S_OK) - ha->hdr[k].devtype = (ushort)info; - GDTH_UNLOCK_HA(ha, flags); - - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_CLUST_INFO; - gdtcmd.u.cache.DeviceNo = k; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - status = (ushort)scp->SCp.Status; - info = (ulong32)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - status = (ushort)scp.SCp.Status; - info = (ulong32)scp.SCp.Message; -#endif - GDTH_LOCK_HA(ha, flags); - ha->hdr[k].cluster_type = 0; - if (status == S_OK && !shared_access) - ha->hdr[k].cluster_type = (ushort)info; - GDTH_UNLOCK_HA(ha, flags); - piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type; - - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_RW_ATTRIBS; - gdtcmd.u.cache.DeviceNo = k; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - status = (ushort)scp->SCp.Status; - info = (ulong32)scp->SCp.Message; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - status = (ushort)scp.SCp.Status; - info = (ulong32)scp.SCp.Message; -#endif - GDTH_LOCK_HA(ha, flags); - ha->hdr[k].rw_attribs = 0; - if (status == S_OK) - ha->hdr[k].rw_attribs = (ushort)info; - GDTH_UNLOCK_HA(ha, flags); - } - break; - - case GDTIOCTL_RESET_DRV: - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) - return(-EBUSY); - piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str); - piord->status = S_OK; - i = piowr->iu.scsi.target; - if (ha->hdr[i].present) { - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_CLUST_RESET; - gdtcmd.u.cache.DeviceNo = i; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; -#endif - } - break; - - default: - return(-EINVAL); - } - return length; -} - -static int gdth_get_info(char *buffer,char **start,off_t offset, - int length,int vh,int hanum,int busnum) +static int gdth_get_info(char *buffer,char **start,off_t offset,int length, + struct Scsi_Host *host,int hanum,int busnum) { int size = 0,len = 0; off_t begin = 0,pos = 0; gdth_ha_str *ha; - gdth_iord_str *piord; int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; ulong32 cnt; + ulong64 paddr; gdth_cmd_str gdtcmd; gdth_evt_str estr; -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + Scsi_Request *scp; + Scsi_Device *sdev; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) Scsi_Cmnd *scp; Scsi_Device *sdev; #else @@ -710,8 +274,15 @@ TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum)); ha = HADATA(gdth_ctr_tab[hanum]); -#if LINUX_VERSION_CODE >= 0x020322 - sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sdev = scsi_get_host_dev(host); + scp = scsi_allocate_request(sdev, GFP_KERNEL); + if (!scp) + return -ENOMEM; + scp->sr_cmd_len = 12; + scp->sr_use_sg = 0; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + sdev = scsi_get_host_dev(host); scp = scsi_allocate_device(sdev, 1, FALSE); if (!scp) return -ENOMEM; @@ -720,465 +291,415 @@ #else memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.host = scp.host = host; sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; #endif - - /* ioctl from tool? */ - if (!gdth_ioctl_check_bin(hanum, (ushort)length)) { - /* request is i.e. "cat /proc/scsi/gdth/0" */ - /* format: %-15s\t%-10s\t%-15s\t%s */ - /* driver parameters */ - size = sprintf(buffer+len,"Driver Parameters:\n"); - len += size; pos = begin + len; - if (reserve_list[0] == 0xff) - strcpy(hrec, "--"); - else { - sprintf(hrec, "%d", reserve_list[0]); - for (i = 1; i < MAX_RES_ARGS; i++) { - if (reserve_list[i] == 0xff) - break; - sprintf(hrec,"%s,%d", hrec, reserve_list[i]); - } + + + /* request is i.e. "cat /proc/scsi/gdth/0" */ + /* format: %-15s\t%-10s\t%-15s\t%s */ + /* driver parameters */ + size = sprintf(buffer+len,"Driver Parameters:\n"); + len += size; pos = begin + len; + if (reserve_list[0] == 0xff) + strcpy(hrec, "--"); + else { + sprintf(hrec, "%d", reserve_list[0]); + for (i = 1; i < MAX_RES_ARGS; i++) { + if (reserve_list[i] == 0xff) + break; + sprintf(hrec,"%s,%d", hrec, reserve_list[i]); } - size = sprintf(buffer+len, - " reserve_mode: \t%d \treserve_list: \t%s\n", - reserve_mode, hrec); - len += size; pos = begin + len; - size = sprintf(buffer+len, - " max_ids: \t%-3d \thdr_channel: \t%d\n", - max_ids, hdr_channel); - len += size; pos = begin + len; + } + size = sprintf(buffer+len, + " reserve_mode: \t%d \treserve_list: \t%s\n", + reserve_mode, hrec); + len += size; pos = begin + len; + size = sprintf(buffer+len, + " max_ids: \t%-3d \thdr_channel: \t%d\n", + max_ids, hdr_channel); + len += size; pos = begin + len; + + /* controller information */ + size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); + len += size; pos = begin + len; + if (virt_ctr) + sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); + else + strcpy(hrec, ha->binfo.type_string); + size = sprintf(buffer+len, + " Number: \t%d \tName: \t%s\n", + hanum, hrec); + len += size; pos = begin + len; + + if (ha->more_proc) + sprintf(hrec, "%d.%02d.%02d-%c%03X", + (unchar)(ha->binfo.upd_fw_ver>>24), + (unchar)(ha->binfo.upd_fw_ver>>16), + (unchar)(ha->binfo.upd_fw_ver), + ha->bfeat.raid ? 'R':'N', + ha->binfo.upd_revision); + else + sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), + (unchar)(ha->cpar.version)); - /* controller information */ - size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); - len += size; pos = begin + len; - if (virt_ctr) - sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); - else - strcpy(hrec, ha->binfo.type_string); + size = sprintf(buffer+len, + " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", + GDTH_VERSION_STR, hrec); + len += size; pos = begin + len; + + if (ha->more_proc) { + /* more information: 1. about controller */ size = sprintf(buffer+len, - " Number: \t%d \tName: \t%s\n", - hanum, hrec); + " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", + ha->binfo.ser_no, ha->binfo.memsize / 1024); len += size; pos = begin + len; + } - if (ha->more_proc) - sprintf(hrec, "%d.%02d.%02d-%c%03X", - (unchar)(ha->binfo.upd_fw_ver>>24), - (unchar)(ha->binfo.upd_fw_ver>>16), - (unchar)(ha->binfo.upd_fw_ver), - ha->bfeat.raid ? 'R':'N', - ha->binfo.upd_revision); - else - sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), - (unchar)(ha->cpar.version)); +#ifdef GDTH_DMA_STATISTICS + /* controller statistics */ + size = sprintf(buffer+len,"\nController Statistics:\n"); + len += size; pos = begin + len; + size = sprintf(buffer+len, + " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n", + ha->dma32_cnt, ha->dma64_cnt); + len += size; pos = begin + len; +#endif - size = sprintf(buffer+len, - " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", - GDTH_VERSION_STR, hrec); + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + if (ha->more_proc) { + /* more information: 2. about physical devices */ + size = sprintf(buffer+len,"\nPhysical Devices:"); len += size; pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) + flag = FALSE; + + buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + if (!buf) goto stop_output; + for (i = 0; i < ha->bus_cnt; ++i) { + /* 2.a statistics (and retries/reassigns) */ + TRACE2(("pdr_statistics() chn %d\n",i)); + pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4); + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4; + gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4; + gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL; + pds->bid = ha->raw[i].local_no; + pds->first = 0; + pds->entries = ha->raw[i].pdev_cnt; + cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / + sizeof(pds->list[0]); + if (pds->entries > cnt) + pds->entries = cnt; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status != S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status != S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status != S_OK) +#endif + { + pds->count = 0; + } - if (ha->more_proc) { - /* more information: 1. about controller */ - size = sprintf(buffer+len, - " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", - ha->binfo.ser_no, ha->binfo.memsize / 1024); - len += size; pos = begin + len; - - /* 2. about physical devices */ - size = sprintf(buffer+len,"\nPhysical Devices:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); - if (!buf) - goto stop_output; - for (i = 0; i < ha->bus_cnt; ++i) { - /* 2.a statistics (and retries/reassigns) */ - TRACE2(("pdr_statistics() chn %d\n",i)); - pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4); + /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ + for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { + /* 2.b drive info */ + TRACE2(("scsi_drv_info() chn %d dev %d\n", + i, ha->raw[i].id_list[j])); + pdi = (gdth_diskinfo_str *)buf; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pds); - gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4; - gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN; - gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL; - pds->bid = ha->raw[i].local_no; - pds->first = 0; - pds->entries = ha->raw[i].pdev_cnt; - cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / - sizeof(pds->list[0]); - if (pds->entries > cnt) - pds->entries = cnt; -#if LINUX_VERSION_CODE >= 0x020322 + gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str); + gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = + ha->raw[i].address | ha->raw[i].id_list[j]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status == S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status != S_OK) + if (scp->SCp.Status == S_OK) #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status != S_OK) + if (scp.SCp.Status == S_OK) #endif - { - pds->count = 0; + { + strncpy(hrec,pdi->vendor,8); + strncpy(hrec+8,pdi->product,16); + strncpy(hrec+24,pdi->revision,4); + hrec[28] = 0; + size = sprintf(buffer+len, + "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", + 'A'+i,pdi->target_id,pdi->lun,hrec); + len += size; pos = begin + len; + flag = TRUE; + pdi->no_ldrive &= 0xffff; + if (pdi->no_ldrive == 0xffff) + strcpy(hrec,"--"); + else + sprintf(hrec,"%d",pdi->no_ldrive); + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n", + pdi->blkcnt/(1024*1024/pdi->blksize), + hrec); + len += size; pos = begin + len; + } else { + pdi->devtype = 0xff; } - - /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ - for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { - /* 2.b drive info */ - TRACE2(("scsi_drv_info() chn %d dev %d\n", - i, ha->raw[i].id_list[j])); - pdi = (gdth_diskinfo_str *)buf; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pdi); - gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str); - gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; - gdtcmd.u.ioctl.channel = - ha->raw[i].address | ha->raw[i].id_list[j]; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status == S_OK) -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status == S_OK) -#endif - { - strncpy(hrec,pdi->vendor,8); - strncpy(hrec+8,pdi->product,16); - strncpy(hrec+24,pdi->revision,4); - hrec[28] = 0; - size = sprintf(buffer+len, - "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", - 'A'+i,pdi->target_id,pdi->lun,hrec); - len += size; pos = begin + len; - flag = TRUE; - pdi->no_ldrive &= 0xffff; - if (pdi->no_ldrive == 0xffff) - strcpy(hrec,"--"); - else - sprintf(hrec,"%d",pdi->no_ldrive); - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n", - pdi->blkcnt/(1024*1024/pdi->blksize), - hrec); - len += size; pos = begin + len; - } else { - pdi->devtype = 0xff; - } - if (pdi->devtype == 0) { - /* search retries/reassigns */ - for (k = 0; k < pds->count; ++k) { - if (pds->list[k].tid == pdi->target_id && - pds->list[k].lun == pdi->lun) { - size = sprintf(buffer+len, - " Retries: \t%-6d \tReassigns: \t%d\n", - pds->list[k].retries, - pds->list[k].reassigns); - len += size; pos = begin + len; - break; - } - } - /* 2.c grown defects */ - TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", - i, ha->raw[i].id_list[j])); - pdef = (gdth_defcnt_str *)buf; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pdef); - gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str); - gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN; - gdtcmd.u.ioctl.channel = - ha->raw[i].address | ha->raw[i].id_list[j]; - pdef->sddc_type = 0x08; -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status == S_OK) -#else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status == S_OK) -#endif - { + if (pdi->devtype == 0) { + /* search retries/reassigns */ + for (k = 0; k < pds->count; ++k) { + if (pds->list[k].tid == pdi->target_id && + pds->list[k].lun == pdi->lun) { size = sprintf(buffer+len, - " Grown Defects:\t%d\n", - pdef->sddc_cnt); + " Retries: \t%-6d \tReassigns: \t%d\n", + pds->list[k].retries, + pds->list[k].reassigns); len += size; pos = begin + len; + break; } } - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - } - gdth_ioctl_free(hanum, buf); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - - /* 3. about logical drives */ - size = sprintf(buffer+len,"\nLogical Drives:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); - if (!buf) - goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!ha->hdr[i].is_logdrv) - continue; - drv_no = i; - j = k = 0; - is_mirr = FALSE; - do { - /* 3.a log. drive info */ - TRACE2(("cache_drv_info() drive no %d\n",drv_no)); - pcdi = (gdth_cdrinfo_str *)buf; + /* 2.c grown defects */ + TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", + i, ha->raw[i].id_list[j])); + pdef = (gdth_defcnt_str *)buf; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi); - gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); - gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; - gdtcmd.u.ioctl.channel = drv_no; -#if LINUX_VERSION_CODE >= 0x020322 + gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str); + gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = + ha->raw[i].address | ha->raw[i].id_list[j]; + pdef->sddc_type = 0x08; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status == S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status != S_OK) + if (scp->SCp.Status == S_OK) #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status != S_OK) + if (scp.SCp.Status == S_OK) #endif { - break; - } - pcdi->ld_dtype >>= 16; - j++; - if (pcdi->ld_dtype > 2) { - strcpy(hrec, "missing"); - } else if (pcdi->ld_error & 1) { - strcpy(hrec, "fault"); - } else if (pcdi->ld_error & 2) { - strcpy(hrec, "invalid"); - k++; j--; - } else { - strcpy(hrec, "ok"); - } - - if (drv_no == i) { - size = sprintf(buffer+len, - "\n Number: \t%-2d \tStatus: \t%s\n", - drv_no, hrec); - len += size; pos = begin + len; - flag = TRUE; - no_mdrv = pcdi->cd_ldcnt; - if (no_mdrv > 1 || pcdi->ld_slave != -1) { - is_mirr = TRUE; - strcpy(hrec, "RAID-1"); - } else if (pcdi->ld_dtype == 0) { - strcpy(hrec, "Disk"); - } else if (pcdi->ld_dtype == 1) { - strcpy(hrec, "RAID-0"); - } else if (pcdi->ld_dtype == 2) { - strcpy(hrec, "Chain"); - } else { - strcpy(hrec, "???"); - } - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tType: \t%s\n", - pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize), - hrec); - len += size; pos = begin + len; - } else { size = sprintf(buffer+len, - " Slave Number: \t%-2d \tStatus: \t%s\n", - drv_no & 0x7fff, hrec); + " Grown Defects:\t%d\n", + pdef->sddc_cnt); len += size; pos = begin + len; } - drv_no = pcdi->ld_slave; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } while (drv_no != -1); - - if (is_mirr) { - size = sprintf(buffer+len, - " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n", - no_mdrv - j - k, k); - len += size; pos = begin + len; } - - if (!ha->hdr[i].is_arraydrv) - strcpy(hrec, "--"); - else - sprintf(hrec, "%d", ha->hdr[i].master_no); - size = sprintf(buffer+len, - " To Array Drv.:\t%s\n", hrec); - len += size; pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) goto stop_output; - } - gdth_ioctl_free(hanum, buf); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + } + } + gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); - /* 4. about array drives */ - size = sprintf(buffer+len,"\nArray Drives:"); + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); len += size; pos = begin + len; - flag = FALSE; + } - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); - if (!buf) - goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) - continue; - /* 4.a array drive info */ - TRACE2(("array_info() drive no %d\n",i)); - pai = (gdth_arrayinf_str *)buf; + /* 3. about logical drives */ + size = sprintf(buffer+len,"\nLogical Drives:"); + len += size; pos = begin + len; + flag = FALSE; + + buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + if (!buf) + goto stop_output; + for (i = 0; i < MAX_LDRIVES; ++i) { + if (!ha->hdr[i].is_logdrv) + continue; + drv_no = i; + j = k = 0; + is_mirr = FALSE; + do { + /* 3.a log. drive info */ + TRACE2(("cache_drv_info() drive no %d\n",drv_no)); + pcdi = (gdth_cdrinfo_str *)buf; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(pai); - gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); - gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; - gdtcmd.u.ioctl.channel = i; -#if LINUX_VERSION_CODE >= 0x020322 + gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); + gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; + gdtcmd.u.ioctl.channel = drv_no; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status != S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status == S_OK) + if (scp->SCp.Status != S_OK) #else gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status == S_OK) + if (scp.SCp.Status != S_OK) #endif { - if (pai->ai_state == 0) - strcpy(hrec, "idle"); - else if (pai->ai_state == 2) - strcpy(hrec, "build"); - else if (pai->ai_state == 4) - strcpy(hrec, "ready"); - else if (pai->ai_state == 6) - strcpy(hrec, "fail"); - else if (pai->ai_state == 8 || pai->ai_state == 10) - strcpy(hrec, "rebuild"); - else - strcpy(hrec, "error"); - if (pai->ai_ext_state & 0x10) - strcat(hrec, "/expand"); - else if (pai->ai_ext_state & 0x1) - strcat(hrec, "/patch"); + break; + } + pcdi->ld_dtype >>= 16; + j++; + if (pcdi->ld_dtype > 2) { + strcpy(hrec, "missing"); + } else if (pcdi->ld_error & 1) { + strcpy(hrec, "fault"); + } else if (pcdi->ld_error & 2) { + strcpy(hrec, "invalid"); + k++; j--; + } else { + strcpy(hrec, "ok"); + } + + if (drv_no == i) { size = sprintf(buffer+len, "\n Number: \t%-2d \tStatus: \t%s\n", - i,hrec); + drv_no, hrec); len += size; pos = begin + len; flag = TRUE; - - if (pai->ai_type == 0) + no_mdrv = pcdi->cd_ldcnt; + if (no_mdrv > 1 || pcdi->ld_slave != -1) { + is_mirr = TRUE; + strcpy(hrec, "RAID-1"); + } else if (pcdi->ld_dtype == 0) { + strcpy(hrec, "Disk"); + } else if (pcdi->ld_dtype == 1) { strcpy(hrec, "RAID-0"); - else if (pai->ai_type == 4) - strcpy(hrec, "RAID-4"); - else if (pai->ai_type == 5) - strcpy(hrec, "RAID-5"); - else - strcpy(hrec, "RAID-10"); + } else if (pcdi->ld_dtype == 2) { + strcpy(hrec, "Chain"); + } else { + strcpy(hrec, "???"); + } size = sprintf(buffer+len, " Capacity [MB]:\t%-6d \tType: \t%s\n", - pai->ai_size/(1024*1024/pai->ai_secsize), + pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize), hrec); len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; + } else { + size = sprintf(buffer+len, + " Slave Number: \t%-2d \tStatus: \t%s\n", + drv_no & 0x7fff, hrec); + len += size; pos = begin + len; } - } - gdth_ioctl_free(hanum, buf); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); + drv_no = pcdi->ld_slave; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } while (drv_no != -1); + + if (is_mirr) { + size = sprintf(buffer+len, + " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n", + no_mdrv - j - k, k); len += size; pos = begin + len; } - - /* 5. about host drives */ - size = sprintf(buffer+len,"\nHost Drives:"); + + if (!ha->hdr[i].is_arraydrv) + strcpy(hrec, "--"); + else + sprintf(hrec, "%d", ha->hdr[i].master_no); + size = sprintf(buffer+len, + " To Array Drv.:\t%s\n", hrec); len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); - if (!buf) + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!ha->hdr[i].is_logdrv || - (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) - continue; - /* 5.a get host drive list */ - TRACE2(("host_get() drv_no %d\n",i)); - phg = (gdth_hget_str *)buf; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = virt_to_bus(phg); - gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str); - gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN; - gdtcmd.u.ioctl.channel = i; - phg->entries = MAX_HDRIVES; - phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); -#if LINUX_VERSION_CODE >= 0x020322 - gdth_do_cmd(scp, &gdtcmd, cmnd, 30); - if (scp->SCp.Status != S_OK) + } + gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + + /* 4. about array drives */ + size = sprintf(buffer+len,"\nArray Drives:"); + len += size; pos = begin + len; + flag = FALSE; + + buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + if (!buf) + goto stop_output; + for (i = 0; i < MAX_LDRIVES; ++i) { + if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) + continue; + /* 4.a array drive info */ + TRACE2(("array_info() drive no %d\n",i)); + pai = (gdth_arrayinf_str *)buf; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); + gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = i; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status == S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status == S_OK) #else - gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); - if (scp.SCp.Status != S_OK) + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status == S_OK) #endif - { - ha->hdr[i].ldr_no = i; - ha->hdr[i].rw_attribs = 0; - ha->hdr[i].start_sec = 0; - } else { - for (j = 0; j < phg->entries; ++j) { - k = phg->entry[j].host_drive; - if (k >= MAX_LDRIVES) - continue; - ha->hdr[k].ldr_no = phg->entry[j].log_drive; - ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; - ha->hdr[k].start_sec = phg->entry[j].start_sec; - } - } - } - gdth_ioctl_free(hanum, buf); - - for (i = 0; i < MAX_HDRIVES; ++i) { - if (!(ha->hdr[i].present)) - continue; - + { + if (pai->ai_state == 0) + strcpy(hrec, "idle"); + else if (pai->ai_state == 2) + strcpy(hrec, "build"); + else if (pai->ai_state == 4) + strcpy(hrec, "ready"); + else if (pai->ai_state == 6) + strcpy(hrec, "fail"); + else if (pai->ai_state == 8 || pai->ai_state == 10) + strcpy(hrec, "rebuild"); + else + strcpy(hrec, "error"); + if (pai->ai_ext_state & 0x10) + strcat(hrec, "/expand"); + else if (pai->ai_ext_state & 0x1) + strcat(hrec, "/patch"); size = sprintf(buffer+len, - "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", - i, ha->hdr[i].ldr_no); + "\n Number: \t%-2d \tStatus: \t%s\n", + i,hrec); len += size; pos = begin + len; flag = TRUE; + if (pai->ai_type == 0) + strcpy(hrec, "RAID-0"); + else if (pai->ai_type == 4) + strcpy(hrec, "RAID-4"); + else if (pai->ai_type == 5) + strcpy(hrec, "RAID-5"); + else + strcpy(hrec, "RAID-10"); size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", - ha->hdr[i].size/2048, ha->hdr[i].start_sec); + " Capacity [MB]:\t%-6d \tType: \t%s\n", + pai->ai_size/(1024*1024/pai->ai_secsize), + hrec); len += size; pos = begin + len; if (pos < offset) { len = 0; @@ -1187,53 +708,125 @@ if (pos > offset + length) goto stop_output; } + } + gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; } - /* controller events */ - size = sprintf(buffer+len,"\nController Events:\n"); + /* 5. about host drives */ + size = sprintf(buffer+len,"\nHost Drives:"); len += size; pos = begin + len; + flag = FALSE; - for (id = -1;;) { - id = gdth_read_event(ha, id, &estr); - if (estr.event_source == 0) - break; - if (estr.event_data.eu.driver.ionode == hanum && - estr.event_source == ES_ASYNC) { - gdth_log_event(&estr.event_data, hrec); - do_gettimeofday(&tv); - sec = (int)(tv.tv_sec - estr.first_stamp); - if (sec < 0) sec = 0; - size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", - sec/3600, sec%3600/60, sec%60, hrec); - len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; + buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr); + if (!buf) + goto stop_output; + for (i = 0; i < MAX_LDRIVES; ++i) { + if (!ha->hdr[i].is_logdrv || + (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) + continue; + /* 5.a get host drive list */ + TRACE2(("host_get() drv_no %d\n",i)); + phg = (gdth_hget_str *)buf; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str); + gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = i; + phg->entries = MAX_HDRIVES; + phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + gdth_do_req(scp, &gdtcmd, cmnd, 30); + if (scp->sr_command->SCp.Status != S_OK) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status != S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status != S_OK) +#endif + { + ha->hdr[i].ldr_no = i; + ha->hdr[i].rw_attribs = 0; + ha->hdr[i].start_sec = 0; + } else { + for (j = 0; j < phg->entries; ++j) { + k = phg->entry[j].host_drive; + if (k >= MAX_LDRIVES) + continue; + ha->hdr[k].ldr_no = phg->entry[j].log_drive; + ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; + ha->hdr[k].start_sec = phg->entry[j].start_sec; } - if (pos > offset + length) - goto stop_output; } - if (id == -1) - break; } - } else { - /* request from tool (GDTMON,..) */ - piord = (gdth_iord_str *)ha->pscratch; - if (piord == NULL) - goto stop_output; - length = piord->size; - memcpy(buffer+len, (char *)piord, length); - gdth_ioctl_free(hanum, ha->pscratch); - len = length; + gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr); + + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!(ha->hdr[i].present)) + continue; + + size = sprintf(buffer+len, + "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", + i, ha->hdr[i].ldr_no); + len += size; pos = begin + len; + flag = TRUE; + + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", + (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); + len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + } + + /* controller events */ + size = sprintf(buffer+len,"\nController Events:\n"); + len += size; pos = begin + len; + + for (id = -1;;) { + id = gdth_read_event(ha, id, &estr); + if (estr.event_source == 0) + break; + if (estr.event_data.eu.driver.ionode == hanum && + estr.event_source == ES_ASYNC) { + gdth_log_event(&estr.event_data, hrec); + do_gettimeofday(&tv); + sec = (int)(tv.tv_sec - estr.first_stamp); + if (sec < 0) sec = 0; + size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", + sec/3600, sec%3600/60, sec%60, hrec); + len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + if (id == -1) + break; } stop_output: -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scsi_release_request(scp); + scsi_free_host_dev(sdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsi_release_command(scp); scsi_free_host_dev(sdev); #endif @@ -1246,13 +839,34 @@ return(len); } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd, + char *cmnd, int timeout) +{ + unsigned bufflen; + DECLARE_COMPLETION(wait); + + TRACE2(("gdth_do_req()\n")); + if (gdtcmd != NULL) { + bufflen = sizeof(gdth_cmd_str); + } else { + bufflen = 0; + } + scp->sr_request->rq_status = RQ_SCSI_BUSY; + scp->sr_request->waiting = &wait; + scsi_do_req(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); + wait_for_completion(&wait); +} + +#else static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, char *cmnd, int timeout) { unsigned bufflen; -#if LINUX_VERSION_CODE >= 0x020407 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) DECLARE_COMPLETION(wait); -#elif LINUX_VERSION_CODE >= 0x020322 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) DECLARE_MUTEX_LOCKED(sem); #else struct semaphore sem = MUTEX_LOCKED; @@ -1266,63 +880,73 @@ scp->SCp.this_residual = DEFAULT_PRI; bufflen = 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) scp->request.rq_status = RQ_SCSI_BUSY; -#if LINUX_VERSION_CODE >= 0x020407 scp->request.waiting = &wait; scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); wait_for_completion(&wait); #else scp->request.sem = &sem; -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); #else - GDTH_LOCK_SCSI_DOCMD(); + spin_lock_irq(&io_request_lock); scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); + spin_unlock_irq(&io_request_lock); #endif down(&sem); #endif } +#endif void gdth_scsi_done(Scsi_Cmnd *scp) { TRACE2(("gdth_scsi_done()\n")); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + scp->request->rq_status = RQ_SCSI_DONE; + if (scp->request->waiting != NULL) + complete(scp->request->waiting); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) scp->request.rq_status = RQ_SCSI_DONE; - -#if LINUX_VERSION_CODE >= 0x020407 if (scp->request.waiting != NULL) complete(scp->request.waiting); #else + scp->request.rq_status = RQ_SCSI_DONE; if (scp->request.sem != NULL) up(scp->request.sem); #endif } -static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch) +static char *gdth_ioctl_alloc(int hanum, int size, int scratch, + ulong64 *paddr) { gdth_ha_str *ha; ulong flags; char *ret_val; - if (size == 0 || size > GDTH_SCRATCH) - return FALSE; + if (size == 0) + return NULL; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); - if (scratch) { - if (!ha->scratch_busy) { - ha->scratch_busy = TRUE; - ret_val = ha->pscratch; - } else - ret_val = NULL; + if (!ha->scratch_busy && size <= GDTH_SCRATCH) { + ha->scratch_busy = TRUE; + ret_val = ha->pscratch; + *paddr = ha->scratch_phys; + } else if (scratch) { + ret_val = NULL; } else { -#if LINUX_VERSION_CODE >= 0x020322 - ret_val = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - GDTH_SCRATCH_ORD); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + dma_addr_t dma_addr; + + ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr); + *paddr = dma_addr; #else - ret_val = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); + ret_val = scsi_init_malloc(size, GFP_ATOMIC | GFP_DMA); + if (ret_val) + *paddr = virt_to_bus(ret_val); #endif } @@ -1330,7 +954,7 @@ return ret_val; } -static void gdth_ioctl_free(int hanum, char *buf) +static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr) { gdth_ha_str *ha; ulong flags; @@ -1341,16 +965,17 @@ if (buf == ha->pscratch) { ha->scratch_busy = FALSE; } else { -#if LINUX_VERSION_CODE >= 0x020322 - free_pages((unsigned long)buf, GDTH_SCRATCH_ORD); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_free_consistent(ha->pdev, size, buf, paddr); #else - scsi_init_free((void *)buf, GDTH_SCRATCH); + scsi_init_free((void *)buf, size); #endif } GDTH_UNLOCK_HA(ha, flags); } +#ifdef GDTH_IOCTL_PROC static int gdth_ioctl_check_bin(int hanum, ushort size) { gdth_ha_str *ha; @@ -1368,7 +993,7 @@ GDTH_UNLOCK_HA(ha, flags); return ret_val; } - +#endif static void gdth_wait_completion(int hanum, int busnum, int id) { @@ -1376,23 +1001,35 @@ ulong flags; int i; Scsi_Cmnd *scp; - unchar b; + unchar b, t; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (i = 0; i < GDTH_MAXCMDS; ++i) { scp = ha->cmd_tab[i].cmnd; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + t = scp->device->id; +#else b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; - if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && + t = scp->target; +#endif + if (!SPECIAL_SCP(scp) && t == (unchar)id && b == (unchar)busnum) { scp->SCp.have_data_in = 0; GDTH_UNLOCK_HA(ha, flags); while (!scp->SCp.have_data_in) barrier(); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + GDTH_LOCK_SCSI_DONE(scp->device->host, flags); + scp->scsi_done(scp); + GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags); +#else GDTH_LOCK_SCSI_DONE(flags); scp->scsi_done(scp); GDTH_UNLOCK_SCSI_DONE(flags); +#endif GDTH_LOCK_HA(ha, flags); } } @@ -1404,14 +1041,20 @@ gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; - unchar b; + unchar b, t; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + t = scp->device->id; +#else b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; - if (scp->target == (unchar)id && b == (unchar)busnum) { + t = scp->target; +#endif + if (t == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_stop_timeout(): update_timeout()\n")); scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); } @@ -1424,14 +1067,20 @@ gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; - unchar b; + unchar b, t; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + t = scp->device->id; +#else b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; - if (scp->target == (unchar)id && b == (unchar)busnum) { + t = scp->target; +#endif + if (t == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_start_timeout(): update_timeout()\n")); gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual); } @@ -1446,7 +1095,6 @@ oldto = scp->timeout_per_command; scp->timeout_per_command = timeout; -#if LINUX_VERSION_CODE >= 0x02014B if (timeout == 0) { del_timer(&scp->eh_timeout); scp->eh_timeout.data = (unsigned long) NULL; @@ -1458,17 +1106,6 @@ scp->eh_timeout.expires = jiffies + timeout; add_timer(&scp->eh_timeout); } -#else - if (timeout > 0) { - if (timer_table[SCSI_TIMER].expires == 0) { - timer_table[SCSI_TIMER].expires = jiffies + timeout; - timer_active |= 1 << SCSI_TIMER; - } else { - if (time_before(jiffies + timeout < timer_table[SCSI_TIMER].expires)) - timer_table[SCSI_TIMER].expires = jiffies + timeout; - } - } -#endif return oldto; } diff -urN linux-2.4.27/drivers/scsi/gdth_proc.h linux-2.4.28/drivers/scsi/gdth_proc.h --- linux-2.4.27/drivers/scsi/gdth_proc.h 2001-09-07 09:28:37.000000000 -0700 +++ linux-2.4.28/drivers/scsi/gdth_proc.h 2004-11-17 03:54:21.659400402 -0800 @@ -2,26 +2,31 @@ #define _GDTH_PROC_H /* gdth_proc.h - * $Id: gdth_proc.h,v 1.11 2001/07/25 15:37:40 achim Exp $ + * $Id: gdth_proc.h,v 1.16 2004/01/14 13:09:01 achim Exp $ */ -static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum); -static int gdth_get_info(char *buffer,char **start,off_t offset, - int length,int vh,int hanum,int busnum); +static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, + int hanum,int busnum); +static int gdth_get_info(char *buffer,char **start,off_t offset,int length, + struct Scsi_Host *host,int hanum,int busnum); -#if LINUX_VERSION_CODE >= 0x020322 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, + char *cmnd, int timeout); +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, + char *cmnd, int timeout); static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp); -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp); #else -static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp); -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp); -#endif static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, char *cmnd, int timeout); +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp); +#endif -static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch); -static void gdth_ioctl_free(int hanum, char *buf); -static int gdth_ioctl_check_bin(int hanum, ushort size); +static char *gdth_ioctl_alloc(int hanum, int size, int scratch, + ulong64 *paddr); +static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr); static void gdth_wait_completion(int hanum, int busnum, int id); static void gdth_stop_timeout(int hanum, int busnum, int id); static void gdth_start_timeout(int hanum, int busnum, int id); diff -urN linux-2.4.27/drivers/scsi/ips.c linux-2.4.28/drivers/scsi/ips.c --- linux-2.4.27/drivers/scsi/ips.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/ips.c 2004-11-17 03:54:21.666400690 -0800 @@ -133,6 +133,10 @@ /* 6.10.00 - Remove 1G Addressing Limitations */ /* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */ /* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */ +/* 7.10.xx - Add highmem_io flag in SCSI Templete for 2.4 kernels */ +/* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ +/* - Fix sort order of 7k */ +/* - Remove 3 unused "inline" functions */ /*****************************************************************************/ /* @@ -176,7 +180,13 @@ #include #include "scsi.h" + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) #include "hosts.h" +#else +#include +#endif + #include "ips.h" #include @@ -197,8 +207,8 @@ /* * DRIVER_VER */ -#define IPS_VERSION_HIGH "7.00" -#define IPS_VERSION_LOW ".15 " +#define IPS_VERSION_HIGH "7.10" +#define IPS_VERSION_LOW ".18 " #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" @@ -277,9 +287,9 @@ .use_clustering = ENABLE_CLUSTERING, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) .use_new_eh_code = 1, -#ifdef RHEL3 - .vary_io = 1, #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + .highmem_io = 1, #endif }; @@ -477,21 +487,17 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); -static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_copp_head(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static inline void ips_putq_copp_tail(ips_copp_queue_t *, +static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); +static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); -static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); -static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, +static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); +static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); +static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); +static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); +static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); +static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); static int ips_is_passthru(Scsi_Cmnd *); static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); @@ -1888,7 +1894,7 @@ /* Fill in a single scb sg_list element from an address */ /* return a -1 if a breakup occurred */ /****************************************************************************/ -static inline int +static int ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, ips_scb_t * scb, int indx, unsigned int e_len) { @@ -2953,7 +2959,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) { METHOD_TRACE("ips_putq_scb_head", 1); @@ -2972,38 +2978,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_scb_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item) -{ - METHOD_TRACE("ips_putq_scb_tail", 1); - - if (!item) - return; - - item->q_next = NULL; - - if (queue->tail) - queue->tail->q_next = item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_removeq_scb_head */ /* */ /* Routine Description: */ @@ -3013,7 +2987,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t * queue) { ips_scb_t *item; @@ -3048,7 +3022,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) { ips_scb_t *p; @@ -3085,34 +3059,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_wait_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item) -{ - METHOD_TRACE("ips_putq_wait_head", 1); - - if (!item) - return; - - item->host_scribble = (char *) queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_wait_tail */ /* */ /* Routine Description: */ @@ -3122,7 +3068,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) { METHOD_TRACE("ips_putq_wait_tail", 1); @@ -3154,7 +3100,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t * queue) { Scsi_Cmnd *item; @@ -3189,7 +3135,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) { Scsi_Cmnd *p; @@ -3226,34 +3172,6 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_putq_copp_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - METHOD_TRACE("ips_putq_copp_head", 1); - - if (!item) - return; - - item->next = queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_copp_tail */ /* */ /* Routine Description: */ @@ -3263,7 +3181,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { METHOD_TRACE("ips_putq_copp_tail", 1); @@ -3295,7 +3213,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t * queue) { ips_copp_wait_item_t *item; @@ -3330,7 +3248,7 @@ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { ips_copp_wait_item_t *p; @@ -4014,7 +3932,7 @@ scb->cmd.logical_info.reserved2 = 0; scb->cmd.logical_info.reserved3 = 0; scb->data_len = sizeof (IPS_LD_INFO); - scb->data_busaddr = ha->logical_drive_info_dma_addr; + scb->data_busaddr = ha->logical_drive_info_dma_addr; scb->flags = 0; scb->cmd.logical_info.buffer_addr = scb->data_busaddr; ret = IPS_SUCCESS; @@ -4340,7 +4258,7 @@ if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); - return (0); + return (0); } if (ha->logical_drive_info->drive_info[scb->target_id].state != @@ -4579,7 +4497,7 @@ if (ha->logical_drive_info) { pci_free_consistent(ha->pcidev, sizeof (IPS_LD_INFO), - ha->logical_drive_info, + ha->logical_drive_info, ha->logical_drive_info_dma_addr); ha->logical_drive_info = NULL; } @@ -4773,7 +4691,7 @@ } ha->scb_freelist = scb->q_next; - scb->flags = 0; + scb->flags = 0; scb->q_next = NULL; ips_init_scb(ha, scb); @@ -6831,7 +6749,7 @@ METHOD_TRACE("ips_version_check", 1); - VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data; + VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data; memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1); memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1); @@ -6843,7 +6761,7 @@ rc = IPS_FAILURE; if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) { /* If Versioning is Supported */ /* Get the Version Info with a Get Version Command */ - memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA)); + memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA)); rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr); if (rc == IPS_SUCCESS) memcpy(FirmwareVersion, VersionInfo->compatibilityId, @@ -6999,7 +6917,6 @@ for (j = position; j < ips_num_controllers; j++) { switch (ips_ha[j]->ad_type) { case IPS_ADTYPE_SERVERAID6M: - case IPS_ADTYPE_SERVERAID7k: case IPS_ADTYPE_SERVERAID7M: if (nvram->adapter_order[i] == 'M') { ips_shift_controllers(position, @@ -7020,6 +6937,7 @@ case IPS_ADTYPE_SERVERAID6I: case IPS_ADTYPE_SERVERAID5I2: case IPS_ADTYPE_SERVERAID5I1: + case IPS_ADTYPE_SERVERAID7k: if (nvram->adapter_order[i] == 'S') { ips_shift_controllers(position, j); @@ -7548,6 +7466,15 @@ MODULE_LICENSE("GPL"); #endif +#ifdef MODULE_DESCRIPTION +MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); +#endif + +#ifdef MODULE_VERSION +MODULE_VERSION(IPS_VER_STRING); +#endif + + /* * Overrides for Emacs so that we almost follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -urN linux-2.4.27/drivers/scsi/ips.h linux-2.4.28/drivers/scsi/ips.h --- linux-2.4.27/drivers/scsi/ips.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/ips.h 2004-11-17 03:54:21.667400731 -0800 @@ -95,13 +95,12 @@ #define scsi_set_pci_device(sh,dev) (0) #endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) + #ifndef IRQ_NONE typedef void irqreturn_t; #define IRQ_NONE #define IRQ_HANDLED #define IRQ_RETVAL(x) #endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #define IPS_REGISTER_HOSTS(SHT) scsi_register_module(MODULE_SCSI_HA,SHT) #define IPS_UNREGISTER_HOSTS(SHT) scsi_unregister_module(MODULE_SCSI_HA,SHT) @@ -1213,13 +1212,13 @@ #define IPS_VER_MAJOR 7 #define IPS_VER_MAJOR_STRING "7" -#define IPS_VER_MINOR 00 -#define IPS_VER_MINOR_STRING "00" -#define IPS_VER_BUILD 15 -#define IPS_VER_BUILD_STRING "15" -#define IPS_VER_STRING "7.00.15" +#define IPS_VER_MINOR 10 +#define IPS_VER_MINOR_STRING "10" +#define IPS_VER_BUILD 18 +#define IPS_VER_BUILD_STRING "18" +#define IPS_VER_STRING "7.10.18" #define IPS_RELEASE_ID 0x00020000 -#define IPS_BUILD_IDENT 625 +#define IPS_BUILD_IDENT 731 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved." #define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to 2004. All Rights Reserved." #define IPS_DELLCOPYRIGHT_STRING "(c) Copyright Dell 2004. All Rights Reserved." @@ -1230,32 +1229,35 @@ #define IPS_VER_SERVERAID2 "2.88.13" #define IPS_VER_NAVAJO "2.88.13" #define IPS_VER_SERVERAID3 "6.10.24" -#define IPS_VER_SERVERAID4H "7.00.15" -#define IPS_VER_SERVERAID4MLx "7.00.15" -#define IPS_VER_SARASOTA "7.00.15" -#define IPS_VER_MARCO "7.00.15" -#define IPS_VER_SEBRING "7.00.15" +#define IPS_VER_SERVERAID4H "7.10.11" +#define IPS_VER_SERVERAID4MLx "7.10.18" +#define IPS_VER_SARASOTA "7.10.18" +#define IPS_VER_MARCO "7.10.18" +#define IPS_VER_SEBRING "7.10.18" +#define IPS_VER_KEYWEST "7.10.18" /* Compatability IDs for various adapters */ #define IPS_COMPAT_UNKNOWN "" -#define IPS_COMPAT_CURRENT "SB610" +#define IPS_COMPAT_CURRENT "KW710" #define IPS_COMPAT_SERVERAID1 "2.25.01" #define IPS_COMPAT_SERVERAID2 "2.88.13" #define IPS_COMPAT_NAVAJO "2.88.13" #define IPS_COMPAT_KIOWA "2.88.13" #define IPS_COMPAT_SERVERAID3H "SB610" #define IPS_COMPAT_SERVERAID3L "SB610" -#define IPS_COMPAT_SERVERAID4H "SB610" -#define IPS_COMPAT_SERVERAID4M "SB610" -#define IPS_COMPAT_SERVERAID4L "SB610" -#define IPS_COMPAT_SERVERAID4Mx "SB610" -#define IPS_COMPAT_SERVERAID4Lx "SB610" -#define IPS_COMPAT_SARASOTA "SB610" -#define IPS_COMPAT_MARCO "SB610" -#define IPS_COMPAT_SEBRING "SB610" -#define IPS_COMPAT_BIOS "SB610" +#define IPS_COMPAT_SERVERAID4H "KW710" +#define IPS_COMPAT_SERVERAID4M "KW710" +#define IPS_COMPAT_SERVERAID4L "KW710" +#define IPS_COMPAT_SERVERAID4Mx "KW710" +#define IPS_COMPAT_SERVERAID4Lx "KW710" +#define IPS_COMPAT_SARASOTA "KW710" +#define IPS_COMPAT_MARCO "KW710" +#define IPS_COMPAT_SEBRING "KW710" +#define IPS_COMPAT_TAMPA "KW710" +#define IPS_COMPAT_KEYWEST "KW710" +#define IPS_COMPAT_BIOS "KW710" -#define IPS_COMPAT_MAX_ADAPTER_TYPE 16 +#define IPS_COMPAT_MAX_ADAPTER_TYPE 18 #define IPS_COMPAT_ID_LENGTH 8 #define IPS_DEFINE_COMPAT_TABLE(tablename) \ @@ -1275,7 +1277,9 @@ IPS_COMPAT_SARASOTA, /* one-channel variety of SARASOTA */ \ IPS_COMPAT_SARASOTA, /* two-channel variety of SARASOTA */ \ IPS_COMPAT_MARCO, \ - IPS_COMPAT_SEBRING \ + IPS_COMPAT_SEBRING, \ + IPS_COMPAT_TAMPA, \ + IPS_COMPAT_KEYWEST \ } diff -urN linux-2.4.27/drivers/scsi/libata-core.c linux-2.4.28/drivers/scsi/libata-core.c --- linux-2.4.27/drivers/scsi/libata-core.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/libata-core.c 2004-11-17 03:54:21.674401019 -0800 @@ -42,20 +42,21 @@ #include #include #include +#include #include "libata.h" static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); -static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat); -static void ata_host_set_pio(struct ata_port *ap); -static void ata_host_set_udma(struct ata_port *ap); -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); static void ata_set_mode(struct ata_port *ap); -static int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static int fgb(u32 bitmap); +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static unsigned int ata_unique_id = 1; static LIST_HEAD(ata_probe_list); @@ -65,37 +66,6 @@ MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); -static const char * thr_state_name[] = { - "THR_UNKNOWN", - "THR_PORT_RESET", - "THR_AWAIT_DEATH", - "THR_PROBE_FAILED", - "THR_IDLE", - "THR_PROBE_SUCCESS", - "THR_PROBE_START", -}; - -/** - * ata_thr_state_name - convert thread state enum to string - * @thr_state: thread state to be converted to string - * - * Converts the specified thread state id to a constant C string. - * - * LOCKING: - * None. - * - * RETURNS: - * The THR_xxx-prefixed string naming the specified thread - * state id, or the string "". - */ - -static const char *ata_thr_state_name(unsigned int thr_state) -{ - if (thr_state < ARRAY_SIZE(thr_state_name)) - return thr_state_name[thr_state]; - return ""; -} - /** * msleep - sleep for a number of milliseconds * @msecs: number of milliseconds to sleep @@ -113,18 +83,23 @@ schedule_timeout(msecs_to_jiffies(msecs) + 1); } +void libata_msleep(unsigned long msecs) +{ + msleep(msecs); +} + /** - * ata_tf_load_pio - send taskfile registers to host controller + * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Outputs ATA taskfile to standard ATA host controller using PIO. + * Outputs ATA taskfile to standard ATA host controller. * * LOCKING: * Inherited from caller. */ -void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -182,23 +157,23 @@ * Inherited from caller. */ -void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, ap->ioaddr.ctl_addr); + writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void *) ioaddr->feature_addr); - writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr); - writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr); - writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr); - writeb(tf->hob_lbah, (void *) ioaddr->lbah_addr); + writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -208,11 +183,11 @@ } if (is_addr) { - writeb(tf->feature, (void *) ioaddr->feature_addr); - writeb(tf->nsect, (void *) ioaddr->nsect_addr); - writeb(tf->lbal, (void *) ioaddr->lbal_addr); - writeb(tf->lbam, (void *) ioaddr->lbam_addr); - writeb(tf->lbah, (void *) ioaddr->lbah_addr); + writeb(tf->feature, (void __iomem *) ioaddr->feature_addr); + writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr); + writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr); + writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr); + writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr); VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, @@ -222,26 +197,34 @@ } if (tf->flags & ATA_TFLAG_DEVICE) { - writeb(tf->device, (void *) ioaddr->device_addr); + writeb(tf->device, (void __iomem *) ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } ata_wait_idle(ap); } +void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_load_mmio(ap, tf); + else + ata_tf_load_pio(ap, tf); +} + /** - * ata_exec_command_pio - issue ATA command to host controller + * ata_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -262,20 +245,28 @@ * spin_lock_irqsave(host_set lock) */ -void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void *) ap->ioaddr.command_addr); + writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr); ata_pause(ap); } +void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_exec_command_mmio(ap, tf); + else + ata_exec_command_pio(ap, tf); +} + /** * ata_exec - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues PIO write to ATA command register, with proper + * Issues PIO/MMIO write to ATA command register, with proper * synchronization with interrupt handler / other threads. * * LOCKING: @@ -298,7 +289,7 @@ * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -318,7 +309,7 @@ * @tf: ATA taskfile register set * * Issues ATA taskfile register set to ATA host controller, - * via PIO, with proper synchronization with interrupt handler and + * with proper synchronization with interrupt handler and * other threads. * * LOCKING: @@ -332,18 +323,18 @@ } /** - * ata_tf_read_pio - input device's ATA taskfile shadow registers + * ata_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf via PIO. + * into @tf. * * LOCKING: * Inherited from caller. */ -void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -375,38 +366,46 @@ * Inherited from caller. */ -void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->nsect = readb((void *)ioaddr->nsect_addr); - tf->lbal = readb((void *)ioaddr->lbal_addr); - tf->lbam = readb((void *)ioaddr->lbam_addr); - tf->lbah = readb((void *)ioaddr->lbah_addr); - tf->device = readb((void *)ioaddr->device_addr); + tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->lbah = readb((void __iomem *)ioaddr->lbah_addr); + tf->device = readb((void __iomem *)ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - writeb(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr); - tf->hob_feature = readb((void *)ioaddr->error_addr); - tf->hob_nsect = readb((void *)ioaddr->nsect_addr); - tf->hob_lbal = readb((void *)ioaddr->lbal_addr); - tf->hob_lbam = readb((void *)ioaddr->lbam_addr); - tf->hob_lbah = readb((void *)ioaddr->lbah_addr); + writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr); + tf->hob_feature = readb((void __iomem *)ioaddr->error_addr); + tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr); + tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr); + tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr); + tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr); } } +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_tf_read_mmio(ap, tf); + else + ata_tf_read_pio(ap, tf); +} + /** - * ata_check_status_pio - Read device status reg & clear interrupt + * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is * * Reads ATA taskfile status register for currently-selected device - * via PIO and return it's value. This also clears pending interrupts + * and return it's value. This also clears pending interrupts * from this device * * LOCKING: * Inherited from caller. */ -u8 ata_check_status_pio(struct ata_port *ap) +static u8 ata_check_status_pio(struct ata_port *ap) { return inb(ap->ioaddr.status_addr); } @@ -422,9 +421,16 @@ * LOCKING: * Inherited from caller. */ -u8 ata_check_status_mmio(struct ata_port *ap) +static u8 ata_check_status_mmio(struct ata_port *ap) { - return readb((void *) ap->ioaddr.status_addr); + return readb((void __iomem *) ap->ioaddr.status_addr); +} + +u8 ata_check_status(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) + return ata_check_status_mmio(ap); + return ata_check_status_pio(ap); } /** @@ -574,7 +580,7 @@ dev->write_cmd = (cmd >> 8) & 0xff; } -static const char * udma_str[] = { +static const char * xfer_mode_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", @@ -583,6 +589,14 @@ "UDMA/100", "UDMA/133", "UDMA7", + "MWDMA0", + "MWDMA1", + "MWDMA2", + "PIO0", + "PIO1", + "PIO2", + "PIO3", + "PIO4", }; /** @@ -600,16 +614,24 @@ * @udma_mask, or the constant C string "". */ -static const char *ata_udma_string(unsigned int udma_mask) +static const char *ata_mode_string(unsigned int mask) { int i; - for (i = 7; i >= 0; i--) { - if (udma_mask & (1 << i)) - return udma_str[i]; - } + for (i = 7; i >= 0; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--) + if (mask & (1 << i)) + goto out; return ""; + +out: + return xfer_mode_str[i]; } /** @@ -636,7 +658,7 @@ struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); outb(0x55, ioaddr->nsect_addr); outb(0xaa, ioaddr->lbal_addr); @@ -680,19 +702,19 @@ struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - writeb(0xaa, (void *) ioaddr->nsect_addr); - writeb(0x55, (void *) ioaddr->lbal_addr); + writeb(0xaa, (void __iomem *) ioaddr->nsect_addr); + writeb(0x55, (void __iomem *) ioaddr->lbal_addr); - writeb(0x55, (void *) ioaddr->nsect_addr); - writeb(0xaa, (void *) ioaddr->lbal_addr); + writeb(0x55, (void __iomem *) ioaddr->nsect_addr); + writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -701,7 +723,7 @@ } /** - * ata_dev_devchk - PATA device presence detection + * ata_devchk - PATA device presence detection * @ap: ATA channel to examine * @device: Device to examine (starting at zero) * @@ -713,7 +735,7 @@ * caller. */ -static unsigned int ata_dev_devchk(struct ata_port *ap, +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { if (ap->flags & ATA_FLAG_MMIO) @@ -737,7 +759,7 @@ * the event of failure. */ -static unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -785,7 +807,7 @@ unsigned int class; u8 err; - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); memset(&tf, 0, sizeof(tf)); @@ -848,8 +870,12 @@ } } +void ata_noop_dev_select (struct ata_port *ap, unsigned int device) +{ +} + /** - * __ata_dev_select - Select device 0/1 on ATA bus + * ata_std_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * @@ -861,7 +887,7 @@ * caller. */ -static void __ata_dev_select (struct ata_port *ap, unsigned int device) +void ata_std_dev_select (struct ata_port *ap, unsigned int device) { u8 tmp; @@ -871,7 +897,7 @@ tmp = ATA_DEVICE_OBS | ATA_DEV1; if (ap->flags & ATA_FLAG_MMIO) { - writeb(tmp, (void *) ap->ioaddr.device_addr); + writeb(tmp, (void __iomem *) ap->ioaddr.device_addr); } else { outb(tmp, ap->ioaddr.device_addr); } @@ -889,7 +915,7 @@ * make either device 0, or device 1, active on the * ATA channel. * - * This is a high-level version of __ata_dev_select(), + * This is a high-level version of ata_std_dev_select(), * which additionally provides the services of inserting * the proper pauses and status polling, where needed. * @@ -906,7 +932,7 @@ if (wait) ata_wait_idle(ap); - __ata_dev_select(ap, device); + ap->ops->dev_select(ap, device); if (wait) { if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) @@ -980,10 +1006,14 @@ { struct ata_device *dev = &ap->device[device]; unsigned int i; - u16 tmp, udma_modes; + u16 tmp; + unsigned long xfer_modes; u8 status; - struct ata_taskfile tf; unsigned int using_edd; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; if (!ata_dev_present(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", @@ -1003,27 +1033,34 @@ ata_dev_select(ap, device, 1, 1); /* select device 0/1 */ -retry: - ata_tf_init(ap, &tf, device); - tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO; + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->pci_dma_dir = PCI_DMA_FROMDEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + +retry: if (dev->class == ATA_DEV_ATA) { - tf.command = ATA_CMD_ID_ATA; + qc->tf.command = ATA_CMD_ID_ATA; DPRINTK("do ATA identify\n"); } else { - tf.command = ATA_CMD_ID_ATAPI; + qc->tf.command = ATA_CMD_ID_ATAPI; DPRINTK("do ATAPI identify\n"); } - ata_tf_to_host(ap, &tf); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) + if (rc) goto err_out; + else + wait_for_completion(&wait); status = ata_chk_status(ap); if (status & ATA_ERR) { @@ -1038,44 +1075,21 @@ * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) { + if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; + qc->cursg = 0; + qc->cursg_ofs = 0; + qc->cursect = 0; + qc->nsect = 1; goto retry; } } goto err_out; } - /* make sure we have BSY=0, DRQ=1 */ - if ((status & ATA_DRQ) == 0) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - /* read IDENTIFY [X] DEVICE page */ - if (ap->flags & ATA_FLAG_MMIO) { - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = readw((void *)ap->ioaddr.data_addr); - } else - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = inw(ap->ioaddr.data_addr); - - /* wait for host_idle */ - status = ata_wait_idle(ap); - if (status & (ATA_BUSY | ATA_DRQ)) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - ata_irq_on(ap); /* re-enable interrupts */ + swap_buf_le16(dev->id, ATA_ID_WORDS); /* print device capabilities */ printk(KERN_DEBUG "ata%u: dev %u cfg " @@ -1095,12 +1109,13 @@ goto err_out_nosup; } - /* we require UDMA support */ - udma_modes = - tmp = dev->id[ATA_ID_UDMA_MODES]; - if ((tmp & 0xff) == 0) { - printk(KERN_DEBUG "ata%u: no udma\n", ap->id); - goto err_out_nosup; + /* quick-n-dirty find max transfer mode; for printk only */ + xfer_modes = dev->id[ATA_ID_UDMA_MODES]; + if (!xfer_modes) + xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; + if (!xfer_modes) { + xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); + xfer_modes |= (0x7 << ATA_SHIFT_PIO); } ata_dump_id(dev); @@ -1133,7 +1148,7 @@ /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", ap->id, device, - ata_udma_string(udma_modes), + ata_mode_string(xfer_modes), (unsigned long long)dev->n_sectors, dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } @@ -1143,15 +1158,18 @@ if (ata_id_is_ata(dev)) /* sanity check */ goto err_out_nosup; - /* see if 16-byte commands supported */ - tmp = dev->id[0] & 0x3; - if (tmp == 1) - ap->host->max_cmd_len = 16; + rc = atapi_cdb_len(dev->id); + if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { + printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + goto err_out_nosup; + } + ap->cdb_len = (unsigned int) rc; + ap->host->max_cmd_len = (unsigned char) ap->cdb_len; /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, - ata_udma_string(udma_modes)); + ata_mode_string(xfer_modes)); } DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap)); @@ -1167,13 +1185,16 @@ } /** - * ata_port_reset - - * @ap: + * ata_bus_probe - Reset and probe ATA bus + * @ap: Bus to probe * * LOCKING: + * + * RETURNS: + * Zero on success, non-zero on error. */ -static void ata_port_reset(struct ata_port *ap) +static int ata_bus_probe(struct ata_port *ap) { unsigned int i, found = 0; @@ -1197,14 +1218,12 @@ if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out_disable; - ap->thr_state = THR_PROBE_SUCCESS; - - return; + return 0; err_out_disable: ap->ops->port_disable(ap); err_out: - ap->thr_state = THR_PROBE_FAILED; + return -1; } /** @@ -1220,13 +1239,13 @@ } /** - * sata_phy_reset - + * __sata_phy_reset - * @ap: * * LOCKING: * */ -void sata_phy_reset(struct ata_port *ap) +void __sata_phy_reset(struct ata_port *ap) { u32 sstatus; unsigned long timeout = jiffies + (HZ * 5); @@ -1264,6 +1283,21 @@ return; } + ap->cbl = ATA_CBL_SATA; +} + +/** + * __sata_phy_reset - + * @ap: + * + * LOCKING: + * + */ +void sata_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; ata_bus_reset(ap); } @@ -1281,6 +1315,101 @@ ap->flags |= ATA_FLAG_PORT_DISABLED; } +static struct { + unsigned int shift; + u8 base; +} xfer_mode_classes[] = { + { ATA_SHIFT_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_PIO, XFER_PIO_0 }, +}; + +static inline u8 base_from_shift(unsigned int shift) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) + if (xfer_mode_classes[i].shift == shift) + return xfer_mode_classes[i].base; + + return 0xff; +} + +static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +{ + int ofs, idx; + u8 base; + + if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) + return; + + if (dev->xfer_shift == ATA_SHIFT_PIO) + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ap, dev); + + base = base_from_shift(dev->xfer_shift); + ofs = dev->xfer_mode - base; + idx = ofs + dev->xfer_shift; + WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str)); + + DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n", + idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs); + + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ap->id, dev->devno, xfer_mode_str[idx]); +} + +static int ata_host_set_pio(struct ata_port *ap) +{ + unsigned int mask; + int x, i; + u8 base, xfer_mode; + + mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); + x = fgb(mask); + if (x < 0) { + printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); + return -1; + } + + base = base_from_shift(ATA_SHIFT_PIO); + xfer_mode = base + x; + + DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", + (int)base, (int)xfer_mode, mask, x); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = ATA_SHIFT_PIO; + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, dev); + } + } + + return 0; +} + +static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, + unsigned int xfer_shift) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->dma_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = xfer_shift; + if (ap->ops->set_dmamode) + ap->ops->set_dmamode(ap, dev); + } + } +} + /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed @@ -1290,29 +1419,28 @@ */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio, i; - - ata_host_set_pio(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + unsigned int i, xfer_shift; + u8 xfer_mode; + int rc; - ata_host_set_udma(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 1: always set host PIO timings */ + rc = ata_host_set_pio(ap); + if (rc) + goto err_out; -#ifdef ATA_FORCE_PIO - force_pio = 1; -#else - force_pio = 0; -#endif + /* step 2: choose the best data xfer mode */ + xfer_mode = xfer_shift = 0; + rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); + if (rc) + goto err_out; - if (force_pio) { - ata_dev_set_pio(ap, 0); - ata_dev_set_pio(ap, 1); - } else { - ata_dev_set_udma(ap, 0); - ata_dev_set_udma(ap, 1); - } + /* step 3: if that xfer mode isn't PIO, set host DMA timings */ + if (xfer_shift != ATA_SHIFT_PIO) + ata_host_set_dma(ap, xfer_mode, xfer_shift); + + /* step 4: update devices' xfer mode */ + ata_dev_set_mode(ap, &ap->device[0]); + ata_dev_set_mode(ap, &ap->device[1]); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; @@ -1324,6 +1452,11 @@ struct ata_device *dev = &ap->device[i]; ata_dev_set_protocol(dev); } + + return; + +err_out: + ata_port_disable(ap); } /** @@ -1377,23 +1510,23 @@ unsigned int dev1 = devmask & (1 << 1); unsigned long timeout; - /* if device 0 was found in ata_dev_devchk, wait for its + /* if device 0 was found in ata_devchk, wait for its * BSY bit to clear */ if (dev0) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - /* if device 1 was found in ata_dev_devchk, wait for + /* if device 1 was found in ata_devchk, wait for * register access, then wait for BSY to clear */ timeout = jiffies + ATA_TMOUT_BOOT; while (dev1) { u8 nsect, lbal; - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->flags & ATA_FLAG_MMIO) { - nsect = readb((void *) ioaddr->nsect_addr); - lbal = readb((void *) ioaddr->lbal_addr); + nsect = readb((void __iomem *) ioaddr->nsect_addr); + lbal = readb((void __iomem *) ioaddr->lbal_addr); } else { nsect = inb(ioaddr->nsect_addr); lbal = inb(ioaddr->lbal_addr); @@ -1410,11 +1543,11 @@ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); /* is all this really necessary? */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); if (dev1) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (dev0) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); } /** @@ -1457,11 +1590,11 @@ /* software reset. causes dev0 to be selected */ if (ap->flags & ATA_FLAG_MMIO) { - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr); udelay(20); /* FIXME: flush */ - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); } else { outb(ap->ctl, ioaddr->ctl_addr); udelay(10); @@ -1518,9 +1651,9 @@ if (ap->flags & ATA_FLAG_SATA_RESET) dev0 = 1; else { - dev0 = ata_dev_devchk(ap, 0); + dev0 = ata_devchk(ap, 0); if (slave_possible) - dev1 = ata_dev_devchk(ap, 1); + dev1 = ata_devchk(ap, 1); } if (dev0) @@ -1529,7 +1662,7 @@ devmask |= (1 << 1); /* select device 0 again */ - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) @@ -1537,7 +1670,7 @@ else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { /* set up device control */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); rc = ata_bus_edd(ap); @@ -1558,9 +1691,9 @@ /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) - __ata_dev_select(ap, 1); + ap->ops->dev_select(ap, 1); if (ap->device[0].class != ATA_DEV_NONE) - __ata_dev_select(ap, 0); + ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ if ((ap->device[0].class == ATA_DEV_NONE) && @@ -1570,7 +1703,7 @@ if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { /* set up device control for ATA_FLAG_SATA_RESET */ if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); } @@ -1585,116 +1718,102 @@ DPRINTK("EXIT\n"); } -/** - * ata_host_set_pio - - * @ap: - * - * LOCKING: - */ - -static void ata_host_set_pio(struct ata_port *ap) +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; - unsigned int pio, i; - u16 mask; + unsigned int mask; master = &ap->device[0]; slave = &ap->device[1]; assert (ata_dev_present(master) || ata_dev_present(slave)); - mask = ap->pio_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); - - /* require pio mode 3 or 4 support for host and all devices */ - if (mask == 0) { - printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", - ap->id); - goto err_out; + if (shift == ATA_SHIFT_UDMA) { + mask = ap->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + } + else if (shift == ATA_SHIFT_MWDMA) { + mask = ap->mwdma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + } + else if (shift == ATA_SHIFT_PIO) { + mask = ap->pio_mask; + if (ata_dev_present(master)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + if (ata_dev_present(slave)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + } + else { + mask = 0xffffffff; /* shut up compiler warning */ + BUG(); } - pio = (mask & ATA_ID_PIO4) ? 4 : 3; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].pio_mode = (pio == 3) ? - XFER_PIO_3 : XFER_PIO_4; - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, &ap->device[i], pio); - } + return mask; +} - return; +/* find greatest bit */ +static int fgb(u32 bitmap) +{ + unsigned int i; + int x = -1; -err_out: - ap->ops->port_disable(ap); + for (i = 0; i < 32; i++) + if (bitmap & (1 << i)) + x = i; + + return x; } /** - * ata_host_set_udma - + * ata_choose_xfer_mode - * @ap: * * LOCKING: + * + * RETURNS: + * Zero on success, negative on error. */ -static void ata_host_set_udma(struct ata_port *ap) -{ - struct ata_device *master, *slave; - u16 mask; - unsigned int i, j; - int udma_mode = -1; - - master = &ap->device[0]; - slave = &ap->device[1]; - - assert (ata_dev_present(master) || ata_dev_present(slave)); - assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0); - - DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", - ap->udma_mask, - (!ata_dev_present(master)) ? 0xff : - (master->id[ATA_ID_UDMA_MODES] & 0xff), - (!ata_dev_present(slave)) ? 0xff : - (slave->id[ATA_ID_UDMA_MODES] & 0xff)); - - mask = ap->udma_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - - i = XFER_UDMA_7; - while (i >= XFER_UDMA_0) { - j = i - XFER_UDMA_0; - DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); - if (mask & (1 << j)) { - udma_mode = i; - break; +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out) +{ + unsigned int mask, shift; + int x, i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { + shift = xfer_mode_classes[i].shift; + mask = ata_get_mode_mask(ap, shift); + + x = fgb(mask); + if (x >= 0) { + *xfer_mode_out = xfer_mode_classes[i].base + x; + *xfer_shift_out = shift; + return 0; } - - i--; - } - - /* require udma for host and all attached devices */ - if (udma_mode < 0) { - printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", - ap->id); - goto err_out; } - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].udma_mode = udma_mode; - if (ap->ops->set_udmamode) - ap->ops->set_udmamode(ap, &ap->device[i], - udma_mode); - } - - return; - -err_out: - ap->ops->port_disable(ap); + return -1; } /** @@ -1707,89 +1826,39 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) { - struct ata_taskfile tf; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_XFER; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - if (dev->flags & ATA_DFLAG_PIO) - tf.nsect = dev->pio_mode; - else - tf.nsect = dev->udma_mode; - /* do bus reset */ - ata_tf_to_host(ap, &tf); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + qc->tf.command = ATA_CMD_SET_FEATURES; + qc->tf.feature = SETFEATURES_XFER; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = dev->xfer_mode; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - ata_irq_on(ap); /* re-enable interrupts */ + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - ata_wait_idle(ap); + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); DPRINTK("EXIT\n"); } /** - * ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->udma_mode >= XFER_UDMA_0) && - (dev->udma_mode <= XFER_UDMA_7)); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, device, - udma_str[dev->udma_mode - XFER_UDMA_0]); -} - -/** - * ata_dev_set_pio - Set ATA device's transfer mode to PIO - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - /* force PIO mode */ - dev->flags |= ATA_DFLAG_PIO; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->pio_mode >= XFER_PIO_3) && - (dev->pio_mode <= XFER_PIO_4)); - printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", - ap->id, device, - dev->pio_mode == 3 ? '3' : '4'); -} - -/** * ata_sg_clean - * @qc: * @@ -1799,37 +1868,35 @@ static void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; struct scatterlist *sg = qc->sg; - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = qc->pci_dma_dir; - assert(dir == SCSI_DATA_READ || dir == SCSI_DATA_WRITE); - assert(qc->flags & ATA_QCFLAG_SG); + assert(qc->flags & ATA_QCFLAG_DMAMAP); assert(sg != NULL); - if (!cmd->use_sg) + if (qc->flags & ATA_QCFLAG_SINGLE) assert(qc->n_elem == 1); DPRINTK("unmapping %u sg elements\n", qc->n_elem); - if (cmd->use_sg) + if (qc->flags & ATA_QCFLAG_SG) pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir); else pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]), sg_dma_len(&sg[0]), dir); - qc->flags &= ~ATA_QCFLAG_SG; + qc->flags &= ~ATA_QCFLAG_DMAMAP; qc->sg = NULL; } /** - * ata_fill_sg - - * @qc: + * ata_fill_sg - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred * * LOCKING: * */ -void ata_fill_sg(struct ata_queued_cmd *qc) +static void ata_fill_sg(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -1840,7 +1907,7 @@ idx = 0; for (nelem = qc->n_elem; nelem; nelem--,sg++) { - u32 addr, boundary; + u32 addr, offset; u32 sg_len, len; /* determine if physical DMA addr spans 64K boundary. @@ -1851,10 +1918,10 @@ sg_len = sg_dma_len(sg); while (sg_len) { - boundary = (addr & ~0xffff) + (0xffff + 1); + offset = addr & 0xffff; len = sg_len; - if ((addr + sg_len) > boundary) - len = boundary - addr; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; ap->prd[idx].addr = cpu_to_le32(addr); ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); @@ -1871,6 +1938,48 @@ } /** + * ata_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + ata_fill_sg(qc); +} + +void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) +{ + struct scatterlist *sg; + + qc->flags |= ATA_QCFLAG_SINGLE; + + memset(&qc->sgent, 0, sizeof(qc->sgent)); + qc->sg = &qc->sgent; + qc->n_elem = 1; + qc->buf_virt = buf; + + sg = qc->sg; + sg->page = virt_to_page(buf); + sg->offset = (unsigned long) buf & ~PAGE_MASK; + sg_dma_len(sg) = buflen; + + WARN_ON(buflen > PAGE_SIZE); +} + +void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, + unsigned int n_elem) +{ + qc->flags |= ATA_QCFLAG_SG; + qc->sg = sg; + qc->n_elem = n_elem; +} + +/** * ata_sg_setup_one - * @qc: * @@ -1884,29 +1993,16 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = qc->pci_dma_dir; struct scatterlist *sg = qc->sg; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); dma_addr_t dma_address; - assert(sg == &qc->sgent); - assert(qc->n_elem == 1); - - sg->address = cmd->request_buffer; - sg->page = virt_to_page(cmd->request_buffer); - sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK; - sg_dma_len(sg) = cmd->request_bufflen; - - if (!have_sg) - return 0; - - dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer, - cmd->request_bufflen, dir); + dma_address = pci_map_single(ap->host_set->pdev, qc->buf_virt, + sg_dma_len(sg), dir); sg_dma_address(sg) = dma_address; - DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen, + DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); return 0; @@ -1926,24 +2022,19 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; - struct scatterlist *sg; - int n_elem; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); + struct scatterlist *sg = qc->sg; + int n_elem, dir; - VPRINTK("ENTER, ata%u, use_sg %d\n", ap->id, cmd->use_sg); - assert(cmd->use_sg > 0); + VPRINTK("ENTER, ata%u\n", ap->id); + assert(qc->flags & ATA_QCFLAG_SG); + + dir = qc->pci_dma_dir; + n_elem = pci_map_sg(ap->host_set->pdev, sg, qc->n_elem, dir); + if (n_elem < 1) + return -1; + + DPRINTK("%d sg elements mapped\n", n_elem); - sg = (struct scatterlist *)cmd->request_buffer; - if (have_sg) { - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir); - if (n_elem < 1) - return -1; - DPRINTK("%d sg elements mapped\n", n_elem); - } else { - n_elem = cmd->use_sg; - } qc->n_elem = n_elem; return 0; @@ -2028,7 +2119,7 @@ } drv_stat = ata_wait_idle(ap); - if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; return; } @@ -2043,6 +2134,126 @@ ata_qc_complete(qc, drv_stat); } +void swap_buf_le16(u16 *buf, unsigned int buf_words) +{ +#ifdef __BIG_ENDIAN + unsigned int i; + + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +#endif /* __BIG_ENDIAN */ +} + +static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + + if (write_data) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(mmio)); + } +} + +static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int dwords = buflen >> 1; + + if (write_data) + outsw(ap->ioaddr.data_addr, buf, dwords); + else + insw(ap->ioaddr.data_addr, buf, dwords); +} + +static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int do_write) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_mmio_data_xfer(ap, buf, buflen, do_write); + else + ata_pio_data_xfer(ap, buf, buflen, do_write); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct page *page; + unsigned char *buf; + + if (qc->cursect == (qc->nsect - 1)) + ap->pio_task_state = PIO_ST_LAST; + + page = sg[qc->cursg].page; + buf = kmap(page) + + sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); + + qc->cursect++; + qc->cursg_ofs++; + + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + qc->cursg++; + qc->cursg_ofs = 0; + } + + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + /* do the actual data transfer */ + do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); + + kunmap(page); +} + +static void atapi_pio_sector(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + unsigned int i, ireason, bc_lo, bc_hi, bytes; + int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0; + + ap->ops->tf_read(ap, &qc->tf); + ireason = qc->tf.nsect; + bc_lo = qc->tf.lbam; + bc_hi = qc->tf.lbah; + bytes = (bc_hi << 8) | bc_lo; + + /* shall be cleared to zero, indicating xfer of data */ + if (ireason & (1 << 0)) + goto err_out; + + /* make sure transfer direction matches expected */ + i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; + if (do_write != i_write) + goto err_out; + + /* make sure byte count is multiple of sector size; not + * required by standard (warning! warning!), but IDE driver + * does this to simplify things a bit. We are lazy, and + * follow suit. + */ + if (bytes & (ATA_SECT_SIZE - 1)) + goto err_out; + + for (i = 0; i < (bytes >> 9); i++) + ata_pio_sector(qc); + + return; + +err_out: + printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", + ap->id, dev->devno); + ap->pio_task_state = PIO_ST_ERR; +} + /** * ata_pio_sector - * @ap: @@ -2050,12 +2261,9 @@ * LOCKING: */ -static void ata_pio_sector(struct ata_port *ap) +static void ata_pio_block(struct ata_port *ap) { struct ata_queued_cmd *qc; - struct scatterlist *sg; - struct scsi_cmnd *cmd; - unsigned char *buf; u8 status; /* @@ -2086,36 +2294,29 @@ qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - cmd = qc->scsicmd; - sg = qc->sg; + if (is_atapi_taskfile(&qc->tf)) + atapi_pio_sector(qc); + else + ata_pio_sector(qc); +} - if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; +static void ata_pio_error(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; - buf = kmap(sg[qc->cursg].page) + - sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); - qc->cursect++; - qc->cursg_ofs++; + drv_stat = ata_chk_status(ap); + printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", + ap->id, drv_stat); - if (cmd->use_sg) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { - qc->cursg++; - qc->cursg_ofs = 0; - } - - DPRINTK("data %s, drv_stat 0x%X\n", - qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", - status); + ap->pio_task_state = PIO_ST_IDLE; - /* do the actual data transfer */ - /* FIXME: mmio-ize */ - if (qc->tf.flags & ATA_TFLAG_WRITE) - outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); - else - insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); + ata_irq_on(ap); - kunmap(sg[qc->cursg].page); + ata_qc_complete(qc, drv_stat | ATA_ERR); } static void ata_pio_task(void *_data) @@ -2125,7 +2326,7 @@ switch (ap->pio_task_state) { case PIO_ST: - ata_pio_sector(ap); + ata_pio_block(ap); break; case PIO_ST_LAST: @@ -2138,15 +2339,8 @@ break; case PIO_ST_TMOUT: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; - break; - case PIO_ST_ERR: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; + ata_pio_error(ap); break; } @@ -2157,13 +2351,14 @@ if ((ap->pio_task_state != PIO_ST_IDLE) && (ap->pio_task_state != PIO_ST_TMOUT) && - (ap->pio_task_state != PIO_ST_ERR)) + (ap->pio_task_state != PIO_ST_ERR)) { schedule_task(&ap->pio_task); + } } /** - * ata_eng_timeout - Handle timeout of queued command - * @ap: Port on which timed-out command is active + * ata_qc_timeout - Handle timeout of queued command + * @qc: Command that timed out * * Some part of the kernel (currently, only the SCSI layer) * has noticed that the active command on port @ap has not @@ -2177,23 +2372,15 @@ * transaction completed successfully. * * LOCKING: - * Inherited from SCSI layer (none, can sleep) */ -void ata_eng_timeout(struct ata_port *ap) +static void ata_qc_timeout(struct ata_queued_cmd *qc) { - u8 host_stat, drv_stat; - struct ata_queued_cmd *qc; + struct ata_port *ap = qc->ap; + u8 host_stat = 0, drv_stat; DPRINTK("ENTER\n"); - qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { - printk(KERN_ERR "ata%u: BUG: timeout without command\n", - ap->id); - goto out; - } - /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -2203,38 +2390,68 @@ qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { + case ATA_PROT_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + case ATA_PROT_ATAPI_DMA: + host_stat = ata_bmdma_status(ap); - printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n", - ap->id, host_stat); + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); - ata_dma_complete(qc, host_stat); - break; + /* fall through */ - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + default: + ata_altstatus(ap); + drv_stat = ata_chk_status(ap); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); + printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", + ap->id, qc->tf.command, drv_stat, host_stat); + /* complete taskfile transaction */ ata_qc_complete(qc, drv_stat); break; + } - default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + DPRINTK("EXIT\n"); +} + +/** + * ata_eng_timeout - Handle timeout of queued command + * @ap: Port on which timed-out command is active + * + * Some part of the kernel (currently, only the SCSI layer) + * has noticed that the active command on port @ap has not + * completed after a specified length of time. Handle this + * condition by disabling DMA (if necessary) and completing + * transactions, with error if necessary. + * + * This also handles the case of the "lost interrupt", where + * for some reason (possibly hardware bug, possibly driver bug) + * an interrupt was not delivered to the driver, even though the + * transaction completed successfully. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + */ - printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); +void ata_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; - ata_qc_complete(qc, drv_stat); - break; + DPRINTK("ENTER\n"); + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + goto out; } + ata_qc_timeout(qc); + out: DPRINTK("EXIT\n"); } @@ -2289,8 +2506,6 @@ ata_tf_init(ap, &qc->tf, dev->devno); - if (likely((dev->flags & ATA_DFLAG_PIO) == 0)) - qc->flags |= ATA_QCFLAG_DMA; if (dev->flags & ATA_DFLAG_LBA48) qc->tf.flags |= ATA_TFLAG_LBA48; } @@ -2298,6 +2513,11 @@ return qc; } +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +{ + return 0; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -2310,29 +2530,25 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; unsigned int tag, do_clear = 0; + int rc; assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */ assert(qc->flags & ATA_QCFLAG_ACTIVE); - if (likely(qc->flags & ATA_QCFLAG_SG)) + if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); - if (cmd) { - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - if (is_atapi_taskfile(&qc->tf)) - cmd->result = SAM_STAT_CHECK_CONDITION; - else - ata_to_sense_error(qc); - } else { - cmd->result = SAM_STAT_GOOD; - } + /* call completion callback */ + rc = qc->complete_fn(qc, drv_stat); - qc->scsidone(cmd); - } + /* if callback indicates not to complete command (non-zero), + * return immediately + */ + if (rc != 0) + return; - qc->flags &= ~ATA_QCFLAG_ACTIVE; + qc->flags = 0; tag = qc->tag; if (likely(ata_tag_valid(tag))) { if (tag == ap->active_tag) @@ -2341,11 +2557,16 @@ do_clear = 1; } - if (qc->waiting) - complete(qc->waiting); + if (qc->waiting) { + struct completion *waiting = qc->waiting; + qc->waiting = NULL; + complete(waiting); + } if (likely(do_clear)) clear_bit(tag, &ap->qactive); + + VPRINTK("EXIT\n"); } /** @@ -2367,25 +2588,21 @@ int ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; if (qc->flags & ATA_QCFLAG_SG) { - /* set up SG table */ - if (cmd->use_sg) { - if (ata_sg_setup(qc)) - goto err_out; - } else { - if (ata_sg_setup_one(qc)) - goto err_out; - } - - ap->ops->fill_sg(qc); + if (ata_sg_setup(qc)) + goto err_out; + } else if (qc->flags & ATA_QCFLAG_SINGLE) { + if (ata_sg_setup_one(qc)) + goto err_out; } + ap->ops->qc_prep(qc); + qc->ap->active_tag = qc->tag; qc->flags |= ATA_QCFLAG_ACTIVE; - return ata_qc_issue_prot(qc); + return ap->ops->qc_issue(qc); err_out: return -1; @@ -2407,7 +2624,7 @@ * Zero on success, negative on error. */ -static int ata_qc_issue_prot(struct ata_queued_cmd *qc) +int ata_qc_issue_prot(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -2432,6 +2649,12 @@ break; case ATA_PROT_ATAPI: + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + schedule_task(&ap->packet_task); + break; + + case ATA_PROT_ATAPI_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); schedule_task(&ap->packet_task); break; @@ -2443,6 +2666,7 @@ break; default: + WARN_ON(1); return -1; } @@ -2450,19 +2674,19 @@ } /** - * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + u8 dmactl; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ @@ -2475,26 +2699,22 @@ dmactl |= ATA_DMA_WR; writeb(dmactl, mmio + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = readb(mmio + ATA_DMA_STATUS); - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } /** - * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * ata_bmdma_start - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ @@ -2522,11 +2742,11 @@ * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; + u8 dmactl; /* load PRD table addr. */ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); @@ -2538,11 +2758,6 @@ dmactl |= ATA_DMA_WR; outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } @@ -2555,7 +2770,7 @@ * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_start_pio (struct ata_queued_cmd *qc) +static void ata_bmdma_start_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; u8 dmactl; @@ -2566,48 +2781,25 @@ ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } -/** - * ata_dma_complete - Complete an active ATA BMDMA command - * @qc: Command to complete - * @host_stat: BMDMA status register contents - * - * LOCKING: - */ - -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat) +void ata_bmdma_start(struct ata_queued_cmd *qc) { - struct ata_port *ap = qc->ap; - VPRINTK("ENTER\n"); - - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - - /* ack intr, err bits */ - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - mmio + ATA_DMA_STATUS); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* ack intr, err bits */ - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } - - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_start_mmio(qc); + else + ata_bmdma_start_pio(qc); +} - DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n", - ap->id, (u32) host_stat, (u32) ata_chk_status(ap)); +void ata_bmdma_setup(struct ata_queued_cmd *qc) +{ + if (qc->ap->flags & ATA_FLAG_MMIO) + ata_bmdma_setup_mmio(qc); + else + ata_bmdma_setup_pio(qc); +} - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); +void ata_bmdma_irq_clear(struct ata_port *ap) +{ + ata_bmdma_ack_irq(ap); } /** @@ -2630,59 +2822,63 @@ struct ata_queued_cmd *qc) { u8 status, host_stat; - unsigned int handled = 0; switch (qc->tf.protocol) { - /* BMDMA completion */ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + case ATA_PROT_ATAPI: + /* check status of DMA engine */ + host_stat = ata_bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); - if (!(host_stat & ATA_DMA_INTR)) { - ap->stats.idle_irq++; - break; - } + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; - ata_dma_complete(qc, host_stat); - handled = 1; - break; + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); - /* command completion, but no data xfer */ - /* FIXME: a shared interrupt _will_ cause a non-data command - * to be completed prematurely, with an error. - * - * This doesn't matter right now, since we aren't sending - * non-data commands down this pipe except in development - * situations. - */ - case ATA_PROT_ATAPI: + /* fall through */ + + case ATA_PROT_ATAPI_NODATA: case ATA_PROT_NODATA: - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + /* check altstatus */ + status = ata_altstatus(ap); + if (status & ATA_BUSY) + goto idle_irq; + + /* check main status, clearing INTRQ */ + status = ata_chk_status(ap); + if (unlikely(status & ATA_BUSY)) + goto idle_irq; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); + + /* complete taskfile transaction */ ata_qc_complete(qc, status); - handled = 1; break; default: - ap->stats.idle_irq++; + goto idle_irq; + } + + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; #ifdef ATA_IRQ_TRAP - if ((ap->stats.idle_irq % 1000) == 0) { - handled = 1; - ata_irq_ack(ap, 0); /* debug trap */ - printk(KERN_WARNING "ata%d: irq trap\n", ap->id); - } -#endif - break; + if ((ap->stats.idle_irq % 1000) == 0) { + handled = 1; + ata_irq_ack(ap, 0); /* debug trap */ + printk(KERN_WARNING "ata%d: irq trap\n", ap->id); } - - return handled; +#endif + return 0; /* irq not handled */ } /** @@ -2716,7 +2912,7 @@ qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) - handled += ata_host_intr(ap, qc); + handled |= ata_host_intr(ap, qc); } } @@ -2726,62 +2922,6 @@ } /** - * ata_thread_iter - - * @ap: - * - * LOCKING: - * - * RETURNS: - * - */ - -static unsigned long ata_thread_iter(struct ata_port *ap) -{ - long timeout = 0; - - DPRINTK("ata%u: thr_state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - - switch (ap->thr_state) { - case THR_UNKNOWN: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PROBE_START: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PORT_RESET: - ata_port_reset(ap); - break; - - case THR_PROBE_SUCCESS: - up(&ap->probe_sem); - ap->thr_state = THR_IDLE; - break; - - case THR_PROBE_FAILED: - up(&ap->probe_sem); - ap->thr_state = THR_AWAIT_DEATH; - break; - - case THR_AWAIT_DEATH: - case THR_IDLE: - timeout = -1; - break; - - default: - printk(KERN_DEBUG "ata%u: unknown thr state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - break; - } - - DPRINTK("ata%u: new thr_state %s, returning %ld\n", - ap->id, ata_thr_state_name(ap->thr_state), timeout); - return timeout; -} - -/** * atapi_packet_task - Write CDB bytes to hardware * @_data: Port to which ATAPI device is attached. * @@ -2812,21 +2952,20 @@ /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & ATA_DRQ) == 0) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; /* send SCSI cdb */ - /* FIXME: mmio-ize */ DPRINTK("send cdb\n"); - outsl(ap->ioaddr.data_addr, - qc->scsicmd->cmnd, ap->host->max_cmd_len / 4); + assert(ap->cdb_len >= 12); + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ /* non-data commands are also handled via irq */ - else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) { + else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { /* do nothing */ } @@ -2862,23 +3001,6 @@ pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); } -static void ata_probe_task(void *_data) -{ - struct ata_port *ap = _data; - long timeout; - - timeout = ata_thread_iter(ap); - if (timeout < 0) - return; - - if (timeout > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - } - - schedule_task(&ap->probe_task); -} - /** * ata_host_remove - Unregister SCSI host structure with upper layers * @ap: Port to unregister @@ -2930,25 +3052,23 @@ ap->ctl = ATA_DEVCTL_OBS; ap->host_set = host_set; ap->port_no = port_no; + ap->hard_port_no = + ent->legacy_mode ? ent->hard_port_no : port_no; ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; - ap->thr_state = THR_PROBE_START; ap->cbl = ATA_CBL_NONE; - ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; INIT_TQUEUE(&ap->packet_task, atapi_packet_task, ap); INIT_TQUEUE(&ap->pio_task, ata_pio_task, ap); - INIT_TQUEUE(&ap->probe_task, ata_probe_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) ap->device[i].devno = i; - init_MUTEX_LOCKED(&ap->probe_sem); - #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; @@ -3027,28 +3147,35 @@ host_set->irq = ent->irq; host_set->mmio_base = ent->mmio_base; host_set->private_data = ent->private_data; + host_set->ops = ent->port_ops; /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { struct ata_port *ap; + unsigned long xfer_mode_mask; ap = ata_host_add(ent, host_set, i); if (!ap) goto err_out; host_set->ports[i] = ap; + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " "bmdma 0x%lX irq %lu\n", ap->id, ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_udma_string(ent->udma_mask), + ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, ap->ioaddr.bmdma_addr, ent->irq); + ata_chk_status(ap); + host_set->ops->irq_clear(ap); count++; } @@ -3066,16 +3193,22 @@ DPRINTK("probe begin\n"); for (i = 0; i < count; i++) { struct ata_port *ap; + int rc; ap = host_set->ports[i]; DPRINTK("ata%u: probe begin\n", ap->id); - schedule_task(&ap->probe_task); /* start probe */ - - DPRINTK("ata%u: probe-wait begin\n", ap->id); - down(&ap->probe_sem); /* wait for end */ + rc = ata_bus_probe(ap); + DPRINTK("ata%u: probe end\n", ap->id); - DPRINTK("ata%u: probe-wait end\n", ap->id); + if (rc) { + /* FIXME: do something useful here? + * Current libata behavior will + * tear down everything when + * the module is removed + * or the h/w is unplugged. + */ + } } pci_set_drvdata(pdev, host_set); @@ -3176,6 +3309,101 @@ ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } +static struct ata_probe_ent * +ata_probe_ent_alloc(int n, struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent; + int i; + + probe_ent = kmalloc(sizeof(*probe_ent) * n, GFP_KERNEL); + if (!probe_ent) { + printk(KERN_ERR DRV_NAME "(%s): out of memory\n", + pci_name(pdev)); + return NULL; + } + + memset(probe_ent, 0, sizeof(*probe_ent) * n); + + for (i = 0; i < n; i++) { + INIT_LIST_HEAD(&probe_ent[i].node); + probe_ent[i].pdev = pdev; + + probe_ent[i].sht = port[i]->sht; + probe_ent[i].host_flags = port[i]->host_flags; + probe_ent[i].pio_mask = port[i]->pio_mask; + probe_ent[i].mwdma_mask = port[i]->mwdma_mask; + probe_ent[i].udma_mask = port[i]->udma_mask; + probe_ent[i].port_ops = port[i]->port_ops; + + } + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(1, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + + ata_std_ports(&probe_ent->port[0]); + ata_std_ports(&probe_ent->port[1]); + + return probe_ent; +} + +struct ata_probe_ent * +ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port) +{ + struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(2, pdev, port); + if (!probe_ent) + return NULL; + + probe_ent[0].n_ports = 1; + probe_ent[0].irq = 14; + + probe_ent[0].hard_port_no = 0; + probe_ent[0].legacy_mode = 1; + + probe_ent[1].n_ports = 1; + probe_ent[1].irq = 15; + + probe_ent[1].hard_port_no = 1; + probe_ent[1].legacy_mode = 1; + + probe_ent[0].port[0].cmd_addr = 0x1f0; + probe_ent[0].port[0].altstatus_addr = + probe_ent[0].port[0].ctl_addr = 0x3f6; + probe_ent[0].port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent[1].port[0].cmd_addr = 0x170; + probe_ent[1].port[0].altstatus_addr = + probe_ent[1].port[0].ctl_addr = 0x376; + probe_ent[1].port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; + + ata_std_ports(&probe_ent[0].port[0]); + ata_std_ports(&probe_ent[1].port[0]); + + return probe_ent; +} + /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -3193,20 +3421,20 @@ unsigned int n_ports) { struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; - struct ata_port_info *port0, *port1; + struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; int rc; DPRINTK("ENTER\n"); - port0 = port_info[0]; + port[0] = port_info[0]; if (n_ports > 1) - port1 = port_info[1]; + port[1] = port_info[1]; else - port1 = port0; + port[1] = port[0]; - if ((port0->host_flags & ATA_FLAG_NO_LEGACY) == 0) { + if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0) { /* TODO: support transitioning to native mode? */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); @@ -3250,87 +3478,32 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (legacy_mode) { + probe_ent = ata_pci_init_legacy_mode(pdev, port); + if (probe_ent) + probe_ent2 = &probe_ent[1]; + } else + probe_ent = ata_pci_init_native_mode(pdev, port); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - if (legacy_mode) { - probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (!probe_ent2) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - memset(probe_ent2, 0, sizeof(*probe_ent)); - probe_ent2->pdev = pdev; - INIT_LIST_HEAD(&probe_ent2->node); - } - - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - probe_ent->sht = port0->sht; - probe_ent->host_flags = port0->host_flags; - probe_ent->pio_mask = port0->pio_mask; - probe_ent->udma_mask = port0->udma_mask; - probe_ent->port_ops = port0->port_ops; - - if (legacy_mode) { - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->n_ports = 1; - probe_ent->irq = 14; - ata_std_ports(&probe_ent->port[0]); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - ata_std_ports(&probe_ent2->port[0]); - - probe_ent2->sht = port1->sht; - probe_ent2->host_flags = port1->host_flags; - probe_ent2->pio_mask = port1->pio_mask; - probe_ent2->udma_mask = port1->udma_mask; - probe_ent2->port_ops = port1->port_ops; - } else { - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - } - pci_set_master(pdev); spin_lock(&ata_module_lock); if (legacy_mode) { + int free = 0; if (legacy_mode & (1 << 0)) list_add_tail(&probe_ent->node, &ata_probe_list); else - kfree(probe_ent); + free++; if (legacy_mode & (1 << 1)) list_add_tail(&probe_ent2->node, &ata_probe_list); else - kfree(probe_ent2); + free++; + if (free > 1) + kfree(probe_ent); } else { list_add_tail(&probe_ent->node, &ata_probe_list); } @@ -3338,8 +3511,6 @@ return 0; -err_out_free_ent: - kfree(probe_ent); err_out_regions: if (legacy_mode & (1 << 0)) release_region(0x1f0, 8); @@ -3383,10 +3554,10 @@ /* FIXME: handle 'rc' failure? */ free_irq(host_set->irq, host_set); + if (host_set->ops->host_stop) + host_set->ops->host_stop(host_set); if (host_set->mmio_base) iounmap(host_set->mmio_base); - if (host_set->ports[0]->ops->host_stop) - host_set->ports[0]->ops->host_stop(host_set); pci_release_regions(pdev); @@ -3492,36 +3663,42 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); +EXPORT_SYMBOL_GPL(ata_sg_init); +EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); +EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_eng_timeout); -EXPORT_SYMBOL_GPL(ata_tf_load_pio); -EXPORT_SYMBOL_GPL(ata_tf_load_mmio); -EXPORT_SYMBOL_GPL(ata_tf_read_pio); -EXPORT_SYMBOL_GPL(ata_tf_read_mmio); +EXPORT_SYMBOL_GPL(ata_tf_load); +EXPORT_SYMBOL_GPL(ata_tf_read); +EXPORT_SYMBOL_GPL(ata_noop_dev_select); +EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); -EXPORT_SYMBOL_GPL(ata_check_status_pio); -EXPORT_SYMBOL_GPL(ata_check_status_mmio); -EXPORT_SYMBOL_GPL(ata_exec_command_pio); -EXPORT_SYMBOL_GPL(ata_exec_command_mmio); +EXPORT_SYMBOL_GPL(ata_pci_init_legacy_mode); +EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); +EXPORT_SYMBOL_GPL(ata_check_status); +EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_fill_sg); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_pio); -EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio); -EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio); +EXPORT_SYMBOL_GPL(ata_qc_prep); +EXPORT_SYMBOL_GPL(ata_bmdma_setup); +EXPORT_SYMBOL_GPL(ata_bmdma_start); +EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); +EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); +EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_detect); EXPORT_SYMBOL_GPL(ata_add_to_probe_list); +EXPORT_SYMBOL_GPL(libata_msleep); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_id_string); diff -urN linux-2.4.27/drivers/scsi/libata-scsi.c linux-2.4.28/drivers/scsi/libata-scsi.c --- linux-2.4.27/drivers/scsi/libata-scsi.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/libata-scsi.c 2004-11-17 03:54:21.677401142 -0800 @@ -31,6 +31,7 @@ #include #include "sd.h" #include +#include #include "libata.h" @@ -38,13 +39,15 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @disk: SCSI device for which BIOS geometry is to be determined - * @dev: device major/minor - * @ip: location to which geometry will be output + * @bdev: device major/minor + * @geom: location to which geometry will be output * * Generic bios head/sector/cylinder calculator * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) @@ -58,16 +61,53 @@ * Zero. */ int ata_std_bios_param(Disk * disk, /* SCSI disk */ - kdev_t dev, /* Device major, minor */ - int *ip /* Heads, sectors, cylinders in that order */ ) + kdev_t bdev, /* Device major, minor */ + int *geom /* Heads, sectors, cylinders in that order */ ) { - ip[0] = 255; - ip[1] = 63; - ip[2] = disk->capacity / (ip[0] * ip[1]); + geom[0] = 255; + geom[1] = 63; + geom[2] = disk->capacity / (geom[0] * geom[1]); return 0; } +int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) +{ + struct ata_port *ap; + struct ata_device *dev; + int val = -EINVAL, rc = -EINVAL; + + ap = (struct ata_port *) &scsidev->host->hostdata[0]; + if (!ap) + goto out; + + dev = ata_scsi_find_dev(ap, scsidev); + if (!dev) { + rc = -ENODEV; + goto out; + } + + switch (cmd) { + case ATA_IOC_GET_IO32: + val = 0; + if (copy_to_user(arg, &val, 1)) + return -EFAULT; + return 0; + + case ATA_IOC_SET_IO32: + val = (unsigned long) arg; + if (val != 0) + return -EINVAL; + return 0; + + default: + rc = -EOPNOTSUPP; + break; + } + +out: + return rc; +} /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference @@ -121,34 +161,158 @@ * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out * - * Converts an ATA error into a SCSI error. - * - * Right now, this routine is laughably primitive. We - * don't even examine what ATA told us, we just look at - * the command data direction, and return a fatal SCSI - * sense error based on that. + * Converts an ATA error into a SCSI error. While we are at it + * we decode and dump the ATA error for the user so that they + * have some idea what really happened at the non make-believe + * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_to_sense_error(struct ata_queued_cmd *qc) +void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 err = 0; + unsigned char *sb = cmd->sense_buffer; + /* Based on the 3ware driver translation table */ + static unsigned char sense_table[][4] = { + /* BBD|ECC|ID|MAR */ + {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* BBD|ECC|ID */ + {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* ECC|MC|MARK */ + {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error + /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ + {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error + /* MC|ID|ABRT|TRK0|MARK */ + {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready + /* MCR|MARK */ + {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready + /* Bad address mark */ + {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field + /* TRK0 */ + {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error + /* Abort & !ICRC */ + {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command + /* Media change request */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline + /* SRV */ + {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found + /* Media change */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline + /* ECC */ + {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error + /* BBD - block marked bad */ + {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + static unsigned char stat_table[][4] = { + /* Must be first because BUSY means no other bits valid */ + {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now + {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault + {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now + {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = MEDIUM_ERROR; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - + + /* + * Is this an error we can process/parse + */ + + if(drv_stat & ATA_ERR) + /* Read the err bits */ + err = ata_chk_err(qc->ap); + + /* Display the ATA level error info */ + + printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); + if(drv_stat & 0x80) + { + printk("Busy "); + err = 0; /* Data is not valid in this case */ + } + else { + if(drv_stat & 0x40) printk("DriveReady "); + if(drv_stat & 0x20) printk("DeviceFault "); + if(drv_stat & 0x10) printk("SeekComplete "); + if(drv_stat & 0x08) printk("DataRequest "); + if(drv_stat & 0x04) printk("CorrectedError "); + if(drv_stat & 0x02) printk("Index "); + if(drv_stat & 0x01) printk("Error "); + } + printk("}\n"); + + if(err) + { + printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); + if(err & 0x04) printk("DriveStatusError "); + if(err & 0x80) + { + if(err & 0x04) + printk("BadCRC "); + else + printk("Sector "); + } + if(err & 0x40) printk("UncorrectableError "); + if(err & 0x10) printk("SectorIdNotFound "); + if(err & 0x02) printk("TrackZeroNotFound "); + if(err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + + /* Should we dump sector info here too ?? */ + } + + + /* Look for err */ + while(sense_table[i][0] != 0xFF) + { + /* Look for best matches first */ + if((sense_table[i][0] & err) == sense_table[i][0]) + { + sb[0] = 0x70; + sb[2] = sense_table[i][1]; + sb[7] = 0x0a; + sb[12] = sense_table[i][2]; + sb[13] = sense_table[i][3]; + return; + } + i++; + } + /* No immediate match */ + if(err) + printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); + + /* Fall back to interpreting status bits */ + while(stat_table[i][0] != 0xFF) + { + if(stat_table[i][0] & drv_stat) + { + sb[0] = 0x70; + sb[2] = stat_table[i][1]; + sb[7] = 0x0a; + sb[12] = stat_table[i][2]; + sb[13] = stat_table[i][3]; + return; + } + i++; + } + /* No error ?? */ + printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ + + sb[0] = 0x70; + sb[2] = MEDIUM_ERROR; + sb[7] = 0x0A; if (cmd->sc_data_direction == SCSI_DATA_READ) { - cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ - cmd->sense_buffer[13] = 0x04; + sb[12] = 0x11; /* "unrecovered read error" */ + sb[13] = 0x04; } else { - cmd->sense_buffer[12] = 0x0C; /* "write error - */ - cmd->sense_buffer[13] = 0x02; /* auto-reallocation failed" */ + sb[12] = 0x0C; /* "write error - */ + sb[13] = 0x02; /* auto-reallocation failed" */ } } @@ -174,11 +338,137 @@ ap = (struct ata_port *) &host->hostdata[0]; ap->ops->eng_timeout(ap); + host->in_recovery = 0; + + /* TODO: this is per-command; when queueing is supported + * this code will either change or move to a more + * appropriate place + */ + host->host_failed--; + DPRINTK("EXIT\n"); return 0; } /** + * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate (ignored) + * + * Sets up an ATA taskfile to issue FLUSH CACHE or + * FLUSH CACHE EXT. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + + if ((tf->flags & ATA_TFLAG_LBA48) && + (ata_id_has_flush_ext(qc->dev))) + tf->command = ATA_CMD_FLUSH_EXT; + else + tf->command = ATA_CMD_FLUSH; + + return 0; +} + +/** + * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Converts SCSI VERIFY command to an ATA READ VERIFY command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 dev_sectors = qc->dev->n_sectors; + u64 sect = 0; + u32 n_sect = 0; + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->device |= ATA_LBA; + + if (scsicmd[0] == VERIFY) { + sect |= ((u64)scsicmd[2]) << 24; + sect |= ((u64)scsicmd[3]) << 16; + sect |= ((u64)scsicmd[4]) << 8; + sect |= ((u64)scsicmd[5]); + + n_sect |= ((u32)scsicmd[7]) << 8; + n_sect |= ((u32)scsicmd[8]); + } + + else if (scsicmd[0] == VERIFY_16) { + sect |= ((u64)scsicmd[2]) << 56; + sect |= ((u64)scsicmd[3]) << 48; + sect |= ((u64)scsicmd[4]) << 40; + sect |= ((u64)scsicmd[5]) << 32; + sect |= ((u64)scsicmd[6]) << 24; + sect |= ((u64)scsicmd[7]) << 16; + sect |= ((u64)scsicmd[8]) << 8; + sect |= ((u64)scsicmd[9]); + + n_sect |= ((u32)scsicmd[10]) << 24; + n_sect |= ((u32)scsicmd[11]) << 16; + n_sect |= ((u32)scsicmd[12]) << 8; + n_sect |= ((u32)scsicmd[13]); + } + + else + return 1; + + if (!n_sect) + return 1; + if (sect >= dev_sectors) + return 1; + if ((sect + n_sect) > dev_sectors) + return 1; + if (lba48) { + if (n_sect > (64 * 1024)) + return 1; + } else { + if (n_sect > 256) + return 1; + } + + if (lba48) { + tf->hob_nsect = (n_sect >> 8) & 0xff; + + tf->hob_lbah = (sect >> 40) & 0xff; + tf->hob_lbam = (sect >> 32) & 0xff; + tf->hob_lbal = (sect >> 24) & 0xff; + } else + tf->device |= (sect >> 24) & 0xf; + + tf->nsect = n_sect & 0xff; + + tf->hob_lbah = (sect >> 16) & 0xff; + tf->hob_lbam = (sect >> 8) & 0xff; + tf->hob_lbal = sect & 0xff; + + return 0; +} + +/** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate @@ -204,10 +494,6 @@ unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->hob_nsect = 0; - tf->hob_lbal = 0; - tf->hob_lbam = 0; - tf->hob_lbah = 0; tf->protocol = qc->dev->xfer_protocol; tf->device |= ATA_LBA; @@ -295,6 +581,20 @@ return 1; } +static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else + cmd->result = SAM_STAT_GOOD; + + qc->scsidone(cmd); + + return 0; +} + /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @ap: ATA port to which the command is addressed @@ -328,6 +628,7 @@ if (!qc) return; + /* data is present; dma-map it */ if (cmd->sc_data_direction == SCSI_DATA_READ || cmd->sc_data_direction == SCSI_DATA_WRITE) { if (unlikely(cmd->request_bufflen < 1)) { @@ -336,9 +637,17 @@ goto err_out; } - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ + if (cmd->use_sg) + ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); + else + ata_sg_init_one(qc, cmd->request_buffer, + cmd->request_bufflen); + + qc->pci_dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); } + qc->complete_fn = ata_scsi_qc_complete; + if (xlat_func(qc, scsicmd)) goto err_out; @@ -384,7 +693,6 @@ buflen = cmd->request_bufflen; } - memset(buf, 0, buflen); *buf_out = buf; return buflen; } @@ -433,6 +741,7 @@ struct scsi_cmnd *cmd = args->cmd; buflen = ata_scsi_rbuf_get(cmd, &rbuf); + memset(rbuf, 0, buflen); rc = actor(args, rbuf, buflen); ata_scsi_rbuf_put(cmd); @@ -467,7 +776,7 @@ 0, 0x5, /* claim SPC-3 version compatibility */ 2, - 96 - 4 + 95 - 4 }; /* set scsi removeable (RMB) bit per ata bit */ @@ -478,7 +787,7 @@ memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > 36) { + if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16); ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4); @@ -897,6 +1206,31 @@ done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + cmd->result = SAM_STAT_CHECK_CONDITION; + else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized @@ -912,6 +1246,13 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); + + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -921,19 +1262,18 @@ qc->tf.command = ATA_CMD_PACKET; - /* no data - interrupt-driven */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) - qc->tf.protocol = ATA_PROT_ATAPI; - - /* PIO data xfer - polling */ - else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { - ata_qc_set_polling(qc); - qc->tf.protocol = ATA_PROT_ATAPI; + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = (8 * 1024) & 0xff; qc->tf.lbah = (8 * 1024) >> 8; + } - /* DMA data xfer - interrupt-driven */ - } else { + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; @@ -964,19 +1304,19 @@ * Associated ATA device, or %NULL if not found. */ -static inline struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) { struct ata_device *dev; /* skip commands not addressed to targets we simulate */ - if (likely(cmd->target < ATA_MAX_DEVICES)) - dev = &ap->device[cmd->target]; + if (likely(scsidev->id < ATA_MAX_DEVICES)) + dev = &ap->device[scsidev->id]; else return NULL; - if (unlikely((cmd->channel != 0) || - (cmd->lun != 0))) + if (unlikely((scsidev->channel != 0) || + (scsidev->lun != 0))) return NULL; if (unlikely(!ata_dev_present(dev))) @@ -992,6 +1332,7 @@ /** * ata_get_xlat_func - check if SCSI to ATA translation is possible + * @dev: ATA device * @cmd: SCSI command opcode to consider * * Look up the SCSI command given, and determine whether the @@ -1001,7 +1342,7 @@ * Pointer to translation function if possible, %NULL if not. */ -static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) +static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) { switch (cmd) { case READ_6: @@ -1012,6 +1353,15 @@ case WRITE_10: case WRITE_16: return ata_scsi_rw_xlat; + + case SYNCHRONIZE_CACHE: + if (ata_try_flush_cache(dev)) + return ata_scsi_flush_xlat; + break; + + case VERIFY: + case VERIFY_16: + return ata_scsi_verify_xlat; } return NULL; @@ -1029,11 +1379,12 @@ struct scsi_cmnd *cmd) { #ifdef ATA_DEBUG + struct scsi_device *scsidev = cmd->device; u8 *scsicmd = cmd->cmnd; DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ap->id, - cmd->channel, cmd->target, cmd->lun, + scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], scsicmd[8]); @@ -1063,17 +1414,18 @@ { struct ata_port *ap; struct ata_device *dev; + struct scsi_device *scsidev = cmd->device; /* Note: spin_lock_irqsave is held by caller... */ spin_unlock(&io_request_lock); - ap = (struct ata_port *) &cmd->host->hostdata[0]; + ap = (struct ata_port *) &scsidev->host->hostdata[0]; spin_lock(&ap->host_set->lock); ata_scsi_dump_cdb(ap, cmd); - dev = ata_scsi_find_dev(ap, cmd); + dev = ata_scsi_find_dev(ap, scsidev); if (unlikely(!dev)) { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -1081,7 +1433,8 @@ } if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]); + ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, + cmd->cmnd[0]); if (xlat_func) ata_scsi_translate(ap, dev, cmd, done, xlat_func); @@ -1124,7 +1477,7 @@ switch(scsicmd[0]) { /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: /* FIXME: temporary */ + case SYNCHRONIZE_CACHE: case REZERO_UNIT: case SEEK_6: case SEEK_10: diff -urN linux-2.4.27/drivers/scsi/libata.h linux-2.4.28/drivers/scsi/libata.h --- linux-2.4.27/drivers/scsi/libata.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/libata.h 2004-11-17 03:54:21.677401142 -0800 @@ -35,7 +35,6 @@ void (*done)(struct scsi_cmnd *); }; - /* libata-core.c */ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); @@ -43,10 +42,11 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc); +extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff -urN linux-2.4.27/drivers/scsi/megaraid.c linux-2.4.28/drivers/scsi/megaraid.c --- linux-2.4.27/drivers/scsi/megaraid.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/scsi/megaraid.c 2004-11-17 03:54:21.730403321 -0800 @@ -3471,6 +3471,24 @@ return count; } +static inline void mega_freeSgList (mega_host_config * megaCfg) +{ + int i; + + for (i = 0; i < megaCfg->max_cmds; i++) { + if (megaCfg->scbList[i].sgList) + pci_free_consistent (megaCfg->dev, + sizeof (mega_64sglist) * + MAX_SGLIST, + megaCfg->scbList[i].sgList, + megaCfg->scbList[i]. + dma_sghandle64); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */ + kfree (megaCfg->scbList[i].sgList); /* free sgList */ +#endif + } +} + /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ @@ -3880,24 +3898,6 @@ return; } -static inline void mega_freeSgList (mega_host_config * megaCfg) -{ - int i; - - for (i = 0; i < megaCfg->max_cmds; i++) { - if (megaCfg->scbList[i].sgList) - pci_free_consistent (megaCfg->dev, - sizeof (mega_64sglist) * - MAX_SGLIST, - megaCfg->scbList[i].sgList, - megaCfg->scbList[i]. - dma_sghandle64); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */ - kfree (megaCfg->scbList[i].sgList); /* free sgList */ -#endif - } -} - /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ diff -urN linux-2.4.27/drivers/scsi/megaraid2.c linux-2.4.28/drivers/scsi/megaraid2.c --- linux-2.4.27/drivers/scsi/megaraid2.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/megaraid2.c 2004-11-17 03:54:21.734403486 -0800 @@ -936,6 +936,19 @@ } +/** + * mega_runpendq() + * @adapter - pointer to our soft state + * + * Runs through the list of pending requests. + */ +static inline void +mega_runpendq(adapter_t *adapter) +{ + if(!list_empty(&adapter->pending_list)) + __mega_runpendq(adapter); +} + /* * megaraid_queue() * @scmd - Issue this scsi command @@ -986,6 +999,98 @@ /** + * mega_allocate_scb() + * @adapter - pointer to our soft state + * @cmd - scsi command from the mid-layer + * + * Allocate a SCB structure. This is the central structure for controller + * commands. + */ +static inline scb_t * +mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd) +{ + struct list_head *head = &adapter->free_list; + scb_t *scb; + + /* Unlink command from Free List */ + if( !list_empty(head) ) { + + scb = list_entry(head->next, scb_t, list); + + list_del_init(head->next); + + scb->state = SCB_ACTIVE; + scb->cmd = cmd; + scb->dma_type = MEGA_DMA_TYPE_NONE; + + return scb; + } + + return NULL; +} + + +/** + * mega_get_ldrv_num() + * @adapter - pointer to our soft state + * @cmd - scsi mid layer command + * @channel - channel on the controller + * + * Calculate the logical drive number based on the information in scsi command + * and the channel number. + */ +static inline int +mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel) +{ + int tgt; + int ldrv_num; + + tgt = cmd->target; + + if ( tgt > adapter->this_id ) + tgt--; /* we do not get inquires for initiator id */ + + ldrv_num = (channel * 15) + tgt; + + + /* + * If we have a logical drive with boot enabled, project it first + */ + if( adapter->boot_ldrv_enabled ) { + if( ldrv_num == 0 ) { + ldrv_num = adapter->boot_ldrv; + } + else { + if( ldrv_num <= adapter->boot_ldrv ) { + ldrv_num--; + } + } + } + + /* + * If "delete logical drive" feature is enabled on this controller. + * Do only if at least one delete logical drive operation was done. + * + * Also, after logical drive deletion, instead of logical drive number, + * the value returned should be 0x80+logical drive id. + * + * These is valid only for IO commands. + */ + + if (adapter->support_random_del && adapter->read_ldidmap ) + switch (cmd->cmnd[0]) { + case READ_6: /* fall through */ + case WRITE_6: /* fall through */ + case READ_10: /* fall through */ + case WRITE_10: + ldrv_num += 0x80; + } + + return ldrv_num; +} + + +/** * mega_build_cmd() * @adapter - pointer to our soft state * @cmd - Prepare using this scsi command @@ -1566,51 +1671,6 @@ } -/** - * mega_allocate_scb() - * @adapter - pointer to our soft state - * @cmd - scsi command from the mid-layer - * - * Allocate a SCB structure. This is the central structure for controller - * commands. - */ -static inline scb_t * -mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd) -{ - struct list_head *head = &adapter->free_list; - scb_t *scb; - - /* Unlink command from Free List */ - if( !list_empty(head) ) { - - scb = list_entry(head->next, scb_t, list); - - list_del_init(head->next); - - scb->state = SCB_ACTIVE; - scb->cmd = cmd; - scb->dma_type = MEGA_DMA_TYPE_NONE; - - return scb; - } - - return NULL; -} - - -/** - * mega_runpendq() - * @adapter - pointer to our soft state - * - * Runs through the list of pending requests. - */ -static inline void -mega_runpendq(adapter_t *adapter) -{ - if(!list_empty(&adapter->pending_list)) - __mega_runpendq(adapter); -} - static void __mega_runpendq(adapter_t *adapter) { @@ -1642,7 +1702,7 @@ * busy. We also take the scb from the pending list if the mailbox is * available. */ -static inline int +static int issue_scb(adapter_t *adapter, scb_t *scb) { volatile mbox64_t *mbox64 = adapter->mbox64; @@ -1705,6 +1765,17 @@ } +/* + * Wait until the controller's mailbox is available + */ +static inline int +mega_busywait_mbox (adapter_t *adapter) +{ + if (adapter->mbox->busy) + return __mega_busywait_mbox(adapter); + return 0; +} + /** * issue_scb_block() * @adapter - pointer to our soft state @@ -1807,38 +1878,6 @@ /** - * megaraid_isr_iomapped() - * @irq - irq - * @devp - pointer to our soft state - * @regs - unused - * - * Interrupt service routine for io-mapped controllers. - * Find out if our device is interrupting. If yes, acknowledge the interrupt - * and service the completed commands. - */ -static void -megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs) -{ - adapter_t *adapter = devp; - unsigned long flags; - - - spin_lock_irqsave(adapter->host_lock, flags); - - megaraid_iombox_ack_sequence(adapter); - - /* Loop through any pending requests */ - if( atomic_read(&adapter->quiescent ) == 0) { - mega_runpendq(adapter); - } - - spin_unlock_irqrestore(adapter->host_lock, flags); - - return; -} - - -/** * megaraid_iombox_ack_sequence - interrupt ack sequence for IO mapped HBAs * @adapter - controller's soft state * @@ -1901,38 +1940,6 @@ /** - * megaraid_isr_memmapped() - * @irq - irq - * @devp - pointer to our soft state - * @regs - unused - * - * Interrupt service routine for memory-mapped controllers. - * Find out if our device is interrupting. If yes, acknowledge the interrupt - * and service the completed commands. - */ -static void -megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs) -{ - adapter_t *adapter = devp; - unsigned long flags; - - - spin_lock_irqsave(adapter->host_lock, flags); - - megaraid_memmbox_ack_sequence(adapter); - - /* Loop through any pending requests */ - if(atomic_read(&adapter->quiescent) == 0) { - mega_runpendq(adapter); - } - - spin_unlock_irqrestore(adapter->host_lock, flags); - - return; -} - - -/** * megaraid_memmbox_ack_sequence - interrupt ack sequence for memory mapped HBAs * @adapter - controller's soft state * @@ -2000,6 +2007,70 @@ /** + * megaraid_isr_iomapped() + * @irq - irq + * @devp - pointer to our soft state + * @regs - unused + * + * Interrupt service routine for io-mapped controllers. + * Find out if our device is interrupting. If yes, acknowledge the interrupt + * and service the completed commands. + */ +static void +megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs) +{ + adapter_t *adapter = devp; + unsigned long flags; + + + spin_lock_irqsave(adapter->host_lock, flags); + + megaraid_iombox_ack_sequence(adapter); + + /* Loop through any pending requests */ + if( atomic_read(&adapter->quiescent ) == 0) { + mega_runpendq(adapter); + } + + spin_unlock_irqrestore(adapter->host_lock, flags); + + return; +} + + +/** + * megaraid_isr_memmapped() + * @irq - irq + * @devp - pointer to our soft state + * @regs - unused + * + * Interrupt service routine for memory-mapped controllers. + * Find out if our device is interrupting. If yes, acknowledge the interrupt + * and service the completed commands. + */ +static void +megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs) +{ + adapter_t *adapter = devp; + unsigned long flags; + + + spin_lock_irqsave(adapter->host_lock, flags); + + megaraid_memmbox_ack_sequence(adapter); + + /* Loop through any pending requests */ + if(atomic_read(&adapter->quiescent) == 0) { + mega_runpendq(adapter); + } + + spin_unlock_irqrestore(adapter->host_lock, flags); + + return; +} + + +/** * mega_cmd_done() * @adapter - pointer to our soft state * @completed - array of ids of completed commands @@ -2008,7 +2079,7 @@ * * Complete the comamnds and call the scsi mid-layer callback hooks. */ -static inline void +static void mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) { mega_ext_passthru *epthru = NULL; @@ -2311,17 +2382,6 @@ } -/* - * Wait until the controller's mailbox is available - */ -static inline int -mega_busywait_mbox (adapter_t *adapter) -{ - if (adapter->mbox->busy) - return __mega_busywait_mbox(adapter); - return 0; -} - static int __mega_busywait_mbox (adapter_t *adapter) { @@ -2476,6 +2536,44 @@ } +static inline void +mega_free_sgl(adapter_t *adapter) +{ + scb_t *scb; + int i; + + for(i = 0; i < adapter->max_cmds; i++) { + + scb = &adapter->scb_list[i]; + + if( scb->sgl64 ) { + pci_free_consistent(adapter->dev, + sizeof(mega_sgl64) * adapter->sglen, + scb->sgl64, + scb->sgl_dma_addr); + + scb->sgl64 = NULL; + } + + if( scb->pthru ) { + pci_free_consistent(adapter->dev, sizeof(mega_passthru), + scb->pthru, scb->pthru_dma_addr); + + scb->pthru = NULL; + } + + if( scb->epthru ) { + pci_free_consistent(adapter->dev, + sizeof(mega_ext_passthru), + scb->epthru, scb->epthru_dma_addr); + + scb->epthru = NULL; + } + + } +} + + /* * Release the controller's resources */ @@ -2605,44 +2703,6 @@ return 0; } -static inline void -mega_free_sgl(adapter_t *adapter) -{ - scb_t *scb; - int i; - - for(i = 0; i < adapter->max_cmds; i++) { - - scb = &adapter->scb_list[i]; - - if( scb->sgl64 ) { - pci_free_consistent(adapter->dev, - sizeof(mega_sgl64) * adapter->sglen, - scb->sgl64, - scb->sgl_dma_addr); - - scb->sgl64 = NULL; - } - - if( scb->pthru ) { - pci_free_consistent(adapter->dev, sizeof(mega_passthru), - scb->pthru, scb->pthru_dma_addr); - - scb->pthru = NULL; - } - - if( scb->epthru ) { - pci_free_consistent(adapter->dev, - sizeof(mega_ext_passthru), - scb->epthru, scb->epthru_dma_addr); - - scb->epthru = NULL; - } - - } -} - - /* * Get information about the card/driver */ @@ -2860,6 +2920,27 @@ } +/** + * mega_allocate_inquiry() + * @dma_handle - handle returned for dma address + * @pdev - handle to pci device + * + * allocates memory for inquiry structure + */ +static inline caddr_t +mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) +{ + return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle); +} + + +static inline void +mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) +{ + pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle); +} + + #ifdef CONFIG_PROC_FS /* Following code handles /proc fs */ @@ -5069,66 +5150,6 @@ /** - * mega_get_ldrv_num() - * @adapter - pointer to our soft state - * @cmd - scsi mid layer command - * @channel - channel on the controller - * - * Calculate the logical drive number based on the information in scsi command - * and the channel number. - */ -static inline int -mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel) -{ - int tgt; - int ldrv_num; - - tgt = cmd->target; - - if ( tgt > adapter->this_id ) - tgt--; /* we do not get inquires for initiator id */ - - ldrv_num = (channel * 15) + tgt; - - - /* - * If we have a logical drive with boot enabled, project it first - */ - if( adapter->boot_ldrv_enabled ) { - if( ldrv_num == 0 ) { - ldrv_num = adapter->boot_ldrv; - } - else { - if( ldrv_num <= adapter->boot_ldrv ) { - ldrv_num--; - } - } - } - - /* - * If "delete logical drive" feature is enabled on this controller. - * Do only if at least one delete logical drive operation was done. - * - * Also, after logical drive deletion, instead of logical drive number, - * the value returned should be 0x80+logical drive id. - * - * These is valid only for IO commands. - */ - - if (adapter->support_random_del && adapter->read_ldidmap ) - switch (cmd->cmnd[0]) { - case READ_6: /* fall through */ - case WRITE_6: /* fall through */ - case READ_10: /* fall through */ - case WRITE_10: - ldrv_num += 0x80; - } - - return ldrv_num; -} - - -/** * mega_reorder_hosts() * * Hack: reorder the scsi hosts in mid-layer so that the controller with the @@ -5342,27 +5363,6 @@ } -/** - * mega_allocate_inquiry() - * @dma_handle - handle returned for dma address - * @pdev - handle to pci device - * - * allocates memory for inquiry structure - */ -static inline caddr_t -mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) -{ - return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle); -} - - -static inline void -mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) -{ - pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle); -} - - /** mega_internal_dev_inquiry() * @adapter - pointer to our soft state * @ch - channel for this device diff -urN linux-2.4.27/drivers/scsi/megaraid2.h linux-2.4.28/drivers/scsi/megaraid2.h --- linux-2.4.27/drivers/scsi/megaraid2.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/megaraid2.h 2004-11-17 03:54:21.735403527 -0800 @@ -1091,14 +1091,12 @@ static int megaraid_detect(Scsi_Host_Template *); static void mega_find_card(Scsi_Host_Template *, u16, u16); static int mega_query_adapter(adapter_t *); -static inline int issue_scb(adapter_t *, scb_t *); +static int issue_scb(adapter_t *, scb_t *); static int mega_setup_mailbox(adapter_t *); static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *); -static inline scb_t *mega_allocate_scb(adapter_t *, Scsi_Cmnd *); static void __mega_runpendq(adapter_t *); -static inline void mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); static void megaraid_isr_memmapped(int, void *, struct pt_regs *); @@ -1115,9 +1113,8 @@ static int mega_build_sglist (adapter_t *adapter, scb_t *scb, u32 *buffer, u32 *length); -static inline int mega_busywait_mbox (adapter_t *); static int __mega_busywait_mbox (adapter_t *); -static inline void mega_cmd_done(adapter_t *, u8 [], int, int); +static void mega_cmd_done(adapter_t *, u8 [], int, int); static inline void mega_free_sgl (adapter_t *adapter); static void mega_8_to_40ld (mraid_inquiry *inquiry, mega_inquiry3 *enquiry3, mega_product_info *); @@ -1167,8 +1164,6 @@ static int mega_adapinq(adapter_t *, dma_addr_t); static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t); -static inline caddr_t mega_allocate_inquiry(dma_addr_t *, struct pci_dev *); -static inline void mega_free_inquiry(caddr_t, dma_addr_t, struct pci_dev *); static int mega_print_inquiry(char *, char *); #endif @@ -1179,7 +1174,6 @@ scb_t *, Scsi_Cmnd *, int, int); static void mega_enum_raid_scsi(adapter_t *); static void mega_get_boot_drv(adapter_t *); -static inline int mega_get_ldrv_num(adapter_t *, Scsi_Cmnd *, int); static int mega_support_random_del(adapter_t *); static int mega_del_logdrv(adapter_t *, int); static int mega_do_del_logdrv(adapter_t *, int); diff -urN linux-2.4.27/drivers/scsi/nsp32.c linux-2.4.28/drivers/scsi/nsp32.c --- linux-2.4.27/drivers/scsi/nsp32.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/scsi/nsp32.c 2004-11-17 03:54:21.738403650 -0800 @@ -3365,6 +3365,48 @@ return val; } +static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) +{ + unsigned int base = data->BaseAddress; + int tmp; + + tmp = nsp32_index_read1(base, SERIAL_ROM_CTL); + + if (val == 0) { + tmp &= ~bit; + } else { + tmp |= bit; + } + + nsp32_index_write1(base, SERIAL_ROM_CTL, tmp); + + udelay(10); +} + +static inline int nsp32_prom_get(nsp32_hw_data *data, int bit) +{ + unsigned int base = data->BaseAddress; + int tmp, ret; + + if (bit != SROM_DATA) { + nsp32_msg(KERN_ERR, "return value is not appropriate"); + return 0; + } + + + tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit; + + if (tmp == 0) { + ret = 0; + } else { + ret = 1; + } + + udelay(10); + + return ret; +} + static void nsp32_prom_start (nsp32_hw_data *data) { /* start condition */ @@ -3410,49 +3452,6 @@ return val; } -static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) -{ - unsigned int base = data->BaseAddress; - int tmp; - - tmp = nsp32_index_read1(base, SERIAL_ROM_CTL); - - if (val == 0) { - tmp &= ~bit; - } else { - tmp |= bit; - } - - nsp32_index_write1(base, SERIAL_ROM_CTL, tmp); - - udelay(10); -} - -static inline int nsp32_prom_get(nsp32_hw_data *data, int bit) -{ - unsigned int base = data->BaseAddress; - int tmp, ret; - - if (bit != SROM_DATA) { - nsp32_msg(KERN_ERR, "return value is not appropriate"); - return 0; - } - - - tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit; - - if (tmp == 0) { - ret = 0; - } else { - ret = 1; - } - - udelay(10); - - return ret; -} - - /************************************************************************** * Power Management */ diff -urN linux-2.4.27/drivers/scsi/nsp32.h linux-2.4.28/drivers/scsi/nsp32.h --- linux-2.4.27/drivers/scsi/nsp32.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/scsi/nsp32.h 2004-11-17 03:54:21.738403650 -0800 @@ -22,7 +22,6 @@ * VENDOR/DEVICE ID */ #define PCI_VENDOR_ID_IODATA 0x10fc -#define PCI_VENDOR_ID_WORKBIT 0x1145 #define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 #define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 diff -urN linux-2.4.27/drivers/scsi/pluto.c linux-2.4.28/drivers/scsi/pluto.c --- linux-2.4.27/drivers/scsi/pluto.c 2001-02-09 11:30:23.000000000 -0800 +++ linux-2.4.28/drivers/scsi/pluto.c 2004-11-17 03:54:21.763404678 -0800 @@ -339,4 +339,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/scsi/qla1280.c linux-2.4.28/drivers/scsi/qla1280.c --- linux-2.4.27/drivers/scsi/qla1280.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/scsi/qla1280.c 2004-11-17 03:54:21.766404801 -0800 @@ -875,6 +875,41 @@ } + /* + * qla2100_enable_intrs + * qla2100_disable_intrs + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * None + */ +static inline void +qla1280_enable_intrs(struct scsi_qla_host *ha) +{ + struct device_reg *reg; + + reg = ha->iobase; + /* enable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); + RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ + ha->flags.ints_enabled = 1; +} + +static inline void +qla1280_disable_intrs(struct scsi_qla_host *ha) +{ + struct device_reg *reg; + + reg = ha->iobase; + /* disable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, 0); + RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ + ha->flags.ints_enabled = 0; +} + + /************************************************************************** * qla1280_do_device_init * This routine will register the device with the SCSI subsystem, @@ -2049,40 +2084,6 @@ /* QLogic ISP1280 Hardware Support Functions. */ /****************************************************************************/ - /* - * qla2100_enable_intrs - * qla2100_disable_intrs - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * None - */ -static inline void -qla1280_enable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg *reg; - - reg = ha->iobase; - /* enable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 1; -} - -static inline void -qla1280_disable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg *reg; - - reg = ha->iobase; - /* disable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, 0); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 0; -} - /* * qla1280_initialize_adapter * Initialize board. diff -urN linux-2.4.27/drivers/scsi/qlogicfc.c linux-2.4.28/drivers/scsi/qlogicfc.c --- linux-2.4.27/drivers/scsi/qlogicfc.c 2004-04-14 06:05:31.000000000 -0700 +++ linux-2.4.28/drivers/scsi/qlogicfc.c 2004-11-17 03:54:21.769404925 -0800 @@ -722,7 +722,7 @@ continue; /* Try to configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && pci_set_dma_mask(pdev, (u64) 0xffffffff)) continue; diff -urN linux-2.4.27/drivers/scsi/qlogicpti.c linux-2.4.28/drivers/scsi/qlogicpti.c --- linux-2.4.27/drivers/scsi/qlogicpti.c 2004-04-14 06:05:31.000000000 -0700 +++ linux-2.4.28/drivers/scsi/qlogicpti.c 2004-11-17 03:54:21.770404966 -0800 @@ -1533,4 +1533,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -urN linux-2.4.27/drivers/scsi/sata_nv.c linux-2.4.28/drivers/scsi/sata_nv.c --- linux-2.4.27/drivers/scsi/sata_nv.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/scsi/sata_nv.c 2004-11-17 03:54:21.772405048 -0800 @@ -0,0 +1,535 @@ +/* + * sata_nv.c - NVIDIA nForce SATA + * + * Copyright 2004 NVIDIA Corp. All rights reserved. + * Copyright 2004 Andrew Chew + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + * 0.03 + * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using + * mmio_base, which is only set for the CK804/MCP04 case. + * + * 0.02 + * - Added support for CK804 SATA controller. + * + * 0.01 + * - Initial revision. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "sata_nv" +#define DRV_VERSION "0.03" + +#define NV_PORTS 2 +#define NV_PIO_MASK 0x1f +#define NV_MWDMA_MASK 0x07 +#define NV_UDMA_MASK 0x7f +#define NV_PORT0_SCR_REG_OFFSET 0x00 +#define NV_PORT1_SCR_REG_OFFSET 0x40 + +#define NV_INT_STATUS 0x10 +#define NV_INT_STATUS_CK804 0x440 +#define NV_INT_STATUS_PDEV_INT 0x01 +#define NV_INT_STATUS_PDEV_PM 0x02 +#define NV_INT_STATUS_PDEV_ADDED 0x04 +#define NV_INT_STATUS_PDEV_REMOVED 0x08 +#define NV_INT_STATUS_SDEV_INT 0x10 +#define NV_INT_STATUS_SDEV_PM 0x20 +#define NV_INT_STATUS_SDEV_ADDED 0x40 +#define NV_INT_STATUS_SDEV_REMOVED 0x80 +#define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \ + NV_INT_STATUS_PDEV_REMOVED) +#define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \ + NV_INT_STATUS_SDEV_REMOVED) +#define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \ + NV_INT_STATUS_SDEV_HOTPLUG) + +#define NV_INT_ENABLE 0x11 +#define NV_INT_ENABLE_CK804 0x441 +#define NV_INT_ENABLE_PDEV_MASK 0x01 +#define NV_INT_ENABLE_PDEV_PM 0x02 +#define NV_INT_ENABLE_PDEV_ADDED 0x04 +#define NV_INT_ENABLE_PDEV_REMOVED 0x08 +#define NV_INT_ENABLE_SDEV_MASK 0x10 +#define NV_INT_ENABLE_SDEV_PM 0x20 +#define NV_INT_ENABLE_SDEV_ADDED 0x40 +#define NV_INT_ENABLE_SDEV_REMOVED 0x80 +#define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \ + NV_INT_ENABLE_PDEV_REMOVED) +#define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \ + NV_INT_ENABLE_SDEV_REMOVED) +#define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \ + NV_INT_ENABLE_SDEV_HOTPLUG) + +#define NV_INT_CONFIG 0x12 +#define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI + +// For PCI config register 20 +#define NV_MCP_SATA_CFG_20 0x50 +#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN 0x04 + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void nv_host_stop (struct ata_host_set *host_set); +static void nv_enable_hotplug(struct ata_probe_ent *probe_ent); +static void nv_disable_hotplug(struct ata_host_set *host_set); +static void nv_check_hotplug(struct ata_host_set *host_set); +static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent); +static void nv_disable_hotplug_ck804(struct ata_host_set *host_set); +static void nv_check_hotplug_ck804(struct ata_host_set *host_set); + +enum nv_host_type +{ + NFORCE2, + NFORCE3, + CK804 +}; + +static struct pci_device_id nv_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { 0, } /* terminate list */ +}; + +#define NV_HOST_FLAGS_SCR_MMIO 0x00000001 + +struct nv_host_desc +{ + enum nv_host_type host_type; + unsigned long host_flags; + void (*enable_hotplug)(struct ata_probe_ent *probe_ent); + void (*disable_hotplug)(struct ata_host_set *host_set); + void (*check_hotplug)(struct ata_host_set *host_set); + +}; +static struct nv_host_desc nv_device_tbl[] = { + { + .host_type = NFORCE2, + .host_flags = 0x00000000, + .enable_hotplug = nv_enable_hotplug, + .disable_hotplug= nv_disable_hotplug, + .check_hotplug = nv_check_hotplug, + }, + { + .host_type = NFORCE3, + .host_flags = 0x00000000, + .enable_hotplug = nv_enable_hotplug, + .disable_hotplug= nv_disable_hotplug, + .check_hotplug = nv_check_hotplug, + }, + { .host_type = CK804, + .host_flags = NV_HOST_FLAGS_SCR_MMIO, + .enable_hotplug = nv_enable_hotplug_ck804, + .disable_hotplug= nv_disable_hotplug_ck804, + .check_hotplug = nv_check_hotplug_ck804, + }, +}; + +struct nv_host +{ + struct nv_host_desc *host_desc; +}; + +static struct pci_driver nv_pci_driver = { + .name = DRV_NAME, + .id_table = nv_pci_tbl, + .probe = nv_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template nv_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .use_new_eh_code = ATA_SHT_NEW_EH_CODE, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations nv_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + .phy_reset = sata_phy_reset, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, + .irq_handler = nv_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = nv_host_stop, +}; + +static struct ata_port_info nv_port_info = { + .sht = &nv_sht, + .host_flags = ATA_FLAG_SATA | + ATA_FLAG_SATA_RESET | + ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_ops, +}; + +MODULE_AUTHOR("NVIDIA"); +MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, nv_pci_tbl); + +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct nv_host *host = host_set->private_data; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + spin_lock_irqsave(&host_set->lock, flags); + + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap; + + ap = host_set->ports[i]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) + handled += ata_host_intr(ap, qc); + } + + } + + if (host->host_desc->check_hotplug) + host->host_desc->check_hotplug(host_set); + + spin_unlock_irqrestore(&host_set->lock, flags); + + return IRQ_RETVAL(handled); +} + +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + struct ata_host_set *host_set = ap->host_set; + struct nv_host *host = host_set->private_data; + + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + else + return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + struct ata_host_set *host_set = ap->host_set; + struct nv_host *host = host_set->private_data; + + if (sc_reg > SCR_CONTROL) + return; + + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + else + outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_host_stop (struct ata_host_set *host_set) +{ + struct nv_host *host = host_set->private_data; + + // Disable hotplug event interrupts. + if (host->host_desc->disable_hotplug) + host->host_desc->disable_hotplug(host_set); + + kfree(host); +} + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + struct nv_host *host; + struct ata_port_info *ppi; + struct ata_probe_ent *probe_ent; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + goto err_out; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out_disable; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + rc = -ENOMEM; + + ppi = &nv_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (!probe_ent) + goto err_out_regions; + + host = kmalloc(sizeof(struct nv_host), GFP_KERNEL); + if (!host) + goto err_out_free_ent; + + host->host_desc = &nv_device_tbl[ent->driver_data]; + + probe_ent->private_data = host; + + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) { + unsigned long base; + + probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5), + pci_resource_len(pdev, 5)); + if (probe_ent->mmio_base == NULL) { + rc = -EIO; + goto err_out_free_host; + } + + base = (unsigned long)probe_ent->mmio_base; + + probe_ent->port[0].scr_addr = + base + NV_PORT0_SCR_REG_OFFSET; + probe_ent->port[1].scr_addr = + base + NV_PORT1_SCR_REG_OFFSET; + } else { + + probe_ent->port[0].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET; + probe_ent->port[1].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET; + } + + pci_set_master(pdev); + + ata_add_to_probe_list(probe_ent); + + // Enable hotplug event interrupts. + if (host->host_desc->enable_hotplug) + host->host_desc->enable_hotplug(probe_ent); + + return 0; + +err_out_iounmap: + if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) + iounmap(probe_ent->mmio_base); +err_out_free_host: + kfree(host); +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); +err_out: + return rc; +} + +static void nv_enable_hotplug(struct ata_probe_ent *probe_ent) +{ + u8 intr_mask; + + outb(NV_INT_STATUS_HOTPLUG, + probe_ent->port[0].scr_addr + NV_INT_STATUS); + + intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE); + intr_mask |= NV_INT_ENABLE_HOTPLUG; + + outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE); +} + +static void nv_disable_hotplug(struct ata_host_set *host_set) +{ + u8 intr_mask; + + intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); + + intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); + + outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); +} + +static void nv_check_hotplug(struct ata_host_set *host_set) +{ + u8 intr_status; + + intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); + + // Clear interrupt status. + outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); + + if (intr_status & NV_INT_STATUS_HOTPLUG) { + if (intr_status & NV_INT_STATUS_PDEV_ADDED) + printk(KERN_WARNING "nv_sata: " + "Primary device added\n"); + + if (intr_status & NV_INT_STATUS_PDEV_REMOVED) + printk(KERN_WARNING "nv_sata: " + "Primary device removed\n"); + + if (intr_status & NV_INT_STATUS_SDEV_ADDED) + printk(KERN_WARNING "nv_sata: " + "Secondary device added\n"); + + if (intr_status & NV_INT_STATUS_SDEV_REMOVED) + printk(KERN_WARNING "nv_sata: " + "Secondary device removed\n"); + } +} + +static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent) +{ + u8 intr_mask; + u8 regval; + + pci_read_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, ®val); + regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN; + pci_write_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, regval); + + writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804); + + intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_CK804); + intr_mask |= NV_INT_ENABLE_HOTPLUG; + + writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_CK804); +} + +static void nv_disable_hotplug_ck804(struct ata_host_set *host_set) +{ + u8 intr_mask; + u8 regval; + + intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804); + + intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); + + writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804); + + pci_read_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, ®val); + regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN; + pci_write_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, regval); +} + +static void nv_check_hotplug_ck804(struct ata_host_set *host_set) +{ + u8 intr_status; + + intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804); + + // Clear interrupt status. + writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804); + + if (intr_status & NV_INT_STATUS_HOTPLUG) { + if (intr_status & NV_INT_STATUS_PDEV_ADDED) + printk(KERN_WARNING "nv_sata: " + "Primary device added\n"); + + if (intr_status & NV_INT_STATUS_PDEV_REMOVED) + printk(KERN_WARNING "nv_sata: " + "Primary device removed\n"); + + if (intr_status & NV_INT_STATUS_SDEV_ADDED) + printk(KERN_WARNING "nv_sata: " + "Secondary device added\n"); + + if (intr_status & NV_INT_STATUS_SDEV_REMOVED) + printk(KERN_WARNING "nv_sata: " + "Secondary device removed\n"); + } +} + +static int __init nv_init(void) +{ + int rc; + + rc = pci_module_init(&nv_pci_driver); + if (rc) + return rc; + + rc = scsi_register_module(MODULE_SCSI_HA, &nv_sht); + if (rc) { + pci_unregister_driver(&nv_pci_driver); + /* TODO: does scsi_register_module return errno val? */ + return -ENODEV; + } + + return 0; +} + +static void __exit nv_exit(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &nv_sht); + pci_unregister_driver(&nv_pci_driver); +} + +module_init(nv_init); +module_exit(nv_exit); diff -urN linux-2.4.27/drivers/scsi/sata_promise.c linux-2.4.28/drivers/scsi/sata_promise.c --- linux-2.4.27/drivers/scsi/sata_promise.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_promise.c 2004-11-17 03:54:21.773405089 -0800 @@ -42,6 +42,7 @@ #define DRV_NAME "sata_promise" #define DRV_VERSION "1.00" +#define msleep libata_msleep /* 2.4-specific */ enum { PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ @@ -74,24 +75,23 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc_dma_setup(struct ata_queued_cmd *qc); -static void pdc_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc_phy_reset(struct ata_port *ap); -static void pdc_fill_sg(struct ata_queued_cmd *qc); +static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); +static void pdc_irq_clear(struct ata_port *ap); +static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -109,15 +109,16 @@ static struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_phy_reset, - .bmdma_setup = pdc_dma_setup, - .bmdma_start = pdc_dma_start, - .fill_sg = pdc_fill_sg, + .qc_prep = pdc_qc_prep, + .qc_issue = pdc_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, + .irq_clear = pdc_irq_clear, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_port_start, @@ -130,7 +131,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -140,7 +142,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -262,33 +265,33 @@ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void pdc_fill_sg(struct ata_queued_cmd *qc) +static void pdc_qc_prep(struct ata_queued_cmd *qc) { struct pdc_port_priv *pp = qc->ap->private_data; unsigned int i; VPRINTK("ENTER\n"); - ata_fill_sg(qc); - - i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + ata_qc_prep(qc); + /* fall through */ - if (qc->tf.flags & ATA_TFLAG_LBA48) - i = pdc_prep_lba48(&qc->tf, pp->pkt, i); - else - i = pdc_prep_lba28(&qc->tf, pp->pkt, i); + case ATA_PROT_NODATA: + i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, + qc->dev->devno, pp->pkt); - pdc_pkt_footer(&qc->tf, pp->pkt, i); -} + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, pp->pkt, i); + else + i = pdc_prep_lba28(&qc->tf, pp->pkt, i); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; + pdc_pkt_footer(&qc->tf, pp->pkt, i); + break; - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); + default: + break; + } } static void pdc_eng_timeout(struct ata_port *ap) @@ -315,17 +318,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -358,13 +353,8 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_complete(ap, qc, have_err); - handled = 1; - break; - - case ATA_PROT_NODATA: /* command completion, but no data xfer */ - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + case ATA_PROT_NODATA: + status = ata_wait_idle(ap); if (have_err) status |= ATA_ERR; ata_qc_complete(qc, status); @@ -379,6 +369,14 @@ return handled; } +static void pdc_irq_clear(struct ata_port *ap) +{ + struct ata_host_set *host_set = ap->host_set; + void *mmio = host_set->mmio_base; + + readl(mmio + PDC_INT_SEQMASK); +} + static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; @@ -432,13 +430,7 @@ return IRQ_RETVAL(handled); } -static void pdc_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc_dma_start(struct ata_queued_cmd *qc) +static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; @@ -456,17 +448,38 @@ readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } +static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -519,8 +532,7 @@ writel(tmp, mmio + PDC_TBG_MODE); readl(mmio + PDC_TBG_MODE); /* flush */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10) + 1); + msleep(10); /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); @@ -578,6 +590,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; diff -urN linux-2.4.27/drivers/scsi/sata_sil.c linux-2.4.28/drivers/scsi/sata_sil.c --- linux-2.4.27/drivers/scsi/sata_sil.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_sil.c 2004-11-17 03:54:21.774405130 -0800 @@ -6,7 +6,7 @@ * on emails. * * Copyright 2003 Red Hat, Inc. - * Copyright 2003 Benjamin Herrenschmidt + * Copyright 2003 Benjamin Herrenschmidt * * The contents of this file are subject to the Open * Software License version 1.1 that can be found at @@ -86,6 +86,7 @@ { "ST360015AS", SIL_QUIRK_MOD15WRITE }, { "ST380023AS", SIL_QUIRK_MOD15WRITE }, { "ST3120023AS", SIL_QUIRK_MOD15WRITE }, + { "ST3160023AS", SIL_QUIRK_MOD15WRITE }, { "ST340014ASL", SIL_QUIRK_MOD15WRITE }, { "ST360014ASL", SIL_QUIRK_MOD15WRITE }, { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, @@ -107,6 +108,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -124,17 +126,20 @@ static struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, - .tf_load = ata_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, - .exec_command = ata_exec_command_mmio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, .post_set_mode = sil_post_set_mode, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, @@ -147,7 +152,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ @@ -155,7 +161,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, @@ -303,6 +310,7 @@ ap->id, dev->devno); ap->host->max_sectors = 15; ap->host->hostt->max_sectors = 15; + dev->flags |= ATA_DFLAG_LOCK_SECTORS; return; } @@ -357,6 +365,7 @@ probe_ent->sht = sil_port_info[ent->driver_data].sht; probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; diff -urN linux-2.4.27/drivers/scsi/sata_sis.c linux-2.4.28/drivers/scsi/sata_sis.c --- linux-2.4.27/drivers/scsi/sata_sis.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_sis.c 2004-11-17 03:54:21.775405171 -0800 @@ -78,6 +78,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -94,22 +95,35 @@ static struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, }; +static struct ata_port_info sis_port_info = { + .sht = &sis_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x7, + .udma_mask = 0x7f, + .port_ops = &sis_ops, +}; + MODULE_AUTHOR("Uwe Koziolek"); MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); @@ -183,6 +197,7 @@ struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; + struct ata_port_info *ppi; rc = pci_enable_device(pdev); if (rc) @@ -196,20 +211,13 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &sis_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - probe_ent->pdev = pdev; - INIT_LIST_HEAD(&probe_ent->node); - - probe_ent->sht = &sis_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | - ATA_FLAG_NO_LEGACY; - /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) @@ -226,31 +234,12 @@ probe_ent->host_flags |= SIS_FLAG_CFGSCR; } - probe_ent->pio_mask = 0x03; - probe_ent->udma_mask = 0x7f; - probe_ent->port_ops = &sis_ops; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) + if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) probe_ent->port[1].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64; - - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; + } pci_set_master(pdev); pci_enable_intx(pdev); diff -urN linux-2.4.27/drivers/scsi/sata_svw.c linux-2.4.28/drivers/scsi/sata_svw.c --- linux-2.4.27/drivers/scsi/sata_svw.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_svw.c 2004-11-17 03:54:21.775405171 -0800 @@ -148,7 +148,73 @@ } } +/** + * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = readb(mmio + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + writeb(dmactl, mmio + ATA_DMA_CMD); + + /* issue r/w command if this is not a ATA DMA command*/ + if (qc->tf.protocol != ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) + * @qc: Info associated with this ATA transaction. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void *mmio = (void *) ap->ioaddr.bmdma_addr; + u8 dmactl; + + /* start host DMA transaction */ + dmactl = readb(mmio + ATA_DMA_CMD); + writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); + /* There is a race condition in certain SATA controllers that can + be seen when the r/w command is given to the controller before the + host DMA is started. On a Read command, the controller would initiate + the command to the drive even before it sees the DMA start. When there + are very fast drives connected to the controller, or when the data request + hits in the drive cache, there is the possibility that the drive returns a part + or all of the requested data to the controller before the DMA start is issued. + In this case, the controller would become confused as to what to do with the data. + In the worst case when all the data is returned back to the controller, the + controller could hang. In other cases it could return partial data returning + in data corruption. This problem has been seen in PPC systems and can also appear + on an system with very fast disks, where the SATA controller is sitting behind a + number of bridges, and hence there is significant latency between the r/w command + and the start command. */ + /* issue r/w command if the access is to ATA*/ + if (qc->tf.protocol == ATA_PROT_DMA) + ap->ops->exec_command(ap, &qc->tf); +} + static u8 k2_stat_check_status(struct ata_port *ap) { return readl((void *) ap->ioaddr.status_addr); @@ -207,6 +273,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -230,13 +297,16 @@ .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, - .exec_command = ata_exec_command_mmio, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .bmdma_setup = k2_bmdma_setup_mmio, + .bmdma_start = k2_bmdma_start_mmio, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, @@ -339,6 +409,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ @@ -365,6 +436,8 @@ static struct pci_device_id k2_sata_pci_tbl[] = { { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { } }; diff -urN linux-2.4.27/drivers/scsi/sata_sx4.c linux-2.4.28/drivers/scsi/sata_sx4.c --- linux-2.4.27/drivers/scsi/sata_sx4.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_sx4.c 2004-11-17 03:54:21.777405254 -0800 @@ -146,19 +146,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc20621_dma_setup(struct ata_queued_cmd *qc); -static void pdc20621_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); -static void pdc20621_fill_sg(struct ata_queued_cmd *qc); +static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -171,6 +167,8 @@ #endif static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); +static void pdc20621_irq_clear(struct ata_port *ap); +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { @@ -178,6 +176,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -195,15 +194,16 @@ static struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read_mmio, - .check_status = ata_check_status_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, .phy_reset = pdc_20621_phy_reset, - .bmdma_setup = pdc20621_dma_setup, - .bmdma_start = pdc20621_dma_start, - .fill_sg = pdc20621_fill_sg, + .qc_prep = pdc20621_qc_prep, + .qc_issue = pdc20621_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, + .irq_clear = pdc20621_irq_clear, .port_start = pdc_port_start, .port_stop = pdc_port_stop, .host_stop = pdc20621_host_stop, @@ -215,7 +215,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_20621_ops, }, @@ -375,7 +376,10 @@ /* dimm dma S/G, and next-pkt */ dw = i >> 2; - buf32[dw] = cpu_to_le32(dimm_sg); + if (tf->protocol == ATA_PROT_NODATA) + buf32[dw] = 0; + else + buf32[dw] = cpu_to_le32(dimm_sg); buf32[dw + 1] = 0; i += 8; @@ -435,7 +439,7 @@ buf32[dw + 3]); } -static void pdc20621_fill_sg(struct ata_queued_cmd *qc) +static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -447,6 +451,8 @@ unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; + assert(qc->flags & ATA_QCFLAG_DMAMAP); + VPRINTK("ata%u: ENTER\n", ap->id); /* hard-code chip #0 */ @@ -496,6 +502,56 @@ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + void *mmio = ap->host_set->mmio_base; + struct pdc_host_priv *hpriv = ap->host_set->private_data; + void *dimm_mmio = hpriv->dimm_mmio; + unsigned int portno = ap->port_no; + unsigned int i; + + VPRINTK("ata%u: ENTER\n", ap->id); + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno); + + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); + else + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); + + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); + + /* copy three S/G tables and two packets to DIMM MMIO window */ + memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP), + &pp->dimm_buf, PDC_DIMM_HEADER_SZ); + + /* force host FIFO dump */ + writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); + + readl(dimm_mmio); /* MMIO PCI posting flush */ + + VPRINTK("ata pkt buf ofs %u, mmio copied\n", i); +} + +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pdc20621_dma_prep(qc); + break; + case ATA_PROT_NODATA: + pdc20621_nodata_prep(qc); + break; + default: + break; + } +} + static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, unsigned int seq, u32 pkt_ofs) @@ -571,13 +627,7 @@ static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { } #endif /* ATA_VERBOSE_DEBUG */ -static void pdc20621_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc20621_dma_start(struct ata_queued_cmd *qc) +static void pdc20621_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; @@ -585,24 +635,21 @@ void *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); - unsigned int doing_hdma = 0, port_ofs; + unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->id); + wmb(); /* flush PRD, pkt writes */ + port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no); /* if writing, we (1) DMA to DIMM, then (2) do ATA command */ - if (rw) { - doing_hdma = 1; + if (rw && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; - } - wmb(); /* flush PRD, pkt writes */ - - if (doing_hdma) { pdc20621_dump_hdma(qc); pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); VPRINTK("queued ofs 0x%x (%u), seq %u\n", @@ -623,6 +670,25 @@ } } +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc20621_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, @@ -643,7 +709,8 @@ if (doing_hdma) { VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } @@ -680,7 +747,8 @@ else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } handled = 1; @@ -700,6 +768,16 @@ return handled; } +static void pdc20621_irq_clear(struct ata_port *ap) +{ + struct ata_host_set *host_set = ap->host_set; + void *mmio = host_set->mmio_base; + + mmio += PDC_CHIP0_OFS; + + readl(mmio + PDC_20621_SEQMASK); +} + static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; @@ -764,16 +842,6 @@ return IRQ_RETVAL(handled); } -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); -} - static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; @@ -798,17 +866,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -827,15 +887,17 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command(ap, tf); } @@ -1366,6 +1428,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; @@ -1376,21 +1439,11 @@ probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; + probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); - - /* notice 4-port boards */ - switch (board_idx) { - case board_20621: - probe_ent->n_ports = 4; - - pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); - break; - default: - BUG(); - break; - } + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); diff -urN linux-2.4.27/drivers/scsi/sata_uli.c linux-2.4.28/drivers/scsi/sata_uli.c --- linux-2.4.27/drivers/scsi/sata_uli.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/drivers/scsi/sata_uli.c 2004-11-17 03:54:21.778405295 -0800 @@ -0,0 +1,292 @@ +/* + * sata_uli.c - ULi Electronics SATA + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "sata_uli" +#define DRV_VERSION "0.11" + +enum { + uli_5289 = 0, + uli_5287 = 1, + + /* PCI configuration registers */ + ULI_SCR_BASE = 0x90, /* sata0 phy SCR registers */ + ULI_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ + +}; + +static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); + +static struct pci_device_id uli_pci_tbl[] = { + { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 }, + { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 }, + { } /* terminate list */ +}; + + +static struct pci_driver uli_pci_driver = { + .name = DRV_NAME, + .id_table = uli_pci_tbl, + .probe = uli_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template uli_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .use_new_eh_code = ATA_SHT_NEW_EH_CODE, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations uli_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .phy_reset = sata_phy_reset, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .scr_read = uli_scr_read, + .scr_write = uli_scr_write, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static struct ata_port_info uli_port_info = { + .sht = &uli_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY, + .pio_mask = 0x03, //support pio mode 4 (FIXME) + .udma_mask = 0x7f, //support udma mode 6 + .port_ops = &uli_ops, +}; + + +MODULE_AUTHOR("Peer Chen"); +MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, uli_pci_tbl); + +static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg) +{ + unsigned int addr = ULI_SCR_BASE + (4 * sc_reg); + + switch (port_no) { + case 0: + break; + case 1: + addr += ULI_SATA1_OFS; + break; + case 2: + addr += ULI_SATA1_OFS*4; + break; + case 3: + addr += ULI_SATA1_OFS*5; + break; + default: + BUG(); + break; + } + return addr; +} + +static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) +{ + unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg); + u32 val; + + pci_read_config_dword(ap->host_set->pdev, cfg_addr, &val); + return val; +} + +static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) +{ + unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr); + + pci_write_config_dword(ap->host_set->pdev, cfg_addr, val); +} + +static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + + return uli_scr_cfg_read(ap, sc_reg); +} + +static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 + return; + + uli_scr_cfg_write(ap, sc_reg, val); +} + +/* move to PCI layer, integrate w/ MSI stuff */ +static void pci_enable_intx(struct pci_dev *pdev) +{ + u16 pci_command; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_INTX_DISABLE) { + pci_command &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } +} + +static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct ata_probe_ent *probe_ent; + struct ata_port_info *ppi; + int rc; + unsigned int board_idx = (unsigned int) ent->driver_data; + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + ppi = &uli_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (!probe_ent) { + rc = -ENOMEM; + goto err_out_regions; + } + + switch (board_idx) { + case uli_5287: + probe_ent->n_ports = 4; + + probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; + probe_ent->port[2].altstatus_addr = + probe_ent->port[2].ctl_addr = + (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; + + probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; + probe_ent->port[3].altstatus_addr = + probe_ent->port[3].ctl_addr = + (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; + + ata_std_ports(&probe_ent->port[2]); + ata_std_ports(&probe_ent->port[3]); + break; + + case uli_5289: + /* do nothing; ata_pci_init_native_mode did it all */ + break; + + default: + BUG(); + break; + } + + pci_set_master(pdev); + pci_enable_intx(pdev); + + ata_add_to_probe_list(probe_ent); + + return 0; + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + return rc; + +} + +static int __init uli_init(void) +{ + int rc; + + rc = pci_module_init(&uli_pci_driver); + if (rc) + return rc; + + rc = scsi_register_module(MODULE_SCSI_HA, &uli_sht); + if (rc) { + pci_unregister_driver(&uli_pci_driver); + /* TODO: does scsi_register_module return errno val? */ + return -ENODEV; + } + + return 0; +} + +static void __exit uli_exit(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &uli_sht); + pci_unregister_driver(&uli_pci_driver); +} + + +module_init(uli_init); +module_exit(uli_exit); diff -urN linux-2.4.27/drivers/scsi/sata_via.c linux-2.4.28/drivers/scsi/sata_via.c --- linux-2.4.27/drivers/scsi/sata_via.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_via.c 2004-11-17 03:54:21.779405336 -0800 @@ -83,6 +83,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -100,19 +101,23 @@ static struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_pio, - .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = svia_scr_read, .scr_write = svia_scr_write, @@ -121,6 +126,15 @@ .port_stop = ata_port_stop, }; +static struct ata_port_info svia_port_info = { + .sht = &svia_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + .port_ops = &svia_sata_ops, +}; + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); MODULE_LICENSE("GPL"); @@ -154,6 +168,7 @@ static int printed_version; unsigned int i; int rc; + struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; u8 tmp8; @@ -191,41 +206,17 @@ if (rc) goto err_out_regions; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + ppi = &svia_port_info; + probe_ent = ata_pci_init_native_mode(pdev, &ppi); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); rc = -ENOMEM; goto err_out_regions; } - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); - probe_ent->pdev = pdev; - probe_ent->sht = &svia_sht; - probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY; - probe_ent->port_ops = &svia_sata_ops; - probe_ent->n_ports = 2; - probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; - - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - ata_std_ports(&probe_ent->port[0]); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->port[0].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 0); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - ata_std_ports(&probe_ent->port[1]); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; probe_ent->port[1].scr_addr = svia_scr_addr(pci_resource_start(pdev, 5), 1); diff -urN linux-2.4.27/drivers/scsi/sata_vsc.c linux-2.4.28/drivers/scsi/sata_vsc.c --- linux-2.4.27/drivers/scsi/sata_vsc.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sata_vsc.c 2004-11-17 03:54:21.780405377 -0800 @@ -192,6 +192,7 @@ .name = DRV_NAME, .detect = ata_scsi_detect, .release = ata_scsi_release, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -211,14 +212,17 @@ .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, - .exec_command = ata_exec_command_mmio, - .check_status = ata_check_status_mmio, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, .phy_reset = sata_phy_reset, - .bmdma_setup = ata_bmdma_setup_mmio, - .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = vsc_sata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, @@ -316,6 +320,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ diff -urN linux-2.4.27/drivers/scsi/scsi_debug.c linux-2.4.28/drivers/scsi/scsi_debug.c --- linux-2.4.27/drivers/scsi/scsi_debug.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/scsi/scsi_debug.c 2004-11-17 03:54:21.781405418 -0800 @@ -48,7 +48,7 @@ #include "scsi_debug.h" -static const char * scsi_debug_version_str = "Version: 0.61 (20020815)"; +static const char * scsi_debug_version_str = "Version: 0.63 (20040831)"; #ifndef SCSI_CMD_READ_16 @@ -73,7 +73,7 @@ #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 #define SCSI_DEBUG_OPT_EVERY_NTH 4 -#define OPT_MEDIUM_ERR_ADDR 0x1234 +#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's 4660 in decimal */ static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS; static int scsi_debug_opts = DEF_OPTS; @@ -124,7 +124,7 @@ static unsigned char * fake_storep; /* ramdisk storage */ -static unsigned char broken_buff[SDEBUG_SENSE_LEN]; +static unsigned char spare_buff[SDEBUG_SENSE_LEN]; static int num_aborts = 0; static int num_dev_resets = 0; @@ -193,8 +193,7 @@ else buff = (unsigned char *) SCpnt->request_buffer; if (NULL == buff) { - printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n"); - buff = broken_buff; /* just point at dummy */ + buff = spare_buff; /* just point at dummy */ bufflen = SDEBUG_SENSE_LEN; } @@ -370,7 +369,7 @@ if ((errsts = check_reset(SCpnt, devip))) break; mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14); - errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + errsts = (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); break; } return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay); @@ -390,7 +389,7 @@ if (devip->reset) { devip->reset = 0; mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } return 0; } @@ -451,7 +450,7 @@ arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } else if (0x1 & cmd[1]) { /* EVPD bit set */ int dev_id_num, len; char dev_id_str[6]; @@ -476,7 +475,7 @@ } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } memcpy(buff, arr, min_len); return 0; @@ -589,7 +588,7 @@ memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); if (0x3 == pcontrol) { /* Saving values not supported */ mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; if (msense_6) { @@ -631,7 +630,7 @@ break; default: mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } if (msense_6) arr[0] = offset - 1; @@ -655,14 +654,14 @@ if (upper_blk || (block + num > CAPACITY)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && - (block >= OPT_MEDIUM_ERR_ADDR) && - (block < (OPT_MEDIUM_ERR_ADDR + num))) { + (block <= OPT_MEDIUM_ERR_ADDR) && + ((block + num) > OPT_MEDIUM_ERR_ADDR)) { mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14); /* claim unrecoverable read error */ - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } read_lock_irqsave(&atomic_rw, iflags); sgcount = 0; @@ -704,7 +703,7 @@ if (upper_blk || (block + num > CAPACITY)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } write_lock_irqsave(&atomic_rw, iflags); @@ -744,7 +743,7 @@ alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); if ((alloc_len < 16) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); - return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1); } if (bufflen > 3) { memset(buff, 0, bufflen); @@ -773,8 +772,10 @@ return; } sqcp->in_use = 0; - if (sqcp->done_funct) + if (sqcp->done_funct) { + sqcp->a_cmnd->result = sqcp->scsi_result; sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ + } sqcp->done_funct = NULL; spin_unlock_irqrestore(&queued_arr_lock, iflags); } diff -urN linux-2.4.27/drivers/scsi/scsi_error.c linux-2.4.28/drivers/scsi/scsi_error.c --- linux-2.4.27/drivers/scsi/scsi_error.c 2004-04-14 06:05:31.000000000 -0700 +++ linux-2.4.28/drivers/scsi/scsi_error.c 2004-11-17 03:54:21.782405459 -0800 @@ -664,7 +664,10 @@ SCpnt->eh_state = SUCCESS; break; case NEEDS_RETRY: - goto retry; + if ((++SCpnt->retries) < SCpnt->allowed) + goto retry; + SCpnt->eh_state = SUCCESS; + break; case FAILED: default: SCpnt->eh_state = FAILED; diff -urN linux-2.4.27/drivers/scsi/scsi_lib.c linux-2.4.28/drivers/scsi/scsi_lib.c --- linux-2.4.27/drivers/scsi/scsi_lib.c 2004-04-14 06:05:31.000000000 -0700 +++ linux-2.4.28/drivers/scsi/scsi_lib.c 2004-11-17 03:54:21.784405542 -0800 @@ -422,14 +422,6 @@ return SCpnt; } - /* - * This request is done. If there is someone blocked waiting for this - * request, wake them up. Typically used to wake up processes trying - * to swap a page into memory. - */ - if (req->waiting) - complete(req->waiting); - spin_lock_irqsave(&io_request_lock, flags); req_finished_io(req); spin_unlock_irqrestore(&io_request_lock, flags); @@ -437,6 +429,15 @@ add_blkdev_randomness(MAJOR(req->rq_dev)); /* + * This request is done. If there is someone blocked waiting for this + * request, wake them up. Do this last, as 'req' might be on the stack + * and thus not valid right after the complete() call if the task + * exist + */ + if (req->waiting) + complete(req->waiting); + + /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. */ diff -urN linux-2.4.27/drivers/scsi/scsi_merge.c linux-2.4.28/drivers/scsi/scsi_merge.c --- linux-2.4.27/drivers/scsi/scsi_merge.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/scsi/scsi_merge.c 2004-11-17 03:54:21.785405583 -0800 @@ -418,7 +418,7 @@ return 0; if (!BH_PHYS_4G(req->bhtail, bh)) - return 0; + goto new_end_segment; if (use_clustering) { /* @@ -477,7 +477,7 @@ return 0; if (!BH_PHYS_4G(bh, req->bh)) - return 0; + goto new_start_segment; if (use_clustering) { /* @@ -640,7 +640,7 @@ return 0; if (!BH_PHYS_4G(req->bhtail, next->bh)) - return 0; + goto dont_combine; /* * The main question is whether the two segments at the boundaries diff -urN linux-2.4.27/drivers/scsi/scsi_scan.c linux-2.4.28/drivers/scsi/scsi_scan.c --- linux-2.4.27/drivers/scsi/scsi_scan.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/scsi/scsi_scan.c 2004-11-17 03:54:21.786405624 -0800 @@ -157,6 +157,7 @@ {"TOSHIBA","CDROM","*", BLIST_ISROM}, {"TOSHIBA","CD-ROM","*", BLIST_ISROM}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, + {"3PARdata", "VV", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // 3PARdata InServ Virtual Volume {"DGC", "RAID", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (tgt @ LUN 0) {"DGC", "DISK", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (no tgt @ LUN 0) {"DELL", "PV660F", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, @@ -189,6 +190,7 @@ {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"IOI", "Media Bay", "*", BLIST_FORCELUN}, {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI XP Arrays */ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI 9960 */ {"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN}, @@ -208,6 +210,7 @@ {"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"Xyratex", "4200", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* * Must be at end of list... diff -urN linux-2.4.27/drivers/scsi/scsiiom.c linux-2.4.28/drivers/scsi/scsiiom.c --- linux-2.4.27/drivers/scsi/scsiiom.c 2000-12-31 11:06:00.000000000 -0800 +++ linux-2.4.28/drivers/scsi/scsiiom.c 2004-11-17 03:54:21.787405665 -0800 @@ -211,6 +211,24 @@ }; #endif +static void __inline__ +dc390_InvalidCmd( PACB pACB ) +{ + if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); +} + +#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD) + +/* abort command */ +static void __inline__ +dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) +{ + pSRB->MsgOutBuf[0] = ABORT; + pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; + pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; +} + void __inline__ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { @@ -569,8 +587,6 @@ }; #endif -#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD) - /* reject_msg */ static void __inline__ dc390_MsgIn_reject (PACB pACB, PSRB pSRB) @@ -580,15 +596,6 @@ DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");) } -/* abort command */ -static void __inline__ -dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) -{ - pSRB->MsgOutBuf[0] = ABORT; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; -} - static PSRB dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag) { @@ -1355,6 +1362,47 @@ }; +static void __inline__ +dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSCSICMD pcmd; + + REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ + pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) + + pSRB->SRBFlag |= AUTO_REQSENSE; + //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0]; + //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4]; + //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount; + //pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->SavedSGCount = pSRB->SGcount; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ + + pcmd = pSRB->pcmd; + + pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer); + pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); + pSRB->pSegmentList = &pSRB->Segmentx; + pSRB->SGcount = 1; + pSRB->SGIndex = 0; + + //pSRB->CmdBlock[0] = REQUEST_SENSE; + //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; + //(USHORT) pSRB->CmdBlock[2] = 0; + //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); + //pSRB->ScsiCmdLen = 6; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } +} + + void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { @@ -1738,53 +1786,3 @@ return; } - -static void __inline__ -dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) -{ - PSCSICMD pcmd; - - REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) - - pSRB->SRBFlag |= AUTO_REQSENSE; - //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0]; - //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4]; - //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount; - //pSRB->Segment1[1] = pSRB->TotalXferredLen; - pSRB->SavedSGCount = pSRB->SGcount; - pSRB->SavedTotXLen = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ - - pcmd = pSRB->pcmd; - - pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer); - pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); - pSRB->pSegmentList = &pSRB->Segmentx; - pSRB->SGcount = 1; - pSRB->SGIndex = 0; - - //pSRB->CmdBlock[0] = REQUEST_SENSE; - //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; - //(USHORT) pSRB->CmdBlock[2] = 0; - //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - //pSRB->ScsiCmdLen = 6; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { - dc390_Going_to_Waiting ( pDCB, pSRB ); - dc390_waiting_timer (pACB, HZ/5); - } -} - - - -static void __inline__ -dc390_InvalidCmd( PACB pACB ) -{ - if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); -} - diff -urN linux-2.4.27/drivers/scsi/seagate.c linux-2.4.28/drivers/scsi/seagate.c --- linux-2.4.27/drivers/scsi/seagate.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/scsi/seagate.c 2004-11-17 03:54:21.788405706 -0800 @@ -698,7 +698,7 @@ done_fn = done; current_target = SCpnt->target; current_lun = SCpnt->lun; - (const void *) current_cmnd = SCpnt->cmnd; + current_cmnd = SCpnt->cmnd; current_data = (unsigned char *) SCpnt->request_buffer; current_bufflen = SCpnt->request_bufflen; SCint = SCpnt; diff -urN linux-2.4.27/drivers/scsi/sg.c linux-2.4.28/drivers/scsi/sg.c --- linux-2.4.27/drivers/scsi/sg.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/scsi/sg.c 2004-11-17 03:54:21.792405870 -0800 @@ -742,6 +742,16 @@ return 0; } +static inline unsigned sg_jif_to_ms(int jifs) +{ + if (jifs <= 0) + return 0U; + else { + unsigned int j = (unsigned int)jifs; + return (j < (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * 1000); + } +} + static int sg_ioctl(struct inode * inode, struct file * filp, unsigned int cmd_in, unsigned long arg) { @@ -1640,6 +1650,24 @@ return mx_sc_elems; /* number of scat_gath elements allocated */ } +static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp) +{ +#if SG_NEW_KIOVEC + return alloc_kiovec_sz(nr, bufp, szp); +#else + return alloc_kiovec(nr, bufp); +#endif +} + +static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp) +{ +#if SG_NEW_KIOVEC + free_kiovec_sz(nr, bufp, szp); +#else + free_kiovec(nr, bufp); +#endif +} + static void sg_unmap_and(Sg_scatter_hold * schp, int free_also) { #ifdef SG_ALLOW_DIO_CODE @@ -2568,15 +2596,6 @@ return resp; } -static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp) -{ -#if SG_NEW_KIOVEC - return alloc_kiovec_sz(nr, bufp, szp); -#else - return alloc_kiovec(nr, bufp); -#endif -} - static void sg_low_free(char * buff, int size, int mem_src) { if (! buff) return; @@ -2620,15 +2639,6 @@ sg_low_free(buff, size, mem_src); } -static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp) -{ -#if SG_NEW_KIOVEC - free_kiovec_sz(nr, bufp, szp); -#else - free_kiovec(nr, bufp); -#endif -} - static int sg_ms_to_jif(unsigned int msecs) { if ((UINT_MAX / 2U) < msecs) @@ -2638,16 +2648,6 @@ : (((int)msecs / 1000) * HZ); } -static inline unsigned sg_jif_to_ms(int jifs) -{ - if (jifs <= 0) - return 0U; - else { - unsigned int j = (unsigned int)jifs; - return (j < (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * 1000); - } -} - static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE, INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, MODE_SENSE, MODE_SENSE_10, LOG_SENSE}; diff -urN linux-2.4.27/drivers/scsi/sim710.c linux-2.4.28/drivers/scsi/sim710.c --- linux-2.4.27/drivers/scsi/sim710.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.28/drivers/scsi/sim710.c 2004-11-17 03:54:21.794405953 -0800 @@ -921,172 +921,6 @@ } -/* A quick wrapper for sim710_intr_handle to grab the spin lock */ - -static void -do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); - sim710_intr_handle(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); -} - - -/* A "high" level interrupt handler */ - -static void -sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs) -{ - struct Scsi_Host * host = (struct Scsi_Host *)dev_id; - struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0]; - Scsi_Cmnd * cmd; - unsigned char istat, dstat; - unsigned char sstat0; - u32 scratch, dsps, resume_offset = 0; - - istat = NCR_read8(ISTAT_REG); - if (!(istat & (ISTAT_SIP|ISTAT_DIP))) - return; - else { - sim710_intrs++; - dsps = NCR_read32(DSPS_REG); - hostdata->state = STATE_HALTED; - sstat0 = dstat = 0; - scratch = NCR_read32(SCRATCH_REG); - if (istat & ISTAT_SIP) { - sstat0 = NCR_read8(SSTAT0_REG); - } - if (istat & ISTAT_DIP) { - udelay(10); /* Some comment somewhere about 10cycles - * between accesses to sstat0 and dstat ??? */ - dstat = NCR_read8(DSTAT_REG); - } - DEB(DEB_INTS, printk("scsi%d: Int %d, istat %02x, sstat0 %02x " - "dstat %02x, dsp [%04x], scratch %02x\n", - host->host_no, sim710_intrs, istat, sstat0, dstat, - (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script, - scratch)); - if (scratch & 0x100) { - u8 *p = hostdata->msgin_buf; - - DEB(DEB_INTS, printk(" msgin_buf: %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3])); - } - if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) { - /* Reselected. Identify the target from LCRC_REG, and - * update current command. If we were trying to select - * a device, then that command needs to go back on the - * issue_queue for later. - */ - unsigned char lcrc = NCR_read8(LCRC_REG_10); - int id = 0; - - if (!(lcrc & 0x7f)) { - printk("scsi%d: Reselected with LCRC = %02x\n", - host->host_no, lcrc); - cmd = NULL; - } - else { - while (!(lcrc & 1)) { - id++; - lcrc >>= 1; - } - DEB(DEB_DISC, printk("scsi%d: Reselected by ID %d\n", - host->host_no, id)); - if (hostdata->running) { - /* Clear SIGP */ - (void)NCR_read8(CTEST2_REG_700); - - DEB(DEB_DISC, printk("scsi%d: Select of %d interrupted " - "by reselect from %d (%p)\n", - host->host_no, hostdata->running->target, - id, hostdata->target[id].cur_cmd)); - cmd = hostdata->running; - hostdata->target[cmd->target].cur_cmd = NULL; - cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue; - hostdata->issue_queue = cmd; - } - cmd = hostdata->running = hostdata->target[id].cur_cmd; - } - } - else - cmd = hostdata->running; - - if (!cmd) { - printk("scsi%d: No active command!\n", host->host_no); - printk("scsi%d: Int %d, istat %02x, sstat0 %02x " - "dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n", - host->host_no, sim710_intrs, istat, sstat0, dstat, - (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script, - NCR_read32(SCRATCH_REG), dsps); - /* resume_offset is zero, which will cause a host reset */ - } - else if (sstat0 & SSTAT0_700_STO) { - DEB(DEB_TOUT, printk("scsi%d: Selection timeout\n", host->host_no)); - cmd->result = DID_NO_CONNECT << 16; - SCSI_DONE(cmd); - hostdata->target[cmd->target].cur_cmd = NULL; - resume_offset = Ent_reselect; - } - else if (sstat0 & (SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) { - printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no, - sstat0); - sim710_errors++; - /* resume_offset is zero, which will cause a host reset */ - } - else if (dstat & (DSTAT_BF|DSTAT_ABRT|DSTAT_SSI|DSTAT_WTD)) { - printk("scsi%d: Serious error, dstat = %02x\n", host->host_no, - dstat); - sim710_errors++; - /* resume_offset is zero, which will cause a host reset */ - } - else if (dstat & DSTAT_SIR) - resume_offset = handle_script_int(host, cmd); - else if (sstat0 & SSTAT0_MA) - resume_offset = handle_phase_mismatch(host, cmd); - else if (dstat & DSTAT_IID) { - /* This can be due to a quick reselect while doing a WAIT - * DISCONNECT. - */ - resume_offset = handle_idd(host, cmd); - } - else { - sim710_errors++; - printk("scsi%d: Spurious interrupt!\n", host->host_no); - /* resume_offset is zero, which will cause a host reset */ - } - } - - if (resume_offset) { - if (resume_offset == Ent_reselect) { - hostdata->running = NULL; - hostdata->state = STATE_IDLE; - } - else - hostdata->state = STATE_BUSY; - DEB(DEB_RESUME, printk("scsi%d: Resuming at script[0x%x]\n", - host->host_no, resume_offset/4)); -#ifdef DEBUG_LIMIT_INTS - if (sim710_intrs < DEBUG_LIMIT_INTS) -#endif - { - NCR_write32(SCRATCH_REG, 0); - NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4)); - } - if (resume_offset == Ent_reselect) - run_process_issue_queue(hostdata); - } - else { - printk("scsi%d: Failed to handle interrupt. Failing commands " - "and resetting SCSI bus and chip\n", host->host_no); - mdelay(1000); /* Give chance to read screen!! */ - full_reset(host); - } -} - - static void run_command (struct sim710_hostdata *hostdata, Scsi_Cmnd *cmd) { @@ -1284,6 +1118,172 @@ } +/* A quick wrapper for sim710_intr_handle to grab the spin lock */ + +static void +do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + sim710_intr_handle(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); +} + + +/* A "high" level interrupt handler */ + +static void +sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host * host = (struct Scsi_Host *)dev_id; + struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0]; + Scsi_Cmnd * cmd; + unsigned char istat, dstat; + unsigned char sstat0; + u32 scratch, dsps, resume_offset = 0; + + istat = NCR_read8(ISTAT_REG); + if (!(istat & (ISTAT_SIP|ISTAT_DIP))) + return; + else { + sim710_intrs++; + dsps = NCR_read32(DSPS_REG); + hostdata->state = STATE_HALTED; + sstat0 = dstat = 0; + scratch = NCR_read32(SCRATCH_REG); + if (istat & ISTAT_SIP) { + sstat0 = NCR_read8(SSTAT0_REG); + } + if (istat & ISTAT_DIP) { + udelay(10); /* Some comment somewhere about 10cycles + * between accesses to sstat0 and dstat ??? */ + dstat = NCR_read8(DSTAT_REG); + } + DEB(DEB_INTS, printk("scsi%d: Int %d, istat %02x, sstat0 %02x " + "dstat %02x, dsp [%04x], scratch %02x\n", + host->host_no, sim710_intrs, istat, sstat0, dstat, + (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script, + scratch)); + if (scratch & 0x100) { + u8 *p = hostdata->msgin_buf; + + DEB(DEB_INTS, printk(" msgin_buf: %02x %02x %02x %02x\n", + p[0], p[1], p[2], p[3])); + } + if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) { + /* Reselected. Identify the target from LCRC_REG, and + * update current command. If we were trying to select + * a device, then that command needs to go back on the + * issue_queue for later. + */ + unsigned char lcrc = NCR_read8(LCRC_REG_10); + int id = 0; + + if (!(lcrc & 0x7f)) { + printk("scsi%d: Reselected with LCRC = %02x\n", + host->host_no, lcrc); + cmd = NULL; + } + else { + while (!(lcrc & 1)) { + id++; + lcrc >>= 1; + } + DEB(DEB_DISC, printk("scsi%d: Reselected by ID %d\n", + host->host_no, id)); + if (hostdata->running) { + /* Clear SIGP */ + (void)NCR_read8(CTEST2_REG_700); + + DEB(DEB_DISC, printk("scsi%d: Select of %d interrupted " + "by reselect from %d (%p)\n", + host->host_no, hostdata->running->target, + id, hostdata->target[id].cur_cmd)); + cmd = hostdata->running; + hostdata->target[cmd->target].cur_cmd = NULL; + cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = cmd; + } + cmd = hostdata->running = hostdata->target[id].cur_cmd; + } + } + else + cmd = hostdata->running; + + if (!cmd) { + printk("scsi%d: No active command!\n", host->host_no); + printk("scsi%d: Int %d, istat %02x, sstat0 %02x " + "dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n", + host->host_no, sim710_intrs, istat, sstat0, dstat, + (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script, + NCR_read32(SCRATCH_REG), dsps); + /* resume_offset is zero, which will cause a host reset */ + } + else if (sstat0 & SSTAT0_700_STO) { + DEB(DEB_TOUT, printk("scsi%d: Selection timeout\n", host->host_no)); + cmd->result = DID_NO_CONNECT << 16; + SCSI_DONE(cmd); + hostdata->target[cmd->target].cur_cmd = NULL; + resume_offset = Ent_reselect; + } + else if (sstat0 & (SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) { + printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no, + sstat0); + sim710_errors++; + /* resume_offset is zero, which will cause a host reset */ + } + else if (dstat & (DSTAT_BF|DSTAT_ABRT|DSTAT_SSI|DSTAT_WTD)) { + printk("scsi%d: Serious error, dstat = %02x\n", host->host_no, + dstat); + sim710_errors++; + /* resume_offset is zero, which will cause a host reset */ + } + else if (dstat & DSTAT_SIR) + resume_offset = handle_script_int(host, cmd); + else if (sstat0 & SSTAT0_MA) + resume_offset = handle_phase_mismatch(host, cmd); + else if (dstat & DSTAT_IID) { + /* This can be due to a quick reselect while doing a WAIT + * DISCONNECT. + */ + resume_offset = handle_idd(host, cmd); + } + else { + sim710_errors++; + printk("scsi%d: Spurious interrupt!\n", host->host_no); + /* resume_offset is zero, which will cause a host reset */ + } + } + + if (resume_offset) { + if (resume_offset == Ent_reselect) { + hostdata->running = NULL; + hostdata->state = STATE_IDLE; + } + else + hostdata->state = STATE_BUSY; + DEB(DEB_RESUME, printk("scsi%d: Resuming at script[0x%x]\n", + host->host_no, resume_offset/4)); +#ifdef DEBUG_LIMIT_INTS + if (sim710_intrs < DEBUG_LIMIT_INTS) +#endif + { + NCR_write32(SCRATCH_REG, 0); + NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4)); + } + if (resume_offset == Ent_reselect) + run_process_issue_queue(hostdata); + } + else { + printk("scsi%d: Failed to handle interrupt. Failing commands " + "and resetting SCSI bus and chip\n", host->host_no); + mdelay(1000); /* Give chance to read screen!! */ + full_reset(host); + } +} + + int sim710_queuecommand(Scsi_Cmnd * cmd, void (*done)(Scsi_Cmnd *)) { diff -urN linux-2.4.27/drivers/sound/ac97_codec.c linux-2.4.28/drivers/sound/ac97_codec.c --- linux-2.4.27/drivers/sound/ac97_codec.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/sound/ac97_codec.c 2004-11-17 03:54:21.795405994 -0800 @@ -30,6 +30,9 @@ ************************************************************************** * * History + * Feb 25, 2004 Liam Girdwood + * Added support for codecs that require a warm reset to power up. + * Support for WM9713 * May 02, 2003 Liam Girdwood * Removed non existant WM9700 * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 @@ -71,6 +74,7 @@ static int wolfson_init04(struct ac97_codec * codec); static int wolfson_init05(struct ac97_codec * codec); static int wolfson_init11(struct ac97_codec * codec); +static int wolfson_init13(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); @@ -107,6 +111,7 @@ static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL }; static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL }; static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL }; +static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL }; static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL }; static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL }; static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL }; @@ -150,6 +155,7 @@ {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops}, {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops}, {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops}, + {0x43585430, "CXT48", &default_ops, AC97_DELUDED_MODEM }, {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM }, {0x44543031, "Diamond Technology DT0893", &default_ops}, {0x45838308, "ESS Allegro ES1988", &null_ops}, @@ -168,6 +174,7 @@ {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05}, {0x574D4C09, "Wolfson WM9709", &null_ops}, {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11}, + {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF}, {0x83847600, "SigmaTel STAC????", &null_ops}, {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops}, {0x83847605, "SigmaTel STAC9704", &null_ops}, @@ -793,6 +800,9 @@ * Currently codec_wait is used to wait for AC97 codec * reset to complete. * + * Some codecs will power down when a register reset is + * performed. We now check for such codecs. + * * Returns 1 (true) on success, or 0 (false) on failure. */ @@ -805,35 +815,18 @@ u16 f; struct list_head *l; struct ac97_driver *d; - - /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should - * be read zero. - * - * FIXME: is the following comment outdated? -jgarzik - * Probing of AC97 in this way is not reliable, it is not even SAFE !! - */ - codec->codec_write(codec, AC97_RESET, 0L); - /* also according to spec, we wait for codec-ready state */ + /* wait for codec-ready state */ if (codec->codec_wait) codec->codec_wait(codec); else udelay(10); - - if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { - printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", - (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") - : (codec->id&1 ? "Secondary": "Primary")); - return 0; - } - - /* probe for Modem Codec */ - codec->modem = ac97_check_modem(codec); - codec->name = NULL; - codec->codec_ops = &default_ops; - + + /* will the codec power down if register reset ? */ id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + codec->name = NULL; + codec->codec_ops = &null_ops; 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; @@ -843,11 +836,35 @@ break; } } - codec->model = (id1 << 16) | id2; + if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) { + /* reset codec and wait for the ready bit before we continue */ + codec->codec_write(codec, AC97_RESET, 0L); + if (codec->codec_wait) + codec->codec_wait(codec); + else + udelay(10); + } + /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should + * be read zero. + * + * FIXME: is the following comment outdated? -jgarzik + * Probing of AC97 in this way is not reliable, it is not even SAFE !! + */ + if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { + printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", + (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") + : (codec->id&1 ? "Secondary": "Primary")); + return 0; + } + + /* probe for Modem Codec */ + codec->modem = ac97_check_modem(codec); + + /* enable SPDIF */ f = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if(f & 4) + if((codec->codec_ops == &null_ops) && (f & 4)) codec->codec_ops = &default_digital_ops; /* A device which thinks its a modem but isnt */ @@ -916,11 +933,6 @@ codec->recmask_io = ac97_recmask_io; codec->mixer_ioctl = ac97_mixer_ioctl; - /* codec specific initialization for 4-6 channel output or secondary codec stuff */ - if (codec->codec_ops->init != NULL) { - codec->codec_ops->init(codec); - } - /* initialize mixer channel volumes */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { struct mixer_defaults *md = &mixer_defaults[i]; @@ -930,6 +942,11 @@ continue; ac97_set_mixer(codec, md->mixer, md->value); } + + /* codec specific initialization for 4-6 channel output or secondary codec stuff */ + if (codec->codec_ops->init != NULL) { + codec->codec_ops->init(codec); + } /* * Volume is MUTE only on this device. We have to initialise @@ -1085,6 +1102,19 @@ return 0; } +/* WM9713 */ +static int wolfson_init13(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0); + codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000); + codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00); + codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810); + codec->codec_write(codec, AC97_PHONE_VOL, 0x0808); + codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808); + + return 0; +} + static int tritech_init(struct ac97_codec * codec) { codec->codec_write(codec, 0x26, 0x0300); diff -urN linux-2.4.27/drivers/sound/i810_audio.c linux-2.4.28/drivers/sound/i810_audio.c --- linux-2.4.27/drivers/sound/i810_audio.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/sound/i810_audio.c 2004-11-17 03:54:21.798406117 -0800 @@ -304,6 +304,14 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2S_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP04_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768}, {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO, diff -urN linux-2.4.27/drivers/usb/audio.c linux-2.4.28/drivers/usb/audio.c --- linux-2.4.27/drivers/usb/audio.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/audio.c 2004-11-17 03:54:21.801406240 -0800 @@ -593,9 +593,10 @@ return 0; } -static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size) +static void dmabuf_copyin(struct dmabuf *db, const void *_buffer, unsigned int size) { unsigned int pgrem, rem; + const char *buffer = _buffer; db->total_bytes += size; for (;;) { @@ -609,16 +610,17 @@ pgrem = rem; memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->wrptr += pgrem; if (db->wrptr >= db->dmasize) db->wrptr = 0; } } -static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size) +static void dmabuf_copyout(struct dmabuf *db, void *_buffer, unsigned int size) { unsigned int pgrem, rem; + char *buffer = _buffer; db->total_bytes += size; for (;;) { @@ -632,16 +634,17 @@ pgrem = rem; memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->rdptr += pgrem; if (db->rdptr >= db->dmasize) db->rdptr = 0; } } -static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size) +static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *_buffer, unsigned int size) { unsigned int pgrem, rem; + const char *buffer = _buffer; if (!db->ready || db->mapped) return -EINVAL; @@ -657,16 +660,17 @@ if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; } } -static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size) +static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *_buffer, unsigned int size) { unsigned int pgrem, rem; + char *buffer = _buffer; if (!db->ready || db->mapped) return -EINVAL; @@ -682,7 +686,7 @@ if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; diff -urN linux-2.4.27/drivers/usb/devices.c linux-2.4.28/drivers/usb/devices.c --- linux-2.4.27/drivers/usb/devices.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/usb/devices.c 2004-11-17 03:54:21.802406282 -0800 @@ -387,22 +387,31 @@ if (start > end) return start; - + + /* + * Grab device's exclusive_access mutex to prevent its driver or + * devio from using this device while we are accessing it. + */ + down (&dev->exclusive_access); + start = usb_dump_device_descriptor(start, end, &dev->descriptor); if (start > end) - return start; - + goto out; + start = usb_dump_device_strings (start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) - return start; + goto out; start = usb_dump_config(dev->speed, start, end, dev->config + i, /* active ? */ (dev->config + i) == dev->actconfig); } + +out: + up (&dev->exclusive_access); return start; } @@ -543,9 +552,13 @@ /* Now look at all of this device's children. */ for (chix = 0; chix < usbdev->maxchild; chix++) { - if (usbdev->children[chix]) { - ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix], + struct usb_device *childdev = usbdev->children[chix]; + if (childdev) { + usb_inc_dev_use(childdev); + ret = usb_device_dump(buffer, nbytes, skip_bytes, + file_offset, childdev, bus, level + 1, chix, ++cnt); + usb_dec_dev_use(childdev); if (ret == -EFAULT) return total_written; total_written += ret; diff -urN linux-2.4.27/drivers/usb/devio.c linux-2.4.28/drivers/usb/devio.c --- linux-2.4.27/drivers/usb/devio.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/devio.c 2004-11-17 03:54:21.803406323 -0800 @@ -1158,6 +1158,13 @@ up_read(&ps->devsem); return -ENODEV; } + + /* + * grab device's exclusive_access mutex to prevent its driver from + * using this device while it is being accessed by us. + */ + down(&ps->dev->exclusive_access); + switch (cmd) { case USBDEVFS_CONTROL: ret = proc_control(ps, (void *)arg); @@ -1237,6 +1244,7 @@ ret = proc_ioctl(ps, (void *) arg); break; } + up(&ps->dev->exclusive_access); up_read(&ps->devsem); if (ret >= 0) inode->i_atime = CURRENT_TIME; diff -urN linux-2.4.27/drivers/usb/gadget/net2280.c linux-2.4.28/drivers/usb/gadget/net2280.c --- linux-2.4.27/drivers/usb/gadget/net2280.c 2004-04-14 06:05:32.000000000 -0700 +++ linux-2.4.28/drivers/usb/gadget/net2280.c 2004-11-17 03:54:21.804406364 -0800 @@ -537,7 +537,10 @@ } /* write just one packet at a time */ - count = min (ep->ep.maxpacket, total); + count = ep->ep.maxpacket; + if (count > total) /* min() cannot be used on a bitfield */ + count = total; + VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", ep->ep.name, count, (count != ep->ep.maxpacket) ? " (short)" : "", @@ -2191,7 +2194,8 @@ unsigned len; len = req->req.length - req->req.actual; - len = min (ep->ep.maxpacket, len); + if (len > ep->ep.maxpacket) + len = ep->ep.maxpacket; req->req.actual += len; /* if we wrote it all, we're usually done */ diff -urN linux-2.4.27/drivers/usb/hid-core.c linux-2.4.28/drivers/usb/hid-core.c --- linux-2.4.27/drivers/usb/hid-core.c 2004-04-14 06:05:32.000000000 -0700 +++ linux-2.4.28/drivers/usb/hid-core.c 2004-11-17 03:54:21.806406446 -0800 @@ -620,14 +620,16 @@ case 2: if ((end - start) >= 2) { - item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); + item->data.u16 = le16_to_cpu(get_unaligned((__u16*)start)); + start = (__u8 *)((__u16 *)start + 1); return start; } case 3: item->size++; if ((end - start) >= 4) { - item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); + item->data.u32 = le32_to_cpu(get_unaligned((__u32*)start)); + start = (__u8 *)((__u32 *)start + 1); return start; } } @@ -1457,8 +1459,8 @@ static void __exit hid_exit(void) { - hiddev_exit(); usb_deregister(&hid_driver); + hiddev_exit(); } module_init(hid_init); diff -urN linux-2.4.27/drivers/usb/host/ehci-hcd.c linux-2.4.28/drivers/usb/host/ehci-hcd.c --- linux-2.4.27/drivers/usb/host/ehci-hcd.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/host/ehci-hcd.c 2004-11-17 03:54:21.807406487 -0800 @@ -303,7 +303,8 @@ if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + pci_write_config_dword (ehci->hcd.pdev, where, 0); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } @@ -547,7 +548,8 @@ /* root hub is shut down separately (first, when possible) */ spin_lock_irq (&ehci->lock); - ehci_work (ehci, NULL); + if (ehci->async) + ehci_work (ehci, NULL); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); diff -urN linux-2.4.27/drivers/usb/host/hc_sl811.c linux-2.4.28/drivers/usb/host/hc_sl811.c --- linux-2.4.27/drivers/usb/host/hc_sl811.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.28/drivers/usb/host/hc_sl811.c 2004-11-17 03:54:21.808406528 -0800 @@ -117,9 +117,6 @@ static int urb_debug = 0; -#include "hc_simple.c" -#include "hc_sl811_rh.c" - /* Include hardware and board depens */ #include @@ -601,6 +598,9 @@ return 0; } +#include "hc_simple.c" +#include "hc_sl811_rh.c" + /************************************************************************ * Function Name : hc_start_int * diff -urN linux-2.4.27/drivers/usb/host/usb-uhci.c linux-2.4.28/drivers/usb/host/usb-uhci.c --- linux-2.4.27/drivers/usb/host/usb-uhci.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/usb/host/usb-uhci.c 2004-11-17 03:54:21.810406611 -0800 @@ -2746,13 +2746,8 @@ dbg("interrupt"); if (status != 1) { - // Avoid too much error messages at a time - if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) { - warn("interrupt, status %x, frame# %i", status, - UHCI_GET_CURRENT_FRAME(s)); - s->last_error_time = jiffies; - } - + dbg("status %x, frame# %i", status, UHCI_GET_CURRENT_FRAME(s)); + // remove host controller halted state if ((status&0x20) && (s->running)) { err("Host controller halted, trying to restart."); diff -urN linux-2.4.27/drivers/usb/host/usb-uhci.h linux-2.4.28/drivers/usb/host/usb-uhci.h --- linux-2.4.27/drivers/usb/host/usb-uhci.h 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/usb/host/usb-uhci.h 2004-11-17 03:54:21.810406611 -0800 @@ -218,7 +218,6 @@ int timeout_urbs; struct pci_dev *uhci_pci; struct pci_pool *desc_pool; - long last_error_time; // last error output in uhci_interrupt() } uhci_t, *puhci_t; diff -urN linux-2.4.27/drivers/usb/hpusbscsi.c linux-2.4.28/drivers/usb/hpusbscsi.c --- linux-2.4.27/drivers/usb/hpusbscsi.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/usb/hpusbscsi.c 2004-11-17 03:54:21.811406652 -0800 @@ -182,7 +182,7 @@ memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template, sizeof (hpusbscsi_scsi_host_template)); - (struct hpusbscsi *) new->ctempl.proc_dir = new; + new->ctempl.proc_dir = (void *) new; new->ctempl.module = THIS_MODULE; if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl))) diff -urN linux-2.4.27/drivers/usb/kaweth.c linux-2.4.28/drivers/usb/kaweth.c --- linux-2.4.27/drivers/usb/kaweth.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/usb/kaweth.c 2004-11-17 03:54:21.843407967 -0800 @@ -735,7 +735,7 @@ } } - private_header = __skb_push(skb, 2); + private_header = (u16 *)__skb_push(skb, 2); *private_header = cpu_to_le16(skb->len-2); kaweth->tx_skb = skb; diff -urN linux-2.4.27/drivers/usb/microtek.c linux-2.4.28/drivers/usb/microtek.c --- linux-2.4.27/drivers/usb/microtek.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/usb/microtek.c 2004-11-17 03:54:21.844408008 -0800 @@ -987,7 +987,7 @@ /* Initialize the host template based on the default one */ memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); /* HACK from usb-storage - this is needed for scsi detection */ - (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */ + new_desc->ctempl.proc_dir = (void *)new_desc; /* FIXME */ MTS_DEBUG("registering SCSI module\n"); diff -urN linux-2.4.27/drivers/usb/ov511.c linux-2.4.28/drivers/usb/ov511.c --- linux-2.4.27/drivers/usb/ov511.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.28/drivers/usb/ov511.c 2004-11-17 03:54:21.848408173 -0800 @@ -334,8 +334,8 @@ **********************************************************************/ static void ov51x_clear_snapshot(struct usb_ov511 *); -static inline int sensor_get_picture(struct usb_ov511 *, - struct video_picture *); +static int sensor_get_picture(struct usb_ov511 *, + struct video_picture *); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, @@ -2014,7 +2014,7 @@ return 0; } -static inline int +static int sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; diff -urN linux-2.4.27/drivers/usb/se401.c linux-2.4.28/drivers/usb/se401.c --- linux-2.4.27/drivers/usb/se401.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/usb/se401.c 2004-11-17 03:54:21.849408214 -0800 @@ -986,6 +986,44 @@ return 0; } +static inline void usb_se401_remove_disconnected (struct usb_se401 *se401) +{ + int i; + + se401->dev = NULL; + se401->frame[0].grabstate = FRAME_ERROR; + se401->frame[1].grabstate = FRAME_ERROR; + + se401->streaming = 0; + + wake_up_interruptible(&se401->wq); + + for (i=0; iurb[i]) { + se401->urb[i]->next = NULL; + usb_unlink_urb(se401->urb[i]); + usb_free_urb(se401->urb[i]); + se401->urb[i] = NULL; + kfree(se401->sbuf[i].data); + } + for (i=0; iscratch[i].data) { + kfree(se401->scratch[i].data); + } + if (se401->inturb) { + usb_unlink_urb(se401->inturb); + usb_free_urb(se401->inturb); + } + info("%s disconnected", se401->camera_name); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + destroy_proc_se401_cam(se401); +#endif + + /* Free the memory */ + kfree(se401->width); + kfree(se401->height); + kfree(se401); +} + /**************************************************************************** * @@ -1531,44 +1569,6 @@ unlock_kernel(); } -static inline void usb_se401_remove_disconnected (struct usb_se401 *se401) -{ - int i; - - se401->dev = NULL; - se401->frame[0].grabstate = FRAME_ERROR; - se401->frame[1].grabstate = FRAME_ERROR; - - se401->streaming = 0; - - wake_up_interruptible(&se401->wq); - - for (i=0; iurb[i]) { - se401->urb[i]->next = NULL; - usb_unlink_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - kfree(se401->sbuf[i].data); - } - for (i=0; iscratch[i].data) { - kfree(se401->scratch[i].data); - } - if (se401->inturb) { - usb_unlink_urb(se401->inturb); - usb_free_urb(se401->inturb); - } - info("%s disconnected", se401->camera_name); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_se401_cam(se401); -#endif - - /* Free the memory */ - kfree(se401->width); - kfree(se401->height); - kfree(se401); -} - static struct usb_driver se401_driver = { name: "se401", id_table: device_table, diff -urN linux-2.4.27/drivers/usb/serial/usbserial.c linux-2.4.28/drivers/usb/serial/usbserial.c --- linux-2.4.27/drivers/usb/serial/usbserial.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/serial/usbserial.c 2004-11-17 03:54:21.851408296 -0800 @@ -508,8 +508,18 @@ down(&port->sem); dbg("%s - port %d len %d backlog %d", __FUNCTION__, port->number, job->len, port->write_backlog); - if (port->tty != NULL) - __serial_write(port, 0, job->buff, job->len); + if (port->tty != NULL) { + int rc; + int sent = 0; + while (sent < job->len) { + rc = __serial_write(port, 0, job->buff + sent, job->len - sent); + if ((rc < 0) || signal_pending(current)) + break; + sent += rc; + if ((sent < job->len) && current->need_resched) + schedule(); + } + } up(&port->sem); spin_lock_irqsave(&post_lock, flags); diff -urN linux-2.4.27/drivers/usb/storage/scsiglue.c linux-2.4.28/drivers/usb/storage/scsiglue.c --- linux-2.4.27/drivers/usb/storage/scsiglue.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/storage/scsiglue.c 2004-11-17 03:54:21.852408337 -0800 @@ -127,7 +127,7 @@ wait_for_completion(&(us->notify)); /* remove the pointer to the data structure we were using */ - (struct us_data*)psh->hostdata[0] = NULL; + psh->hostdata[0] = (unsigned long)NULL; /* we always have a successful release */ return 0; diff -urN linux-2.4.27/drivers/usb/storage/sddr09.c linux-2.4.28/drivers/usb/storage/sddr09.c --- linux-2.4.27/drivers/usb/storage/sddr09.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/usb/storage/sddr09.c 2004-11-17 03:54:21.853408379 -0800 @@ -444,6 +444,7 @@ * byte 0: opcode: 03 * byte 4: data length */ +#if 0 static int sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { unsigned char command[12] = { @@ -465,7 +466,7 @@ return result; } - +#endif /* * Read Command: 12 bytes. * byte 0: opcode: E8 diff -urN linux-2.4.27/drivers/usb/storage/transport.c linux-2.4.28/drivers/usb/storage/transport.c --- linux-2.4.27/drivers/usb/storage/transport.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/usb/storage/transport.c 2004-11-17 03:54:21.854408420 -0800 @@ -627,8 +627,17 @@ int need_auto_sense; int result; + /* + * Grab device's exclusive_access mutex to prevent libusb/usbfs from + * sending out a command in the middle of ours (if libusb sends a + * get_descriptor or something on pipe 0 after our CBW and before + * our CSW, and then we get a stall, we have trouble). + */ + down(&(us->pusb_dev->exclusive_access)); + /* send the command to the transport layer */ result = us->transport(srb, us); + up(&(us->pusb_dev->exclusive_access)); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing @@ -748,7 +757,9 @@ srb->use_sg = 0; /* issue the auto-sense command */ + down(&(us->pusb_dev->exclusive_access)); temp_result = us->transport(us->srb, us); + up(&(us->pusb_dev->exclusive_access)); /* let's clean up right away */ srb->request_buffer = old_request_buffer; diff -urN linux-2.4.27/drivers/usb/storage/unusual_devs.h linux-2.4.28/drivers/usb/storage/unusual_devs.h --- linux-2.4.27/drivers/usb/storage/unusual_devs.h 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/storage/unusual_devs.h 2004-11-17 03:54:21.855408461 -0800 @@ -153,6 +153,16 @@ "CD-R/RW Drive", US_SC_8070, US_PR_CB, NULL, 0), +/* Reported by Adriaan Penning + * Note that these cameras report "Medium not present" after + * ALLOW_MEDIUM_REMOVAL, so they also need to be marked + * NOT_LOCKABLE in the SCSI blacklist (and the vendor is MATSHITA). */ +UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999, + "Panasonic", + "DMC-LCx Camera", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -430,6 +440,13 @@ US_FL_SINGLE_LUN ), #endif +/* Reported by Darsen Lu */ +UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, + "SigmaTel", + "USBMSC Audio Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Submitted by Benny Sjostrand */ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, "Minolta", @@ -679,7 +696,7 @@ UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001, "Minds@Work", "Digital Wallet", - US_SC_SCSI, US_PR_CB, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, diff -urN linux-2.4.27/drivers/usb/storage/usb.c linux-2.4.28/drivers/usb/storage/usb.c --- linux-2.4.27/drivers/usb/storage/usb.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/storage/usb.c 2004-11-17 03:54:21.856408502 -0800 @@ -994,7 +994,7 @@ * the host controller thread in us_detect. But how else are * we to do it? */ - (struct us_data *)ss->htmplt.proc_dir = ss; + ss->htmplt.proc_dir = (void *)ss; /* Just before we start our control thread, initialize * the device if it needs initialization */ diff -urN linux-2.4.27/drivers/usb/usb.c linux-2.4.28/drivers/usb/usb.c --- linux-2.4.27/drivers/usb/usb.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/usb/usb.c 2004-11-17 03:54:21.917411010 -0800 @@ -989,6 +989,7 @@ INIT_LIST_HEAD(&dev->filelist); init_MUTEX(&dev->serialize); + init_MUTEX(&dev->exclusive_access); dev->bus->op->allocate(dev); diff -urN linux-2.4.27/drivers/usb/uss720.c linux-2.4.28/drivers/usb/uss720.c --- linux-2.4.27/drivers/usb/uss720.c 2001-10-20 19:13:11.000000000 -0700 +++ linux-2.4.28/drivers/usb/uss720.c 2004-11-17 03:54:21.918411051 -0800 @@ -327,13 +327,14 @@ { struct parport_uss720_private *priv = pp->private_data; size_t got = 0; + char *buff = buf; if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { - if (get_1284_register(pp, 4, (char *)buf)) + if (get_1284_register(pp, 4, buff)) break; - ((char*)buf)++; + buff++; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; @@ -348,13 +349,14 @@ #if 0 struct parport_uss720_private *priv = pp->private_data; size_t written = 0; + const char *buff = buf; if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { - if (set_1284_register(pp, 4, (char *)buf)) + if (set_1284_register(pp, 4, *buff)) break; - ((char*)buf)++; + buff++; if (get_1284_register(pp, 1, NULL)) break; if (priv->reg[0] & 0x01) { @@ -386,13 +388,14 @@ { struct parport_uss720_private *priv = pp->private_data; size_t got = 0; + char *buff = buf; if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { - if (get_1284_register(pp, 3, (char *)buf)) + if (get_1284_register(pp, 3, buff)) break; - ((char*)buf)++; + buff++; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; @@ -406,13 +409,14 @@ { struct parport_uss720_private *priv = pp->private_data; size_t written = 0; + const char *buff = buf; if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { - if (set_1284_register(pp, 3, *(char *)buf)) + if (set_1284_register(pp, 3, *buff)) break; - ((char*)buf)++; + buff++; if (get_1284_register(pp, 1, NULL)) break; if (priv->reg[0] & 0x01) { @@ -463,13 +467,14 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags) { size_t written = 0; + const char *buff = buffer; if (change_mode(pp, ECR_ECP)) return 0; for (; written < len; written++) { - if (set_1284_register(pp, 5, *(char *)buffer)) + if (set_1284_register(pp, 5, *buff)) break; - ((char*)buffer)++; + buff++; } change_mode(pp, ECR_PS2); return written; diff -urN linux-2.4.27/drivers/usb/w9968cf.c linux-2.4.28/drivers/usb/w9968cf.c --- linux-2.4.27/drivers/usb/w9968cf.c 2004-04-14 06:05:37.000000000 -0700 +++ linux-2.4.28/drivers/usb/w9968cf.c 2004-11-17 03:54:21.921411174 -0800 @@ -446,8 +446,8 @@ /* High-level CMOS sensor control functions */ static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); -static inline int w9968cf_sensor_cmd(struct w9968cf_device*, - unsigned int cmd, void *arg); +static int w9968cf_sensor_cmd(struct w9968cf_device*, + unsigned int cmd, void *arg); static int w9968cf_sensor_init(struct w9968cf_device*); static int w9968cf_sensor_update_settings(struct w9968cf_device*); static int w9968cf_sensor_get_picture(struct w9968cf_device*); @@ -463,7 +463,7 @@ static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); static int w9968cf_set_window(struct w9968cf_device*, struct video_window); static inline u16 w9968cf_valid_palette(u16 palette); -static inline u16 w9968cf_valid_depth(u16 palette); +static u16 w9968cf_valid_depth(u16 palette); static inline u8 w9968cf_need_decompression(u16 palette); static int w9968cf_postprocess_frame(struct w9968cf_device*, struct w9968cf_frame_t*); @@ -2214,7 +2214,7 @@ Return the depth corresponding to the given palette. Palette _must_ be supported ! --------------------------------------------------------------------------*/ -static inline u16 w9968cf_valid_depth(u16 palette) +static u16 w9968cf_valid_depth(u16 palette) { u8 i=0; while (w9968cf_formatlist[i].palette != palette) @@ -2433,7 +2433,7 @@ } -static inline int +static int w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) { struct i2c_client* c = cam->sensor_client; diff -urN linux-2.4.27/drivers/video/amifb.c linux-2.4.28/drivers/video/amifb.c --- linux-2.4.27/drivers/video/amifb.c 2004-04-14 06:05:37.000000000 -0700 +++ linux-2.4.28/drivers/video/amifb.c 2004-11-17 03:54:21.923411257 -0800 @@ -1605,19 +1605,6 @@ return -ENXIO; /* - * TODO: where should we put this? The DMI Resolver doesn't have a - * frame buffer accessible by the CPU - */ - -#ifdef CONFIG_GSP_RESOLVER - if (amifb_resolver){ - custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | - DMAF_BLITTER | DMAF_SPRITE; - return 0; - } -#endif - - /* * We request all registers starting from bplpt[0] */ if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120, diff -urN linux-2.4.27/drivers/video/fbcon.c linux-2.4.28/drivers/video/fbcon.c --- linux-2.4.27/drivers/video/fbcon.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/video/fbcon.c 2004-11-17 03:54:21.926411380 -0800 @@ -660,9 +660,8 @@ if (logo) { /* Need to make room for the logo */ - int cnt; - int step; - + int cnt, step, erase_char; + logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p); q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); step = logo_lines * old_cols; @@ -692,8 +691,10 @@ conp->vc_pos += logo_lines * conp->vc_size_row; } } - scr_memsetw((unsigned short *)conp->vc_origin, - conp->vc_video_erase_char, + erase_char = conp->vc_video_erase_char; + if (! conp->vc_can_do_color) + erase_char &= ~0x400; /* disable underline */ + scr_memsetw((unsigned short *)conp->vc_origin, erase_char, conp->vc_size_row * logo_lines); } @@ -1877,7 +1878,10 @@ font length must be multiple of 256, at least. And 256 is multiple of 4 */ k = 0; - while (p > new_data) k += *--(u32 *)p; + while (p > new_data) { + p = (u8 *)((u32 *)p - 1); + k += *(u32 *) p; + } FNTSUM(new_data) = k; /* Check if the same font is on some other console already */ for (i = 0; i < MAX_NR_CONSOLES; i++) { diff -urN linux-2.4.27/drivers/video/matrox/matroxfb_base.h linux-2.4.28/drivers/video/matrox/matroxfb_base.h --- linux-2.4.27/drivers/video/matrox/matroxfb_base.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.28/drivers/video/matrox/matroxfb_base.h 2004-11-17 03:54:21.927411421 -0800 @@ -253,21 +253,21 @@ #ifdef MEMCPYTOIO_WORKS memcpy_toio(va.vaddr + offs, src, len); #elif defined(MEMCPYTOIO_WRITEL) -#define srcd ((const u_int32_t*)src) if (offs & 3) { while (len >= 4) { - mga_writel(va, offs, get_unaligned(srcd++)); + mga_writel(va, offs, get_unaligned((u32 *)src)); offs += 4; len -= 4; + src += 4; } } else { while (len >= 4) { - mga_writel(va, offs, *srcd++); + mga_writel(va, offs, *(u32 *)src); offs += 4; len -= 4; + src += 4; } } -#undef srcd if (len) { u_int32_t tmp; diff -urN linux-2.4.27/drivers/video/matrox/matroxfb_g450.c linux-2.4.28/drivers/video/matrox/matroxfb_g450.c --- linux-2.4.27/drivers/video/matrox/matroxfb_g450.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.28/drivers/video/matrox/matroxfb_g450.c 2004-11-17 03:54:21.928411462 -0800 @@ -558,7 +558,7 @@ } static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) { - MINFO_FROM(md); +// MINFO_FROM(md); switch (arg) { case MATROXFB_OUTPUT_MODE_PAL: diff -urN linux-2.4.27/drivers/video/pm3fb.c linux-2.4.28/drivers/video/pm3fb.c --- linux-2.4.27/drivers/video/pm3fb.c 2004-04-14 06:05:38.000000000 -0700 +++ linux-2.4.28/drivers/video/pm3fb.c 2004-11-17 03:54:21.931411586 -0800 @@ -3838,11 +3838,9 @@ (unsigned char *) -1) { pm3fb_unmapIO(l_fb_info); #if (defined KERNEL_2_4) || (defined KERNEL_2_5) - release_mem_region(l_fb_info->p_fb, - l_fb_info-> - fb_size); - release_mem_region(l_fb_info-> - pIOBase, + release_mem_region((u_long)l_fb_info->p_fb, + l_fb_info->fb_size); + release_mem_region((u_long)l_fb_info->pIOBase, PM3_REGS_SIZE); #endif /* KERNEL_2_4 or KERNEL_2_5 */ } diff -urN linux-2.4.27/drivers/video/radeonfb.c linux-2.4.28/drivers/video/radeonfb.c --- linux-2.4.27/drivers/video/radeonfb.c 2004-04-14 06:05:39.000000000 -0700 +++ linux-2.4.28/drivers/video/radeonfb.c 2004-11-17 03:54:21.936411791 -0800 @@ -935,6 +935,7 @@ #endif /* CONFIG_PMAC_BACKLIGHT */ static struct fb_ops radeon_fb_ops = { + owner: THIS_MODULE, fb_get_fix: radeonfb_get_fix, fb_get_var: radeonfb_get_var, fb_set_var: radeonfb_set_var, @@ -2368,7 +2369,7 @@ disp->visual = FB_VISUAL_DIRECTCOLOR; v.red.offset = 10; v.green.offset = 5; - v.red.offset = 0; + v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 5; v.transp.offset = v.transp.length = 0; break; diff -urN linux-2.4.27/drivers/video/riva/accel.c linux-2.4.28/drivers/video/riva/accel.c --- linux-2.4.27/drivers/video/riva/accel.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/video/riva/accel.c 2004-11-17 03:54:21.937411832 -0800 @@ -153,8 +153,10 @@ for (j = 0; j < cnt; j++) { if (w <= 8) cdat2 = *cdat++; - else - cdat2 = *((u16*)cdat)++; + else { + cdat2 = *(u16*)cdat; + cdat += sizeof(u16); + } fbcon_reverse_order(&cdat2); d[j] = cdat2; } diff -urN linux-2.4.27/drivers/video/riva/fbdev.c linux-2.4.28/drivers/video/riva/fbdev.c --- linux-2.4.27/drivers/video/riva/fbdev.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/video/riva/fbdev.c 2004-11-17 03:54:21.939411914 -0800 @@ -117,7 +117,7 @@ static void rivafb_blank(int blank, struct fb_info *info); extern void riva_setup_accel(struct rivafb_info *rinfo); -extern inline void wait_for_idle(struct rivafb_info *rinfo); +extern void wait_for_idle(struct rivafb_info *rinfo); @@ -2221,7 +2221,6 @@ release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size); err_out_free_base0: release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size); -err_out_kfree: kfree(rinfo); err_out: return -ENODEV; diff -urN linux-2.4.27/drivers/video/sstfb.c linux-2.4.28/drivers/video/sstfb.c --- linux-2.4.27/drivers/video/sstfb.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/video/sstfb.c 2004-11-17 03:54:21.940411956 -0800 @@ -968,7 +968,6 @@ struct fb_info *info) { #define sst_info ((struct sstfb_info *) info) - int i; u_long p; u32 tmp, val; u32 fbiinit0; @@ -980,12 +979,14 @@ #if (SST_DEBUG_VAR >0) /* tmp ioctl : dumps fb_display[0-5] */ - case _IO('F', 0xdb): /* 0x46db */ + case _IO('F', 0xdb): /* 0x46db */ { + int i; f_dprintk("dumping fb_display[0-5].var\n"); for (i = 0 ; i< 6 ; i++) { print_var(&fb_display[i].var, "var(%d)", i); } return 0; + } #endif /* (SST_DEBUG_VAR >0) */ /* fills the lfb up to given count of pixels */ diff -urN linux-2.4.27/fs/Config.in linux-2.4.28/fs/Config.in --- linux-2.4.27/fs/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/fs/Config.in 2004-11-17 03:54:21.941411997 -0800 @@ -121,7 +121,7 @@ dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD - dep_mbool ' Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL + dep_mbool ' Provide NFS server over TCP support' CONFIG_NFSD_TCP $CONFIG_NFSD if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y diff -urN linux-2.4.27/fs/affs/super.c linux-2.4.28/fs/affs/super.c --- linux-2.4.27/fs/affs/super.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/fs/affs/super.c 2004-11-17 03:54:21.941411997 -0800 @@ -130,7 +130,7 @@ printk("AFFS: Argument for set[ug]id option missing\n"); return 0; } else { - (f ? *uid : *gid) = simple_strtoul(value,&value,0); + *(f ? uid : gid) = simple_strtoul(value,&value,0); if (*value) { printk("AFFS: Bad set[ug]id argument\n"); return 0; diff -urN linux-2.4.27/fs/befs/btree.c linux-2.4.28/fs/befs/btree.c --- linux-2.4.27/fs/befs/btree.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.28/fs/befs/btree.c 2004-11-17 03:54:21.942412038 -0800 @@ -85,7 +85,7 @@ } befs_btree_node; /* local constants */ -const static befs_off_t befs_bt_inval = 0xffffffffffffffff; +const static befs_off_t befs_bt_inval = 0xffffffffffffffffULL; /* local functions */ static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, diff -urN linux-2.4.27/fs/befs/linuxvfs.c linux-2.4.28/fs/befs/linuxvfs.c --- linux-2.4.27/fs/befs/linuxvfs.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.28/fs/befs/linuxvfs.c 2004-11-17 03:54:21.943412079 -0800 @@ -55,13 +55,6 @@ static int befs_statfs(struct super_block *, struct statfs *); static int parse_options(char *, befs_mount_options *); -static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size); -static ssize_t befs_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size); -static int befs_setxattr(struct dentry *dentry, const char *name, void *value, - size_t size, int flags); -static int befs_removexattr(struct dentry *dentry, const char *name); - /* slab cache for befs_inode_info objects */ static kmem_cache_t *befs_inode_cachep; @@ -584,11 +577,11 @@ } } result[o] = '\0'; + *out_len = o; befs_debug(sb, "<--- utf2nls()"); return o; - *out_len = o; conv_err: befs_error(sb, "Name using charecter set %s contains a charecter that " @@ -675,35 +668,6 @@ return -EILSEQ; } -/****Xattr****/ - -static ssize_t -befs_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - printk(KERN_ERR "befs_listxattr called\n"); - return 0; -} - -static ssize_t -befs_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size) -{ - return 0; -} - -static int -befs_setxattr(struct dentry *dentry, const char *name, - void *value, size_t size, int flags) -{ - return 0; -} - -static int -befs_removexattr(struct dentry *dentry, const char *name) -{ - return 0; -} - /****Superblock****/ static int diff -urN linux-2.4.27/fs/binfmt_elf.c linux-2.4.28/fs/binfmt_elf.c --- linux-2.4.27/fs/binfmt_elf.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/binfmt_elf.c 2004-11-17 03:54:21.944412120 -0800 @@ -299,9 +299,12 @@ goto out; retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size); - error = retval; - if (retval < 0) + error = -EIO; + if (retval != size) { + if (retval < 0) + error = retval; goto out_close; + } eppnt = elf_phdata; for (i=0; ie_phnum; i++, eppnt++) { @@ -375,7 +378,6 @@ unsigned long text_data, elf_entry = ~0UL; char * addr; loff_t offset; - int retval; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; @@ -397,11 +399,9 @@ } do_brk(0, text_data); - retval = -ENOEXEC; if (!interpreter->f_op || !interpreter->f_op->read) goto out; - retval = interpreter->f_op->read(interpreter, addr, text_data, &offset); - if (retval < 0) + if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); @@ -475,9 +475,12 @@ goto out; retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size); - if (retval < 0) + if (retval != size) { + if (retval >= 0) + retval = -EIO; goto out_free_ph; - + } + files = current->files; /* Refcounted so ok */ retval = unshare_files(); if (retval < 0) @@ -513,7 +516,8 @@ */ retval = -ENOMEM; - if (elf_ppnt->p_filesz > PATH_MAX) + if (elf_ppnt->p_filesz > PATH_MAX || + elf_ppnt->p_filesz == 0) goto out_free_file; elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); @@ -523,8 +527,16 @@ retval = kernel_read(bprm->file, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz); - if (retval < 0) + if (retval != elf_ppnt->p_filesz) { + if (retval >= 0) + retval = -EIO; goto out_free_interp; + } + /* make sure path is NULL terminated */ + retval = -EINVAL; + if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') + goto out_free_interp; + /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. @@ -543,8 +555,11 @@ if (IS_ERR(interpreter)) goto out_free_interp; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); - if (retval < 0) + if (retval != BINPRM_BUF_SIZE) { + if (retval >= 0) + retval = -EIO; goto out_free_dentry; + } /* Get the exec headers */ interp_ex = *((struct exec *) bprm->buf); @@ -682,8 +697,10 @@ } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); - if (BAD_ADDR(error)) - continue; + if (BAD_ADDR(error)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } if (!load_addr_set) { load_addr_set = 1; diff -urN linux-2.4.27/fs/buffer.c linux-2.4.28/fs/buffer.c --- linux-2.4.27/fs/buffer.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/fs/buffer.c 2004-11-17 03:54:21.946412202 -0800 @@ -160,7 +160,7 @@ ll_rw_block(WRITE, 1, &bh); } -void unlock_buffer(struct buffer_head *bh) +void fastcall unlock_buffer(struct buffer_head *bh) { clear_bit(BH_Wait_IO, &bh->b_state); clear_bit(BH_Launder, &bh->b_state); @@ -371,6 +371,7 @@ } return err; } +EXPORT_SYMBOL(sync_buffers); int fsync_super(struct super_block *sb) { @@ -649,7 +650,7 @@ return bh; } -void buffer_insert_list(struct buffer_head *bh, struct list_head *list) +void fastcall buffer_insert_list(struct buffer_head *bh, struct list_head *list) { spin_lock(&lru_list_lock); if (buffer_attached(bh)) @@ -1092,7 +1093,7 @@ } EXPORT_SYMBOL(balance_dirty); -inline void __mark_dirty(struct buffer_head *bh) +inline void fastcall __mark_dirty(struct buffer_head *bh) { bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer; refile_buffer(bh); @@ -1100,13 +1101,13 @@ /* atomic version, the user must call balance_dirty() by hand as soon as it become possible to block */ -void __mark_buffer_dirty(struct buffer_head *bh) +void fastcall __mark_buffer_dirty(struct buffer_head *bh) { if (!atomic_set_buffer_dirty(bh)) __mark_dirty(bh); } -void mark_buffer_dirty(struct buffer_head *bh) +void fastcall mark_buffer_dirty(struct buffer_head *bh) { if (!atomic_set_buffer_dirty(bh)) { if (block_dump) @@ -1122,7 +1123,7 @@ } EXPORT_SYMBOL(set_buffer_flushtime); -inline int get_buffer_flushtime(void) +int get_buffer_flushtime(void) { return bdf_prm.b_un.interval; } @@ -1260,8 +1261,9 @@ /* * If we need an async buffer, use the reserved buffer heads. + * Non-PF_MEMALLOC tasks can just loop in create_buffers(). */ - if (async) { + if (async && (current->flags & PF_MEMALLOC)) { spin_lock(&unused_list_lock); if (unused_list) { bh = unused_list; @@ -2730,7 +2732,7 @@ * obtain a reference to a buffer head within a page. So we must * lock out all of these paths to cleanly toss the page. */ -int try_to_free_buffers(struct page * page, unsigned int gfp_mask) +int fastcall try_to_free_buffers(struct page * page, unsigned int gfp_mask) { struct buffer_head * tmp, * bh = page->buffers; diff -urN linux-2.4.27/fs/dcache.c linux-2.4.28/fs/dcache.c --- linux-2.4.27/fs/dcache.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.28/fs/dcache.c 2004-11-17 03:54:21.947412243 -0800 @@ -55,7 +55,10 @@ /* Statistics gathering. */ struct dentry_stat_t dentry_stat = {0, 0, 45, 0,}; -/* no dcache_lock, please */ +/* + * no dcache_lock, please. The caller must decrement dentry_stat.nr_dentry + * inside dcache_lock. + */ static inline void d_free(struct dentry *dentry) { if (dentry->d_op && dentry->d_op->d_release) @@ -63,7 +66,6 @@ if (dname_external(dentry)) kfree(dentry->d_name.name); kmem_cache_free(dentry_cache, dentry); - dentry_stat.nr_dentry--; } /* @@ -148,6 +150,7 @@ kill_it: { struct dentry *parent; list_del(&dentry->d_child); + dentry_stat.nr_dentry--; /* For d_free, below */ /* drops the lock, at that point nobody can reach this dentry */ dentry_iput(dentry); parent = dentry->d_parent; @@ -297,6 +300,7 @@ list_del_init(&dentry->d_hash); list_del(&dentry->d_child); + dentry_stat.nr_dentry--; /* For d_free, below */ dentry_iput(dentry); parent = dentry->d_parent; d_free(dentry); @@ -623,13 +627,15 @@ if (parent) { dentry->d_parent = dget(parent); dentry->d_sb = parent->d_sb; - spin_lock(&dcache_lock); - list_add(&dentry->d_child, &parent->d_subdirs); - spin_unlock(&dcache_lock); } else INIT_LIST_HEAD(&dentry->d_child); + spin_lock(&dcache_lock); + if (parent) + list_add(&dentry->d_child, &parent->d_subdirs); dentry_stat.nr_dentry++; + spin_unlock(&dcache_lock); + return dentry; } diff -urN linux-2.4.27/fs/ext3/super.c linux-2.4.28/fs/ext3/super.c --- linux-2.4.27/fs/ext3/super.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/fs/ext3/super.c 2004-11-17 03:54:21.949412326 -0800 @@ -1302,6 +1302,7 @@ if (!journal) { printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); iput(journal_inode); + return NULL; } ext3_init_journal_params(EXT3_SB(sb), journal); return journal; diff -urN linux-2.4.27/fs/file_table.c linux-2.4.28/fs/file_table.c --- linux-2.4.27/fs/file_table.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/fs/file_table.c 2004-11-17 03:54:21.949412326 -0800 @@ -97,7 +97,7 @@ return 0; } -void fput(struct file * file) +void fastcall fput(struct file * file) { struct dentry * dentry = file->f_dentry; struct vfsmount * mnt = file->f_vfsmnt; @@ -126,7 +126,7 @@ } } -struct file * fget(unsigned int fd) +struct file fastcall *fget(unsigned int fd) { struct file * file; struct files_struct *files = current->files; diff -urN linux-2.4.27/fs/freevxfs/vxfs_extern.h linux-2.4.28/fs/freevxfs/vxfs_extern.h --- linux-2.4.27/fs/freevxfs/vxfs_extern.h 2002-02-25 11:38:08.000000000 -0800 +++ linux-2.4.28/fs/freevxfs/vxfs_extern.h 2004-11-17 03:54:21.950412367 -0800 @@ -72,7 +72,7 @@ /* vxfs_subr.c */ extern struct page * vxfs_get_page(struct address_space *, u_long); -extern __inline__ void vxfs_put_page(struct page *); +extern void vxfs_put_page(struct page *); extern struct buffer_head * vxfs_bread(struct inode *, int); #endif /* _VXFS_EXTERN_H_ */ diff -urN linux-2.4.27/fs/freevxfs/vxfs_subr.c linux-2.4.28/fs/freevxfs/vxfs_subr.c --- linux-2.4.27/fs/freevxfs/vxfs_subr.c 2002-02-25 11:38:08.000000000 -0800 +++ linux-2.4.28/fs/freevxfs/vxfs_subr.c 2004-11-17 03:54:21.950412367 -0800 @@ -50,6 +50,12 @@ .sync_page = block_sync_page, }; +__inline__ void +vxfs_put_page(struct page *pp) +{ + kunmap(pp); + page_cache_release(pp); +} /** * vxfs_get_page - read a page into memory. @@ -88,13 +94,6 @@ return ERR_PTR(-EIO); } -__inline__ void -vxfs_put_page(struct page *pp) -{ - kunmap(pp); - page_cache_release(pp); -} - /** * vxfs_bread - read buffer for a give inode,block tuple * @ip: inode diff -urN linux-2.4.27/fs/hfs/file_hdr.c linux-2.4.28/fs/hfs/file_hdr.c --- linux-2.4.27/fs/hfs/file_hdr.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/fs/hfs/file_hdr.c 2004-11-17 03:54:21.951412408 -0800 @@ -241,7 +241,9 @@ if (HFS_NEW(new)) { memcpy(new, old, sizeof(*new)); for (lcv = 0; lcv < new->entries; ++lcv) { - (char *)(new->order[lcv]) += (char *)new - (char *)old; + new->order[lcv] = (struct hfs_hdr_descr *) + ((char *)(new->order[lcv]) + + ((char *)new - (char *)old)); } } return new; @@ -640,18 +642,19 @@ int left, lcv, written = 0; struct hdr_hdr meta; int built_meta = 0; - off_t pos; + loff_t pos; if (!S_ISREG(inode->i_mode)) { hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode); return -EINVAL; } + + pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos; + if (count <= 0 || pos != (unsigned)pos) { return 0; } - pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos; - if (!HFS_I(inode)->layout) { HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout); } diff -urN linux-2.4.27/fs/intermezzo/cache.c linux-2.4.28/fs/intermezzo/cache.c --- linux-2.4.27/fs/intermezzo/cache.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/fs/intermezzo/cache.c 2004-11-17 03:54:21.952412449 -0800 @@ -78,6 +78,14 @@ } } +int izo_ioctl_packlen(struct izo_ioctl_data *data) +{ + int len = sizeof(struct izo_ioctl_data); + len += size_round(data->ioc_inllen1); + len += size_round(data->ioc_inllen2); + return len; +} + /* map a device to a cache */ struct presto_cache *presto_cache_find(kdev_t dev) { diff -urN linux-2.4.27/fs/intermezzo/sysctl.c linux-2.4.28/fs/intermezzo/sysctl.c --- linux-2.4.27/fs/intermezzo/sysctl.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/fs/intermezzo/sysctl.c 2004-11-17 03:54:21.952412449 -0800 @@ -290,6 +290,8 @@ * happens once per reboot. */ for(i = 0; i < total_dev; i++) { + void *p; + /* entry for this /proc/sys/intermezzo/intermezzo"i" */ ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; /* entries for the individual "files" in this "directory" */ @@ -302,7 +304,8 @@ /* the psdev has to point to psdev_entries, and fix the number */ psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */ - PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE); + PRESTO_ALLOC(p, PROCNAME_SIZE); + psdev->procname = p; if (!psdev->procname) { PRESTO_FREE(dev_ctl_table, sizeof(ctl_table) * total_entries); diff -urN linux-2.4.27/fs/jbd/journal.c linux-2.4.28/fs/jbd/journal.c --- linux-2.4.27/fs/jbd/journal.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/jbd/journal.c 2004-11-17 03:54:21.954412531 -0800 @@ -1581,7 +1581,7 @@ * journal_datalist_lock spinlock: most callers will need those anyway * in order to probe the buffer's journaling state safely. */ -void __jbd_unexpected_dirty_buffer(char *function, int line, +void __jbd_unexpected_dirty_buffer(const char *function, int line, struct journal_head *jh) { struct buffer_head *bh = jh2bh(jh); @@ -1646,7 +1646,7 @@ * Simple support for retying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ -void * __jbd_kmalloc (char *where, size_t size, int flags, int retry) +void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry) { void *p; static unsigned long last_warning; diff -urN linux-2.4.27/fs/jfs/jfs_metapage.c linux-2.4.28/fs/jfs/jfs_metapage.c --- linux-2.4.27/fs/jfs/jfs_metapage.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/fs/jfs/jfs_metapage.c 2004-11-17 03:54:21.954412531 -0800 @@ -606,6 +606,7 @@ if (page) { block_flushpage(page, 0); UnlockPage(page); + page_cache_release(page); } } } diff -urN linux-2.4.27/fs/jfs/jfs_mount.c linux-2.4.28/fs/jfs/jfs_mount.c --- linux-2.4.27/fs/jfs/jfs_mount.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/fs/jfs/jfs_mount.c 2004-11-17 03:54:21.955412572 -0800 @@ -197,9 +197,6 @@ /* * unwind on error */ -//errout42: /* close fileset inode allocation map */ - diUnmount(ipimap, 1); - errout41: /* close fileset inode allocation map inode */ diFreeSpecial(ipimap); diff -urN linux-2.4.27/fs/namei.c linux-2.4.28/fs/namei.c --- linux-2.4.27/fs/namei.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/namei.c 2004-11-17 03:54:21.956412613 -0800 @@ -447,7 +447,7 @@ * * We expect 'base' to be positive and a directory. */ -int link_path_walk(const char * name, struct nameidata *nd) +int fastcall link_path_walk(const char * name, struct nameidata *nd) { struct dentry *dentry; struct inode *inode; @@ -653,7 +653,7 @@ return err; } -int path_walk(const char * name, struct nameidata *nd) +int fastcall path_walk(const char * name, struct nameidata *nd) { current->total_link_count = 0; return link_path_walk(name, nd); @@ -741,7 +741,7 @@ } /* SMP-safe */ -int path_lookup(const char *path, unsigned flags, struct nameidata *nd) +int fastcall path_lookup(const char *path, unsigned flags, struct nameidata *nd) { int error = 0; if (path_init(path, flags, nd)) @@ -751,7 +751,7 @@ /* SMP-safe */ -int path_init(const char *name, unsigned int flags, struct nameidata *nd) +int fastcall path_init(const char *name, unsigned int flags, struct nameidata *nd) { nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -847,7 +847,7 @@ * that namei follows links, while lnamei does not. * SMP-safe */ -int __user_walk(const char *name, unsigned flags, struct nameidata *nd) +int fastcall __user_walk(const char *name, unsigned flags, struct nameidata *nd) { char *tmp; int err; diff -urN linux-2.4.27/fs/ncpfs/ncplib_kernel.h linux-2.4.28/fs/ncpfs/ncplib_kernel.h --- linux-2.4.27/fs/ncpfs/ncplib_kernel.h 2001-02-09 11:29:44.000000000 -0800 +++ linux-2.4.28/fs/ncpfs/ncplib_kernel.h 2004-11-17 03:54:21.957412655 -0800 @@ -131,7 +131,7 @@ #endif /* CONFIG_NCPFS_NLS */ -inline int +int ncp_strnicmp(struct nls_table *, const unsigned char *, const unsigned char *, int); diff -urN linux-2.4.27/fs/nfs/unlink.c linux-2.4.28/fs/nfs/unlink.c --- linux-2.4.27/fs/nfs/unlink.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/nfs/unlink.c 2004-11-17 03:54:21.957412655 -0800 @@ -130,13 +130,14 @@ if (nfs_async_handle_jukebox(task)) return; if (!dir) - return; + goto out; dir_i = dir->d_inode; nfs_zap_caches(dir_i); NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg); put_rpccred(data->cred); data->cred = NULL; dput(dir); +out: data->completed = 1; wake_up(&data->waitq); } diff -urN linux-2.4.27/fs/nfsd/nfs3xdr.c linux-2.4.28/fs/nfsd/nfs3xdr.c --- linux-2.4.27/fs/nfsd/nfs3xdr.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.28/fs/nfsd/nfs3xdr.c 2004-11-17 03:54:21.958412696 -0800 @@ -273,7 +273,7 @@ { struct svc_buf *buf = &rqstp->rq_argbuf; - return p - buf->base <= buf->buflen; + return p >= buf->base && p <= buf->base + buf->buflen ; } static inline int diff -urN linux-2.4.27/fs/nfsd/vfs.c linux-2.4.28/fs/nfsd/vfs.c --- linux-2.4.27/fs/nfsd/vfs.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/fs/nfsd/vfs.c 2004-11-17 03:54:21.959412737 -0800 @@ -586,6 +586,22 @@ return ra; } +/* copied from fs/read_write.c */ +static inline loff_t llseek(struct file *file, loff_t offset, int origin) +{ + loff_t (*fn)(struct file *, loff_t, int); + loff_t retval; + + fn = default_llseek; + if (file->f_op && file->f_op->llseek) + fn = file->f_op->llseek; + lock_kernel(); + retval = fn(file, offset, origin); + unlock_kernel(); + return retval; +} + + /* * Read data from a file. count must contain the requested read count * on entry. On return, *count contains the number of bytes actually read. @@ -621,7 +637,7 @@ file.f_ralen = ra->p_ralen; file.f_rawin = ra->p_rawin; } - file.f_pos = offset; + llseek(&file, offset, 0); oldfs = get_fs(); set_fs(KERNEL_DS); err = file.f_op->read(&file, buf, *count, &file.f_pos); @@ -706,7 +722,8 @@ if (stable && !EX_WGATHER(exp)) file.f_flags |= O_SYNC; - file.f_pos = offset; /* set write offset */ + + llseek(&file, offset, 0); /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); @@ -1398,10 +1415,12 @@ err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); if (err) goto out; - if (offset > ~(u32) 0) - goto out_close; - file.f_pos = offset; + offset = llseek(&file, offset, 0); + if (offset < 0) { + err = nfserrno((int)offset); + goto out_close; + } /* Set up the readdir context */ memset(&cd, 0, sizeof(cd)); @@ -1429,11 +1448,13 @@ /* If we didn't fill the buffer completely, we're at EOF */ eof = !cd.eob; + + offset = llseek(&file, 0LL, 1); if (cd.offset) { if (rqstp->rq_vers == 3) - (void)xdr_encode_hyper(cd.offset, file.f_pos); + (void)xdr_encode_hyper(cd.offset, offset); else - *cd.offset = htonl(file.f_pos); + *cd.offset = htonl(offset); } p = cd.buffer; diff -urN linux-2.4.27/fs/ntfs/fs.c linux-2.4.28/fs/ntfs/fs.c --- linux-2.4.27/fs/ntfs/fs.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/fs/ntfs/fs.c 2004-11-17 03:54:21.960412778 -0800 @@ -1045,7 +1045,7 @@ } ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn); brelse(bh); - NTFS_SB(vol) = sb; + vol->sb = sb; if (vol->cluster_size > PAGE_SIZE) { ntfs_error("Partition cluster size is not supported yet (it " "is > max kernel blocksize).\n"); diff -urN linux-2.4.27/fs/ntfs/util.c linux-2.4.28/fs/ntfs/util.c --- linux-2.4.27/fs/ntfs/util.c 2001-08-13 16:40:19.000000000 -0700 +++ linux-2.4.28/fs/ntfs/util.c 2004-11-17 03:54:21.961412819 -0800 @@ -165,13 +165,13 @@ void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n) { ntfs_memcpy(dest->param, src, n); - ((char*)dest->param) += n; + dest->param = (char*)dest->param + n; } void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n) { ntfs_memcpy(dest, src->param, n); - ((char*)src->param) += n; + src->param = (char*)src->param + n; } void *ntfs_calloc(int size) diff -urN linux-2.4.27/fs/partitions/ibm.c linux-2.4.28/fs/partitions/ibm.c --- linux-2.4.27/fs/partitions/ibm.c 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.28/fs/partitions/ibm.c 2004-11-17 03:54:21.961412819 -0800 @@ -9,6 +9,7 @@ * 07/10/00 Fixed detection of CMS formatted disks * 02/13/00 VTOC partition support added * 12/27/01 fixed PL030593 (CMS reserved minidisk not detected on 64 bit) + * 07/24/03 no longer using contents of freed page for CMS label recognition (BZ3611) */ #include @@ -141,7 +142,7 @@ /* * VM style CMS1 labeled disk */ - int *label = (int *) data; + int *label = (int *) vlabel; if (label[13] != 0) { printk("CMS1/%8s(MDSK):", name); @@ -158,7 +159,8 @@ add_gd_partition(hd, first_part_minor, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); - } else if (strncmp(type, "VOL1", 4) == 0) { + } else if ((strncmp(type, "VOL1", 4) == 0) && + (!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { /* * New style VOL1 labeled disk */ diff -urN linux-2.4.27/fs/partitions/ldm.h linux-2.4.28/fs/partitions/ldm.h --- linux-2.4.27/fs/partitions/ldm.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/fs/partitions/ldm.h 2004-11-17 03:54:21.962412860 -0800 @@ -38,8 +38,8 @@ /* Magic numbers in CPU format. */ #define MAGIC_VMDB 0x564D4442 /* VMDB */ #define MAGIC_VBLK 0x56424C4B /* VBLK */ -#define MAGIC_PRIVHEAD 0x5052495648454144 /* PRIVHEAD */ -#define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */ +#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */ +#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */ /* The defined vblk types. */ #define VBLK_VOL5 0x51 /* Volume, version 5 */ diff -urN linux-2.4.27/fs/proc/base.c linux-2.4.28/fs/proc/base.c --- linux-2.4.27/fs/proc/base.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/proc/base.c 2004-11-17 03:54:21.963412901 -0800 @@ -780,6 +780,7 @@ return inode; out_unlock: + inode->u.generic_ip = NULL; iput(inode); return NULL; } diff -urN linux-2.4.27/fs/proc/root.c linux-2.4.28/fs/proc/root.c --- linux-2.4.27/fs/proc/root.c 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.28/fs/proc/root.c 2004-11-17 03:54:21.963412901 -0800 @@ -17,7 +17,7 @@ #include #include -struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL struct proc_dir_entry *proc_sys_root; @@ -38,6 +38,8 @@ } proc_misc_init(); proc_net = proc_mkdir("net", 0); + proc_net_stat = proc_mkdir("net/stat", NULL); + #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", 0); #endif @@ -143,5 +145,6 @@ EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); EXPORT_SYMBOL(proc_net); +EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff -urN linux-2.4.27/fs/readdir.c linux-2.4.28/fs/readdir.c --- linux-2.4.27/fs/readdir.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/fs/readdir.c 2004-11-17 03:54:21.964412942 -0800 @@ -264,7 +264,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; @@ -347,7 +347,7 @@ copy_to_user(dirent, &d, NAME_OFFSET(&d)); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; diff -urN linux-2.4.27/fs/smbfs/proc.c linux-2.4.28/fs/smbfs/proc.c --- linux-2.4.27/fs/smbfs/proc.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/smbfs/proc.c 2004-11-17 03:54:21.966413025 -0800 @@ -1289,10 +1289,12 @@ data_len = WVAL(buf, 1); /* we can NOT simply trust the data_len given by the server ... */ - if (data_len > server->packet_size - (buf+3 - server->packet)) { - printk(KERN_ERR "smb_proc_read: invalid data length!! " - "%d > %d - (%p - %p)\n", - data_len, server->packet_size, buf+3, server->packet); + if (data_len > count || + (buf+3 - server->packet) + data_len > server->packet_size) { + printk(KERN_ERR "smb_proc_read: invalid data length/offset!! " + "%d > %d || (%p - %p) + %d > %d\n", + data_len, count, + buf+3, server->packet, data_len, server->packet_size); result = -EIO; goto out; } @@ -1378,10 +1380,12 @@ buf = smb_base(server->packet) + data_off; /* we can NOT simply trust the info given by the server ... */ - if (data_len > server->packet_size - (buf - server->packet)) { - printk(KERN_ERR "smb_proc_read: invalid data length!! " - "%d > %d - (%p - %p)\n", - data_len, server->packet_size, buf, server->packet); + if (data_len > count || + (buf - server->packet) + data_len > server->packet_size) { + printk(KERN_ERR "smb_proc_readX: invalid data length/offset!! " + "%d > %d || (%p - %p) + %d > %d\n", + data_len, count, + buf, server->packet, data_len, server->packet_size); result = -EIO; goto out; } diff -urN linux-2.4.27/fs/smbfs/sock.c linux-2.4.28/fs/smbfs/sock.c --- linux-2.4.27/fs/smbfs/sock.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/fs/smbfs/sock.c 2004-11-17 03:54:21.967413066 -0800 @@ -571,7 +571,11 @@ parm_disp, parm_offset, parm_count, data_disp, data_offset, data_count); *parm = base + parm_offset; + if (*parm - inbuf + parm_tot > server->packet_size) + goto out_bad_parm; *data = base + data_offset; + if (*data - inbuf + data_tot > server->packet_size) + goto out_bad_data; goto success; } @@ -591,6 +595,8 @@ rcv_buf = smb_vmalloc(buf_len); if (!rcv_buf) goto out_no_mem; + memset(rcv_buf, 0, buf_len); + *parm = rcv_buf; *data = rcv_buf + total_p; } else if (data_tot > total_d || parm_tot > total_p) @@ -598,8 +604,12 @@ if (parm_disp + parm_count > total_p) goto out_bad_parm; + if (parm_offset + parm_count > server->packet_size) + goto out_bad_parm; if (data_disp + data_count > total_d) goto out_bad_data; + if (data_offset + data_count > server->packet_size) + goto out_bad_data; memcpy(*parm + parm_disp, base + parm_offset, parm_count); memcpy(*data + data_disp, base + data_offset, data_count); @@ -610,8 +620,11 @@ * Check whether we've received all of the data. Note that * we use the packet totals -- total lengths might shrink! */ - if (data_len >= data_tot && parm_len >= parm_tot) + if (data_len >= data_tot && parm_len >= parm_tot) { + data_len = data_tot; + parm_len = parm_tot; break; + } } /* @@ -625,6 +638,9 @@ server->packet = rcv_buf; rcv_buf = inbuf; } else { + if (parm_len + data_len > buf_len) + goto out_data_grew; + PARANOIA("copying data, old size=%d, new size=%u\n", server->packet_size, buf_len); memcpy(inbuf, rcv_buf, parm_len + data_len); diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_aops.c linux-2.4.28/fs/xfs/linux-2.4/xfs_aops.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_aops.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_aops.c 2004-11-17 03:54:21.968413107 -0800 @@ -209,6 +209,7 @@ sector_shift = block_bits - BBSHIFT; bn = iomapp->iomap_bn >> sector_shift; bn += delta; + BUG_ON(!bn && !(iomapp->iomap_flags & IOMAP_REALTIME)); ASSERT((bn << sector_shift) >= iomapp->iomap_bn); lock_buffer(bh); @@ -887,7 +888,7 @@ bn = iomap.iomap_bn >> (inode->i_blkbits - BBSHIFT); bn += delta; - + BUG_ON(!bn && !(iomap.iomap_flags & IOMAP_REALTIME)); bh_result->b_blocknr = bn; set_buffer_mapped(bh_result); } @@ -911,10 +912,10 @@ } if (iomap.iomap_flags & IOMAP_DELAY) { - if (unlikely(direct)) - BUG(); + BUG_ON(direct); if (create) { set_buffer_mapped(bh_result); + set_buffer_uptodate(bh_result); } set_buffer_delay(bh_result); } @@ -934,17 +935,6 @@ } STATIC int -linvfs_get_block_sync( - struct inode *inode, - long iblock, - struct buffer_head *bh_result, - int create) -{ - return linvfs_get_block_core(inode, iblock, bh_result, - create, 0, BMAPI_SYNC|BMAPI_WRITE); -} - -STATIC int linvfs_get_block_direct( struct inode *inode, long iblock, @@ -1155,13 +1145,7 @@ unsigned int from, unsigned int to) { - if (file && (file->f_flags & O_SYNC)) { - return block_prepare_write(page, from, to, - linvfs_get_block_sync); - } else { - return block_prepare_write(page, from, to, - linvfs_get_block); - } + return block_prepare_write(page, from, to, linvfs_get_block); } /* diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_buf.c linux-2.4.28/fs/xfs/linux-2.4/xfs_buf.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_buf.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_buf.c 2004-11-17 03:54:21.969413148 -0800 @@ -767,11 +767,8 @@ pb = _pagebuf_find(target, ioff, isize, flags, new_pb); if (pb == new_pb) { error = _pagebuf_lookup_pages(pb, flags); - if (unlikely(error)) { - printk(KERN_WARNING - "pagebuf_get: failed to lookup pages\n"); + if (error) goto no_buffer; - } } else { pagebuf_deallocate(new_pb); if (unlikely(pb == NULL)) @@ -1445,6 +1442,7 @@ xfs_flush_buftarg(btp, 1); if (external) xfs_blkdev_put(btp->pbr_bdev); + iput(btp->pbr_mapping->host); kmem_free(btp, sizeof(*btp)); } @@ -1458,7 +1456,7 @@ truncate_inode_pages(btp->pbr_mapping, 0LL); } -void +int xfs_setsize_buftarg( xfs_buftarg_t *btp, unsigned int blocksize, @@ -1472,7 +1470,40 @@ printk(KERN_WARNING "XFS: Cannot set_blocksize to %u on device 0x%x\n", sectorsize, kdev_t_to_nr(btp->pbr_kdev)); + return EINVAL; } + return 0; +} + +STATIC int +xfs_mapping_buftarg( + xfs_buftarg_t *btp, + struct block_device *bdev) +{ + kdev_t kdev; + struct inode *inode; + struct address_space *mapping; + static struct address_space_operations mapping_aops = { + .sync_page = block_sync_page, + }; + + kdev = to_kdev_t(bdev->bd_dev); + inode = new_inode(bdev->bd_inode->i_sb); + if (!inode) { + printk(KERN_WARNING + "XFS: Cannot allocate mapping inode for device %s\n", + XFS_BUFTARG_NAME(btp)); + return ENOMEM; + } + inode->i_mode = S_IFBLK; + inode->i_dev = kdev; + inode->i_rdev = kdev; + inode->i_bdev = bdev; + mapping = &inode->i_data; + mapping->a_ops = &mapping_aops; + mapping->gfp_mask = GFP_KERNEL; + btp->pbr_mapping = mapping; + return 0; } xfs_buftarg_t * @@ -1480,16 +1511,14 @@ struct block_device *bdev) { xfs_buftarg_t *btp; + kdev_t kdev; btp = kmem_zalloc(sizeof(*btp), KM_SLEEP); + kdev = to_kdev_t(bdev->bd_dev); btp->pbr_dev = bdev->bd_dev; - btp->pbr_kdev = to_kdev_t(btp->pbr_dev); + btp->pbr_kdev = kdev; btp->pbr_bdev = bdev; - btp->pbr_mapping = bdev->bd_inode->i_mapping; - xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE, - get_hardsect_size(btp->pbr_kdev)); - switch (MAJOR(btp->pbr_dev)) { case MD_MAJOR: case EVMS_MAJOR: @@ -1499,8 +1528,15 @@ btp->pbr_flags = PBR_SECTOR_ONLY; break; } - + if (xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE, get_hardsect_size(kdev))) + goto error; + if (xfs_mapping_buftarg(btp, bdev)) + goto error; return btp; + +error: + kmem_free(btp, sizeof(*btp)); + return NULL; } /* diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_buf.h linux-2.4.28/fs/xfs/linux-2.4/xfs_buf.h --- linux-2.4.27/fs/xfs/linux-2.4/xfs_buf.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_buf.h 2004-11-17 03:54:21.970413189 -0800 @@ -617,7 +617,7 @@ extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *); extern void xfs_free_buftarg(xfs_buftarg_t *, int); -extern void xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); +extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern void xfs_incore_relse(xfs_buftarg_t *, int, int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int); diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_ioctl.c linux-2.4.28/fs/xfs/linux-2.4/xfs_ioctl.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_ioctl.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_ioctl.c 2004-11-17 03:54:21.971413230 -0800 @@ -71,14 +71,6 @@ #include /* - * ioctl commands that are used by Linux filesystems - */ -#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) -#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) -#define XFS_IOC_GETVERSION _IOR('v', 1, long) - - -/* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to * a file or fs handle. * @@ -827,13 +819,23 @@ case XFS_IOC_FREEZE: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_freeze(mp); + + if (vp->v_vfsp->vfs_frozen == SB_UNFROZEN) { + freeze_bdev(mp->m_ddev_targp->pbr_bdev); + if (mp->m_rtdev_targp) + freeze_bdev(mp->m_rtdev_targp->pbr_bdev); + } return 0; case XFS_IOC_THAW: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_thaw(mp); + + if (vp->v_vfsp->vfs_frozen != SB_UNFROZEN) { + thaw_bdev(mp->m_ddev_targp->pbr_bdev, inode->i_sb); + if (mp->m_rtdev_targp) + thaw_bdev(mp->m_ddev_targp->pbr_bdev, NULL); + } return 0; case XFS_IOC_GOINGDOWN: { diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_linux.h linux-2.4.28/fs/xfs/linux-2.4/xfs_linux.h --- linux-2.4.27/fs/xfs/linux-2.4/xfs_linux.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_linux.h 2004-11-17 03:54:21.972413271 -0800 @@ -35,6 +35,9 @@ #include #include +#undef __user +#define __user + /* * Some types are conditional depending on the target system. * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_lrw.c linux-2.4.28/fs/xfs/linux-2.4/xfs_lrw.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_lrw.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_lrw.c 2004-11-17 03:54:21.972413271 -0800 @@ -604,7 +604,7 @@ io = &xip->i_iocore; mp = io->io_mount; - xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE); + fs_check_frozen(vp->v_vfsp, SB_FREEZE_WRITE); if (XFS_FORCED_SHUTDOWN(xip->i_mount)) { return -EIO; @@ -619,8 +619,6 @@ iolock = XFS_IOLOCK_SHARED; locktype = VRWLOCK_WRITE_DIRECT; } else { - if (io->io_flags & XFS_IOCORE_RT) - return XFS_ERROR(-EINVAL); iolock = XFS_IOLOCK_EXCL; locktype = VRWLOCK_WRITE; } diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_super.c linux-2.4.28/fs/xfs/linux-2.4/xfs_super.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_super.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_super.c 2004-11-17 03:54:21.973413312 -0800 @@ -568,32 +568,73 @@ return -error; } +struct super_block *freeze_bdev(struct block_device *bdev) +{ + struct super_block *sb; + struct vfs *vfsp; + int error; + + sb = get_super(to_kdev_t(bdev->bd_dev)); + if (sb && !(sb->s_flags & MS_RDONLY)) { + vfsp = LINVFS_GET_VFS(sb); + + /* Stop new writers */ + vfsp->vfs_frozen = SB_FREEZE_WRITE; + wmb(); + + /* Flush the refcache */ + VFS_SYNC(vfsp, SYNC_REFCACHE|SYNC_WAIT, NULL, error); + + /* Flush delalloc and delwri data */ + VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error); + + /* Pause transaction subsystem */ + vfsp->vfs_frozen = SB_FREEZE_TRANS; + wmb(); + + /* Flush any remaining inodes into buffers */ + VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); + + /* Push all buffers out to disk */ + sync_buffers(sb->s_dev, 1); + + /* Push the superblock and write an unmount record */ + VFS_FREEZE(vfsp); + } + + sync_buffers(to_kdev_t(bdev->bd_dev), 1); + return sb; /* thaw_bdev releases sb->s_umount */ +} + +void thaw_bdev(struct block_device *bdev, struct super_block *sb) +{ + if (sb) { + struct vfs *vfsp = LINVFS_GET_VFS(sb); + + BUG_ON(sb->s_bdev != bdev); + + vfsp->vfs_frozen = SB_UNFROZEN; + wmb(); + wake_up(&vfsp->vfs_wait_unfrozen); + + drop_super(sb); + } +} + STATIC void linvfs_freeze_fs( struct super_block *sb) { - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - if (sb->s_flags & MS_RDONLY) return; - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_FREEZE, 0, error); - VN_RELE(vp); + freeze_bdev(sb->s_bdev); } STATIC void linvfs_unfreeze_fs( struct super_block *sb) { - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_THAW, 0, error); - VN_RELE(vp); + thaw_bdev(sb->s_bdev, sb); } STATIC int diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_super.h linux-2.4.28/fs/xfs/linux-2.4/xfs_super.h --- linux-2.4.27/fs/xfs/linux-2.4/xfs_super.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_super.h 2004-11-17 03:54:21.974413354 -0800 @@ -136,5 +136,7 @@ /* matching a 2.6 kernel export, thus no xfs_ prefix */ extern struct dentry *d_alloc_anon(struct inode *inode); +extern struct super_block *freeze_bdev(struct block_device *bdev); +extern void thaw_bdev(struct block_device *bdev, struct super_block *sb); #endif /* __XFS_SUPER_H__ */ diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_vfs.c linux-2.4.28/fs/xfs/linux-2.4/xfs_vfs.c --- linux-2.4.27/fs/xfs/linux-2.4/xfs_vfs.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_vfs.c 2004-11-17 03:54:21.974413354 -0800 @@ -243,6 +243,18 @@ ((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line)); } +void +vfs_freeze( + struct bhv_desc *bdp) +{ + struct bhv_desc *next = bdp; + + ASSERT(next); + while (! (bhvtovfsops(next))->vfs_freeze) + next = BHV_NEXT(next); + ((*bhvtovfsops(next)->vfs_freeze)(next)); +} + vfs_t * vfs_allocate( void ) { @@ -251,6 +263,7 @@ vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP); bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); init_waitqueue_head(&vfsp->vfs_wait_sync_task); + init_waitqueue_head(&vfsp->vfs_wait_unfrozen); return vfsp; } diff -urN linux-2.4.27/fs/xfs/linux-2.4/xfs_vfs.h linux-2.4.28/fs/xfs/linux-2.4/xfs_vfs.h --- linux-2.4.27/fs/xfs/linux-2.4/xfs_vfs.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/linux-2.4/xfs_vfs.h 2004-11-17 03:54:21.975413395 -0800 @@ -53,6 +53,8 @@ struct super_block *vfs_super; /* Linux superblock structure */ struct task_struct *vfs_sync_task; wait_queue_head_t vfs_wait_sync_task; + int vfs_frozen; + wait_queue_head_t vfs_wait_unfrozen; } vfs_t; #define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ @@ -114,6 +116,7 @@ typedef void (*vfs_init_vnode_t)(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); +typedef void (*vfs_freeze_t)(bhv_desc_t *); typedef struct inode * (*vfs_get_inode_t)(bhv_desc_t *, xfs_ino_t, int); typedef struct vfsops { @@ -132,6 +135,7 @@ vfs_get_inode_t vfs_get_inode; /* bhv specific iget */ vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ + vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ } vfsops_t; /* @@ -152,6 +156,7 @@ #define VFS_GET_INODE(v, ino, fl) ( vfs_get_inode(VHEAD(v), ino,fl) ) #define VFS_INIT_VNODE(v, vp,b,ul) ( vfs_init_vnode(VHEAD(v), vp,b,ul) ) #define VFS_FORCE_SHUTDOWN(v, fl,f,l) ( vfs_force_shutdown(VHEAD(v), fl,f,l) ) +#define VFS_FREEZE(v) ( vfs_freeze(VHEAD(v)) ) /* * PVFS's. Operates on behavior descriptor pointers. @@ -170,6 +175,7 @@ #define PVFS_GET_INODE(b, ino,fl) ( vfs_get_inode(b, ino,fl) ) #define PVFS_INIT_VNODE(b, vp,b2,ul) ( vfs_init_vnode(b, vp,b2,ul) ) #define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) ) +#define PVFS_FREEZE(b) ( vfs_freeze(b) ) extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); @@ -185,6 +191,7 @@ extern struct inode *vfs_get_inode(bhv_desc_t *, xfs_ino_t, int); extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); +extern void vfs_freeze(bhv_desc_t *); typedef struct bhv_vfsops { struct vfsops bhv_common; @@ -205,4 +212,14 @@ extern void bhv_remove_all_vfsops(struct vfs *, int); extern void bhv_remove_vfsops(struct vfs *, int); +enum { + SB_UNFROZEN = 0, + SB_FREEZE_WRITE = 1, + SB_FREEZE_TRANS = 2, +}; + +#define fs_frozen(vfsp) ((vfsp)->vfs_frozen) +#define fs_check_frozen(vfsp, level) \ + wait_event((vfsp)->vfs_wait_unfrozen, ((vfsp)->vfs_frozen < (level))) + #endif /* __XFS_VFS_H__ */ diff -urN linux-2.4.27/fs/xfs/quota/xfs_dquot.c linux-2.4.28/fs/xfs/quota/xfs_dquot.c --- linux-2.4.27/fs/xfs/quota/xfs_dquot.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/quota/xfs_dquot.c 2004-11-17 03:54:21.976413436 -0800 @@ -145,7 +145,7 @@ dqp->q_res_icount = 0; dqp->q_res_rtbcount = 0; dqp->q_pincount = 0; - dqp->q_hash = 0; + dqp->q_hash = NULL; ASSERT(dqp->dq_flnext == dqp->dq_flprev); #ifdef XFS_DQUOT_TRACE @@ -187,9 +187,9 @@ */ STATIC void xfs_qm_dqinit_core( - xfs_dqid_t id, - uint type, - xfs_dqblk_t *d) + xfs_dqid_t id, + uint type, + xfs_dqblk_t *d) { /* * Caller has zero'd the entire dquot 'chunk' already. @@ -250,6 +250,36 @@ /* + * If default limits are in force, push them into the dquot now. + * We overwrite the dquot limits only if they are zero and this + * is not the root dquot. + */ +void +xfs_qm_adjust_dqlimits( + xfs_mount_t *mp, + xfs_disk_dquot_t *d) +{ + xfs_quotainfo_t *q = mp->m_quotainfo; + + ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT)); + + if (q->qi_bsoftlimit && INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT)) + INT_SET(d->d_blk_softlimit, ARCH_CONVERT, q->qi_bsoftlimit); + if (q->qi_bhardlimit && INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT)) + INT_SET(d->d_blk_hardlimit, ARCH_CONVERT, q->qi_bhardlimit); + if (q->qi_isoftlimit && INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) + INT_SET(d->d_ino_softlimit, ARCH_CONVERT, q->qi_isoftlimit); + if (q->qi_ihardlimit && INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT)) + INT_SET(d->d_ino_hardlimit, ARCH_CONVERT, q->qi_ihardlimit); + if (q->qi_rtbsoftlimit && + INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT)) + INT_SET(d->d_rtb_softlimit, ARCH_CONVERT, q->qi_rtbsoftlimit); + if (q->qi_rtbhardlimit && + INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT)) + INT_SET(d->d_rtb_hardlimit, ARCH_CONVERT, q->qi_rtbhardlimit); +} + +/* * Check the limits and timers of a dquot and start or reset timers * if necessary. * This gets called even when quota enforcement is OFF, which makes our @@ -265,53 +295,81 @@ xfs_mount_t *mp, xfs_disk_dquot_t *d) { - /* - * The dquot had better be locked. We are modifying it here. - */ - - /* - * root's limits are not real limits. - */ - if (INT_ISZERO(d->d_id, ARCH_CONVERT)) - return; + ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT)); #ifdef QUOTADEBUG if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)) - ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)); + ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= + INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)); if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)) - ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)); + ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= + INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)); + if (INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)) + ASSERT(INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) <= + INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)); #endif if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) { if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && - (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_bcount, ARCH_CONVERT) >= + INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) || (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) && - (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { - INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp)); + (INT_GET(d->d_bcount, ARCH_CONVERT) >= + INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_btimer, ARCH_CONVERT, + get_seconds() + XFS_QI_BTIMELIMIT(mp)); } } else { if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) || - (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) && + (INT_GET(d->d_bcount, ARCH_CONVERT) < + INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) && (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) || - (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + (INT_GET(d->d_bcount, ARCH_CONVERT) < + INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { INT_ZERO(d->d_btimer, ARCH_CONVERT); } } if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) { if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) && - (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_icount, ARCH_CONVERT) >= + INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) || (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) && - (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { - INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp)); + (INT_GET(d->d_icount, ARCH_CONVERT) >= + INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_itimer, ARCH_CONVERT, + get_seconds() + XFS_QI_ITIMELIMIT(mp)); } } else { if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) || - (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) && + (INT_GET(d->d_icount, ARCH_CONVERT) < + INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) && (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) || - (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + (INT_GET(d->d_icount, ARCH_CONVERT) < + INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { INT_ZERO(d->d_itimer, ARCH_CONVERT); } } + + if (INT_ISZERO(d->d_rtbtimer, ARCH_CONVERT)) { + if ((INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_rtbcount, ARCH_CONVERT) >= + INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT) && + (INT_GET(d->d_rtbcount, ARCH_CONVERT) >= + INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_rtbtimer, ARCH_CONVERT, + get_seconds() + XFS_QI_RTBTIMELIMIT(mp)); + } + } else { + if ((INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT) || + (INT_GET(d->d_rtbcount, ARCH_CONVERT) < + INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) && + (INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT) || + (INT_GET(d->d_rtbcount, ARCH_CONVERT) < + INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) { + INT_ZERO(d->d_rtbtimer, ARCH_CONVERT); + } + } } /* diff -urN linux-2.4.27/fs/xfs/quota/xfs_dquot.h linux-2.4.28/fs/xfs/quota/xfs_dquot.h --- linux-2.4.27/fs/xfs/quota/xfs_dquot.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/quota/xfs_dquot.h 2004-11-17 03:54:21.977413477 -0800 @@ -209,6 +209,8 @@ extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, xfs_disk_dquot_t *); +extern void xfs_qm_adjust_dqlimits(xfs_mount_t *, + xfs_disk_dquot_t *); extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, xfs_dqid_t, uint, uint, xfs_dquot_t **); diff -urN linux-2.4.27/fs/xfs/quota/xfs_qm.c linux-2.4.28/fs/xfs/quota/xfs_qm.c --- linux-2.4.27/fs/xfs/quota/xfs_qm.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/quota/xfs_qm.c 2004-11-17 03:54:21.979413559 -0800 @@ -229,11 +229,8 @@ */ XFS_QM_LOCK(xfs_Gqm); - if (xfs_Gqm == NULL) { - if ((xfs_Gqm = xfs_Gqm_init()) == NULL) { - return (XFS_ERROR(EINVAL)); - } - } + if (xfs_Gqm == NULL) + xfs_Gqm = xfs_Gqm_init(); /* * We can keep a list of all filesystems with quotas mounted for * debugging and statistical purposes, but ... @@ -1216,22 +1213,46 @@ XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, &dqp); if (! error) { + xfs_disk_dquot_t *ddqp = &dqp->q_core; + /* * The warnings and timers set the grace period given to * a user or group before he or she can not perform any * more writing. If it is zero, a default is used. */ - qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ? - INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT; - qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ? - INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT; - qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ? - INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT; - qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ? - INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT; - qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ? - INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT; - + qinf->qi_btimelimit = + INT_GET(ddqp->d_btimer, ARCH_CONVERT) ? + INT_GET(ddqp->d_btimer, ARCH_CONVERT) : + XFS_QM_BTIMELIMIT; + qinf->qi_itimelimit = + INT_GET(ddqp->d_itimer, ARCH_CONVERT) ? + INT_GET(ddqp->d_itimer, ARCH_CONVERT) : + XFS_QM_ITIMELIMIT; + qinf->qi_rtbtimelimit = + INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) ? + INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) : + XFS_QM_RTBTIMELIMIT; + qinf->qi_bwarnlimit = + INT_GET(ddqp->d_bwarns, ARCH_CONVERT) ? + INT_GET(ddqp->d_bwarns, ARCH_CONVERT) : + XFS_QM_BWARNLIMIT; + qinf->qi_iwarnlimit = + INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ? + INT_GET(ddqp->d_iwarns, ARCH_CONVERT) : + XFS_QM_IWARNLIMIT; + qinf->qi_bhardlimit = + INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT); + qinf->qi_bsoftlimit = + INT_GET(ddqp->d_blk_softlimit, ARCH_CONVERT); + qinf->qi_ihardlimit = + INT_GET(ddqp->d_ino_hardlimit, ARCH_CONVERT); + qinf->qi_isoftlimit = + INT_GET(ddqp->d_ino_softlimit, ARCH_CONVERT); + qinf->qi_rtbhardlimit = + INT_GET(ddqp->d_rtb_hardlimit, ARCH_CONVERT); + qinf->qi_rtbsoftlimit = + INT_GET(ddqp->d_rtb_softlimit, ARCH_CONVERT); + /* * We sent the XFS_QMOPT_DQSUSER flag to dqget because * we don't want this dquot cached. We haven't done a @@ -1691,10 +1712,12 @@ } /* - * Adjust the timers since we just changed usages + * Set default limits, adjust timers (since we changed usages) */ - if (! XFS_IS_SUSER_DQUOT(dqp)) + if (! XFS_IS_SUSER_DQUOT(dqp)) { + xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core); xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); + } dqp->dq_flags |= XFS_DQ_DIRTY; } @@ -1735,7 +1758,7 @@ xfs_qm_dqusage_adjust( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ - void *buffer, /* not used */ + void __user *buffer, /* not used */ int ubsize, /* not used */ void *private_data, /* not used */ xfs_daddr_t bno, /* starting block of inode cluster */ diff -urN linux-2.4.27/fs/xfs/quota/xfs_qm.h linux-2.4.28/fs/xfs/quota/xfs_qm.h --- linux-2.4.27/fs/xfs/quota/xfs_qm.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/quota/xfs_qm.h 2004-11-17 03:54:21.980413600 -0800 @@ -136,9 +136,14 @@ xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ mutex_t qi_quotaofflock;/* to serialize quotaoff */ - /* Some useful precalculated constants */ xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ uint qi_dqperchunk; /* # ondisk dqs in above chunk */ + xfs_qcnt_t qi_bhardlimit; /* default data blk hard limit */ + xfs_qcnt_t qi_bsoftlimit; /* default data blk soft limit */ + xfs_qcnt_t qi_ihardlimit; /* default inode count hard limit */ + xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */ + xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */ + xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */ } xfs_quotainfo_t; diff -urN linux-2.4.27/fs/xfs/quota/xfs_qm_stats.c linux-2.4.28/fs/xfs/quota/xfs_qm_stats.c --- linux-2.4.27/fs/xfs/quota/xfs_qm_stats.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/quota/xfs_qm_stats.c 2004-11-17 03:54:21.980413600 -0800 @@ -137,8 +137,8 @@ void xfs_qm_init_procfs(void) { - create_proc_read_entry("fs/xfs/xqmstat", 0, 0, xfs_qm_read_stats, NULL); - create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_qm_read_xfsquota, NULL); + create_proc_read_entry("fs/xfs/xqmstat", 0, NULL, xfs_qm_read_stats, NULL); + create_proc_read_entry("fs/xfs/xqm", 0, NULL, xfs_qm_read_xfsquota, NULL); } void diff -urN linux-2.4.27/fs/xfs/quota/xfs_qm_syscalls.c linux-2.4.28/fs/xfs/quota/xfs_qm_syscalls.c --- linux-2.4.27/fs/xfs/quota/xfs_qm_syscalls.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/quota/xfs_qm_syscalls.c 2004-11-17 03:54:21.981413641 -0800 @@ -648,8 +648,11 @@ if (hard == 0 || hard >= soft) { INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft); - } - else { + if (id == 0) { + mp->m_quotainfo->qi_bhardlimit = hard; + mp->m_quotainfo->qi_bsoftlimit = soft; + } + } else { qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft); } hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ? @@ -661,40 +664,49 @@ if (hard == 0 || hard >= soft) { INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft); - } - else + if (id == 0) { + mp->m_quotainfo->qi_rtbhardlimit = hard; + mp->m_quotainfo->qi_rtbsoftlimit = soft; + } + } else { qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft); + } hard = (newlim->d_fieldmask & FS_DQ_IHARD) ? (xfs_qcnt_t) newlim->d_ino_hardlimit : - INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT); + INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT); soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ? (xfs_qcnt_t) newlim->d_ino_softlimit : - INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT); + INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT); if (hard == 0 || hard >= soft) { INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft); - } - else + if (id == 0) { + mp->m_quotainfo->qi_ihardlimit = hard; + mp->m_quotainfo->qi_isoftlimit = soft; + } + } else { qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); + } if (id == 0) { /* * Timelimits for the super user set the relative time * the other users can be over quota for this file system. - * If it is zero a default is used. + * If it is zero a default is used. Ditto for the default + * soft and hard limit values (already done, above). */ if (newlim->d_fieldmask & FS_DQ_BTIMER) { mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; - INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer); + INT_SET(ddq->d_btimer, ARCH_CONVERT, newlim->d_btimer); } if (newlim->d_fieldmask & FS_DQ_ITIMER) { mp->m_quotainfo->qi_itimelimit = newlim->d_itimer; - INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer); + INT_SET(ddq->d_itimer, ARCH_CONVERT, newlim->d_itimer); } if (newlim->d_fieldmask & FS_DQ_RTBTIMER) { mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; - INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); + INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); } } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { /* @@ -1114,7 +1126,7 @@ cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \ for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \ dqp = (xfs_dqtest_t *)dqp->NXT) { \ - cmn_err(CE_DEBUG, " %d\. \"%d (%s)\" bcnt = %d, icnt = %d", \ + cmn_err(CE_DEBUG, " %d. \"%d (%s)\" bcnt = %d, icnt = %d", \ ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp), \ dqp->d_bcount, dqp->d_icount); } \ } @@ -1299,7 +1311,7 @@ xfs_qm_internalqcheck_adjust( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ - void *buffer, /* not used */ + void __user *buffer, /* not used */ int ubsize, /* not used */ void *private_data, /* not used */ xfs_daddr_t bno, /* starting block of inode cluster */ diff -urN linux-2.4.27/fs/xfs/quota/xfs_trans_dquot.c linux-2.4.28/fs/xfs/quota/xfs_trans_dquot.c --- linux-2.4.27/fs/xfs/quota/xfs_trans_dquot.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/quota/xfs_trans_dquot.c 2004-11-17 03:54:21.982413682 -0800 @@ -452,9 +452,13 @@ INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta); /* + * Get any default limits in use. * Start/reset the timer(s) if needed. */ - xfs_qm_adjust_dqtimers(tp->t_mountp, d); + if (!INT_ISZERO(d->d_id, ARCH_CONVERT)) { + xfs_qm_adjust_dqlimits(tp->t_mountp, d); + xfs_qm_adjust_dqtimers(tp->t_mountp, d); + } dqp->dq_flags |= XFS_DQ_DIRTY; /* @@ -625,6 +629,7 @@ STATIC int xfs_trans_dqresv( xfs_trans_t *tp, + xfs_mount_t *mp, xfs_dquot_t *dqp, long nblks, long ninos, @@ -635,6 +640,7 @@ xfs_qcnt_t softlimit; time_t btimer; xfs_qcnt_t *resbcountp; + xfs_quotainfo_t *q = mp->m_quotainfo; if (! (flags & XFS_QMOPT_DQLOCK)) { xfs_dqlock(dqp); @@ -642,13 +648,21 @@ ASSERT(XFS_DQ_IS_LOCKED(dqp)); if (flags & XFS_TRANS_DQ_RES_BLKS) { hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT); + if (!hardlimit) + hardlimit = q->qi_bhardlimit; softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); + if (!softlimit) + softlimit = q->qi_bsoftlimit; btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); resbcountp = &dqp->q_res_bcount; } else { ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT); + if (!hardlimit) + hardlimit = q->qi_rtbhardlimit; softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); + if (!softlimit) + softlimit = q->qi_rtbsoftlimit; btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); resbcountp = &dqp->q_res_rtbcount; } @@ -689,14 +703,18 @@ } } if (ninos > 0) { - if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL && - INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= - INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) { + hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT); + if (!hardlimit) + hardlimit = q->qi_ihardlimit; + softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT); + if (!softlimit) + softlimit = q->qi_isoftlimit; + if (hardlimit > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) { error = EDQUOT; goto error_return; - } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL && - INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= - INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { + } else if (softlimit > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) { /* * If timer or warnings has expired, * return EDQUOT @@ -786,19 +804,20 @@ resvd = 0; if (udqp) { - if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags)) + if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags)) return (EDQUOT); resvd = 1; } if (gdqp) { - if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) { + if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) { /* * can't do it, so backout previous reservation */ if (resvd) { - xfs_trans_dqresv(tp, udqp, -nblks, -ninos, - flags); + flags |= XFS_QMOPT_FORCE_RES; + xfs_trans_dqresv(tp, mp, udqp, + -nblks, -ninos, flags); } return (EDQUOT); } diff -urN linux-2.4.27/fs/xfs/support/ktrace.c linux-2.4.28/fs/xfs/support/ktrace.c --- linux-2.4.27/fs/xfs/support/ktrace.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/support/ktrace.c 2004-11-17 03:54:21.983413724 -0800 @@ -30,14 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include - -#include -#include "kmem.h" -#include "spin.h" -#include "debug.h" -#include "ktrace.h" +#include static kmem_zone_t *ktrace_hdr_zone; static kmem_zone_t *ktrace_ent_zone; diff -urN linux-2.4.27/fs/xfs/support/move.c linux-2.4.28/fs/xfs/support/move.c --- linux-2.4.27/fs/xfs/support/move.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/support/move.c 2004-11-17 03:54:21.983413724 -0800 @@ -30,13 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#include -#include -#include - -#include -#include "debug.h" -#include "move.h" +#include /* Read from kernel buffer at src to user/kernel buffer defined * by the uio structure. Advance the pointer in the uio struct diff -urN linux-2.4.27/fs/xfs/xfs_acl.h linux-2.4.28/fs/xfs/xfs_acl.h --- linux-2.4.27/fs/xfs/xfs_acl.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_acl.h 2004-11-17 03:54:21.984413765 -0800 @@ -95,7 +95,7 @@ #define _ACL_XFS_IACCESS(i,m,c) (XFS_IFORK_Q(i) ? xfs_acl_iaccess(i,m,c) : -1) #define _ACL_ALLOC(a) ((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP)) -#define _ACL_FREE(a) ((a)? kmem_zone_free(xfs_acl_zone, (a)) : 0) +#define _ACL_FREE(a) ((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0) #else #define xfs_acl_zone_init(zone,name) diff -urN linux-2.4.27/fs/xfs/xfs_alloc.c linux-2.4.28/fs/xfs/xfs_alloc.c --- linux-2.4.27/fs/xfs/xfs_alloc.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_alloc.c 2004-11-17 03:54:21.986413847 -0800 @@ -665,7 +665,7 @@ * Allocate/initialize a cursor for the by-number freespace btree. */ bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO, 0, 0); + args->agno, XFS_BTNUM_BNO, NULL, 0); /* * Lookup bno and minlen in the btree (minlen is irrelevant, really). * Look for the closest free block <= bno, it must contain bno @@ -721,7 +721,7 @@ * Allocate/initialize a cursor for the by-size btree. */ cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT, 0, 0); + args->agno, XFS_BTNUM_CNT, NULL, 0); ASSERT(args->agbno + args->len <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, ARCH_CONVERT)); @@ -788,7 +788,7 @@ * Get a cursor for the by-size btree. */ cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT, 0, 0); + args->agno, XFS_BTNUM_CNT, NULL, 0); ltlen = 0; bno_cur_lt = bno_cur_gt = NULL; /* @@ -916,7 +916,7 @@ * Set up a cursor for the by-bno tree. */ bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, - args->agbp, args->agno, XFS_BTNUM_BNO, 0, 0); + args->agbp, args->agno, XFS_BTNUM_BNO, NULL, 0); /* * Fix up the btree entries. */ @@ -944,7 +944,7 @@ * Allocate and initialize the cursor for the leftward search. */ bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO, 0, 0); + args->agno, XFS_BTNUM_BNO, NULL, 0); /* * Lookup <= bno to find the leftward search's starting point. */ @@ -956,7 +956,7 @@ * search. */ bno_cur_gt = bno_cur_lt; - bno_cur_lt = 0; + bno_cur_lt = NULL; } /* * Found something. Duplicate the cursor for the rightward search. @@ -1301,7 +1301,7 @@ * Allocate and initialize a cursor for the by-size btree. */ cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT, 0, 0); + args->agno, XFS_BTNUM_CNT, NULL, 0); bno_cur = NULL; /* * Look for an entry >= maxlen+alignment-1 blocks. @@ -1406,7 +1406,7 @@ * Allocate and initialize a cursor for the by-block tree. */ bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO, 0, 0); + args->agno, XFS_BTNUM_BNO, NULL, 0); if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, rbno, rlen, XFSA_FIXUP_CNT_OK))) goto error0; @@ -1553,7 +1553,7 @@ /* * Allocate and initialize a cursor for the by-block btree. */ - bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, 0, + bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, NULL, 0); cnt_cur = NULL; /* @@ -1613,7 +1613,7 @@ /* * Now allocate and initialize a cursor for the by-size tree. */ - cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, 0, + cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, NULL, 0); /* * Have both left and right contiguous neighbors. diff -urN linux-2.4.27/fs/xfs/xfs_alloc_btree.c linux-2.4.28/fs/xfs/xfs_alloc_btree.c --- linux-2.4.27/fs/xfs/xfs_alloc_btree.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_alloc_btree.c 2004-11-17 03:54:21.987413888 -0800 @@ -263,7 +263,7 @@ /* * Update the cursor so there's one fewer level. */ - xfs_btree_setbuf(cur, level, 0); + xfs_btree_setbuf(cur, level, NULL); cur->bc_nlevels--; } else if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) diff -urN linux-2.4.27/fs/xfs/xfs_attr.c linux-2.4.28/fs/xfs/xfs_attr.c --- linux-2.4.27/fs/xfs/xfs_attr.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_attr.c 2004-11-17 03:54:21.989413970 -0800 @@ -104,7 +104,6 @@ STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ -#define ATTR_RMTVALUE_TRANSBLKS 8 /* max # of blks in a transaction */ #if defined(XFS_ATTR_TRACE) ktrace_t *xfs_attr_trace_buf; diff -urN linux-2.4.27/fs/xfs/xfs_bmap.c linux-2.4.28/fs/xfs/xfs_bmap.c --- linux-2.4.27/fs/xfs/xfs_bmap.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_bmap.c 2004-11-17 03:54:21.994414176 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -203,8 +203,6 @@ xfs_bmap_check_extents( xfs_inode_t *ip, /* incore inode pointer */ int whichfork); /* data or attr fork */ -#else -#define xfs_bmap_check_extents(ip,w) #endif /* @@ -3429,6 +3427,20 @@ int high; /* high index of binary search */ int low; /* low index of binary search */ + /* + * Initialize the extent entry structure to catch access to + * uninitialized br_startblock field. + */ + got.br_startoff = 0xffa5a5a5a5a5a5a5LL; + got.br_blockcount = 0xa55a5a5a5a5a5a5aLL; + got.br_state = XFS_EXT_INVALID; + +#if XFS_BIG_BLKNOS + got.br_startblock = 0xffffa5a5a5a5a5a5LL; +#else + got.br_startblock = 0xffffa5a5; +#endif + if (lastx != NULLEXTNUM && lastx < nextents) ep = base + lastx; else @@ -3527,6 +3539,8 @@ xfs_bmbt_rec_t *base; /* base of extent list */ xfs_extnum_t lastx; /* last extent index used */ xfs_extnum_t nextents; /* extent list size */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int rt; /* realtime flag */ XFS_STATS_INC(xs_look_exlist); ifp = XFS_IFORK_PTR(ip, whichfork); @@ -3534,8 +3548,18 @@ nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); base = &ifp->if_u1.if_extents[0]; - return xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, + ep = xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, lastxp, gotp, prevp); + rt = ip->i_d.di_flags & XFS_DIFLAG_REALTIME; + if(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM)) { + cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld " + "start_block : %llx start_off : %llx blkcnt : %llx " + "extent-state : %x \n", + (ip->i_mount)->m_fsname,(long long)ip->i_ino, + gotp->br_startblock, gotp->br_startoff, + gotp->br_blockcount,gotp->br_state); + } + return ep; } @@ -4689,8 +4713,41 @@ } break; } + + /* + * Split changing sb for alen and indlen since + * they could be coming from different places. + */ + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + xfs_extlen_t extsz; + xfs_extlen_t ralen; + if (!(extsz = ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + ralen = roundup(alen, extsz); + ralen = ralen / mp->m_sb.sb_rextsize; + if (xfs_mod_incore_sb(mp, + XFS_SBS_FREXTENTS, + -(ralen), rsvd)) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + XFS_TRANS_UNRESERVE_BLKQUOTA( + mp, NULL, ip, + (long)alen); + break; + } + } else { + if (xfs_mod_incore_sb(mp, + XFS_SBS_FDBLOCKS, + -(alen), rsvd)) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + XFS_TRANS_UNRESERVE_BLKQUOTA( + mp, NULL, ip, + (long)alen); + break; + } + } + if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - -(alen + indlen), rsvd)) { + -(indlen), rsvd)) { XFS_TRANS_UNRESERVE_BLKQUOTA( mp, NULL, ip, (long)alen); break; @@ -5445,7 +5502,7 @@ xfs_getbmap( bhv_desc_t *bdp, /* XFS behavior descriptor*/ struct getbmap *bmv, /* user bmap structure */ - void *ap, /* pointer to user's array */ + void __user *ap, /* pointer to user's array */ int interface) /* interface flags */ { __int64_t bmvend; /* last block requested */ @@ -5634,8 +5691,10 @@ (__int64_t)(bmvend - bmv->bmv_offset)); bmv->bmv_entries++; ap = (interface & BMV_IF_EXTENDED) ? - (void *)((struct getbmapx *)ap + 1) : - (void *)((struct getbmap *)ap + 1); + (void __user *) + ((struct getbmapx __user *)ap + 1) : + (void __user *) + ((struct getbmap __user *)ap + 1); } } } while (nmap && nexleft && bmv->bmv_length); diff -urN linux-2.4.27/fs/xfs/xfs_bmap.h linux-2.4.28/fs/xfs/xfs_bmap.h --- linux-2.4.27/fs/xfs/xfs_bmap.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_bmap.h 2004-11-17 03:54:21.994414176 -0800 @@ -328,7 +328,7 @@ xfs_getbmap( bhv_desc_t *bdp, /* XFS behavior descriptor*/ struct getbmap *bmv, /* user bmap structure */ - void *ap, /* pointer to user's array */ + void __user *ap, /* pointer to user's array */ int iflags); /* interface flags */ /* diff -urN linux-2.4.27/fs/xfs/xfs_bmap_btree.c linux-2.4.28/fs/xfs/xfs_bmap_btree.c --- linux-2.4.27/fs/xfs/xfs_bmap_btree.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_bmap_btree.c 2004-11-17 03:54:21.996414258 -0800 @@ -1953,7 +1953,7 @@ *bpp = cur->bc_bufs[level]; rval = XFS_BUF_TO_BMBT_BLOCK(*bpp); } else { - *bpp = 0; + *bpp = NULL; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); rval = ifp->if_broot; diff -urN linux-2.4.27/fs/xfs/xfs_bmap_btree.h linux-2.4.28/fs/xfs/xfs_bmap_btree.h --- linux-2.4.27/fs/xfs/xfs_bmap_btree.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_bmap_btree.h 2004-11-17 03:54:21.997414299 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000,2002-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -153,7 +153,7 @@ */ typedef enum { XFS_EXT_NORM, XFS_EXT_UNWRITTEN, - XFS_EXT_DMAPI_OFFLINE + XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID } xfs_exntst_t; /* diff -urN linux-2.4.27/fs/xfs/xfs_buf_item.c linux-2.4.28/fs/xfs/xfs_buf_item.c --- linux-2.4.27/fs/xfs/xfs_buf_item.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_buf_item.c 2004-11-17 03:54:21.998414340 -0800 @@ -55,8 +55,6 @@ #include "xfs_error.h" -#define ROUNDUPNBWORD(x) (((x) + (NBWORD - 1)) & ~(NBWORD - 1)) - kmem_zone_t *xfs_buf_item_zone; #ifdef XFS_TRANS_DEBUG diff -urN linux-2.4.27/fs/xfs/xfs_da_btree.c linux-2.4.28/fs/xfs/xfs_da_btree.c --- linux-2.4.27/fs/xfs/xfs_da_btree.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_da_btree.c 2004-11-17 03:54:22.000414423 -0800 @@ -2092,7 +2092,7 @@ int caller, inst_t *ra) { - xfs_buf_t *bp = 0; + xfs_buf_t *bp = NULL; xfs_buf_t **bplist; int error=0; int i; diff -urN linux-2.4.27/fs/xfs/xfs_dfrag.c linux-2.4.28/fs/xfs/xfs_dfrag.c --- linux-2.4.27/fs/xfs/xfs_dfrag.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_dfrag.c 2004-11-17 03:54:22.000414423 -0800 @@ -65,7 +65,7 @@ */ int xfs_swapext( - xfs_swapext_t *sxp) + xfs_swapext_t __user *sxp) { xfs_swapext_t sx; xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; diff -urN linux-2.4.27/fs/xfs/xfs_dfrag.h linux-2.4.28/fs/xfs/xfs_dfrag.h --- linux-2.4.27/fs/xfs/xfs_dfrag.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_dfrag.h 2004-11-17 03:54:22.001414464 -0800 @@ -60,7 +60,7 @@ /* * Syscall interface for xfs_swapext */ -int xfs_swapext(struct xfs_swapext *sx); +int xfs_swapext(struct xfs_swapext __user *sx); #endif /* __KERNEL__ */ diff -urN linux-2.4.27/fs/xfs/xfs_dinode.h linux-2.4.28/fs/xfs/xfs_dinode.h --- linux-2.4.27/fs/xfs/xfs_dinode.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_dinode.h 2004-11-17 03:54:22.001414464 -0800 @@ -456,6 +456,7 @@ #define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ #define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ #define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */ +#define XFS_DIFLAG_RTINHERIT_BIT 8 /* create with realtime bit set */ #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) @@ -464,5 +465,11 @@ #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) +#define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) + +#define XFS_DIFLAG_ANY \ + (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ + XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ + XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT) #endif /* __XFS_DINODE_H__ */ diff -urN linux-2.4.27/fs/xfs/xfs_dir2_trace.c linux-2.4.28/fs/xfs/xfs_dir2_trace.c --- linux-2.4.27/fs/xfs/xfs_dir2_trace.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_dir2_trace.c 2004-11-17 03:54:22.002414505 -0800 @@ -211,7 +211,7 @@ (void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)args->dp, (void *)args->trans, - (void *)(unsigned long)args->justcheck, (void *)(long)s, 0); + (void *)(unsigned long)args->justcheck, (void *)(long)s, NULL); } void diff -urN linux-2.4.27/fs/xfs/xfs_fs.h linux-2.4.28/fs/xfs/xfs_fs.h --- linux-2.4.27/fs/xfs/xfs_fs.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_fs.h 2004-11-17 03:54:22.003414546 -0800 @@ -76,6 +76,7 @@ #define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ #define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ #define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ /* @@ -164,7 +165,7 @@ __s64 l_start; __s64 l_len; /* len == 0 means until end of file */ __s32 l_sysid; - pid_t l_pid; + __u32 l_pid; __s32 l_pad[4]; /* reserve area */ } xfs_flock64_t; @@ -313,10 +314,10 @@ * The user-level BulkStat Request interface structure. */ typedef struct xfs_fsop_bulkreq { - __u64 *lastip; /* last inode # pointer */ + __u64 __user *lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ - void *ubuffer; /* user buffer for inode desc. */ - __s32 *ocount; /* output count pointer */ + void __user *ubuffer;/* user buffer for inode desc. */ + __s32 __user *ocount; /* output count pointer */ } xfs_fsop_bulkreq_t; @@ -344,12 +345,12 @@ */ typedef struct xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ - void *path; /* user pathname */ + void __user *path; /* user pathname */ __u32 oflags; /* open flags */ - void *ihandle; /* user supplied handle */ + void __user *ihandle;/* user supplied handle */ __u32 ihandlen; /* user supplied length */ - void *ohandle; /* user buffer for handle */ - __u32 *ohandlen; /* user buffer length */ + void __user *ohandle;/* user buffer for handle */ + __u32 __user *ohandlen;/* user buffer length */ } xfs_fsop_handlereq_t; /* @@ -360,35 +361,35 @@ */ typedef struct xfs_fsop_setdm_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - struct fsdmidata *data; /* DMAPI data to set */ + struct xfs_fsop_handlereq hreq; /* handle information */ + struct fsdmidata __user *data; /* DMAPI data */ } xfs_fsop_setdm_handlereq_t; typedef struct xfs_attrlist_cursor { - __u32 opaque[4]; + __u32 opaque[4]; } xfs_attrlist_cursor_t; typedef struct xfs_fsop_attrlist_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ - __u32 flags; /* flags, use ROOT/USER names */ - __u32 buflen; /* length of buffer supplied */ - void *buffer; /* attrlist data to return */ + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ + __u32 flags; /* which namespace to use */ + __u32 buflen; /* length of buffer supplied */ + void __user *buffer; /* returned names */ } xfs_fsop_attrlist_handlereq_t; typedef struct xfs_attr_multiop { - __u32 am_opcode; - __s32 am_error; - void *am_attrname; - void *am_attrvalue; - __u32 am_length; - __u32 am_flags; + __u32 am_opcode; + __s32 am_error; + void __user *am_attrname; + void __user *am_attrvalue; + __u32 am_length; + __u32 am_flags; } xfs_attr_multiop_t; typedef struct xfs_fsop_attrmulti_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - __u32 opcount; /* count of following multiop */ - struct xfs_attr_multiop *ops; /* attr_multi data to get/set */ + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + __u32 opcount;/* count of following multiop */ + struct xfs_attr_multiop __user *ops; /* attr_multi data */ } xfs_fsop_attrmulti_handlereq_t; /* @@ -445,6 +446,13 @@ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ /* + * ioctl commands that are used by Linux filesystems + */ +#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) +#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) +#define XFS_IOC_GETVERSION _IOR('v', 1, long) + +/* * ioctl commands that replace IRIX fcntl()'s * For 'documentation' purposed more than anything else, * the "cmd #" field reflects the IRIX fcntl number. diff -urN linux-2.4.27/fs/xfs/xfs_fsops.c linux-2.4.28/fs/xfs/xfs_fsops.c --- linux-2.4.27/fs/xfs/xfs_fsops.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_fsops.c 2004-11-17 03:54:22.004414587 -0800 @@ -142,6 +142,7 @@ int dpct; int error; xfs_agnumber_t nagcount; + xfs_agnumber_t nagimax = 0; xfs_rfsblock_t nb, nb_mod; xfs_rfsblock_t new; xfs_rfsblock_t nfree; @@ -183,7 +184,7 @@ memset(&mp->m_perag[oagcount], 0, (nagcount - oagcount) * sizeof(xfs_perag_t)); mp->m_flags |= XFS_MOUNT_32BITINODES; - xfs_initialize_perag(mp, nagcount); + nagimax = xfs_initialize_perag(mp, nagcount); up_write(&mp->m_peraglock); } tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); @@ -372,6 +373,9 @@ if (error) { return error; } + /* New allocation groups fully initialized, so update mount struct */ + if (nagimax) + mp->m_maxagi = nagimax; if (mp->m_sb.sb_imax_pct) { __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; do_div(icount, 100); @@ -507,9 +511,9 @@ __uint64_t *inval, xfs_fsop_resblks_t *outval) { - __uint64_t lcounter, delta; - __uint64_t request; - unsigned long s; + __int64_t lcounter, delta; + __uint64_t request; + unsigned long s; /* If inval is null, report current values and return */ @@ -536,8 +540,7 @@ mp->m_resblks = request; } else { delta = request - mp->m_resblks; - lcounter = mp->m_sb.sb_fdblocks; - lcounter -= delta; + lcounter = mp->m_sb.sb_fdblocks - delta; if (lcounter < 0) { /* We can't satisfy the request, just get what we can */ mp->m_resblks += mp->m_sb.sb_fdblocks; @@ -583,63 +586,22 @@ } int -xfs_fs_freeze( - xfs_mount_t *mp) -{ - vfs_t *vfsp; - /*REFERENCED*/ - int error; - - vfsp = XFS_MTOVFS(mp); - - /* Stop new writers */ - xfs_start_freeze(mp, XFS_FREEZE_WRITE); - - /* Flush the refcache */ - xfs_refcache_purge_mp(mp); - - /* Flush delalloc and delwri data */ - VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error); - - /* Pause transaction subsystem */ - xfs_start_freeze(mp, XFS_FREEZE_TRANS); - - /* Flush any remaining inodes into buffers */ - VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); - - /* Push all buffers out to disk */ - xfs_binval(mp->m_ddev_targp); - if (mp->m_rtdev_targp) { - xfs_binval(mp->m_rtdev_targp); - } - - /* Push the superblock and write an unmount record */ - xfs_log_unmount_write(mp); - xfs_unmountfs_writesb(mp); - - return 0; -} - -int -xfs_fs_thaw( - xfs_mount_t *mp) -{ - xfs_finish_freeze(mp); - return 0; -} - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags) { - switch (inflags) - { - case XFS_FSOP_GOING_FLAGS_DEFAULT: - xfs_fs_freeze(mp); - xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); - xfs_fs_thaw(mp); + switch (inflags) { + case XFS_FSOP_GOING_FLAGS_DEFAULT: { + struct vfs *vfsp = XFS_MTOVFS(mp); + struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); + + if (sb) { + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); + thaw_bdev(sb->s_bdev, sb); + } + break; + } case XFS_FSOP_GOING_FLAGS_LOGFLUSH: xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); break; diff -urN linux-2.4.27/fs/xfs/xfs_fsops.h linux-2.4.28/fs/xfs/xfs_fsops.h --- linux-2.4.27/fs/xfs/xfs_fsops.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_fsops.h 2004-11-17 03:54:22.004414587 -0800 @@ -60,14 +60,6 @@ xfs_fsop_resblks_t *outval); int -xfs_fs_freeze( - xfs_mount_t *mp); - -int -xfs_fs_thaw( - xfs_mount_t *mp); - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags); diff -urN linux-2.4.27/fs/xfs/xfs_inode.c linux-2.4.28/fs/xfs/xfs_inode.c --- linux-2.4.27/fs/xfs/xfs_inode.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_inode.c 2004-11-17 03:54:22.007414710 -0800 @@ -860,25 +860,28 @@ xfs_arch_t arch) { __uint16_t di_flags; - uint flags = 0; + uint flags; di_flags = INT_GET(dic->di_flags, arch); - if (di_flags & XFS_DIFLAG_REALTIME) - flags |= XFS_XFLAG_REALTIME; - if (di_flags & XFS_DIFLAG_PREALLOC) - flags |= XFS_XFLAG_PREALLOC; - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= XFS_XFLAG_IMMUTABLE; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= XFS_XFLAG_APPEND; - if (di_flags & XFS_DIFLAG_SYNC) - flags |= XFS_XFLAG_SYNC; - if (di_flags & XFS_DIFLAG_NOATIME) - flags |= XFS_XFLAG_NOATIME; - if (di_flags & XFS_DIFLAG_NODUMP) - flags |= XFS_XFLAG_NODUMP; - if (XFS_CFORK_Q_ARCH(dic, arch)) - flags |= XFS_XFLAG_HASATTR; + flags = XFS_CFORK_Q_ARCH(dic, arch) ? XFS_XFLAG_HASATTR : 0; + if (di_flags & XFS_DIFLAG_ANY) { + if (di_flags & XFS_DIFLAG_REALTIME) + flags |= XFS_XFLAG_REALTIME; + if (di_flags & XFS_DIFLAG_PREALLOC) + flags |= XFS_XFLAG_PREALLOC; + if (di_flags & XFS_DIFLAG_IMMUTABLE) + flags |= XFS_XFLAG_IMMUTABLE; + if (di_flags & XFS_DIFLAG_APPEND) + flags |= XFS_XFLAG_APPEND; + if (di_flags & XFS_DIFLAG_SYNC) + flags |= XFS_XFLAG_SYNC; + if (di_flags & XFS_DIFLAG_NOATIME) + flags |= XFS_XFLAG_NOATIME; + if (di_flags & XFS_DIFLAG_NODUMP) + flags |= XFS_XFLAG_NODUMP; + if (di_flags & XFS_DIFLAG_RTINHERIT) + flags |= XFS_XFLAG_RTINHERIT; + } return flags; } @@ -1236,8 +1239,15 @@ break; case S_IFREG: case S_IFDIR: - if (pip->i_d.di_flags & - (XFS_DIFLAG_NOATIME|XFS_DIFLAG_NODUMP|XFS_DIFLAG_SYNC)) { + if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) { + if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { + if ((mode & S_IFMT) == S_IFDIR) { + ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT; + } else { + ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; + ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } + } if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && xfs_inherit_noatime) ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; @@ -1248,6 +1258,7 @@ xfs_inherit_sync) ip->i_d.di_flags |= XFS_DIFLAG_SYNC; } + /* FALLTHROUGH */ case S_IFLNK: ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS; @@ -3579,6 +3590,7 @@ return XFS_ERROR(EFSCORRUPTED); } + /* * Flush all inactive inodes in mp. Return true if no user references * were found, false otherwise. @@ -3634,7 +3646,6 @@ continue; } if (!(flag & XFS_FLUSH_ALL)) { - ASSERT(0); busy = 1; done = 1; break; @@ -3851,6 +3862,6 @@ (void *)ra, /* caller of ilock */ (void *)(unsigned long)current_cpu(), (void *)(unsigned long)current_pid(), - 0,0,0,0,0,0,0,0,0,0); + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif diff -urN linux-2.4.27/fs/xfs/xfs_iomap.c linux-2.4.28/fs/xfs/xfs_iomap.c --- linux-2.4.27/fs/xfs/xfs_iomap.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_iomap.c 2004-11-17 03:54:22.008414751 -0800 @@ -165,20 +165,24 @@ nisize = io->io_new_size; for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) { - iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ? - mp->m_rtdev_targp : mp->m_ddev_targp; iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff); iomapp->iomap_delta = offset - iomapp->iomap_offset; iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); iomapp->iomap_flags = flags; + if (io->io_flags & XFS_IOCORE_RT) { + iomapp->iomap_flags |= IOMAP_REALTIME; + iomapp->iomap_target = mp->m_rtdev_targp; + } else { + iomapp->iomap_target = mp->m_ddev_targp; + } start_block = imap->br_startblock; if (start_block == HOLESTARTBLOCK) { iomapp->iomap_bn = IOMAP_DADDR_NULL; - iomapp->iomap_flags = IOMAP_HOLE; + iomapp->iomap_flags |= IOMAP_HOLE; } else if (start_block == DELAYSTARTBLOCK) { iomapp->iomap_bn = IOMAP_DADDR_NULL; - iomapp->iomap_flags = IOMAP_DELAY; + iomapp->iomap_flags |= IOMAP_DELAY; } else { iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block); if (ISUNWRITTEN(imap)) @@ -512,6 +516,15 @@ *ret_imap = imap[0]; *nmaps = 1; + if ( !(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) { + cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld " + "start_block : %llx start_off : %llx blkcnt : %llx " + "extent-state : %x \n", + (ip->i_mount)->m_fsname, + (long long)ip->i_ino, + ret_imap->br_startblock, ret_imap->br_startoff, + ret_imap->br_blockcount,ret_imap->br_state); + } return 0; error0: /* Cancel bmap, unlock inode, and cancel trans */ @@ -572,8 +585,10 @@ * out to the file system's write iosize. We clean up any extra * space left over when the file is closed in xfs_inactive(). * - * We don't bother with this for sync writes, because we need - * to minimize the amount we write for good performance. + * For sync writes, we are flushing delayed allocate space to + * try to make additional space available for allocation near + * the filesystem full boundary - preallocation hurts in that + * situation, of course. */ if (!(ioflag & BMAPI_SYNC) && ((offset + count) > ip->i_d.di_size)) { xfs_off_t aligned_offset; @@ -598,6 +613,20 @@ return error; } for (n = 0; n < nimaps; n++) { + if ( !(io->io_flags & XFS_IOCORE_RT) && + !imap[n].br_startblock) { + cmn_err(CE_PANIC,"Access to block " + "zero: fs <%s> inode: %lld " + "start_block : %llx start_off " + ": %llx blkcnt : %llx " + "extent-state : %x \n", + (ip->i_mount)->m_fsname, + (long long)ip->i_ino, + imap[n].br_startblock, + imap[n].br_startoff, + imap[n].br_blockcount, + imap[n].br_state); + } if ((imap[n].br_startblock != HOLESTARTBLOCK) && (imap[n].br_startblock != DELAYSTARTBLOCK)) { goto write_map; @@ -621,7 +650,8 @@ * request to a stripe width boundary if the file size is >= * stripe width and we are allocating past the allocation eof. */ - if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) + if (!(io->io_flags & XFS_IOCORE_RT) && mp->m_swidth + && (mp->m_flags & XFS_MOUNT_SWALLOC) && (isize >= XFS_FSB_TO_B(mp, mp->m_swidth)) && aeof) { int eof; xfs_fileoff_t new_last_fsb; @@ -639,8 +669,8 @@ * if the file size is >= stripe unit size, and we are allocating past * the allocation eof. */ - } else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)) - && aeof) { + } else if (!(io->io_flags & XFS_IOCORE_RT) && mp->m_dalign && + (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)) && aeof) { int eof; xfs_fileoff_t new_last_fsb; new_last_fsb = roundup_64(last_fsb, mp->m_dalign); @@ -651,8 +681,22 @@ if (eof) { last_fsb = new_last_fsb; } - } + /* + * Round up the allocation request to a real-time extent boundary + * if the file is on the real-time subvolume. + */ + } else if (io->io_flags & XFS_IOCORE_RT && aeof) { + int eof; + xfs_fileoff_t new_last_fsb; + new_last_fsb = roundup_64(last_fsb, mp->m_sb.sb_rextsize); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + if (error) { + return error; + } + if (eof) + last_fsb = new_last_fsb; + } error = xfs_bmapi(NULL, ip, offset_fsb, (xfs_filblks_t)(last_fsb - offset_fsb), XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | @@ -680,6 +724,15 @@ *ret_imap = imap[0]; *nmaps = 1; + if ( !(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) { + cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld " + "start_block : %llx start_off : %llx blkcnt : %llx " + "extent-state : %x \n", + (ip->i_mount)->m_fsname, + (long long)ip->i_ino, + ret_imap->br_startblock, ret_imap->br_startoff, + ret_imap->br_blockcount,ret_imap->br_state); + } return 0; } @@ -697,6 +750,7 @@ int *retmap) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb, last_block; xfs_fileoff_t end_fsb, map_start_fsb; xfs_fsblock_t first_block; @@ -802,6 +856,18 @@ */ for (i = 0; i < nimaps; i++) { + if ( !(io->io_flags & XFS_IOCORE_RT) && + !imap[i].br_startblock) { + cmn_err(CE_PANIC,"Access to block zero: " + "fs <%s> inode: %lld " + "start_block : %llx start_off : %llx " + "blkcnt : %llx extent-state : %x \n", + (ip->i_mount)->m_fsname, + (long long)ip->i_ino, + imap[i].br_startblock, + imap[i].br_startoff, + imap[i].br_blockcount,imap[i].br_state); + } if ((map->br_startoff >= imap[i].br_startoff) && (map->br_startoff < (imap[i].br_startoff + imap[i].br_blockcount))) { @@ -837,6 +903,7 @@ size_t count) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_trans_t *tp; xfs_fileoff_t offset_fsb; xfs_filblks_t count_fsb; @@ -853,7 +920,8 @@ &ip->i_iocore, offset, count); offset_fsb = XFS_B_TO_FSBT(mp, offset); - count_fsb = XFS_B_TO_FSB(mp, count); + count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); + count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); do { nres = XFS_DIOSTRAT_SPACE_RES(mp, 0); @@ -898,6 +966,16 @@ xfs_iunlock(ip, XFS_ILOCK_EXCL); if (error) goto error0; + + if ( !(io->io_flags & XFS_IOCORE_RT) && !imap.br_startblock) { + cmn_err(CE_PANIC,"Access to block zero: fs <%s> " + "inode: %lld start_block : %llx start_off : " + "%llx blkcnt : %llx extent-state : %x \n", + (ip->i_mount)->m_fsname, + (long long)ip->i_ino, + imap.br_startblock,imap.br_startoff, + imap.br_blockcount,imap.br_state); + } if ((numblks_fsb = imap.br_blockcount) == 0) { /* diff -urN linux-2.4.27/fs/xfs/xfs_iomap.h linux-2.4.28/fs/xfs/xfs_iomap.h --- linux-2.4.27/fs/xfs/xfs_iomap.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_iomap.h 2004-11-17 03:54:22.009414793 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -42,6 +42,7 @@ IOMAP_EOF = 0x01, /* mapping contains EOF */ IOMAP_HOLE = 0x02, /* mapping covers a hole */ IOMAP_DELAY = 0x04, /* mapping covers delalloc region */ + IOMAP_REALTIME = 0x10, /* mapping on the realtime device */ IOMAP_UNWRITTEN = 0x20, /* mapping covers allocated */ /* but uninitialized file data */ IOMAP_NEW = 0x40 /* just allocate */ @@ -57,7 +58,7 @@ BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */ BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ BMAPI_MMAP = (1 << 6), /* allocate for mmap write */ - BMAPI_SYNC = (1 << 7), /* sync write */ + BMAPI_SYNC = (1 << 7), /* sync write to flush delalloc space */ BMAPI_TRYLOCK = (1 << 8), /* non-blocking request */ BMAPI_DEVICE = (1 << 9), /* we only want to know the device */ } bmapi_flags_t; diff -urN linux-2.4.27/fs/xfs/xfs_itable.c linux-2.4.28/fs/xfs/xfs_itable.c --- linux-2.4.27/fs/xfs/xfs_itable.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_itable.c 2004-11-17 03:54:22.010414834 -0800 @@ -68,7 +68,7 @@ xfs_bulkstat_one( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ - void *buffer, /* buffer to place output in */ + void __user *buffer, /* buffer to place output in */ int ubsize, /* size of buffer */ void *private_data, /* my private data */ xfs_daddr_t bno, /* starting bno of inode cluster */ @@ -231,7 +231,7 @@ bulkstat_one_pf formatter, /* func that'd fill a single buf */ void *private_data,/* private data for formatter */ size_t statstruct_size, /* sizeof struct filling */ - xfs_caddr_t ubuffer, /* buffer with inode stats */ + char __user *ubuffer, /* buffer with inode stats */ int flags, /* defined in xfs_itable.h */ int *done) /* 1 if there're more stats to get */ { @@ -265,7 +265,7 @@ int tmp; /* result value from btree calls */ int ubcount; /* size of user's buffer */ int ubleft; /* bytes left in user's buffer */ - xfs_caddr_t ubufp; /* current pointer into user's buffer */ + char __user *ubufp; /* pointer into user's buffer */ int ubelem; /* spaces used in user's buffer */ int ubused; /* bytes used by formatter */ xfs_buf_t *bp; /* ptr to on-disk inode cluster buf */ @@ -633,7 +633,7 @@ xfs_bulkstat_single( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *lastinop, /* inode to return */ - xfs_caddr_t buffer, /* buffer with inode stats */ + char __user *buffer, /* buffer with inode stats */ int *done) /* 1 if there're more stats to get */ { int count; /* count value for bulkstat call */ @@ -682,7 +682,7 @@ xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *lastino, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_caddr_t ubuffer) /* buffer with inode descriptions */ + xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */ { xfs_buf_t *agbp; xfs_agino_t agino; @@ -766,7 +766,7 @@ error = XFS_ERROR(EFAULT); break; } - ubuffer += bufidx * sizeof(*buffer); + ubuffer += bufidx; *count += bufidx; bufidx = 0; } diff -urN linux-2.4.27/fs/xfs/xfs_itable.h linux-2.4.28/fs/xfs/xfs_itable.h --- linux-2.4.27/fs/xfs/xfs_itable.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_itable.h 2004-11-17 03:54:22.010414834 -0800 @@ -40,7 +40,7 @@ */ typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, xfs_ino_t ino, - void *buffer, + void __user *buffer, int ubsize, void *private_data, xfs_daddr_t bno, @@ -73,7 +73,7 @@ bulkstat_one_pf formatter, /* func that'd fill a single buf */ void *private_data, /* private data for formatter */ size_t statstruct_size,/* sizeof struct that we're filling */ - xfs_caddr_t ubuffer, /* buffer with inode stats */ + char __user *ubuffer,/* buffer with inode stats */ int flags, /* flag to control access method */ int *done); /* 1 if there're more stats to get */ @@ -81,14 +81,14 @@ xfs_bulkstat_single( xfs_mount_t *mp, xfs_ino_t *lastinop, - xfs_caddr_t buffer, + char __user *buffer, int *done); int xfs_bulkstat_one( xfs_mount_t *mp, xfs_ino_t ino, - void *buffer, + void __user *buffer, int ubsize, void *private_data, xfs_daddr_t bno, @@ -101,6 +101,6 @@ xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *last, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_caddr_t buffer);/* buffer with inode descriptions */ + xfs_inogrp_t __user *buffer);/* buffer with inode info */ #endif /* __XFS_ITABLE_H__ */ diff -urN linux-2.4.27/fs/xfs/xfs_log.c linux-2.4.28/fs/xfs/xfs_log.c --- linux-2.4.27/fs/xfs/xfs_log.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_log.c 2004-11-17 03:54:22.013414957 -0800 @@ -122,7 +122,6 @@ /* local debug functions */ #if defined(DEBUG) && !defined(XLOG_NOLOG) STATIC void xlog_verify_dest_ptr(xlog_t *log, __psint_t ptr); -STATIC void xlog_verify_disk_cycle_no(xlog_t *log, xlog_in_core_t *iclog); STATIC void xlog_verify_grant_head(xlog_t *log, int equals); STATIC void xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog, int count, boolean_t syncing); @@ -130,7 +129,6 @@ xfs_lsn_t tail_lsn); #else #define xlog_verify_dest_ptr(a,b) -#define xlog_verify_disk_cycle_no(a,b) #define xlog_verify_grant_head(a,b) #define xlog_verify_iclog(a,b,c,d) #define xlog_verify_tail_lsn(a,b,c) @@ -356,13 +354,13 @@ if (!xlog_debug && xlog_target == log->l_targ) return 0; #endif - cb->cb_next = 0; + cb->cb_next = NULL; spl = LOG_LOCK(log); abortflg = (iclog->ic_state & XLOG_STATE_IOERROR); if (!abortflg) { ASSERT_ALWAYS((iclog->ic_state == XLOG_STATE_ACTIVE) || (iclog->ic_state == XLOG_STATE_WANT_SYNC)); - cb->cb_next = 0; + cb->cb_next = NULL; *(iclog->ic_callback_tail) = cb; iclog->ic_callback_tail = &(cb->cb_next); } @@ -564,7 +562,7 @@ xlog_in_core_t *first_iclog; #endif xfs_log_iovec_t reg[1]; - xfs_log_ticket_t tic = 0; + xfs_log_ticket_t tic = NULL; xfs_lsn_t lsn; int error; SPLDECL(s); @@ -813,7 +811,7 @@ xlog_t *log = mp->m_log; vfs_t *vfsp = XFS_MTOVFS(mp); - if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp) || + if (fs_frozen(vfsp) || XFS_FORCED_SHUTDOWN(mp) || (vfsp->vfs_flag & VFS_RDONLY)) return 0; @@ -1277,7 +1275,7 @@ int error; xfs_log_iovec_t reg[1]; - reg[0].i_addr = 0; + reg[0].i_addr = NULL; reg[0].i_len = 0; ASSERT_ALWAYS(iclog); @@ -1413,9 +1411,13 @@ xlog_pack_data(log, iclog); /* put cycle number in every block */ /* real byte length */ - INT_SET(iclog->ic_header.h_len, - ARCH_CONVERT, - iclog->ic_offset + iclog->ic_roundoff); + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + INT_SET(iclog->ic_header.h_len, + ARCH_CONVERT, + iclog->ic_offset + iclog->ic_roundoff); + } else { + INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); + } /* put ops count in correct order */ ops = iclog->ic_header.h_num_logops; @@ -1857,7 +1859,7 @@ if (iclog->ic_state == XLOG_STATE_DIRTY) { iclog->ic_state = XLOG_STATE_ACTIVE; iclog->ic_offset = 0; - iclog->ic_callback = 0; /* don't need to free */ + iclog->ic_callback = NULL; /* don't need to free */ /* * If the number of ops in this iclog indicate it just * contains the dummy transaction, we can @@ -2080,7 +2082,7 @@ while (cb != 0) { iclog->ic_callback_tail = &(iclog->ic_callback); - iclog->ic_callback = 0; + iclog->ic_callback = NULL; LOG_UNLOCK(log, s); /* perform callbacks in the order given */ @@ -3098,7 +3100,7 @@ log->l_ticket_cnt++; log->l_ticket_tcnt++; } - t_list->t_next = 0; + t_list->t_next = NULL; log->l_tail = t_list; LOG_UNLOCK(log, s); } /* xlog_state_ticket_alloc */ @@ -3126,7 +3128,7 @@ /* no need to clear fields */ #else /* When we debug, it is easier if tickets are cycled */ - ticket->t_next = 0; + ticket->t_next = NULL; if (log->l_tail != 0) { log->l_tail->t_next = ticket; } else { @@ -3242,33 +3244,6 @@ xlog_panic("xlog_verify_dest_ptr: invalid ptr"); } /* xlog_verify_dest_ptr */ - -#ifdef DEBUG -/* check split LR write */ -STATIC void -xlog_verify_disk_cycle_no(xlog_t *log, - xlog_in_core_t *iclog) -{ - xfs_buf_t *bp; - uint cycle_no; - xfs_caddr_t ptr; - xfs_daddr_t i; - - if (BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT) < 10) { - cycle_no = CYCLE_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); - bp = xlog_get_bp(log, 1); - ASSERT(bp); - for (i = 0; i < BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); i++) { - xlog_bread(log, i, 1, bp); - ptr = xlog_align(log, i, 1, bp); - if (GET_CYCLE(ptr, ARCH_CONVERT) != cycle_no) - xlog_warn("XFS: xlog_verify_disk_cycle_no: bad cycle no"); - } - xlog_put_bp(bp); - } -} /* xlog_verify_disk_cycle_no */ -#endif - STATIC void xlog_verify_grant_head(xlog_t *log, int equals) { diff -urN linux-2.4.27/fs/xfs/xfs_log_recover.c linux-2.4.28/fs/xfs/xfs_log_recover.c --- linux-2.4.27/fs/xfs/xfs_log_recover.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_log_recover.c 2004-11-17 03:54:22.015415039 -0800 @@ -2047,12 +2047,11 @@ errs++; } - if (! errs) { + if (! errs && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) { if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) && INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) { - if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) && - !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) { + if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT)) { if (flags & XFS_QMOPT_DOWARN) cmn_err(CE_ALERT, "%s : Dquot ID 0x%x (0x%p) " @@ -2065,8 +2064,7 @@ if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) && INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) { - if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) && - !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) { + if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT)) { if (flags & XFS_QMOPT_DOWARN) cmn_err(CE_ALERT, "%s : Dquot ID 0x%x (0x%p) " @@ -2076,6 +2074,19 @@ errs++; } } + if (INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT) && + INT_GET(ddq->d_rtbcount, ARCH_CONVERT) >= + INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT)) { + if (INT_ISZERO(ddq->d_rtbtimer, ARCH_CONVERT)) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : Dquot ID 0x%x (0x%p) " + "RTBLK TIMER NOT STARTED", + str, (int) + INT_GET(ddq->d_id, ARCH_CONVERT), ddq); + errs++; + } + } } if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) @@ -2319,7 +2330,7 @@ * invalidate the buffer when we write it out below. */ imap.im_blkno = 0; - xfs_imap(log->l_mp, 0, ino, &imap, 0); + xfs_imap(log->l_mp, NULL, ino, &imap, 0); } /* diff -urN linux-2.4.27/fs/xfs/xfs_mount.c linux-2.4.28/fs/xfs/xfs_mount.c --- linux-2.4.27/fs/xfs/xfs_mount.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_mount.c 2004-11-17 03:54:22.017415122 -0800 @@ -140,9 +140,6 @@ */ xfs_trans_ail_init(mp); - /* Init freeze sync structures */ - spinlock_init(&mp->m_freeze_lock, "xfs_freeze"); - init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0); atomic_set(&mp->m_active_trans, 0); return mp; @@ -192,8 +189,6 @@ VFS_REMOVEBHV(vfsp, &mp->m_bhv); } - spinlock_destroy(&mp->m_freeze_lock); - sv_destroy(&mp->m_wait_unfreeze); kmem_free(mp, sizeof(xfs_mount_t)); } @@ -283,17 +278,22 @@ return XFS_ERROR(EFSCORRUPTED); } -#if !XFS_BIG_BLKNOS + ASSERT(PAGE_SHIFT >= sbp->sb_blocklog); + ASSERT(sbp->sb_blocklog >= BBSHIFT); + +#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */ + if (unlikely( + (sbp->sb_dblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX || + (sbp->sb_rblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX)) { +#else /* Limited by UINT_MAX of sectors */ if (unlikely( - (sbp->sb_dblocks << (__uint64_t)(sbp->sb_blocklog - BBSHIFT)) - > UINT_MAX || - (sbp->sb_rblocks << (__uint64_t)(sbp->sb_blocklog - BBSHIFT)) - > UINT_MAX)) { + (sbp->sb_dblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX || + (sbp->sb_rblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX)) { +#endif cmn_err(CE_WARN, "XFS: File system is too large to be mounted on this system."); return XFS_ERROR(E2BIG); } -#endif if (unlikely(sbp->sb_inprogress)) { cmn_err(CE_WARN, "XFS: file system busy"); @@ -318,10 +318,10 @@ return 0; } -void -xfs_initialize_perag(xfs_mount_t *mp, int agcount) +xfs_agnumber_t +xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount) { - int index, max_metadata; + xfs_agnumber_t index, max_metadata; xfs_perag_t *pag; xfs_agino_t agino; xfs_ino_t ino; @@ -377,7 +377,7 @@ pag->pagi_inodeok = 1; } } - mp->m_maxagi = index; + return index; } /* @@ -638,9 +638,8 @@ xfs_buf_t *bp; xfs_sb_t *sbp = &(mp->m_sb); xfs_inode_t *rip; - vnode_t *rvp = 0; + vnode_t *rvp = NULL; int readio_log, writeio_log; - vmap_t vmap; xfs_daddr_t d; __uint64_t ret64; __int64_t update_flags; @@ -952,7 +951,7 @@ mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); - xfs_initialize_perag(mp, sbp->sb_agcount); + mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); /* * log's mount-time initialization. Perform 1st part recovery if needed @@ -984,7 +983,6 @@ ASSERT(rip != NULL); rvp = XFS_ITOV(rip); - VMAP(rvp, vmap); if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { cmn_err(CE_WARN, "XFS: corrupted root inode"); @@ -1048,7 +1046,6 @@ * Free up the root inode. */ VN_RELE(rvp); - vn_purge(rvp, &vmap); error3: xfs_log_unmount_dealloc(mp); error2: @@ -1582,59 +1579,3 @@ xfs_mod_sb(tp, fields); xfs_trans_commit(tp, 0, NULL); } - -/* Functions to lock access out of the filesystem for forced - * shutdown or snapshot. - */ - -void -xfs_start_freeze( - xfs_mount_t *mp, - int level) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - mp->m_frozen = level; - mutex_spinunlock(&mp->m_freeze_lock, s); - - if (level == XFS_FREEZE_TRANS) { - while (atomic_read(&mp->m_active_trans) > 0) - delay(100); - } -} - -void -xfs_finish_freeze( - xfs_mount_t *mp) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen) { - mp->m_frozen = 0; - sv_broadcast(&mp->m_wait_unfreeze); - } - - mutex_spinunlock(&mp->m_freeze_lock, s); -} - -void -xfs_check_frozen( - xfs_mount_t *mp, - bhv_desc_t *bdp, - int level) -{ - unsigned long s; - - if (mp->m_frozen) { - s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen < level) { - mutex_spinunlock(&mp->m_freeze_lock, s); - } else { - sv_wait(&mp->m_wait_unfreeze, 0, &mp->m_freeze_lock, s); - } - } - - if (level == XFS_FREEZE_TRANS) - atomic_inc(&mp->m_active_trans); -} diff -urN linux-2.4.27/fs/xfs/xfs_mount.h linux-2.4.28/fs/xfs/xfs_mount.h --- linux-2.4.27/fs/xfs/xfs_mount.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_mount.h 2004-11-17 03:54:22.018415163 -0800 @@ -382,10 +382,6 @@ struct xfs_dmops m_dm_ops; /* vector of DMI ops */ struct xfs_qmops m_qm_ops; /* vector of XQM ops */ struct xfs_ioops m_io_ops; /* vector of I/O ops */ - lock_t m_freeze_lock; /* Lock for m_frozen */ - uint m_frozen; /* FS frozen for shutdown or - * snapshot */ - sv_t m_wait_unfreeze;/* waiting to unfreeze */ atomic_t m_active_trans; /* number trans frozen */ } xfs_mount_t; @@ -555,20 +551,10 @@ extern void xfs_freesb(xfs_mount_t *); extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); extern int xfs_syncsub(xfs_mount_t *, int, int, int *); -extern void xfs_initialize_perag(xfs_mount_t *, int); +extern xfs_agnumber_t xfs_initialize_perag(xfs_mount_t *, xfs_agnumber_t); extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); -/* - * Flags for freeze operations. - */ -#define XFS_FREEZE_WRITE 1 -#define XFS_FREEZE_TRANS 2 - -extern void xfs_start_freeze(xfs_mount_t *, int); -extern void xfs_finish_freeze(xfs_mount_t *); -extern void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int); - extern struct vfsops xfs_vfsops; extern struct vnodeops xfs_vnodeops; diff -urN linux-2.4.27/fs/xfs/xfs_quota.h linux-2.4.28/fs/xfs/xfs_quota.h --- linux-2.4.27/fs/xfs/xfs_quota.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_quota.h 2004-11-17 03:54:22.018415163 -0800 @@ -309,23 +309,27 @@ } xfs_dqtrxops_t; #define XFS_DQTRXOP(mp, tp, op, args...) \ - ((mp)->m_qm_ops.xfs_dqtrxops ? \ - ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : 0) + ((mp)->m_qm_ops.xfs_dqtrxops ? \ + ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : 0) + +#define XFS_DQTRXOP_VOID(mp, tp, op, args...) \ + ((mp)->m_qm_ops.xfs_dqtrxops ? \ + ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : (void)0) #define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \ - XFS_DQTRXOP(mp, otp, qo_dup_dqinfo, ntp) + XFS_DQTRXOP_VOID(mp, otp, qo_dup_dqinfo, ntp) #define XFS_TRANS_FREE_DQINFO(mp, tp) \ - XFS_DQTRXOP(mp, tp, qo_free_dqinfo) + XFS_DQTRXOP_VOID(mp, tp, qo_free_dqinfo) #define XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, field, delta) \ - XFS_DQTRXOP(mp, tp, qo_mod_dquot_byino, ip, field, delta) + XFS_DQTRXOP_VOID(mp, tp, qo_mod_dquot_byino, ip, field, delta) #define XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp) \ - XFS_DQTRXOP(mp, tp, qo_apply_dquot_deltas) + XFS_DQTRXOP_VOID(mp, tp, qo_apply_dquot_deltas) #define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, fl) \ XFS_DQTRXOP(mp, tp, qo_reserve_quota_nblks, mp, ip, nblks, ninos, fl) #define XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, fl) \ XFS_DQTRXOP(mp, tp, qo_reserve_quota_bydquots, mp, ud, gd, nb, ni, fl) #define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \ - XFS_DQTRXOP(mp, tp, qo_unreserve_and_mod_dquots) + XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots) #define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \ XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \ diff -urN linux-2.4.27/fs/xfs/xfs_rtalloc.c linux-2.4.28/fs/xfs/xfs_rtalloc.c --- linux-2.4.27/fs/xfs/xfs_rtalloc.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_rtalloc.c 2004-11-17 03:54:22.020415245 -0800 @@ -2353,13 +2353,7 @@ ASSERT(sbp->sb_rsumino != NULLFSINO); error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0); if (error) { - vnode_t *rbmvp; /* vnode for bitmap file */ - vmap_t vmap; /* vmap to delete vnode */ - - rbmvp = XFS_ITOV(mp->m_rbmip); - VMAP(rbmvp, vmap); - VN_RELE(rbmvp); - vn_purge(rbmvp, &vmap); + VN_RELE(XFS_ITOV(mp->m_rbmip)); return error; } ASSERT(mp->m_rsumip != NULL); diff -urN linux-2.4.27/fs/xfs/xfs_sb.h linux-2.4.28/fs/xfs/xfs_sb.h --- linux-2.4.27/fs/xfs/xfs_sb.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_sb.h 2004-11-17 03:54:22.021415286 -0800 @@ -250,9 +250,9 @@ ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ - !(((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) && \ - ((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \ - ((sbp)->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)) + !(((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) || \ + (((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \ + ((sbp)->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))) #ifdef __KERNEL__ #define XFS_SB_GOOD_VERSION(sbp) \ diff -urN linux-2.4.27/fs/xfs/xfs_trans.c linux-2.4.28/fs/xfs/xfs_trans.c --- linux-2.4.27/fs/xfs/xfs_trans.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_trans.c 2004-11-17 03:54:22.022415327 -0800 @@ -131,7 +131,9 @@ xfs_mount_t *mp, uint type) { - xfs_check_frozen(mp, NULL, XFS_FREEZE_TRANS); + fs_check_frozen(XFS_MTOVFS(mp), SB_FREEZE_TRANS); + atomic_inc(&mp->m_active_trans); + return (_xfs_trans_alloc(mp, type)); } @@ -489,6 +491,9 @@ if (tp->t_frextents_delta != 0) { INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta); } + if (tp->t_res_frextents_delta != 0) { + INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_res_frextents_delta); + } if (tp->t_dblocks_delta != 0) { INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta); whole = 1; diff -urN linux-2.4.27/fs/xfs/xfs_trans_item.c linux-2.4.28/fs/xfs/xfs_trans_item.c --- linux-2.4.27/fs/xfs/xfs_trans_item.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_trans_item.c 2004-11-17 03:54:22.022415327 -0800 @@ -290,7 +290,7 @@ } ASSERT(0); /* NOTREACHED */ - return 0; /* keep gcc quite */ + return NULL; /* keep gcc quite */ } /* diff -urN linux-2.4.27/fs/xfs/xfs_types.h linux-2.4.28/fs/xfs/xfs_types.h --- linux-2.4.27/fs/xfs/xfs_types.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/fs/xfs/xfs_types.h 2004-11-17 03:54:22.023415368 -0800 @@ -58,7 +58,7 @@ typedef __int64_t prid_t; /* project ID */ typedef __uint32_t inst_t; /* an instruction */ -typedef __u64 xfs_off_t; +typedef __s64 xfs_off_t; /* type */ typedef __u64 xfs_ino_t; /* type */ typedef __s64 xfs_daddr_t; /* type */ typedef char * xfs_caddr_t; /* type */ diff -urN linux-2.4.27/fs/xfs/xfs_vfsops.c linux-2.4.28/fs/xfs/xfs_vfsops.c --- linux-2.4.27/fs/xfs/xfs_vfsops.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_vfsops.c 2004-11-17 03:54:22.024415409 -0800 @@ -431,6 +431,16 @@ logdev = rtdev = NULL; /* + * Setup xfs_mount function vectors from available behaviors + */ + p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM); + mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_stub; + p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM); + mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_stub; + p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO); + mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs; + + /* * Open real time and log devices - order is important. */ if (args->logname[0]) { @@ -455,68 +465,73 @@ } /* - * Setup xfs_mount function vectors from available behaviors - */ - p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM); - mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_stub; - p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM); - mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_stub; - p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO); - mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs; - - /* * Setup xfs_mount buffer target pointers */ + error = ENOMEM; mp->m_ddev_targp = xfs_alloc_buftarg(ddev); - if (rtdev) + if (!mp->m_ddev_targp) { + xfs_blkdev_put(logdev); + xfs_blkdev_put(rtdev); + return error; + } + if (rtdev) { mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev); + if (!mp->m_rtdev_targp) + goto error0; + } mp->m_logdev_targp = (logdev && logdev != ddev) ? xfs_alloc_buftarg(logdev) : mp->m_ddev_targp; + if (!mp->m_logdev_targp) + goto error0; /* * Setup flags based on mount(2) options and then the superblock */ error = xfs_start_flags(vfsp, args, mp); if (error) - goto error; + goto error1; error = xfs_readsb(mp); if (error) - goto error; + goto error1; error = xfs_finish_flags(vfsp, args, mp); - if (error) { - xfs_freesb(mp); - goto error; - } + if (error) + goto error2; /* * Setup xfs_mount buffer target pointers based on superblock */ - xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, - mp->m_sb.sb_sectsize); - if (logdev && logdev != ddev) { + error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, + mp->m_sb.sb_sectsize); + if (!error && logdev && logdev != ddev) { unsigned int log_sector_size = BBSIZE; if (XFS_SB_VERSION_HASSECTOR(&mp->m_sb)) log_sector_size = mp->m_sb.sb_logsectsize; - xfs_setsize_buftarg(mp->m_logdev_targp, mp->m_sb.sb_blocksize, - log_sector_size); - } - if (rtdev) - xfs_setsize_buftarg(mp->m_rtdev_targp, mp->m_sb.sb_blocksize, - mp->m_sb.sb_blocksize); + error = xfs_setsize_buftarg(mp->m_logdev_targp, + mp->m_sb.sb_blocksize, + log_sector_size); + } + if (!error && rtdev) + error = xfs_setsize_buftarg(mp->m_rtdev_targp, + mp->m_sb.sb_blocksize, + mp->m_sb.sb_sectsize); + if (error) + goto error2; - if (!(error = XFS_IOINIT(vfsp, args, flags))) + error = XFS_IOINIT(vfsp, args, flags); + if (!error) return 0; - - error: +error2: + if (mp->m_sb_bp) + xfs_freesb(mp); +error1: xfs_binval(mp->m_ddev_targp); - if (logdev != NULL && logdev != ddev) { + if (logdev && logdev != ddev) xfs_binval(mp->m_logdev_targp); - } - if (rtdev != NULL) { + if (rtdev) xfs_binval(mp->m_rtdev_targp); - } - xfs_unmountfs_close(mp, NULL); +error0: + xfs_unmountfs_close(mp, credp); return error; } @@ -1508,7 +1523,10 @@ * eventually kicked out of the cache. */ if (flags & SYNC_REFCACHE) { - xfs_refcache_purge_some(mp); + if (flags & SYNC_WAIT) + xfs_refcache_purge_mp(mp); + else + xfs_refcache_purge_some(mp); } /* @@ -1866,6 +1884,20 @@ return 0; } +STATIC void +xfs_freeze( + bhv_desc_t *bdp) +{ + xfs_mount_t *mp = XFS_BHVTOM(bdp); + + while (atomic_read(&mp->m_active_trans) > 0) + delay(100); + + /* Push the superblock and write an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); +} + vfsops_t xfs_vfsops = { BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), @@ -1883,4 +1915,5 @@ .vfs_get_inode = xfs_get_inode, .vfs_init_vnode = xfs_initialize_vnode, .vfs_force_shutdown = xfs_do_force_shutdown, + .vfs_freeze = xfs_freeze, }; diff -urN linux-2.4.27/fs/xfs/xfs_vnodeops.c linux-2.4.28/fs/xfs/xfs_vnodeops.c --- linux-2.4.27/fs/xfs/xfs_vnodeops.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/fs/xfs/xfs_vnodeops.c 2004-11-17 03:54:22.027415533 -0800 @@ -283,7 +283,7 @@ /* * xfs_setattr */ -STATIC int +int xfs_setattr( bhv_desc_t *bdp, vattr_t *vap, @@ -305,6 +305,7 @@ int mandlock_before, mandlock_after; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; int file_owner; + int need_iolock = (flags & ATTR_DMI) == 0; vp = BHV_TO_VNODE(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); @@ -406,7 +407,8 @@ goto error_return; } } - lock_flags |= XFS_IOLOCK_EXCL; + if (need_iolock) + lock_flags |= XFS_IOLOCK_EXCL; } xfs_ilock(ip, lock_flags); @@ -678,7 +680,8 @@ XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { xfs_trans_cancel(tp, 0); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + if (need_iolock) + xfs_iunlock(ip, XFS_IOLOCK_EXCL); return code; } commit_flags = XFS_TRANS_RELEASE_LOG_RES; @@ -823,10 +826,15 @@ mp->m_sb.sb_blocklog; } if (mask & XFS_AT_XFLAGS) { - ip->i_d.di_flags = 0; - if (vap->va_xflags & XFS_XFLAG_REALTIME) { + /* can't set PREALLOC this way, just preserve it */ + ip->i_d.di_flags = + (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); + if (vap->va_xflags & XFS_XFLAG_REALTIME && + (ip->i_d.di_mode & S_IFMT) == S_IFREG) { ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } else { + ip->i_iocore.io_flags &= ~XFS_IOCORE_RT; } if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; @@ -838,7 +846,9 @@ ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; if (vap->va_xflags & XFS_XFLAG_NODUMP) ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; - /* can't set PREALLOC this way, just ignore it */ + if ((vap->va_xflags & XFS_XFLAG_RTINHERIT) && + (ip->i_d.di_mode & S_IFMT) == S_IFDIR) + ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT; } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); timeflags |= XFS_ICHGTIME_CHG; @@ -1822,8 +1832,6 @@ } -#define XFS_CREATE_NEW_MAXTRIES 10000 - /* * xfs_create (create a new file). */ @@ -4292,6 +4300,7 @@ int rt; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; + int need_iolock = (attr_flags & ATTR_DMI) == 0; vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); mp = ip->i_mount; @@ -4319,7 +4328,8 @@ return(error); } - xfs_ilock(ip, XFS_IOLOCK_EXCL); + if (need_iolock) + xfs_ilock(ip, XFS_IOLOCK_EXCL); rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog), (__uint8_t)NBPP); ilen = len + (offset & (rounding - 1)); @@ -4338,7 +4348,7 @@ error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL); if (error) - return error; + goto out_unlock_iolock; ASSERT(nimap == 0 || nimap == 1); if (nimap && imap.br_startblock != HOLESTARTBLOCK) { xfs_daddr_t block; @@ -4353,7 +4363,7 @@ error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, &imap, &nimap, NULL); if (error) - return error; + goto out_unlock_iolock; ASSERT(nimap == 0 || nimap == 1); if (nimap && imap.br_startblock != HOLESTARTBLOCK) { ASSERT(imap.br_startblock != DELAYSTARTBLOCK); @@ -4442,14 +4452,17 @@ xfs_iunlock(ip, XFS_ILOCK_EXCL); } - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + out_unlock_iolock: + if (need_iolock) + xfs_iunlock(ip, XFS_IOLOCK_EXCL); return error; error0: xfs_bmap_cancel(&free_list); error1: xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); - xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) : + XFS_ILOCK_EXCL); return error; } @@ -4606,20 +4619,21 @@ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); - ip->i_d.di_mode &= ~S_ISUID; - - /* - * Note that we don't have to worry about mandatory - * file locking being disabled here because we only - * clear the S_ISGID bit if the Group execute bit is - * on, but if it was on then mandatory locking wouldn't - * have been enabled. - */ - if (ip->i_d.di_mode & S_IXGRP) - ip->i_d.di_mode &= ~S_ISGID; + if ((attr_flags & ATTR_DMI) == 0) { + ip->i_d.di_mode &= ~S_ISUID; - xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the S_ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & S_IXGRP) + ip->i_d.di_mode &= ~S_ISGID; + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + } if (setprealloc) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; else if (clrprealloc) diff -urN linux-2.4.27/include/acpi/acglobal.h linux-2.4.28/include/acpi/acglobal.h --- linux-2.4.27/include/acpi/acglobal.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/acpi/acglobal.h 2004-11-17 03:54:22.028415574 -0800 @@ -46,15 +46,17 @@ /* - * Ensure that the globals are actually defined only once. + * Ensure that the globals are actually defined and initialized only once. * - * The use of these defines allows a single list of globals (here) in order + * The use of these macros allows a single list of globals (here) in order * to simplify maintenance of the code. */ #ifdef DEFINE_ACPI_GLOBALS #define ACPI_EXTERN +#define ACPI_INIT_GLOBAL(a,b) a=b #else #define ACPI_EXTERN extern +#define ACPI_INIT_GLOBAL(a,b) a #endif /* @@ -64,6 +66,7 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; + /***************************************************************************** * * Debug support @@ -79,15 +82,36 @@ extern u32 acpi_gbl_nesting_level; + /***************************************************************************** * - * Runtime configuration + * Runtime configuration (static defaults that can be overriden at runtime) * ****************************************************************************/ -ACPI_EXTERN u8 acpi_gbl_create_osi_method; -ACPI_EXTERN u8 acpi_gbl_all_methods_serialized; -ACPI_EXTERN u8 acpi_gbl_leave_wake_gpes_disabled; +/* + * Automatically serialize ALL control methods? Default is FALSE, meaning + * to use the Serialized/not_serialized method flags on a per method basis. + * Only change this if the ASL code is poorly written and cannot handle + * reentrancy even though methods are marked "not_serialized". + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_all_methods_serialized, FALSE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPI CA is fully compatible with other ACPI implementations. + * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_create_osi_method, TRUE); + +/* + * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and + * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only + * be enabled just before going to sleep. + */ +/* Set to FALSE in 2.4 because TRUE requires big ACPICA GPE fixes from 2.6. */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_leave_wake_gpes_disabled, FALSE); + /***************************************************************************** * @@ -102,7 +126,6 @@ * * These tables are single-table only; meaning that there can be at most one * of each in the system. Each global points to the actual table. - * */ ACPI_EXTERN u32 acpi_gbl_table_flags; ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; diff -urN linux-2.4.27/include/acpi/acpi_drivers.h linux-2.4.28/include/acpi/acpi_drivers.h --- linux-2.4.27/include/acpi/acpi_drivers.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/include/acpi/acpi_drivers.h 2004-11-17 03:54:22.029415615 -0800 @@ -288,7 +288,8 @@ #define ACPI_THERMAL_MODE_PASSIVE 0x01 #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" - +/* Motherboard devices */ +int acpi_motherboard_init(void); /* -------------------------------------------------------------------------- Debug Support -------------------------------------------------------------------------- */ diff -urN linux-2.4.27/include/asm-i386/apic.h linux-2.4.28/include/asm-i386/apic.h --- linux-2.4.27/include/asm-i386/apic.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.28/include/asm-i386/apic.h 2004-11-17 03:54:22.029415615 -0800 @@ -77,7 +77,7 @@ extern void smp_local_timer_interrupt (struct pt_regs * regs); extern void setup_APIC_clocks (void); extern void setup_apic_nmi_watchdog (void); -extern inline void nmi_watchdog_tick (struct pt_regs * regs); +extern void nmi_watchdog_tick (struct pt_regs * regs); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); diff -urN linux-2.4.27/include/asm-i386/mpspec.h linux-2.4.28/include/asm-i386/mpspec.h --- linux-2.4.27/include/asm-i386/mpspec.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/asm-i386/mpspec.h 2004-11-17 03:54:22.030415656 -0800 @@ -228,6 +228,7 @@ extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); extern void mp_config_acpi_legacy_irqs (void); extern void mp_parse_prt (void); +extern int mp_irqs_alloc(void); #endif /*!CONFIG_X86_IO_APIC*/ #endif /*CONFIG_ACPI_BOOT*/ diff -urN linux-2.4.27/include/asm-i386/rwsem.h linux-2.4.28/include/asm-i386/rwsem.h --- linux-2.4.27/include/asm-i386/rwsem.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-i386/rwsem.h 2004-11-17 03:54:22.031415697 -0800 @@ -113,8 +113,8 @@ " jmp 1b\n" LOCK_SECTION_END "# ending down_read\n\t" - : "+m"(sem->count) - : "a"(sem) + : "=m"(sem->count) + : "a"(sem), "m"(sem->count) : "memory", "cc"); } @@ -151,8 +151,8 @@ tmp = RWSEM_ACTIVE_WRITE_BIAS; __asm__ __volatile__( "# beginning down_write\n\t" -LOCK_PREFIX " xadd %0,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */ - " testl %0,%0\n\t" /* was the count 0 before? */ +LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */ + " testl %%edx,%%edx\n\t" /* was the count 0 before? */ " jnz 2f\n\t" /* jump if we weren't granted the lock */ "1:\n\t" LOCK_SECTION_START("") @@ -163,8 +163,8 @@ " jmp 1b\n" LOCK_SECTION_END "# ending down_write" - : "+d"(tmp), "+m"(sem->count) - : "a"(sem) + : "=m"(sem->count), "=d"(tmp) + : "a"(sem), "1"(tmp), "m"(sem->count) : "memory", "cc"); } @@ -202,8 +202,8 @@ " jmp 1b\n" LOCK_SECTION_END "# ending __up_read\n" - : "+m"(sem->count), "+d"(tmp) - : "a"(sem) + : "=m"(sem->count), "=d"(tmp) + : "a"(sem), "1"(tmp), "m"(sem->count) : "memory", "cc"); } @@ -228,8 +228,8 @@ " jmp 1b\n" LOCK_SECTION_END "# ending __up_write\n" - : "+m"(sem->count) - : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS) + : "=m"(sem->count) + : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count) : "memory", "cc", "edx"); } diff -urN linux-2.4.27/include/asm-i386/smp.h linux-2.4.28/include/asm-i386/smp.h --- linux-2.4.27/include/asm-i386/smp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-i386/smp.h 2004-11-17 03:54:22.031415697 -0800 @@ -39,7 +39,7 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); -extern void smp_send_reschedule(int cpu); +extern void fastcall smp_send_reschedule(int cpu); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); diff -urN linux-2.4.27/include/asm-i386/smpboot.h linux-2.4.28/include/asm-i386/smpboot.h --- linux-2.4.27/include/asm-i386/smpboot.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/asm-i386/smpboot.h 2004-11-17 03:54:22.031415697 -0800 @@ -130,8 +130,8 @@ cpu = (cpu+1)%smp_num_cpus; return cpu_to_physical_apicid(cpu); default: + return cpu_online_map; } - return cpu_online_map; } #else #define target_cpus() (cpu_online_map) diff -urN linux-2.4.27/include/asm-i386/unistd.h linux-2.4.28/include/asm-i386/unistd.h --- linux-2.4.27/include/asm-i386/unistd.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-i386/unistd.h 2004-11-17 03:54:22.032415738 -0800 @@ -372,7 +372,7 @@ static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) static inline _syscall3(int,open,const char *,file,int,flag,int,mode) static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall1(void,_exit,int,exitcode) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) static inline _syscall1(int,delete_module,const char *,name) diff -urN linux-2.4.27/include/asm-ppc/cputable.h linux-2.4.28/include/asm-ppc/cputable.h --- linux-2.4.27/include/asm-ppc/cputable.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/include/asm-ppc/cputable.h 2004-11-17 03:54:22.032415738 -0800 @@ -75,6 +75,7 @@ #define CPU_FTR_750FX 0x00004000 #define CPU_FTR_NO_DPM 0x00008000 #define CPU_FTR_HAS_HIGH_BATS 0x00010000 +#define CPU_FTR_NEED_COHERENT 0x00020000 #ifdef __ASSEMBLY__ diff -urN linux-2.4.27/include/asm-ppc/unistd.h linux-2.4.28/include/asm-ppc/unistd.h --- linux-2.4.27/include/asm-ppc/unistd.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/asm-ppc/unistd.h 2004-11-17 03:54:22.033415779 -0800 @@ -382,7 +382,7 @@ static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) static inline _syscall3(int,open,const char *,file,int,flag,int,mode) static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall1(void,_exit,int,exitcode) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) static inline _syscall1(int,delete_module,const char *,name) diff -urN linux-2.4.27/include/asm-s390/kmap_types.h linux-2.4.28/include/asm-s390/kmap_types.h --- linux-2.4.27/include/asm-s390/kmap_types.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/include/asm-s390/kmap_types.h 2004-11-17 03:54:22.034415820 -0800 @@ -0,0 +1,16 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#endif diff -urN linux-2.4.27/include/asm-s390/lowcore.h linux-2.4.28/include/asm-s390/lowcore.h --- linux-2.4.27/include/asm-s390/lowcore.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.28/include/asm-s390/lowcore.h 2004-11-17 03:54:22.034415820 -0800 @@ -47,6 +47,7 @@ #define __LC_IPLDEV 0xC7C #define __LC_JIFFY_TIMER 0xC80 +#define __LC_INT_CLOCK 0xC88 #define __LC_PANIC_MAGIC 0xE00 @@ -165,8 +166,9 @@ /* SMP info area: defined by DJB */ __u64 jiffy_timer; /* 0xc80 */ - atomic_t ext_call_fast; /* 0xc88 */ - __u8 pad11[0xe00-0xc8c]; /* 0xc8c */ + __u64 int_clock; /* 0xc88 */ + atomic_t ext_call_fast; /* 0xc90 */ + __u8 pad11[0xe00-0xc94]; /* 0xc94 */ /* 0xe00 is used as indicator for dump tools */ /* whether the kernel died with panic() or not */ diff -urN linux-2.4.27/include/asm-s390/pgtable.h linux-2.4.28/include/asm-s390/pgtable.h --- linux-2.4.27/include/asm-s390/pgtable.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/asm-s390/pgtable.h 2004-11-17 03:54:22.035415862 -0800 @@ -426,9 +426,12 @@ __pte; \ }) -#define arch_set_page_uptodate(__page) \ +#define SetPageUptodate(_page) \ do { \ - asm volatile ("sske %0,%1" : : "d" (get_storage_key()), \ + struct page *__page = (_page); \ + if (!test_and_set_bit(PG_uptodate, &__page->flags)) \ + asm volatile ("sske %0,%1" \ + : : "d" (get_storage_key()), \ "a" (__pa((__page-mem_map) << PAGE_SHIFT)));\ } while (0) diff -urN linux-2.4.27/include/asm-s390/processor.h linux-2.4.28/include/asm-s390/processor.h --- linux-2.4.27/include/asm-s390/processor.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/asm-s390/processor.h 2004-11-17 03:54:22.035415862 -0800 @@ -50,6 +50,8 @@ extern void print_cpu_info(struct cpuinfo_S390 *); +extern void show_trace(unsigned long* esp); + /* Lazy FPU handling on uni-processor */ extern struct task_struct *last_task_used_math; diff -urN linux-2.4.27/include/asm-s390/qdio.h linux-2.4.28/include/asm-s390/qdio.h --- linux-2.4.27/include/asm-s390/qdio.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/asm-s390/qdio.h 2004-11-17 03:54:22.036415903 -0800 @@ -11,7 +11,7 @@ #ifndef __QDIO_H__ #define __QDIO_H__ -#define VERSION_QDIO_H "$Revision: 1.66 $" +#define VERSION_QDIO_H "$Revision: 1.66.4.4 $" /* note, that most of the typedef's are from ingo. */ @@ -42,11 +42,18 @@ #define QDIO_MAX_ELEMENTS_PER_BUFFER 16 #define SBAL_SIZE 256 -#define IQDIO_FILL_LEVEL_TO_POLL (QDIO_MAX_BUFFERS_PER_Q*4/3) +/* unfortunately this can't be (QDIO_MAX_BUFFERS_PER_Q*4/3) or so -- as + * we never know, whether we'll get initiative again, e.g. to give the + * transmit skb's back to the stack, however the stack may be waiting for + * them... therefore we define 4 as threshold to start polling (which + * will stop as soon as the asynchronous queue catches up) + * btw, this only applies to the asynchronous HiperSockets queue */ +#define IQDIO_FILL_LEVEL_TO_POLL 4 #define TIQDIO_THININT_ISC 3 #define TIQDIO_DELAY_TARGET 0 -#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */ +#define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */ +#define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */ #define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */ #define IQDIO_GLOBAL_LAPS_INT 1 /* dont global summary */ #define IQDIO_LOCAL_LAPS 4 @@ -612,6 +619,8 @@ typedef struct qdio_q_t { volatile slsb_t slsb; + char unused[QDIO_MAX_BUFFERS_PER_Q]; + __u32 * volatile dev_st_chg_ind; int is_input_q; @@ -697,7 +706,9 @@ int last_transfer_index; */ __u64 last_transfer_time; + __u64 busy_start; } timing; + atomic_t busy_siga_counter; unsigned int queue_type; } __attribute__ ((aligned(256))) qdio_q_t; @@ -713,7 +724,7 @@ unsigned int sync_done_on_outb_pcis; unsigned int state; - spinlock_t setting_up_lock; + struct semaphore setting_up_lock; unsigned int no_input_qs; unsigned int no_output_qs; diff -urN linux-2.4.27/include/asm-s390/sigp.h linux-2.4.28/include/asm-s390/sigp.h --- linux-2.4.27/include/asm-s390/sigp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-s390/sigp.h 2004-11-17 03:54:22.037415944 -0800 @@ -106,7 +106,7 @@ * Signal processor with parameter and return status */ extern __inline__ sigp_ccode -signal_processor_ps(__u32 *statusptr, __u32 parameter, +signal_processor_ps(unsigned long *statusptr, __u32 parameter, __u16 cpu_addr, sigp_order_code order_code) { sigp_ccode ccode; diff -urN linux-2.4.27/include/asm-s390/smp.h linux-2.4.28/include/asm-s390/smp.h --- linux-2.4.27/include/asm-s390/smp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-s390/smp.h 2004-11-17 03:54:22.037415944 -0800 @@ -26,6 +26,9 @@ __u16 cpu; } sigp_info; +extern int smp_call_function_on(void (*func) (void *info), void *info, + int nonatomic, int wait, int cpu); + extern unsigned long cpu_online_map; #define NO_PROC_ID 0xFF /* No processor magic marker */ @@ -46,23 +49,28 @@ extern __inline__ int cpu_logical_map(int cpu) { - return cpu; + return cpu; } extern __inline__ int cpu_number_map(int cpu) { - return cpu; + return cpu; } extern __inline__ __u16 hard_smp_processor_id(void) { - __u16 cpu_address; + __u16 cpu_address; - __asm__ ("stap %0\n" : "=m" (cpu_address)); - return cpu_address; + __asm__ ("stap %0\n" : "=m" (cpu_address)); + return cpu_address; } #define cpu_logical_map(cpu) (cpu) #endif + +#ifndef CONFIG_SMP +#define smp_call_function_on(func,info,nonatomic,wait,cpu) ({ 0; }) +#endif + #endif diff -urN linux-2.4.27/include/asm-s390x/kmap_types.h linux-2.4.28/include/asm-s390x/kmap_types.h --- linux-2.4.27/include/asm-s390x/kmap_types.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/include/asm-s390x/kmap_types.h 2004-11-17 03:54:22.038415985 -0800 @@ -0,0 +1,16 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#endif diff -urN linux-2.4.27/include/asm-s390x/lowcore.h linux-2.4.28/include/asm-s390x/lowcore.h --- linux-2.4.27/include/asm-s390x/lowcore.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-s390x/lowcore.h 2004-11-17 03:54:22.038415985 -0800 @@ -48,6 +48,7 @@ #define __LC_IPLDEV 0xDB8 #define __LC_JIFFY_TIMER 0xDC0 +#define __LC_INT_CLOCK 0xDC8 #define __LC_PANIC_MAGIC 0xE00 @@ -164,8 +165,9 @@ /* SMP info area: defined by DJB */ __u64 jiffy_timer; /* 0xdc0 */ - __u64 ext_call_fast; /* 0xdc8 */ - __u8 pad12[0xe00-0xdd0]; /* 0xdd0 */ + __u64 int_clock; /* 0xdc8 */ + __u64 ext_call_fast; /* 0xdd0 */ + __u8 pad12[0xe00-0xdd8]; /* 0xdd8 */ /* 0xe00 is used as indicator for dump tools */ /* whether the kernel died with panic() or not */ diff -urN linux-2.4.27/include/asm-s390x/pgtable.h linux-2.4.28/include/asm-s390x/pgtable.h --- linux-2.4.27/include/asm-s390x/pgtable.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/asm-s390x/pgtable.h 2004-11-17 03:54:22.039416026 -0800 @@ -484,9 +484,11 @@ __pte; \ }) -#define arch_set_page_uptodate(__page) \ +#define SetPageUptodate(_page) \ do { \ - asm volatile ("sske %0,%1" : : "d" (0), \ + struct page *__page = (_page); \ + if (!test_and_set_bit(PG_uptodate, &__page->flags)) \ + asm volatile ("sske %0,%1" : : "d" (0), \ "a" (__pa((__page-mem_map) << PAGE_SHIFT)));\ } while (0) diff -urN linux-2.4.27/include/asm-s390x/processor.h linux-2.4.28/include/asm-s390x/processor.h --- linux-2.4.27/include/asm-s390x/processor.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/asm-s390x/processor.h 2004-11-17 03:54:22.039416026 -0800 @@ -52,6 +52,8 @@ extern void print_cpu_info(struct cpuinfo_S390 *); +extern void show_trace(unsigned long* esp); + /* Lazy FPU handling on uni-processor */ extern struct task_struct *last_task_used_math; diff -urN linux-2.4.27/include/asm-s390x/qdio.h linux-2.4.28/include/asm-s390x/qdio.h --- linux-2.4.27/include/asm-s390x/qdio.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/asm-s390x/qdio.h 2004-11-17 03:54:22.040416067 -0800 @@ -11,7 +11,7 @@ #ifndef __QDIO_H__ #define __QDIO_H__ -#define VERSION_QDIO_H "$Revision: 1.57 $" +#define VERSION_QDIO_H "$Revision: 1.57.4.4 $" /* note, that most of the typedef's are from ingo. */ @@ -42,11 +42,18 @@ #define QDIO_MAX_ELEMENTS_PER_BUFFER 16 #define SBAL_SIZE 256 -#define IQDIO_FILL_LEVEL_TO_POLL (QDIO_MAX_BUFFERS_PER_Q*4/3) +/* unfortunately this can't be (QDIO_MAX_BUFFERS_PER_Q*4/3) or so -- as + * we never know, whether we'll get initiative again, e.g. to give the + * transmit skb's back to the stack, however the stack may be waiting for + * them... therefore we define 4 as threshold to start polling (which + * will stop as soon as the asynchronous queue catches up) + * btw, this only applies to the asynchronous HiperSockets queue */ +#define IQDIO_FILL_LEVEL_TO_POLL 4 #define TIQDIO_THININT_ISC 3 #define TIQDIO_DELAY_TARGET 0 -#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */ +#define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */ +#define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */ #define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */ #define IQDIO_GLOBAL_LAPS_INT 1 /* dont global summary */ #define IQDIO_LOCAL_LAPS 4 @@ -612,6 +619,8 @@ typedef struct qdio_q_t { volatile slsb_t slsb; + char unused[QDIO_MAX_BUFFERS_PER_Q]; + __u32 * volatile dev_st_chg_ind; int is_input_q; @@ -697,7 +706,9 @@ int last_transfer_index; */ __u64 last_transfer_time; + __u64 busy_start; } timing; + atomic_t busy_siga_counter; unsigned int queue_type; } __attribute__ ((aligned(256))) qdio_q_t; @@ -713,7 +724,7 @@ unsigned int sync_done_on_outb_pcis; unsigned int state; - spinlock_t setting_up_lock; + struct semaphore setting_up_lock; unsigned int no_input_qs; unsigned int no_output_qs; diff -urN linux-2.4.27/include/asm-s390x/siginfo.h linux-2.4.28/include/asm-s390x/siginfo.h --- linux-2.4.27/include/asm-s390x/siginfo.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.28/include/asm-s390x/siginfo.h 2004-11-17 03:54:22.041416108 -0800 @@ -19,7 +19,7 @@ } sigval_t; #define SI_MAX_SIZE 128 -#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 3) +#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4) typedef struct siginfo { int si_signo; diff -urN linux-2.4.27/include/asm-s390x/sigp.h linux-2.4.28/include/asm-s390x/sigp.h --- linux-2.4.27/include/asm-s390x/sigp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-s390x/sigp.h 2004-11-17 03:54:22.041416108 -0800 @@ -107,7 +107,7 @@ * Signal processor with parameter and return status */ extern __inline__ sigp_ccode -signal_processor_ps(__u32 *statusptr, __u64 parameter, +signal_processor_ps(unsigned long *statusptr, __u64 parameter, __u16 cpu_addr, sigp_order_code order_code) { sigp_ccode ccode; diff -urN linux-2.4.27/include/asm-s390x/smp.h linux-2.4.28/include/asm-s390x/smp.h --- linux-2.4.27/include/asm-s390x/smp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/asm-s390x/smp.h 2004-11-17 03:54:22.042416149 -0800 @@ -26,6 +26,9 @@ __u16 cpu; } sigp_info; +extern int smp_call_function_on(void (*func) (void *info), void *info, + int nonatomic, int wait, int cpu); + extern unsigned long cpu_online_map; #define NO_PROC_ID 0xFF /* No processor magic marker */ @@ -65,4 +68,9 @@ #define cpu_logical_map(cpu) (cpu) #endif + +#ifndef CONFIG_SMP +#define smp_call_function_on(func,info,nonatomic,wait,cpu) ({ 0; }) +#endif + #endif diff -urN linux-2.4.27/include/asm-sparc/sigcontext.h linux-2.4.28/include/asm-sparc/sigcontext.h --- linux-2.4.27/include/asm-sparc/sigcontext.h 1999-09-08 11:14:32.000000000 -0700 +++ linux-2.4.28/include/asm-sparc/sigcontext.h 2004-11-17 03:54:22.042416149 -0800 @@ -57,20 +57,6 @@ } si_fpqueue [16]; } __siginfo_fpu_t; -#ifdef __KERNEL__ - -/* This magic should be in g_upper[0] for all upper parts - to be valid. - This is generated by sparc64 only, but for 32bit processes, - so we define it here as well. */ -#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 -typedef struct { - unsigned int g_upper[8]; - unsigned int o_upper[8]; -} siginfo_extra_v8plus_t; - -#endif - #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC_SIGCONTEXT_H) */ diff -urN linux-2.4.27/include/asm-sparc64/asi.h linux-2.4.28/include/asm-sparc64/asi.h --- linux-2.4.27/include/asm-sparc64/asi.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/asm-sparc64/asi.h 2004-11-17 03:54:22.043416191 -0800 @@ -8,125 +8,138 @@ */ /* V9 Architecture mandary ASIs. */ -#define ASI_N 0x04 /* Nucleus */ -#define ASI_NL 0x0c /* Nucleus, little endian */ -#define ASI_AIUP 0x10 /* Primary, user */ -#define ASI_AIUS 0x11 /* Secondary, user */ -#define ASI_AIUPL 0x18 /* Primary, user, little endian */ -#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ -#define ASI_P 0x80 /* Primary, implicit */ -#define ASI_S 0x81 /* Secondary, implicit */ -#define ASI_PNF 0x82 /* Primary, no fault */ -#define ASI_SNF 0x83 /* Secondary, no fault */ -#define ASI_PL 0x88 /* Primary, implicit, little endian */ -#define ASI_SL 0x89 /* Secondary, implicit, little endian */ -#define ASI_PNFL 0x8a /* Primary, no fault, little endian */ -#define ASI_SNFL 0x8b /* Secondary, no fault, little endian */ +#define ASI_N 0x04 /* Nucleus */ +#define ASI_NL 0x0c /* Nucleus, little endian */ +#define ASI_AIUP 0x10 /* Primary, user */ +#define ASI_AIUS 0x11 /* Secondary, user */ +#define ASI_AIUPL 0x18 /* Primary, user, little endian */ +#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ +#define ASI_P 0x80 /* Primary, implicit */ +#define ASI_S 0x81 /* Secondary, implicit */ +#define ASI_PNF 0x82 /* Primary, no fault */ +#define ASI_SNF 0x83 /* Secondary, no fault */ +#define ASI_PL 0x88 /* Primary, implicit, l-endian */ +#define ASI_SL 0x89 /* Secondary, implicit, l-endian */ +#define ASI_PNFL 0x8a /* Primary, no fault, l-endian */ +#define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */ /* SpitFire and later extended ASIs. The "(III)" marker designates - * UltraSparc-III specific ASIs. + * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates + * Chip Multi Threading specific ASIs. */ -#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ -#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ -#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian */ -#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ -#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ -#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, little endian */ -#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data status RAM diag */ -#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ -#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ -#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ -#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ -#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ -#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ -#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qword load, little endian */ -#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ -#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ -#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ -#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ -#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ -#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control Register */ -#define ASI_DCACHE_DATA 0x46 /* Data cache data-ram diag access */ -#define ASI_DCACHE_TAG 0x47 /* Data cache tag/valid ram diag access */ -#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ -#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ -#define ASI_UPA_CONFIG 0x4a /* UPA config space */ -#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ -#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ -#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ -#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ -#define ASI_AFSR 0x4c /* Async fault status register */ -#define ASI_AFAR 0x4d /* Async fault address register */ -#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag access */ -#define ASI_IMMU 0x50 /* Insn-MMU main register space */ -#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer register */ -#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer register */ -#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in register */ -#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access register */ -#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read register */ -#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ -#define ASI_DMMU 0x58 /* Data-MMU main register space */ -#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer register */ -#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer register */ -#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer register */ -#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in register */ -#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access register */ -#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read register */ -#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ -#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint register */ -#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag access */ -#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag access */ -#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram diag */ -#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag access */ -#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag access */ -#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 */ -#define ASI_UDB_ERROR_W 0x77 /* External UDB error registers write */ -#define ASI_UDB_CONTROL_W 0x77 /* External UDB control registers write */ -#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ -#define ASI_INTR_DATAN_W 0x77 /* (III) Outgoing irq vector data reg N */ -#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ -#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st */ -#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st */ -#define ASI_EC_R 0x7e /* E-cache diag read access */ -#define ASI_UDBH_ERROR_R 0x7f /* External UDB error registers read hi */ -#define ASI_UDBL_ERROR_R 0x7f /* External UDB error registers read low */ -#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control registers read hi */ -#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control registers read low */ -#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ -#define ASI_INTR_DATAN_R 0x7f /* (III) Incoming irq vector data reg N */ -#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ -#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ -#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ -#define ASI_PST16_S 0xc3 /* Seconary, 4 16-bit, partial */ -#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ -#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ -#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, little */ -#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, little */ -#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, little */ -#define ASI_PST16_SL 0xcb /* Seconary, 4 16-bit, partial, little */ -#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, little */ -#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, little */ -#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ -#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ -#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ -#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ -#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, little */ -#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st, little */ -#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ -#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ -#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ -#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ -#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ -#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ +#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ +#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ +#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ +#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ +#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ +#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ +#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ +#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ +#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ +#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ +#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ +#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ +#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ +#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */ +#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ +#define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */ +#define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */ +#define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */ +#define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */ +#define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */ +#define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */ +#define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */ +#define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */ +#define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */ +#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ +#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ +#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ +#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ +#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */ +#define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */ +#define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/ +#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ +#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ +#define ASI_UPA_CONFIG 0x4a /* UPA config space */ +#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ +#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ +#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ +#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ +#define ASI_AFSR 0x4c /* Async fault status register */ +#define ASI_AFAR 0x4d /* Async fault address register */ +#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ +#define ASI_IMMU 0x50 /* Insn-MMU main register space */ +#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ +#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ +#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */ +#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */ +#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */ +#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ +#define ASI_DMMU 0x58 /* Data-MMU main register space */ +#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */ +#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */ +#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */ +#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */ +#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */ +#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */ +#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ +#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */ +#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */ +#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */ +#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */ +#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */ +#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */ +#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */ +#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */ +#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */ +#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 ld/st */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */ +#define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */ +#define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */ +#define ASI_EC_W 0x76 /* E-cache diag write access */ +#define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */ +#define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */ +#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ +#define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */ +#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ +#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/ +#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/ +#define ASI_EC_R 0x7e /* E-cache diag read access */ +#define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */ +#define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */ +#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */ +#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ +#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ +#define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ +#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ +#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ +#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ +#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ +#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ +#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ +#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */ +#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */ +#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */ +#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */ +#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */ +#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */ +#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ +#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ +#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ +#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ +#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */ +#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/ +#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */ +#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ +#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ +#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ +#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ +#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ +#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ +#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ #endif /* _SPARC64_ASI_H */ diff -urN linux-2.4.27/include/asm-sparc64/cmt.h linux-2.4.28/include/asm-sparc64/cmt.h --- linux-2.4.27/include/asm-sparc64/cmt.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.28/include/asm-sparc64/cmt.h 2004-11-17 03:54:22.044416232 -0800 @@ -0,0 +1,59 @@ +#ifndef _SPARC64_CMT_H +#define _SPARC64_CMT_H + +/* cmt.h: Chip Multi-Threading register definitions + * + * Copyright (C) 2004 David S. Miller (davem@redhat.com) + */ + +/* ASI_CORE_ID - private */ +#define LP_ID 0x0000000000000010UL +#define LP_ID_MAX 0x00000000003f0000UL +#define LP_ID_ID 0x000000000000003fUL + +/* ASI_INTR_ID - private */ +#define LP_INTR_ID 0x0000000000000000UL +#define LP_INTR_ID_ID 0x00000000000003ffUL + +/* ASI_CESR_ID - private */ +#define CESR_ID 0x0000000000000040UL +#define CESR_ID_ID 0x00000000000000ffUL + +/* ASI_CORE_AVAILABLE - shared */ +#define LP_AVAIL 0x0000000000000000UL +#define LP_AVAIL_1 0x0000000000000002UL +#define LP_AVAIL_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE_STATUS - shared */ +#define LP_ENAB_STAT 0x0000000000000010UL +#define LP_ENAB_STAT_1 0x0000000000000002UL +#define LP_ENAB_STAT_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE - shared */ +#define LP_ENAB 0x0000000000000020UL +#define LP_ENAB_1 0x0000000000000002UL +#define LP_ENAB_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING - shared */ +#define LP_RUNNING_RW 0x0000000000000050UL +#define LP_RUNNING_W1S 0x0000000000000060UL +#define LP_RUNNING_W1C 0x0000000000000068UL +#define LP_RUNNING_1 0x0000000000000002UL +#define LP_RUNNING_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING_STAT - shared */ +#define LP_RUN_STAT 0x0000000000000058UL +#define LP_RUN_STAT_1 0x0000000000000002UL +#define LP_RUN_STAT_0 0x0000000000000001UL + +/* ASI_XIR_STEERING - shared */ +#define LP_XIR_STEER 0x0000000000000030UL +#define LP_XIR_STEER_1 0x0000000000000002UL +#define LP_XIR_STEER_0 0x0000000000000001UL + +/* ASI_CMT_ERROR_STEERING - shared */ +#define CMT_ER_STEER 0x0000000000000040UL +#define CMT_ER_STEER_1 0x0000000000000002UL +#define CMT_ER_STEER_0 0x0000000000000001UL + +#endif /* _SPARC64_CMT_H */ diff -urN linux-2.4.27/include/asm-sparc64/page.h linux-2.4.28/include/asm-sparc64/page.h --- linux-2.4.27/include/asm-sparc64/page.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/asm-sparc64/page.h 2004-11-17 03:54:22.044416232 -0800 @@ -36,7 +36,7 @@ extern void _clear_page(void *page); #define clear_page(X) _clear_page((void *)(X)) extern void clear_user_page(void *page, unsigned long vaddr); -#define copy_page(X,Y) __memcpy((void *)(X), (void *)(Y), PAGE_SIZE) +#define copy_page(X,Y) memcpy((void *)(X), (void *)(Y), PAGE_SIZE) extern void copy_user_page(void *to, void *from, unsigned long vaddr); /* GROSS, defining this makes gcc pass these types as aggregates, diff -urN linux-2.4.27/include/asm-sparc64/pbm.h linux-2.4.28/include/asm-sparc64/pbm.h --- linux-2.4.27/include/asm-sparc64/pbm.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/asm-sparc64/pbm.h 2004-11-17 03:54:22.045416273 -0800 @@ -70,6 +70,13 @@ */ u32 lowest_consistent_map; + /* In order to deal with some buggy third-party PCI bridges that + * do wrong prefetching, we never mark valid mappings as invalid. + * Instead we point them at this dummy page. + */ + unsigned long dummy_page; + unsigned long dummy_page_pa; + /* If PBM_NCLUSTERS is ever decreased to 4 or lower, * or if largest supported page_table_sz * 8K goes above * 2GB, you must increase the size of the type of @@ -93,6 +100,8 @@ u32 dma_addr_mask; }; +extern void pci_iommu_table_init(struct pci_iommu *, int); + /* This describes a PCI bus module's streaming buffer. */ struct pci_strbuf { int strbuf_enabled; /* Present and using it? */ diff -urN linux-2.4.27/include/asm-sparc64/pgtable.h linux-2.4.28/include/asm-sparc64/pgtable.h --- linux-2.4.27/include/asm-sparc64/pgtable.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/asm-sparc64/pgtable.h 2004-11-17 03:54:22.046416314 -0800 @@ -101,32 +101,36 @@ #endif /* !(__ASSEMBLY__) */ /* Spitfire/Cheetah TTE bits. */ -#define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ -#define _PAGE_R 0x8000000000000000 /* Used to keep ref bit up to date */ -#define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ -#define _PAGE_SZ512K 0x4000000000000000 /* 512K Page */ -#define _PAGE_SZ64K 0x2000000000000000 /* 64K Page */ -#define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ -#define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ -#define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ -#define _PAGE_SN 0x0000800000000000 /* (Cheetah) Snoop */ -#define _PAGE_PADDR_SF 0x000001FFFFFFE000 /* (Spitfire) Phys Address [40:13] */ -#define _PAGE_PADDR 0x000007FFFFFFE000 /* (Cheetah) Phys Address [42:13] */ -#define _PAGE_SOFT 0x0000000000001F80 /* Software bits */ -#define _PAGE_L 0x0000000000000040 /* Locked TTE */ -#define _PAGE_CP 0x0000000000000020 /* Cacheable in Physical Cache */ -#define _PAGE_CV 0x0000000000000010 /* Cacheable in Virtual Cache */ -#define _PAGE_E 0x0000000000000008 /* side-Effect */ -#define _PAGE_P 0x0000000000000004 /* Privileged Page */ -#define _PAGE_W 0x0000000000000002 /* Writable */ -#define _PAGE_G 0x0000000000000001 /* Global */ +#define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ +#define _PAGE_R 0x8000000000000000 /* Keep ref bit up to date */ +#define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ +#define _PAGE_SZ512K 0x4000000000000000 /* 512K Page */ +#define _PAGE_SZ64K 0x2000000000000000 /* 64K Page */ +#define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ +#define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ +#define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ +#define _PAGE_SOFT2 0x07FC000000000000 /* Software bits, set 2 */ +#define _PAGE_RES1 0x0003000000000000 /* Reserved */ +#define _PAGE_SN 0x0000800000000000 /* (Cheetah) Snoop */ +#define _PAGE_RES2 0x0000780000000000 /* Reserved */ +#define _PAGE_PADDR_SF 0x000001FFFFFFE000 /* (Spitfire) paddr[40:13] */ +#define _PAGE_PADDR 0x000007FFFFFFE000 /* (Cheetah) paddr[42:13] */ +#define _PAGE_SOFT 0x0000000000001F80 /* Software bits */ +#define _PAGE_L 0x0000000000000040 /* Locked TTE */ +#define _PAGE_CP 0x0000000000000020 /* Cacheable in P-Cache */ +#define _PAGE_CV 0x0000000000000010 /* Cacheable in V-Cache */ +#define _PAGE_E 0x0000000000000008 /* side-Effect */ +#define _PAGE_P 0x0000000000000004 /* Privileged Page */ +#define _PAGE_W 0x0000000000000002 /* Writable */ +#define _PAGE_G 0x0000000000000001 /* Global */ /* Here are the SpitFire software bits we use in the TTE's. */ -#define _PAGE_MODIFIED 0x0000000000000800 /* Modified Page (ie. dirty) */ -#define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. referenced) */ -#define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ -#define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ -#define _PAGE_PRESENT 0x0000000000000080 /* Present Page (ie. not swapped out) */ +#define _PAGE_EXEC 0x0000000000001000 /* Executable SW bit */ +#define _PAGE_MODIFIED 0x0000000000000800 /* Modified Page (ie. dirty) */ +#define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. ref'd) */ +#define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ +#define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ +#define _PAGE_PRESENT 0x0000000000000080 /* Present */ #if PAGE_SHIFT == 13 #define _PAGE_SZBITS _PAGE_SZ8K @@ -150,16 +154,27 @@ /* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */ #define PAGE_SHARED __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS | _PAGE_WRITE) + __ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC) #define PAGE_COPY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS) + __ACCESS_BITS | _PAGE_EXEC) #define PAGE_READONLY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS) + __ACCESS_BITS | _PAGE_EXEC) #define PAGE_KERNEL __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __PRIV_BITS | __ACCESS_BITS | __DIRTY_BITS) + __PRIV_BITS | \ + __ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC) + +#define PAGE_SHARED_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | \ + __ACCESS_BITS | _PAGE_WRITE) + +#define PAGE_COPY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | __ACCESS_BITS) + +#define PAGE_READONLY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | __ACCESS_BITS) #define PAGE_INVALID __pgprot (0) @@ -170,18 +185,18 @@ #define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | __ACCESS_BITS | _PAGE_E) #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC #define __P100 PAGE_READONLY #define __P101 PAGE_READONLY #define __P110 PAGE_COPY #define __P111 PAGE_COPY #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC #define __S100 PAGE_READONLY #define __S101 PAGE_READONLY #define __S110 PAGE_SHARED diff -urN linux-2.4.27/include/asm-sparc64/sigcontext.h linux-2.4.28/include/asm-sparc64/sigcontext.h --- linux-2.4.27/include/asm-sparc64/sigcontext.h 1999-09-08 11:14:32.000000000 -0700 +++ linux-2.4.28/include/asm-sparc64/sigcontext.h 2004-11-17 03:54:22.046416314 -0800 @@ -83,18 +83,6 @@ unsigned long sigc_mask; }; -#ifdef __KERNEL__ - -/* This magic should be in g_upper[0] for all upper parts - to be valid. */ -#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 -typedef struct { - unsigned int g_upper[8]; - unsigned int o_upper[8]; -} siginfo_extra_v8plus_t; - -#endif - #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_SIGCONTEXT_H) */ diff -urN linux-2.4.27/include/asm-sparc64/string.h linux-2.4.28/include/asm-sparc64/string.h --- linux-2.4.27/include/asm-sparc64/string.h 2001-10-01 09:19:56.000000000 -0700 +++ linux-2.4.28/include/asm-sparc64/string.h 2004-11-17 03:54:22.047416355 -0800 @@ -15,59 +15,25 @@ #include -extern void __memmove(void *,const void *,__kernel_size_t); -extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t); extern void *__memset(void *,int,__kernel_size_t); -extern void *__builtin_memcpy(void *,const void *,__kernel_size_t); -extern void *__builtin_memset(void *,int,__kernel_size_t); #ifndef EXPORT_SYMTAB_STROPS /* First the mem*() things. */ -#define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMMOVE - -#undef memmove -#define memmove(_to, _from, _n) \ -({ \ - void *_t = (_to); \ - __memmove(_t, (_from), (_n)); \ - _t; \ -}) +extern void *memmove(void *, const void *, __kernel_size_t); #define __HAVE_ARCH_MEMCPY - -static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) -{ - if(n) { - if(n <= 32) { - __builtin_memcpy(to, from, n); - } else { - __memcpy(to, from, n); - } - } - return to; -} - -static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n) -{ - __memcpy(to, from, n); - return to; -} - -#undef memcpy -#define memcpy(t, f, n) \ -(__builtin_constant_p(n) ? \ - __constant_memcpy((t),(f),(n)) : \ - __nonconstant_memcpy((t),(f),(n))) +extern void *memcpy(void *, const void *, __kernel_size_t); #define __HAVE_ARCH_MEMSET +extern void *__builtin_memset(void *,int,__kernel_size_t); static inline void *__constant_memset(void *s, int c, __kernel_size_t count) { extern __kernel_size_t __bzero(void *, __kernel_size_t); - if(!c) { + if (!c) { __bzero(s, count); return s; } else @@ -85,19 +51,19 @@ #define __HAVE_ARCH_MEMSCAN #undef memscan -#define memscan(__arg0, __char, __arg2) \ -({ \ - extern void *__memscan_zero(void *, size_t); \ - extern void *__memscan_generic(void *, int, size_t); \ - void *__retval, *__addr = (__arg0); \ - size_t __size = (__arg2); \ - \ - if(__builtin_constant_p(__char) && !(__char)) \ - __retval = __memscan_zero(__addr, __size); \ - else \ - __retval = __memscan_generic(__addr, (__char), __size); \ - \ - __retval; \ +#define memscan(__arg0, __char, __arg2) \ +({ \ + extern void *__memscan_zero(void *, size_t); \ + extern void *__memscan_generic(void *, int, size_t); \ + void *__retval, *__addr = (__arg0); \ + size_t __size = (__arg2); \ + \ + if(__builtin_constant_p(__char) && !(__char)) \ + __retval = __memscan_zero(__addr, __size); \ + else \ + __retval = __memscan_generic(__addr, (__char), __size); \ + \ + __retval; \ }) #define __HAVE_ARCH_MEMCMP diff -urN linux-2.4.27/include/asm-sparc64/uaccess.h linux-2.4.28/include/asm-sparc64/uaccess.h --- linux-2.4.27/include/asm-sparc64/uaccess.h 2001-10-01 09:19:56.000000000 -0700 +++ linux-2.4.28/include/asm-sparc64/uaccess.h 2004-11-17 03:54:22.047416355 -0800 @@ -249,26 +249,50 @@ extern int __get_user_bad(void); -extern __kernel_size_t __copy_from_user(void *to, const void *from, - __kernel_size_t size); +extern unsigned long ___copy_from_user(void *to, const void *from, + unsigned long size); +extern unsigned long copy_from_user_fixup(void *to, const void *from, + unsigned long size); +static inline unsigned long copy_from_user(void *to, const void *from, + unsigned long size) +{ + unsigned long ret = ___copy_from_user(to, from, size); + + if (ret) + ret = copy_from_user_fixup(to, from, size); + return ret; +} +#define __copy_from_user copy_from_user + +extern unsigned long ___copy_to_user(void *to, const void *from, + unsigned long size); +extern unsigned long copy_to_user_fixup(void *to, const void *from, + unsigned long size); +static inline unsigned long copy_to_user(void *to, const void *from, + unsigned long size) +{ + unsigned long ret = ___copy_to_user(to, from, size); -extern __kernel_size_t __copy_to_user(void *to, const void *from, - __kernel_size_t size); + if (ret) + ret = copy_to_user_fixup(to, from, size); + return ret; +} +#define __copy_to_user copy_to_user -extern __kernel_size_t __copy_in_user(void *to, const void *from, - __kernel_size_t size); +extern unsigned long ___copy_in_user(void *to, const void *from, + unsigned long size); +extern unsigned long copy_in_user_fixup(void *to, void *from, + unsigned long size); +static inline unsigned long copy_in_user(void *to, void *from, + unsigned long size) +{ + unsigned long ret = ___copy_in_user(to, from, size); -#define copy_from_user(to,from,n) \ - __copy_from_user((void *)(to), \ - (void *)(from), (__kernel_size_t)(n)) - -#define copy_to_user(to,from,n) \ - __copy_to_user((void *)(to), \ - (void *) (from), (__kernel_size_t)(n)) - -#define copy_in_user(to,from,n) \ - __copy_in_user((void *)(to), \ - (void *) (from), (__kernel_size_t)(n)) + if (ret) + ret = copy_in_user_fixup(to, from, size); + return ret; +} +#define __copy_in_user copy_in_user extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size) { diff -urN linux-2.4.27/include/asm-x86_64/apic.h linux-2.4.28/include/asm-x86_64/apic.h --- linux-2.4.27/include/asm-x86_64/apic.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/asm-x86_64/apic.h 2004-11-17 03:54:22.048416396 -0800 @@ -78,7 +78,7 @@ extern void smp_local_timer_interrupt (struct pt_regs * regs); extern void setup_APIC_clocks (void); extern void setup_apic_nmi_watchdog (void); -extern inline void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); +extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); diff -urN linux-2.4.27/include/asm-x86_64/unistd.h linux-2.4.28/include/asm-x86_64/unistd.h --- linux-2.4.27/include/asm-x86_64/unistd.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/include/asm-x86_64/unistd.h 2004-11-17 03:54:22.049416437 -0800 @@ -673,7 +673,7 @@ } extern long sys_exit(int) __attribute__((noreturn)); -extern inline long exit(int error_code) +static inline void exit(int error_code) { sys_exit(error_code); } diff -urN linux-2.4.27/include/linux/ac97_codec.h linux-2.4.28/include/linux/ac97_codec.h --- linux-2.4.27/include/linux/ac97_codec.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/linux/ac97_codec.h 2004-11-17 03:54:22.049416437 -0800 @@ -290,6 +290,7 @@ #define AC97_DELUDED_MODEM 1 /* Audio codec reports its a modem */ #define AC97_NO_PCM_VOLUME 2 /* Volume control is missing */ +#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */ }; extern int ac97_read_proc (char *page_out, char **start, off_t off, diff -urN linux-2.4.27/include/linux/agp_backend.h linux-2.4.28/include/linux/agp_backend.h --- linux-2.4.27/include/linux/agp_backend.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/agp_backend.h 2004-11-17 03:54:22.050416478 -0800 @@ -55,6 +55,7 @@ INTEL_I855_PM, INTEL_I860, INTEL_I865_G, + INTEL_I915_G, INTEL_I7205, INTEL_I7505, INTEL_460GX, diff -urN linux-2.4.27/include/linux/ata.h linux-2.4.28/include/linux/ata.h --- linux-2.4.27/include/linux/ata.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/ata.h 2004-11-17 03:54:22.050416478 -0800 @@ -42,6 +42,7 @@ ATA_ID_SERNO_OFS = 10, ATA_ID_MAJOR_VER = 80, ATA_ID_PIO_MODES = 64, + ATA_ID_MWDMA_MODES = 63, ATA_ID_UDMA_MODES = 88, ATA_ID_PIO4 = (1 << 1), @@ -78,9 +79,11 @@ ATA_NIEN = (1 << 1), /* disable-irq flag */ ATA_LBA = (1 << 6), /* LBA28 selector */ ATA_DEV1 = (1 << 4), /* Select Device 1 (slave) */ - ATA_BUSY = (1 << 7), /* BSY status bit */ ATA_DEVICE_OBS = (1 << 7) | (1 << 5), /* obs bits in dev reg */ ATA_DEVCTL_OBS = (1 << 3), /* obsolete bit in devctl reg */ + ATA_BUSY = (1 << 7), /* BSY status bit */ + ATA_DRDY = (1 << 6), /* device ready */ + ATA_DF = (1 << 5), /* device fault */ ATA_DRQ = (1 << 3), /* data request i/o */ ATA_ERR = (1 << 0), /* have an error */ ATA_SRST = (1 << 2), /* software reset */ @@ -131,13 +134,20 @@ XFER_UDMA_2 = 0x42, XFER_UDMA_1 = 0x41, XFER_UDMA_0 = 0x40, + XFER_MW_DMA_2 = 0x22, + XFER_MW_DMA_1 = 0x21, + XFER_MW_DMA_0 = 0x20, XFER_PIO_4 = 0x0C, XFER_PIO_3 = 0x0B, + XFER_PIO_2 = 0x0A, + XFER_PIO_1 = 0x09, + XFER_PIO_0 = 0x08, /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: 0=to device, 1=to host */ + ATAPI_CDB_LEN = 16, /* cable types */ ATA_CBL_NONE = 0, @@ -167,16 +177,22 @@ ATA_PROT_PIO, /* PIO single sector */ ATA_PROT_PIO_MULT, /* PIO multiple sector */ ATA_PROT_DMA, /* DMA */ - ATA_PROT_ATAPI, /* packet command */ + ATA_PROT_ATAPI, /* packet command, PIO data xfer*/ + ATA_PROT_ATAPI_NODATA, /* packet command, no data */ ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */ }; +enum ata_ioctls { + ATA_IOC_GET_IO32 = 0x309, + ATA_IOC_SET_IO32 = 0x324, +}; + /* core structures */ struct ata_prd { u32 addr; u32 flags_len; -} __attribute__((packed)); +}; struct ata_taskfile { unsigned long flags; /* ATA_TFLAG_xxx */ @@ -204,11 +220,13 @@ #define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0) #define ata_id_rahead_enabled(dev) ((dev)->id[85] & (1 << 6)) #define ata_id_wcache_enabled(dev) ((dev)->id[85] & (1 << 5)) +#define ata_id_has_flush(dev) ((dev)->id[83] & (1 << 12)) +#define ata_id_has_flush_ext(dev) ((dev)->id[83] & (1 << 13)) #define ata_id_has_lba48(dev) ((dev)->id[83] & (1 << 10)) #define ata_id_has_wcache(dev) ((dev)->id[82] & (1 << 5)) #define ata_id_has_pm(dev) ((dev)->id[82] & (1 << 3)) -#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8)) -#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9)) +#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 9)) +#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 8)) #define ata_id_removeable(dev) ((dev)->id[0] & (1 << 7)) #define ata_id_u32(dev,n) \ (((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)])) @@ -218,10 +236,27 @@ ((u64) dev->id[(n) + 1] << 16) | \ ((u64) dev->id[(n) + 0]) ) +static inline int atapi_cdb_len(u16 *dev_id) +{ + u16 tmp = dev_id[0] & 0x3; + switch (tmp) { + case 0: return 12; + case 1: return 16; + default: return -1; + } +} + static inline int is_atapi_taskfile(struct ata_taskfile *tf) { return (tf->protocol == ATA_PROT_ATAPI) || + (tf->protocol == ATA_PROT_ATAPI_NODATA) || (tf->protocol == ATA_PROT_ATAPI_DMA); } +static inline int ata_ok(u8 status) +{ + return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) + == ATA_DRDY); +} + #endif /* __LINUX_ATA_H__ */ diff -urN linux-2.4.27/include/linux/blkdev.h linux-2.4.28/include/linux/blkdev.h --- linux-2.4.27/include/linux/blkdev.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/include/linux/blkdev.h 2004-11-17 03:54:22.051416519 -0800 @@ -233,7 +233,7 @@ extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size); extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); extern void generic_make_request(int rw, struct buffer_head * bh); -extern inline request_queue_t *blk_get_queue(kdev_t dev); +extern request_queue_t *blk_get_queue(kdev_t dev); extern void blkdev_release_request(struct request *); /* @@ -246,7 +246,7 @@ extern void blk_queue_throttle_sectors(request_queue_t *, int); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void generic_unplug_device(void *); -extern inline int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *); +extern int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *); extern int * blk_size[MAX_BLKDEV]; diff -urN linux-2.4.27/include/linux/compiler.h linux-2.4.28/include/linux/compiler.h --- linux-2.4.27/include/linux/compiler.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/compiler.h 2004-11-17 03:54:22.051416519 -0800 @@ -37,5 +37,6 @@ /* no checker support, so we unconditionally define this as (null) */ #define __user +#define __iomem #endif /* __LINUX_COMPILER_H */ diff -urN linux-2.4.27/include/linux/fs.h linux-2.4.28/include/linux/fs.h --- linux-2.4.27/include/linux/fs.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/fs.h 2004-11-17 03:54:22.053416602 -0800 @@ -1259,7 +1259,7 @@ } extern void set_buffer_flushtime(struct buffer_head *); -extern inline int get_buffer_flushtime(void); +extern int get_buffer_flushtime(void); extern void balance_dirty(void); extern int check_disk_change(kdev_t); extern int invalidate_inodes(struct super_block *); @@ -1523,7 +1523,7 @@ 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 inline ssize_t do_generic_direct_read(struct file *, char *, size_t, loff_t *); +extern ssize_t do_generic_direct_read(struct file *, char *, size_t, loff_t *); extern int precheck_file_write(struct file *, struct inode *, 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); diff -urN linux-2.4.27/include/linux/fsfilter.h linux-2.4.28/include/linux/fsfilter.h --- linux-2.4.27/include/linux/fsfilter.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/linux/fsfilter.h 2004-11-17 03:54:22.053416602 -0800 @@ -74,22 +74,22 @@ struct filter_fs *filter_get_filter_fs(const char *cache_type); void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type); -inline struct super_operations *filter_c2usops(struct filter_fs *cache); -inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache); -inline struct inode_operations *filter_c2udiops(struct filter_fs *cache); -inline struct inode_operations *filter_c2usiops(struct filter_fs *cache); -inline struct file_operations *filter_c2uffops(struct filter_fs *cache); -inline struct file_operations *filter_c2udfops(struct filter_fs *cache); -inline struct file_operations *filter_c2usfops(struct filter_fs *cache); -inline struct super_operations *filter_c2csops(struct filter_fs *cache); -inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache); -inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache); -inline struct inode_operations *filter_c2csiops(struct filter_fs *cache); -inline struct file_operations *filter_c2cffops(struct filter_fs *cache); -inline struct file_operations *filter_c2cdfops(struct filter_fs *cache); -inline struct file_operations *filter_c2csfops(struct filter_fs *cache); -inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache); -inline struct dentry_operations *filter_c2udops(struct filter_fs *cache); +struct super_operations *filter_c2usops(struct filter_fs *cache); +struct inode_operations *filter_c2ufiops(struct filter_fs *cache); +struct inode_operations *filter_c2udiops(struct filter_fs *cache); +struct inode_operations *filter_c2usiops(struct filter_fs *cache); +struct file_operations *filter_c2uffops(struct filter_fs *cache); +struct file_operations *filter_c2udfops(struct filter_fs *cache); +struct file_operations *filter_c2usfops(struct filter_fs *cache); +struct super_operations *filter_c2csops(struct filter_fs *cache); +struct inode_operations *filter_c2cfiops(struct filter_fs *cache); +struct inode_operations *filter_c2cdiops(struct filter_fs *cache); +struct inode_operations *filter_c2csiops(struct filter_fs *cache); +struct file_operations *filter_c2cffops(struct filter_fs *cache); +struct file_operations *filter_c2cdfops(struct filter_fs *cache); +struct file_operations *filter_c2csfops(struct filter_fs *cache); +struct dentry_operations *filter_c2cdops(struct filter_fs *cache); +struct dentry_operations *filter_c2udops(struct filter_fs *cache); void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_ops, struct super_operations *filter_sops); void filter_setup_dir_ops(struct filter_fs *cache, struct inode *cache_inode, struct inode_operations *filter_iops, struct file_operations *ffops); diff -urN linux-2.4.27/include/linux/ide.h linux-2.4.28/include/linux/ide.h --- linux-2.4.27/include/linux/ide.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/linux/ide.h 2004-11-17 03:54:22.055416684 -0800 @@ -1445,10 +1445,10 @@ void *special; } pkt_task_t; -extern inline void SELECT_DRIVE(ide_drive_t *); -extern inline void SELECT_INTERRUPT(ide_drive_t *); -extern inline void SELECT_MASK(ide_drive_t *, int); -extern inline void QUIRK_LIST(ide_drive_t *); +extern void SELECT_DRIVE(ide_drive_t *); +extern void SELECT_INTERRUPT(ide_drive_t *); +extern void SELECT_MASK(ide_drive_t *, int); +extern void QUIRK_LIST(ide_drive_t *); extern void ata_input_data(ide_drive_t *, void *, u32); extern void ata_output_data(ide_drive_t *, void *, u32); diff -urN linux-2.4.27/include/linux/if_fddi.h linux-2.4.28/include/linux/if_fddi.h --- linux-2.4.27/include/linux/if_fddi.h 1999-06-02 11:29:13.000000000 -0700 +++ linux-2.4.28/include/linux/if_fddi.h 2004-11-17 03:54:22.055416684 -0800 @@ -5,7 +5,7 @@ * * Global definitions for the ANSI FDDI interface. * - * Version: @(#)if_fddi.h 1.0.1 09/16/96 + * Version: @(#)if_fddi.h 1.0.2 Sep 29 2004 * * Author: Lawrence V. Stefani, * @@ -103,38 +103,12 @@ } __attribute__ ((packed)); /* Define FDDI statistics structure */ -struct fddi_statistics - { - __u32 rx_packets; /* total packets received */ - __u32 tx_packets; /* total packets transmitted */ - __u32 rx_bytes; /* total bytes received */ - __u32 tx_bytes; /* total bytes transmitted */ - __u32 rx_errors; /* bad packets received */ - __u32 tx_errors; /* packet transmit problems */ - __u32 rx_dropped; /* no space in linux buffers */ - __u32 tx_dropped; /* no space available in linux */ - __u32 multicast; /* multicast packets received */ - __u32 transmit_collision; /* always 0 for FDDI */ - - /* detailed rx_errors */ - __u32 rx_length_errors; - __u32 rx_over_errors; /* receiver ring buff overflow */ - __u32 rx_crc_errors; /* recved pkt with crc error */ - __u32 rx_frame_errors; /* recv'd frame alignment error */ - __u32 rx_fifo_errors; /* recv'r fifo overrun */ - __u32 rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - __u32 tx_aborted_errors; - __u32 tx_carrier_errors; - __u32 tx_fifo_errors; - __u32 tx_heartbeat_errors; - __u32 tx_window_errors; - - /* for cslip etc */ - __u32 rx_compressed; - __u32 tx_compressed; - +struct fddi_statistics { + + /* Generic statistics. */ + + struct net_device_stats gen; + /* Detailed FDDI statistics. Adopted from RFC 1512 */ __u8 smt_station_id[8]; diff -urN linux-2.4.27/include/linux/in6.h linux-2.4.28/include/linux/in6.h --- linux-2.4.27/include/linux/in6.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/linux/in6.h 2004-11-17 03:54:22.056416725 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Sources: * IPv6 Program Interfaces for BSD Systems diff -urN linux-2.4.27/include/linux/intermezzo_fs.h linux-2.4.28/include/linux/intermezzo_fs.h --- linux-2.4.27/include/linux/intermezzo_fs.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/linux/intermezzo_fs.h 2004-11-17 03:54:22.057416766 -0800 @@ -49,8 +49,6 @@ struct presto_version remote_version; }; -static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data); - #ifdef __KERNEL__ # include # include @@ -336,7 +334,7 @@ int presto_psdev_init(void); int izo_psdev_setpid(int minor); extern void presto_psdev_cleanup(void); -inline int presto_lento_up(int minor); +int presto_lento_up(int minor); int izo_psdev_setchannel(struct file *file, int fd); /* inode.c */ @@ -347,7 +345,7 @@ void presto_frob_dop(struct dentry *de); char *presto_path(struct dentry *dentry, struct dentry *root, char *buffer, int buflen); -inline struct presto_dentry_data *izo_alloc_ddata(void); +struct presto_dentry_data *izo_alloc_ddata(void); int presto_set_dd(struct dentry *); int presto_init_ddata_cache(void); void presto_cleanup_ddata_cache(void); @@ -412,7 +410,7 @@ unsigned int flags); int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname, unsigned int flags); -inline int presto_is_read_only(struct presto_file_set *); +int presto_is_read_only(struct presto_file_set *); int presto_truncate_lml(struct presto_file_set *fset); int lento_write_lml(char *path, __u64 remote_ino, @@ -420,13 +418,13 @@ __u32 remote_version, struct presto_version *remote_file_version); int lento_complete_closes(char *path); -inline int presto_f2m(struct presto_file_set *fset); +int presto_f2m(struct presto_file_set *fset); int presto_prep(struct dentry *, struct presto_cache **, struct presto_file_set **); /* cache.c */ extern struct presto_cache *presto_cache_init(void); -extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev); -extern inline void presto_cache_init_hash(void); +extern void presto_cache_add(struct presto_cache *cache, kdev_t dev); +extern void presto_cache_init_hash(void); struct presto_cache *presto_cache_find(kdev_t dev); @@ -553,7 +551,7 @@ #define JOURNAL_PAGE_SZ PAGE_SIZE -__inline__ int presto_no_journal(struct presto_file_set *fset); +int presto_no_journal(struct presto_file_set *fset); int journal_fetch(int minor); int presto_log(struct presto_file_set *fset, struct rec_info *rec, const char *buf, size_t size, @@ -658,6 +656,8 @@ loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid, __u64 remote_recno, __u64 remote_offset); +int izo_ioctl_packlen(struct izo_ioctl_data *data); + /* sysctl.c */ int init_intermezzo_sysctl(void); void cleanup_intermezzo_sysctl(void); @@ -715,6 +715,54 @@ return tmp; } +static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data) +{ + if (data->ioc_len > (1<<30)) { + CERROR("IZO ioctl: ioc_len larger than 1<<30\n"); + return 1; + } + if (data->ioc_inllen1 > (1<<30)) { + CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n"); + return 1; + } + if (data->ioc_inllen2 > (1<<30)) { + CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n"); + return 1; + } + if (data->ioc_inlbuf1 && !data->ioc_inllen1) { + CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n"); + return 1; + } + if (data->ioc_inlbuf2 && !data->ioc_inllen2) { + CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n"); + return 1; + } + if (data->ioc_pbuf1 && !data->ioc_plen1) { + CERROR("IZO ioctl: pbuf1 pointer but 0 length\n"); + return 1; + } + if (data->ioc_pbuf2 && !data->ioc_plen2) { + CERROR("IZO ioctl: pbuf2 pointer but 0 length\n"); + return 1; + } + if (izo_ioctl_packlen(data) != data->ioc_len ) { + CERROR("IZO ioctl: packlen exceeds ioc_len\n"); + return 1; + } + if (data->ioc_inllen1 && + data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') { + CERROR("IZO ioctl: inlbuf1 not 0 terminated\n"); + return 1; + } + if (data->ioc_inllen2 && + data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2 + - 1] != '\0') { + CERROR("IZO ioctl: inlbuf2 not 0 terminated\n"); + return 1; + } + return 0; +} + /* buffer MUST be at least the size of izo_ioctl_hdr */ static inline int izo_ioctl_getdata(char *buf, char *end, void *arg) { @@ -798,8 +846,6 @@ int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird, uuid_t uuid, __u32 generate_kml); -static inline int izo_ioctl_packlen(struct izo_ioctl_data *data); - static inline void izo_ioctl_init(struct izo_ioctl_data *data) { memset(data, 0, sizeof(*data)); @@ -861,62 +907,6 @@ return "Unknown InterMezzo error"; } -static inline int izo_ioctl_packlen(struct izo_ioctl_data *data) -{ - int len = sizeof(struct izo_ioctl_data); - len += size_round(data->ioc_inllen1); - len += size_round(data->ioc_inllen2); - return len; -} - -static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data) -{ - if (data->ioc_len > (1<<30)) { - CERROR("IZO ioctl: ioc_len larger than 1<<30\n"); - return 1; - } - if (data->ioc_inllen1 > (1<<30)) { - CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n"); - return 1; - } - if (data->ioc_inllen2 > (1<<30)) { - CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n"); - return 1; - } - if (data->ioc_inlbuf1 && !data->ioc_inllen1) { - CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n"); - return 1; - } - if (data->ioc_inlbuf2 && !data->ioc_inllen2) { - CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n"); - return 1; - } - if (data->ioc_pbuf1 && !data->ioc_plen1) { - CERROR("IZO ioctl: pbuf1 pointer but 0 length\n"); - return 1; - } - if (data->ioc_pbuf2 && !data->ioc_plen2) { - CERROR("IZO ioctl: pbuf2 pointer but 0 length\n"); - return 1; - } - if (izo_ioctl_packlen(data) != data->ioc_len ) { - CERROR("IZO ioctl: packlen exceeds ioc_len\n"); - return 1; - } - if (data->ioc_inllen1 && - data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') { - CERROR("IZO ioctl: inlbuf1 not 0 terminated\n"); - return 1; - } - if (data->ioc_inllen2 && - data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2 - - 1] != '\0') { - CERROR("IZO ioctl: inlbuf2 not 0 terminated\n"); - return 1; - } - return 0; -} - /* kml_unpack.c */ char *kml_print_rec(struct kml_rec *rec, int brief); int kml_unpack(struct kml_rec *rec, char **buf, char *end); diff -urN linux-2.4.27/include/linux/ipv6_route.h linux-2.4.28/include/linux/ipv6_route.h --- linux-2.4.27/include/linux/ipv6_route.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/ipv6_route.h 2004-11-17 03:54:22.058416807 -0800 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -urN linux-2.4.27/include/linux/irq_cpustat.h linux-2.4.28/include/linux/irq_cpustat.h --- linux-2.4.27/include/linux/irq_cpustat.h 2001-11-22 11:46:18.000000000 -0800 +++ linux-2.4.28/include/linux/irq_cpustat.h 2004-11-17 03:54:22.058416807 -0800 @@ -22,7 +22,7 @@ #ifdef CONFIG_SMP #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) #else -#define __IRQ_STAT(cpu, member) ((void)(cpu), irq_stat[0].member) +#define __IRQ_STAT(cpu, member) (irq_stat[((void)(cpu), 0)].member) #endif /* arch independent irq_stat fields */ diff -urN linux-2.4.27/include/linux/jbd.h linux-2.4.28/include/linux/jbd.h --- linux-2.4.27/include/linux/jbd.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/linux/jbd.h 2004-11-17 03:54:22.059416848 -0800 @@ -70,7 +70,7 @@ #define jbd_debug(f, a...) /**/ #endif -extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); +extern void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry); #define jbd_kmalloc(size, flags) \ __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) #define jbd_rep_kmalloc(size, flags) \ @@ -867,7 +867,7 @@ schedule(); \ } while (1) -extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *); +extern void __jbd_unexpected_dirty_buffer(const char *, int, struct journal_head *); #define jbd_unexpected_dirty_buffer(jh) \ __jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh)) diff -urN linux-2.4.27/include/linux/kernel.h linux-2.4.28/include/linux/kernel.h --- linux-2.4.27/include/linux/kernel.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/kernel.h 2004-11-17 03:54:22.059416848 -0800 @@ -51,8 +51,10 @@ #ifdef __i386__ #define FASTCALL(x) x __attribute__((regparm(3))) +#define fastcall __attribute__((regparm(3))) #else #define FASTCALL(x) x +#define fastcall #endif struct completion; diff -urN linux-2.4.27/include/linux/libata.h linux-2.4.28/include/linux/libata.h --- linux-2.4.27/include/linux/libata.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/libata.h 2004-11-17 03:54:22.061416931 -0800 @@ -32,7 +32,6 @@ /* * compile-time options */ -#undef ATA_FORCE_PIO /* do not configure or use DMA */ #undef ATA_DEBUG /* debugging output */ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ @@ -89,9 +88,7 @@ /* struct ata_device stuff */ ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ - ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ - ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can - * (hopefully) flush? */ + ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -111,8 +108,9 @@ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ - ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */ - ATA_QCFLAG_SG = (1 << 4), /* have s/g table? */ + ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ + ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ + ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, /* various lengths of time */ ATA_TMOUT_EDD = 5 * HZ, /* hueristic */ @@ -134,24 +132,17 @@ BUS_IDENTIFY = 8, BUS_PACKET = 9, - /* thread states */ - THR_UNKNOWN = 0, - THR_PORT_RESET = (THR_UNKNOWN + 1), - THR_AWAIT_DEATH = (THR_PORT_RESET + 1), - THR_PROBE_FAILED = (THR_AWAIT_DEATH + 1), - THR_IDLE = (THR_PROBE_FAILED + 1), - THR_PROBE_SUCCESS = (THR_IDLE + 1), - THR_PROBE_START = (THR_PROBE_SUCCESS + 1), - /* SATA port states */ PORT_UNKNOWN = 0, PORT_ENABLED = 1, PORT_DISABLED = 2, - /* ata_qc_cb_t flags - note uses above ATA_QCFLAG_xxx namespace, - * but not numberspace + /* encoding various smaller bitmaps into a single + * unsigned long bitmap */ - ATA_QCFLAG_TIMEOUT = (1 << 0), + ATA_SHIFT_UDMA = 0, + ATA_SHIFT_MWDMA = 8, + ATA_SHIFT_PIO = 11, }; enum pio_task_states { @@ -166,12 +157,13 @@ }; /* forward declarations */ +struct scsi_device; struct ata_port_operations; struct ata_port; struct ata_queued_cmd; /* typedefs */ -typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc, unsigned int flags); +typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat); struct ata_ioports { unsigned long cmd_addr; @@ -198,13 +190,15 @@ Scsi_Host_Template *sht; struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; + unsigned int hard_port_no; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int legacy_mode; unsigned long irq; unsigned int irq_flags; unsigned long host_flags; - void *mmio_base; + void __iomem *mmio_base; void *private_data; }; @@ -212,9 +206,10 @@ spinlock_t lock; struct pci_dev *pdev; unsigned long irq; - void *mmio_base; + void __iomem *mmio_base; unsigned int n_ports; void *private_data; + struct ata_port_operations *ops; struct ata_port * ports[0]; }; @@ -225,19 +220,26 @@ struct scsi_cmnd *scsicmd; void (*scsidone)(struct scsi_cmnd *); + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned int tag; unsigned int n_elem; + + int pci_dma_dir; + unsigned int nsect; unsigned int cursect; unsigned int cursg; unsigned int cursg_ofs; - struct ata_taskfile tf; + struct scatterlist sgent; + void *buf_virt; struct scatterlist *sg; - ata_qc_cb_t callback; + ata_qc_cb_t complete_fn; struct completion *waiting; @@ -256,8 +258,10 @@ unsigned int class; /* ATA_DEV_xxx */ unsigned int devno; /* 0 or 1 */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ - unsigned int pio_mode; - unsigned int udma_mode; + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ /* cache info about current transfer mode */ u8 xfer_protocol; /* taskfile xfer protocol */ @@ -271,6 +275,7 @@ unsigned long flags; /* ATA_FLAG_xxx */ unsigned int id; /* unique id req'd by scsi midlyr */ unsigned int port_no; /* unique port #; from zero */ + unsigned int hard_port_no; /* hardware port #; from zero */ struct ata_prd *prd; /* our SG list */ dma_addr_t prd_dma; /* and its DMA mapping */ @@ -282,8 +287,10 @@ unsigned int bus_state; unsigned int port_state; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ + unsigned int cdb_len; struct ata_device device[ATA_MAX_DEVICES]; @@ -294,18 +301,12 @@ struct ata_host_stats stats; struct ata_host_set *host_set; - struct semaphore probe_sem; - - unsigned int thr_state; - struct tq_struct packet_task; struct tq_struct pio_task; unsigned int pio_task_state; unsigned long pio_task_timeout; - struct tq_struct probe_task; - void *private_data; }; @@ -314,26 +315,29 @@ void (*dev_config) (struct ata_port *, struct ata_device *); - void (*set_piomode) (struct ata_port *, struct ata_device *, - unsigned int); - void (*set_udmamode) (struct ata_port *, struct ata_device *, - unsigned int); + void (*set_piomode) (struct ata_port *, struct ata_device *); + void (*set_dmamode) (struct ata_port *, struct ata_device *); void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); u8 (*check_status)(struct ata_port *ap); + void (*dev_select)(struct ata_port *ap, unsigned int device); void (*phy_reset) (struct ata_port *ap); void (*post_set_mode) (struct ata_port *ap); void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); - void (*fill_sg) (struct ata_queued_cmd *qc); + + void (*qc_prep) (struct ata_queued_cmd *qc); + int (*qc_issue) (struct ata_queued_cmd *qc); + void (*eng_timeout) (struct ata_port *ap); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); + void (*irq_clear) (struct ata_port *); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, @@ -349,6 +353,7 @@ Scsi_Host_Template *sht; unsigned long host_flags; unsigned long pio_mask; + unsigned long mwdma_mask; unsigned long udma_mask; struct ata_port_operations *port_ops; }; @@ -361,6 +366,7 @@ }; extern void ata_port_probe(struct ata_port *); +extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); extern void ata_port_disable(struct ata_port *); @@ -370,6 +376,7 @@ extern void ata_pci_remove_one (struct pci_dev *pdev); extern int ata_device_add(struct ata_probe_ent *ent); extern int ata_scsi_detect(Scsi_Host_Template *sht); +extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_release(struct Scsi_Host *host); @@ -377,31 +384,39 @@ /* * Default driver ops implementations */ -extern void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp); extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf); -extern u8 ata_check_status_pio(struct ata_port *ap); -extern u8 ata_check_status_mmio(struct ata_port *ap); -extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); +extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); +extern u8 ata_check_status(struct ata_port *ap); +extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); -extern void ata_fill_sg(struct ata_queued_cmd *qc); +extern struct ata_probe_ent * +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port); +extern struct ata_probe_ent * +ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port); +extern void ata_qc_prep(struct ata_queued_cmd *qc); +extern int ata_qc_issue_prot(struct ata_queued_cmd *qc); +extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, + unsigned int buflen); +extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, + unsigned int n_elem); +extern unsigned int ata_dev_classify(struct ata_taskfile *tf); extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s, unsigned int ofs, unsigned int len); -extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc); -extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc); -extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc); -extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc); +extern void ata_bmdma_setup (struct ata_queued_cmd *qc); +extern void ata_bmdma_start (struct ata_queued_cmd *qc); +extern void ata_bmdma_irq_clear(struct ata_port *ap); extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_add_to_probe_list (struct ata_probe_ent *probe_ent); extern int ata_std_bios_param(Disk * disk, kdev_t dev, int *ip); +extern void libata_msleep(unsigned long msecs); static inline unsigned long msecs_to_jiffies(unsigned long msecs) @@ -423,7 +438,7 @@ static inline u8 ata_chk_err(struct ata_port *ap) { if (ap->flags & ATA_FLAG_MMIO) { - return readb((void *) ap->ioaddr.error_addr); + return readb((void __iomem *) ap->ioaddr.error_addr); } return inb(ap->ioaddr.error_addr); } @@ -436,7 +451,7 @@ static inline u8 ata_altstatus(struct ata_port *ap) { if (ap->flags & ATA_FLAG_MMIO) - return readb(ap->ioaddr.altstatus_addr); + return readb((void __iomem *)ap->ioaddr.altstatus_addr); return inb(ap->ioaddr.altstatus_addr); } @@ -476,7 +491,6 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) { - qc->flags &= ~ATA_QCFLAG_DMA; qc->tf.ctl |= ATA_NIEN; } @@ -502,15 +516,20 @@ static inline u8 ata_irq_on(struct ata_port *ap) { struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); - return ata_wait_idle(ap); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; } static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) @@ -524,7 +543,7 @@ /* get controller status; clear intr, err bits */ if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS); @@ -559,4 +578,51 @@ return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; } +static inline void ata_bmdma_stop(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + + /* clear start/stop bit */ + writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); + } else { + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + } + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ +} + +static inline void ata_bmdma_ack_irq(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; + writeb(readb(mmio), mmio); + } else { + unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + outb(inb(addr), addr); + } +} + +static inline u8 ata_bmdma_status(struct ata_port *ap) +{ + u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); + } else + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return host_stat; +} + +static inline int ata_try_flush_cache(struct ata_device *dev) +{ + return ata_id_wcache_enabled(dev) || + ata_id_has_flush(dev) || + ata_id_has_flush_ext(dev); +} + #endif /* __LINUX_LIBATA_H__ */ diff -urN linux-2.4.27/include/linux/mm.h linux-2.4.28/include/linux/mm.h --- linux-2.4.27/include/linux/mm.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/mm.h 2004-11-17 03:54:22.062416972 -0800 @@ -308,11 +308,9 @@ /* Make it prettier to test the above... */ #define UnlockPage(page) unlock_page(page) #define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) -#define SetPageUptodate(page) \ - do { \ - arch_set_page_uptodate(page); \ - set_bit(PG_uptodate, &(page)->flags); \ - } while (0) +#ifndef SetPageUptodate +#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags) +#endif #define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags) #define PageDirty(page) test_bit(PG_dirty, &(page)->flags) #define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags) diff -urN linux-2.4.27/include/linux/netdevice.h linux-2.4.28/include/linux/netdevice.h --- linux-2.4.27/include/linux/netdevice.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/netdevice.h 2004-11-17 03:54:22.062416972 -0800 @@ -352,8 +352,8 @@ struct Qdisc *qdisc; struct Qdisc *qdisc_sleeping; - struct Qdisc *qdisc_list; struct Qdisc *qdisc_ingress; + struct list_head qdisc_list; unsigned long tx_queue_len; /* Max frames per queue allowed */ /* hard_start_xmit synchronizer */ diff -urN linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack.h 2004-11-17 03:54:22.063417013 -0800 @@ -249,6 +249,7 @@ /* Call me when a conntrack is destroyed. */ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); +extern int ip_ct_no_defrag; /* Returns new sk_buff, or NULL */ struct sk_buff * ip_ct_gather_frags(struct sk_buff *skb); diff -urN linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack_ftp.h --- linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack_ftp.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack_ftp.h 2004-11-17 03:54:22.063417013 -0800 @@ -4,11 +4,6 @@ #ifdef __KERNEL__ -#include - -/* Protects ftp part of conntracks */ -DECLARE_LOCK_EXTERN(ip_ftp_lock); - #define FTP_PORT 21 #endif /* __KERNEL__ */ diff -urN linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack_irc.h --- linux-2.4.27/include/linux/netfilter_ipv4/ip_conntrack_irc.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/include/linux/netfilter_ipv4/ip_conntrack_irc.h 2004-11-17 03:54:22.064417054 -0800 @@ -33,8 +33,6 @@ #ifdef __KERNEL__ -#include - #define IRC_PORT 6667 struct dccproto { @@ -42,9 +40,6 @@ int matchlen; }; -/* Protects irc part of conntracks */ -DECLARE_LOCK_EXTERN(ip_irc_lock); - #endif /* __KERNEL__ */ #endif /* _IP_CONNTRACK_IRC_H */ diff -urN linux-2.4.27/include/linux/nfsd/const.h linux-2.4.28/include/linux/nfsd/const.h --- linux-2.4.27/include/linux/nfsd/const.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.28/include/linux/nfsd/const.h 2004-11-17 03:54:22.064417054 -0800 @@ -12,6 +12,7 @@ #include #include #include +#include /* * Maximum protocol version supported by knfsd @@ -19,9 +20,16 @@ #define NFSSVC_MAXVERS 3 /* - * Maximum blocksize supported by daemon currently at 8K + * Maximum blocksize supported by daemon. We want the largest + * value which 1) fits in a UDP datagram less some headers + * 2) is a multiple of page size 3) can be successfully kmalloc()ed + * by each nfsd. */ -#define NFSSVC_MAXBLKSIZE (8*1024) +#if PAGE_SIZE > (16*1024) +#define NFSSVC_MAXBLKSIZE (32*1024) +#else +#define NFSSVC_MAXBLKSIZE (2*PAGE_SIZE) +#endif #ifdef __KERNEL__ diff -urN linux-2.4.27/include/linux/nfsd/xdr3.h linux-2.4.28/include/linux/nfsd/xdr3.h --- linux-2.4.27/include/linux/nfsd/xdr3.h 2001-11-22 11:47:57.000000000 -0800 +++ linux-2.4.28/include/linux/nfsd/xdr3.h 2004-11-17 03:54:22.065417095 -0800 @@ -41,7 +41,7 @@ __u32 count; int stable; __u8 * data; - int len; + __u32 len; }; struct nfsd3_createargs { diff -urN linux-2.4.27/include/linux/parport_pc.h linux-2.4.28/include/linux/parport_pc.h --- linux-2.4.27/include/linux/parport_pc.h 2001-11-14 14:52:47.000000000 -0800 +++ linux-2.4.28/include/linux/parport_pc.h 2004-11-17 03:54:22.065417095 -0800 @@ -41,7 +41,7 @@ struct pci_dev *dev; }; -extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d) +static __inline__ void parport_pc_write_data(struct parport *p, unsigned char d) { #ifdef DEBUG_PARPORT printk (KERN_DEBUG "parport_pc_write_data(%p,0x%02x)\n", p, d); @@ -49,7 +49,7 @@ outb(d, DATA(p)); } -extern __inline__ unsigned char parport_pc_read_data(struct parport *p) +static __inline__ unsigned char parport_pc_read_data(struct parport *p) { unsigned char val = inb (DATA (p)); #ifdef DEBUG_PARPORT @@ -124,17 +124,17 @@ return ctr; } -extern __inline__ void parport_pc_data_reverse (struct parport *p) +static __inline__ void parport_pc_data_reverse (struct parport *p) { __parport_pc_frob_control (p, 0x20, 0x20); } -extern __inline__ void parport_pc_data_forward (struct parport *p) +static __inline__ void parport_pc_data_forward (struct parport *p) { __parport_pc_frob_control (p, 0x20, 0x00); } -extern __inline__ void parport_pc_write_control (struct parport *p, +static __inline__ void parport_pc_write_control (struct parport *p, unsigned char d) { const unsigned char wm = (PARPORT_CONTROL_STROBE | @@ -152,7 +152,7 @@ __parport_pc_frob_control (p, wm, d & wm); } -extern __inline__ unsigned char parport_pc_read_control(struct parport *p) +static __inline__ unsigned char parport_pc_read_control(struct parport *p) { const unsigned char rm = (PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | @@ -162,7 +162,7 @@ return priv->ctr & rm; /* Use soft copy */ } -extern __inline__ unsigned char parport_pc_frob_control (struct parport *p, +static __inline__ unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, unsigned char val) { @@ -189,18 +189,18 @@ return __parport_pc_frob_control (p, mask, val); } -extern __inline__ unsigned char parport_pc_read_status(struct parport *p) +static __inline__ unsigned char parport_pc_read_status(struct parport *p) { return inb(STATUS(p)); } -extern __inline__ void parport_pc_disable_irq(struct parport *p) +static __inline__ void parport_pc_disable_irq(struct parport *p) { __parport_pc_frob_control (p, 0x10, 0x00); } -extern __inline__ void parport_pc_enable_irq(struct parport *p) +static __inline__ void parport_pc_enable_irq(struct parport *p) { __parport_pc_frob_control (p, 0x10, 0x10); } diff -urN linux-2.4.27/include/linux/pci.h linux-2.4.28/include/linux/pci.h --- linux-2.4.27/include/linux/pci.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/pci.h 2004-11-17 03:54:22.066417136 -0800 @@ -835,7 +835,5 @@ #define PCIPCI_VSFX 16 #define PCIPCI_ALIMAGIK 32 -extern int pciehp_msi_quirk; - #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff -urN linux-2.4.27/include/linux/pci_ids.h linux-2.4.28/include/linux/pci_ids.h --- linux-2.4.27/include/linux/pci_ids.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/pci_ids.h 2004-11-17 03:54:22.068417218 -0800 @@ -606,6 +606,7 @@ #define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a #define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e #define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c +#define PCI_DEVICE_ID_HP_CISS 0x3210 #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 @@ -980,13 +981,16 @@ #define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 +#define PCI_DEVICE_ID_NVIDIA_MCP04_AUDIO 0x003a #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 +#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 +#define PCI_DEVICE_ID_NVIDIA_MCP2S_AUDIO 0x008a #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 @@ -995,6 +999,7 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 +#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 @@ -1708,11 +1713,15 @@ #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 #define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 #define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 +#define PCI_DEVICE_ID_TIGON3_5781 0x16dd +#define PCI_DEVICE_ID_TIGON3_5753 0x16f7 +#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd +#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe #define PCI_DEVICE_ID_TIGON3_5901 0x170d +#define PCI_DEVICE_ID_BCM4401B1 0x170c #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e #define PCI_DEVICE_ID_BCM4401 0x4401 #define PCI_DEVICE_ID_BCM4401B0 0x4402 -#define PCI_DEVICE_ID_BCM4401B1 0x170c #define PCI_VENDOR_ID_ENE 0x1524 #define PCI_DEVICE_ID_ENE_1211 0x1211 @@ -2052,3 +2061,6 @@ #define PCI_DEVICE_ID_MICROGATE_USC 0x0010 #define PCI_DEVICE_ID_MICROGATE_SCC 0x0020 #define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 + +#define PCI_VENDOR_ID_WORKBIT 0x1145 +#define PCI_DEVICE_ID_WORKBIT_CB 0xf021 diff -urN linux-2.4.27/include/linux/pkt_sched.h linux-2.4.28/include/linux/pkt_sched.h --- linux-2.4.27/include/linux/pkt_sched.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/pkt_sched.h 2004-11-17 03:54:22.069417260 -0800 @@ -433,6 +433,16 @@ #define TCA_ATM_MAX TCA_ATM_STATE /* Network emulator */ + +enum +{ + TCA_NETEM_UNSPEC, + TCA_NETEM_CORR, + TCA_NETEM_DELAY_DIST, +}; + +#define TCA_NETEM_MAX TCA_NETEM_DELAY_DIST + struct tc_netem_qopt { __u32 latency; /* added delay (us) */ @@ -443,4 +453,13 @@ __u32 jitter; /* random jitter in latency (us) */ }; +struct tc_netem_corr +{ + __u32 delay_corr; /* delay correlation */ + __u32 loss_corr; /* packet loss correlation */ + __u32 dup_corr; /* duplicate correlation */ +}; + +#define NETEM_DIST_SCALE 8192 + #endif diff -urN linux-2.4.27/include/linux/proc_fs.h linux-2.4.28/include/linux/proc_fs.h --- linux-2.4.27/include/linux/proc_fs.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/proc_fs.h 2004-11-17 03:54:22.069417260 -0800 @@ -79,6 +79,7 @@ extern struct proc_dir_entry proc_root; extern struct proc_dir_entry *proc_root_fs; extern struct proc_dir_entry *proc_net; +extern struct proc_dir_entry *proc_net_stat; extern struct proc_dir_entry *proc_bus; extern struct proc_dir_entry *proc_root_driver; extern struct proc_dir_entry *proc_root_kcore; @@ -170,6 +171,16 @@ return create_proc_info_entry(name,mode,proc_net,get_info); } +static inline struct proc_dir_entry *proc_net_fops_create(const char *name, + mode_t mode, struct file_operations *fops) +{ + struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net); + + if (res) + res->proc_fops = fops; + return res; +} + static inline void proc_net_remove(const char *name) { remove_proc_entry(name,proc_net); diff -urN linux-2.4.27/include/linux/rbtree.h linux-2.4.28/include/linux/rbtree.h --- linux-2.4.27/include/linux/rbtree.h 2001-11-22 11:46:18.000000000 -0800 +++ linux-2.4.28/include/linux/rbtree.h 2004-11-17 03:54:22.070417301 -0800 @@ -121,6 +121,12 @@ extern void rb_insert_color(rb_node_t *, rb_root_t *); extern void rb_erase(rb_node_t *, rb_root_t *); +/* Find logical next and previous nodes in a tree */ +extern rb_node_t *rb_next(rb_node_t *); +extern rb_node_t *rb_prev(rb_node_t *); +extern rb_node_t *rb_first(rb_root_t *); +extern rb_node_t *rb_last(rb_root_t *); + static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) { node->rb_parent = parent; diff -urN linux-2.4.27/include/linux/reiserfs_fs.h linux-2.4.28/include/linux/reiserfs_fs.h --- linux-2.4.27/include/linux/reiserfs_fs.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/linux/reiserfs_fs.h 2004-11-17 03:54:22.072417383 -0800 @@ -1771,25 +1771,25 @@ /* stree.c */ int B_IS_IN_TREE(const struct buffer_head *); extern inline void copy_short_key (void * to, const void * from); -extern inline void copy_item_head(struct item_head * p_v_to, +extern void copy_item_head(struct item_head * p_v_to, const struct item_head * p_v_from); // first key is in cpu form, second - le -extern inline int comp_keys (const struct key * le_key, +extern int comp_keys (const struct key * le_key, const struct cpu_key * cpu_key); -extern inline int comp_short_keys (const struct key * le_key, +extern int comp_short_keys (const struct key * le_key, const struct cpu_key * cpu_key); -extern inline void le_key2cpu_key (struct cpu_key * to, const struct key * from); +extern void le_key2cpu_key (struct cpu_key * to, const struct key * from); // both are cpu keys -extern inline int comp_cpu_keys (const struct cpu_key *, const struct cpu_key *); -extern inline int comp_short_cpu_keys (const struct cpu_key *, +extern int comp_cpu_keys (const struct cpu_key *, const struct cpu_key *); +extern int comp_short_cpu_keys (const struct cpu_key *, const struct cpu_key *); -extern inline void cpu_key2cpu_key (struct cpu_key *, const struct cpu_key *); +extern void cpu_key2cpu_key (struct cpu_key *, const struct cpu_key *); // both are in le form -extern inline int comp_le_keys (const struct key *, const struct key *); -extern inline int comp_short_le_keys (const struct key *, const struct key *); +extern int comp_le_keys (const struct key *, const struct key *); +extern int comp_short_le_keys (const struct key *, const struct key *); // // get key version from on disk key - kludge @@ -1824,7 +1824,7 @@ int search_for_position_by_key (struct super_block * p_s_sb, const struct cpu_key * p_s_cpu_key, struct path * p_s_search_path); -extern inline void decrement_bcount (struct buffer_head * p_s_bh); +extern void decrement_bcount (struct buffer_head * p_s_bh); void decrement_counters_in_path (struct path * p_s_search_path); void pathrelse (struct path * p_s_search_path); int reiserfs_check_path(struct path *p) ; @@ -1902,7 +1902,7 @@ void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ); /* namei.c */ -inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de); +void set_de_name_and_namelen (struct reiserfs_dir_entry * de); int search_by_entry_key (struct super_block * sb, const struct cpu_key * key, struct path * path, struct reiserfs_dir_entry * de); @@ -2050,7 +2050,7 @@ struct buffer_head **); /* do_balance.c */ -inline void do_balance_mark_leaf_dirty (struct tree_balance * tb, +void do_balance_mark_leaf_dirty (struct tree_balance * tb, struct buffer_head * bh, int flag); #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty #define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty diff -urN linux-2.4.27/include/linux/sched.h linux-2.4.28/include/linux/sched.h --- linux-2.4.27/include/linux/sched.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/sched.h 2004-11-17 03:54:22.073417424 -0800 @@ -763,7 +763,7 @@ extern void end_lazy_tlb(struct mm_struct *mm); /* mmdrop drops the mm and the page tables */ -extern inline void FASTCALL(__mmdrop(struct mm_struct *)); +extern void FASTCALL(__mmdrop(struct mm_struct *)); static inline void mmdrop(struct mm_struct * mm) { if (atomic_dec_and_test(&mm->mm_count)) diff -urN linux-2.4.27/include/linux/sctp.h linux-2.4.28/include/linux/sctp.h --- linux-2.4.27/include/linux/sctp.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/linux/sctp.h 2004-11-17 03:54:22.073417424 -0800 @@ -281,7 +281,11 @@ sctp_paramhdr_t param_hdr; } __attribute__((packed)) sctp_ecn_capable_param_t; - +/* ADDIP Section 3.2.6 Adaption Layer Indication */ +typedef struct sctp_adaption_ind_param { + struct sctp_paramhdr param_hdr; + __u32 adaption_ind; +} __attribute__((packed)) sctp_adaption_ind_param_t; /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): * The INIT ACK chunk is used to acknowledge the initiation of an SCTP diff -urN linux-2.4.27/include/linux/seq_file.h linux-2.4.28/include/linux/seq_file.h --- linux-2.4.27/include/linux/seq_file.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/seq_file.h 2004-11-17 03:54:22.074417465 -0800 @@ -65,5 +65,8 @@ int single_open(struct file *, int (*)(struct seq_file *, void *), void *); int single_release(struct inode *, struct file *); int seq_release_private(struct inode *, struct file *); + +#define SEQ_START_TOKEN ((void *)1) + #endif #endif diff -urN linux-2.4.27/include/linux/socket.h linux-2.4.28/include/linux/socket.h --- linux-2.4.27/include/linux/socket.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/socket.h 2004-11-17 03:54:22.074417465 -0800 @@ -137,7 +137,6 @@ #define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ #define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ -#define SCM_CONNECT 0x03 /* rw: struct scm_connect */ struct ucred { __u32 pid; diff -urN linux-2.4.27/include/linux/string.h linux-2.4.28/include/linux/string.h --- linux-2.4.27/include/linux/string.h 2001-11-22 11:46:19.000000000 -0800 +++ linux-2.4.28/include/linux/string.h 2004-11-17 03:54:22.075417506 -0800 @@ -7,6 +7,7 @@ #include /* for size_t */ #include /* for NULL */ +#include /* for inline ((always_inline)) */ #ifdef __cplusplus extern "C" { diff -urN linux-2.4.27/include/linux/tcp_diag.h linux-2.4.28/include/linux/tcp_diag.h --- linux-2.4.27/include/linux/tcp_diag.h 2001-12-21 09:42:04.000000000 -0800 +++ linux-2.4.28/include/linux/tcp_diag.h 2004-11-17 03:54:22.075417506 -0800 @@ -98,9 +98,10 @@ TCPDIAG_NONE, TCPDIAG_MEMINFO, TCPDIAG_INFO, + TCPDIAG_VEGASINFO, }; -#define TCPDIAG_MAX TCPDIAG_INFO +#define TCPDIAG_MAX TCPDIAG_VEGASINFO /* TCPDIAG_MEM */ @@ -113,4 +114,14 @@ __u32 tcpdiag_tmem; }; +/* TCPDIAG_VEGASINFO */ + +struct tcpvegas_info { + __u32 tcpv_enabled; + __u32 tcpv_rttcnt; + __u32 tcpv_rtt; + __u32 tcpv_minrtt; +}; + + #endif /* _TCP_DIAG_H_ */ diff -urN linux-2.4.27/include/linux/usb.h linux-2.4.28/include/linux/usb.h --- linux-2.4.27/include/linux/usb.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/linux/usb.h 2004-11-17 03:54:22.076417547 -0800 @@ -828,6 +828,8 @@ atomic_t refcnt; /* Reference count */ struct semaphore serialize; + struct semaphore exclusive_access; /* prevent driver & proc accesses */ + /* from overlapping cmds at device */ unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ diff -urN linux-2.4.27/include/net/dn_neigh.h linux-2.4.28/include/net/dn_neigh.h --- linux-2.4.27/include/net/dn_neigh.h 2000-03-02 10:13:16.000000000 -0800 +++ linux-2.4.28/include/net/dn_neigh.h 2004-11-17 03:54:22.077417588 -0800 @@ -18,7 +18,6 @@ extern void dn_neigh_init(void); extern void dn_neigh_cleanup(void); -extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr); extern int dn_neigh_router_hello(struct sk_buff *skb); extern int dn_neigh_endnode_hello(struct sk_buff *skb); extern void dn_neigh_pointopoint_hello(struct sk_buff *skb); diff -urN linux-2.4.27/include/net/if_inet6.h linux-2.4.28/include/net/if_inet6.h --- linux-2.4.27/include/net/if_inet6.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/net/if_inet6.h 2004-11-17 03:54:22.077417588 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * * This program is free software; you can redistribute it and/or diff -urN linux-2.4.27/include/net/ip.h linux-2.4.28/include/net/ip.h --- linux-2.4.27/include/net/ip.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/net/ip.h 2004-11-17 03:54:22.078417630 -0800 @@ -137,7 +137,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, unsigned int len); -extern __inline__ int ip_finish_output(struct sk_buff *skb); +extern int ip_finish_output(struct sk_buff *skb); struct ipv4_config { @@ -228,6 +228,7 @@ */ struct sk_buff *ip_defrag(struct sk_buff *skb); +extern void ipfrag_flush(void); extern int ip_frag_nqueues; extern atomic_t ip_frag_mem; diff -urN linux-2.4.27/include/net/ip6_fib.h linux-2.4.28/include/net/ip6_fib.h --- linux-2.4.27/include/net/ip6_fib.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/include/net/ip6_fib.h 2004-11-17 03:54:22.078417630 -0800 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -urN linux-2.4.27/include/net/ip_vs.h linux-2.4.28/include/net/ip_vs.h --- linux-2.4.27/include/net/ip_vs.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/net/ip_vs.h 2004-11-17 03:54:22.079417671 -0800 @@ -8,7 +8,7 @@ #include /* For __uXX types */ -#define IP_VS_VERSION_CODE 0x01000B +#define IP_VS_VERSION_CODE 0x01000C #define NVERSION(version) \ (version >> 16) & 0xFF, \ (version >> 8) & 0xFF, \ diff -urN linux-2.4.27/include/net/ipv6.h linux-2.4.28/include/net/ipv6.h --- linux-2.4.27/include/net/ipv6.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/net/ipv6.h 2004-11-17 03:54:22.079417671 -0800 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ * diff -urN linux-2.4.27/include/net/irda/irlmp_frame.h linux-2.4.28/include/net/irda/irlmp_frame.h --- linux-2.4.27/include/net/irda/irlmp_frame.h 2000-12-11 13:33:22.000000000 -0800 +++ linux-2.4.28/include/net/irda/irlmp_frame.h 2004-11-17 03:54:22.080417712 -0800 @@ -40,7 +40,7 @@ #define CONTROL_BIT 0x80 -inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, +void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, int expedited, struct sk_buff *skb); void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, __u8 opcode, struct sk_buff *skb); diff -urN linux-2.4.27/include/net/irda/timer.h linux-2.4.28/include/net/irda/timer.h --- linux-2.4.27/include/net/irda/timer.h 2001-11-09 14:22:17.000000000 -0800 +++ linux-2.4.28/include/net/irda/timer.h 2004-11-17 03:54:22.080417712 -0800 @@ -72,21 +72,21 @@ void irda_start_timer(struct timer_list *ptimer, int timeout, void* data, TIMER_CALLBACK callback); -inline void irlap_start_slot_timer(struct irlap_cb *self, int timeout); -inline void irlap_start_query_timer(struct irlap_cb *self, int timeout); -inline void irlap_start_final_timer(struct irlap_cb *self, int timeout); -inline void irlap_start_wd_timer(struct irlap_cb *self, int timeout); -inline void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); +void irlap_start_slot_timer(struct irlap_cb *self, int timeout); +void irlap_start_query_timer(struct irlap_cb *self, int timeout); +void irlap_start_final_timer(struct irlap_cb *self, int timeout); +void irlap_start_wd_timer(struct irlap_cb *self, int timeout); +void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout); void irlap_stop_mbusy_timer(struct irlap_cb *); struct lsap_cb; struct lap_cb; -inline void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); -inline void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); -inline void irlmp_start_idle_timer(struct lap_cb *, int timeout); -inline void irlmp_stop_idle_timer(struct lap_cb *self); +void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); +void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); +void irlmp_start_idle_timer(struct lap_cb *, int timeout); +void irlmp_stop_idle_timer(struct lap_cb *self); #endif diff -urN linux-2.4.27/include/net/neighbour.h linux-2.4.28/include/net/neighbour.h --- linux-2.4.27/include/net/neighbour.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/net/neighbour.h 2004-11-17 03:54:22.081417753 -0800 @@ -5,8 +5,13 @@ * Generic neighbour manipulation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov + * + * Changes: + * + * Harald Welte: + * - Add neighbour cache statistics like rtstat */ /* The following flags & states are exported to user space, @@ -45,6 +50,7 @@ #include #include +#include #define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE) #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) @@ -78,12 +84,25 @@ struct neigh_statistics { - unsigned long allocs; - unsigned long res_failed; - unsigned long rcv_probes_mcast; - unsigned long rcv_probes_ucast; + unsigned long allocs; /* number of allocated neighs */ + unsigned long destroys; /* number of destroyed neighs */ + unsigned long hash_grows; /* number of hash resizes */ + + unsigned long res_failed; /* nomber of failed resolutions */ + + unsigned long lookups; /* number of lookups */ + unsigned long hits; /* number of hits (among lookups) */ + + unsigned long rcv_probes_mcast; /* number of received mcast ipv6 */ + unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */ + + unsigned long periodic_gc_runs; /* number of periodic GC runs */ + unsigned long forced_gc_runs; /* number of forced GC runs */ }; +#define NEIGH_CACHE_STAT_INC(tbl, field) \ + ((tbl)->stats[smp_processor_id()].field++) + struct neighbour { struct neighbour *next; @@ -128,9 +147,6 @@ u8 key[0]; }; -#define NEIGH_HASHMASK 0x1F -#define PNEIGH_HASHMASK 0xF - /* * neighbour table manipulation */ @@ -158,15 +174,21 @@ struct timer_list gc_timer; struct timer_list proxy_timer; struct sk_buff_head proxy_queue; - int entries; + atomic_t entries; rwlock_t lock; unsigned long last_rand; struct neigh_parms *parms_list; kmem_cache_t *kmem_cachep; struct tasklet_struct gc_task; - struct neigh_statistics stats; - struct neighbour *hash_buckets[NEIGH_HASHMASK+1]; - struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1]; + struct neigh_statistics stats[NR_CPUS]; + struct neighbour **hash_buckets; + unsigned int hash_mask; + __u32 hash_rnd; + unsigned int hash_chain_gc; + struct pneigh_entry **phash_buckets; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pde; +#endif }; extern void neigh_table_init(struct neigh_table *tbl); @@ -174,6 +196,8 @@ extern struct neighbour * neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev); +extern struct neighbour * neigh_lookup_nodev(struct neigh_table *tbl, + const void *pkey); extern struct neighbour * neigh_create(struct neigh_table *tbl, const void *pkey, struct net_device *dev); @@ -205,6 +229,24 @@ extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern void neigh_app_ns(struct neighbour *n); +extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); +extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); +extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); + +struct neigh_seq_state { + struct neigh_table *tbl; + void *(*neigh_sub_iter)(struct neigh_seq_state *state, + struct neighbour *n, loff_t *pos); + unsigned int bucket; + unsigned int flags; +#define NEIGH_SEQ_NEIGH_ONLY 0x00000001 +#define NEIGH_SEQ_IS_PNEIGH 0x00000002 +#define NEIGH_SEQ_SKIP_NOARP 0x00000004 +}; +extern void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, unsigned int); +extern void *neigh_seq_next(struct seq_file *, void *, loff_t *); +extern void neigh_seq_stop(struct seq_file *, void *); + extern int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, int p_id, int pdev_id, char *p_name); extern void neigh_sysctl_unregister(struct neigh_parms *p); diff -urN linux-2.4.27/include/net/pkt_sched.h linux-2.4.28/include/net/pkt_sched.h --- linux-2.4.27/include/net/pkt_sched.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/include/net/pkt_sched.h 2004-11-17 03:54:22.082417794 -0800 @@ -78,13 +78,14 @@ unsigned flags; #define TCQ_F_BUILTIN 1 #define TCQ_F_THROTTLED 2 -#define TCQ_F_INGRES 4 +#define TCQ_F_INGRESS 4 struct Qdisc_ops *ops; - struct Qdisc *next; u32 handle; + u32 parent; atomic_t refcnt; struct sk_buff_head q; struct net_device *dev; + struct list_head list; struct tc_stats stats; int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q); diff -urN linux-2.4.27/include/net/sctp/command.h linux-2.4.28/include/net/sctp/command.h --- linux-2.4.27/include/net/sctp/command.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sctp/command.h 2004-11-17 03:54:22.082417794 -0800 @@ -94,6 +94,9 @@ SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */ SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */ SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */ + SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */ + SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */ + SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */ SCTP_CMD_LAST } sctp_verb_t; diff -urN linux-2.4.27/include/net/sctp/compat.h linux-2.4.28/include/net/sctp/compat.h --- linux-2.4.27/include/net/sctp/compat.h 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/include/net/sctp/compat.h 2004-11-17 03:54:22.083417835 -0800 @@ -61,7 +61,7 @@ #define virt_addr_valid(x) VALID_PAGE(virt_to_page((x))) #define sock_owned_by_user(sk) ((sk)->lock.users) #define sk_set_owner(x, y) -#define __unsafe(x) MOD_INC_USE_COUNT +#define __unsafe(x) #define dst_pmtu(x) ((x)->pmtu) #define sk_family family diff -urN linux-2.4.27/include/net/sctp/constants.h linux-2.4.28/include/net/sctp/constants.h --- linux-2.4.27/include/net/sctp/constants.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sctp/constants.h 2004-11-17 03:54:22.083417835 -0800 @@ -175,6 +175,10 @@ SCTP_IERROR_BAD_TAG, SCTP_IERROR_BIG_GAP, SCTP_IERROR_DUP_TSN, + SCTP_IERROR_HIGH_TSN, + SCTP_IERROR_IGNORE_TSN, + SCTP_IERROR_NO_DATA, + SCTP_IERROR_BAD_STREAM, } sctp_ierror_t; diff -urN linux-2.4.27/include/net/sctp/sm.h linux-2.4.28/include/net/sctp/sm.h --- linux-2.4.27/include/net/sctp/sm.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sctp/sm.h 2004-11-17 03:54:22.084417876 -0800 @@ -322,6 +322,9 @@ const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, struct sctp_chunk *err_chunk); +int sctp_eat_data(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands); /* 3rd level prototypes */ __u32 sctp_generate_tag(const struct sctp_endpoint *); diff -urN linux-2.4.27/include/net/sctp/structs.h linux-2.4.28/include/net/sctp/structs.h --- linux-2.4.27/include/net/sctp/structs.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sctp/structs.h 2004-11-17 03:54:22.085417917 -0800 @@ -266,6 +266,7 @@ __u8 disable_fragments; __u8 pd_mode; __u8 v4mapped; + __u32 adaption_ind; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; @@ -323,6 +324,8 @@ __u8 prsctp_capable; + __u32 adaption_ind; + /* This is a shim for my peer's INIT packet, followed by * a copy of the raw address list of the association. * The length of the raw address list is saved in the @@ -362,6 +365,7 @@ struct sctp_ipv4addr_param *v4; struct sctp_ipv6addr_param *v6; union sctp_addr_param *addr; + struct sctp_adaption_ind_param *aind; }; /* RFC 2960. Section 3.3.5 Heartbeat. @@ -1398,6 +1402,8 @@ __u8 asconf_capable; /* Does peer support ADDIP? */ __u8 prsctp_capable; /* Can peer do PR-SCTP? */ + __u32 adaption_ind; /* Adaption Code point. */ + /* This mask is used to disable sending the ASCONF chunk * with specified parameter to peer. */ diff -urN linux-2.4.27/include/net/sctp/ulpevent.h linux-2.4.28/include/net/sctp/ulpevent.h --- linux-2.4.27/include/net/sctp/ulpevent.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sctp/ulpevent.h 2004-11-17 03:54:22.086417959 -0800 @@ -121,6 +121,9 @@ const struct sctp_association *asoc, __u32 indication, int gfp); +struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication( + const struct sctp_association *asoc, int gfp); + struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_chunk *chunk, int gfp); diff -urN linux-2.4.27/include/net/sock.h linux-2.4.28/include/net/sock.h --- linux-2.4.27/include/net/sock.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/sock.h 2004-11-17 03:54:22.087418000 -0800 @@ -256,6 +256,13 @@ __u32 end_seq; }; +enum tcp_congestion_algo { + TCP_RENO=0, + TCP_VEGAS, + TCP_WESTWOOD, + TCP_BIC, +}; + struct tcp_opt { int tcp_header_len; /* Bytes of tcp header to send */ @@ -428,7 +435,8 @@ unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; - int frto_counter; /* Number of new acks after RTO */ + __u8 adv_cong; /* Using Vegas, Westwood, or BIC */ + __u8 frto_counter; /* Number of new acks after RTO */ __u32 frto_highmark; /* snd_nxt when RTO occurred */ unsigned long last_synq_overflow; @@ -465,7 +473,6 @@ __u32 beg_snd_nxt; /* right edge during last RTT */ __u32 beg_snd_una; /* left edge during last RTT */ __u32 beg_snd_cwnd; /* saves the size of the cwnd */ - __u8 do_vegas; /* do vegas for this connection */ __u8 doing_vegas_now;/* if true, do vegas for this RTT */ __u16 cntRTT; /* # of RTTs measured within last RTT */ __u32 minRTT; /* min of RTTs measured within last RTT (in usec) */ diff -urN linux-2.4.27/include/net/tcp.h linux-2.4.28/include/net/tcp.h --- linux-2.4.27/include/net/tcp.h 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/include/net/tcp.h 2004-11-17 03:54:22.089418082 -0800 @@ -1110,6 +1110,13 @@ return tp->packets_out - tp->left_out + tp->retrans_out; } +/* + * Which congestion algorithim is in use on the connection. + */ +#define tcp_is_vegas(__tp) ((__tp)->adv_cong == TCP_VEGAS) +#define tcp_is_westwood(__tp) ((__tp)->adv_cong == TCP_WESTWOOD) +#define tcp_is_bic(__tp) ((__tp)->adv_cong == TCP_BIC) + /* Recalculate snd_ssthresh, we want to set it to: * * Reno: @@ -1122,7 +1129,7 @@ */ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) { - if (sysctl_tcp_bic) { + if (tcp_is_bic(tp)) { if (sysctl_tcp_bic_fast_convergence && tp->snd_cwnd < tp->bictcp.last_max_cwnd) tp->bictcp.last_max_cwnd @@ -1141,11 +1148,6 @@ /* Stop taking Vegas samples for now. */ #define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0) - -/* Is this TCP connection using Vegas (regardless of whether it is taking - * Vegas measurements at the current time)? - */ -#define tcp_is_vegas(__tp) ((__tp)->vegas.do_vegas) static inline void tcp_vegas_enable(struct tcp_opt *tp) { @@ -1179,7 +1181,7 @@ /* Should we be taking Vegas samples right now? */ #define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now) -extern void tcp_vegas_init(struct tcp_opt *tp); +extern void tcp_ca_init(struct tcp_opt *tp); static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state) { @@ -1978,7 +1980,7 @@ static inline void tcp_westwood_update_rtt(struct tcp_opt *tp, __u32 rtt_seq) { - if (sysctl_tcp_westwood) + if (tcp_is_westwood(tp)) tp->westwood.rtt = rtt_seq; } @@ -2015,13 +2017,13 @@ static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb) { - if (sysctl_tcp_westwood) + if (tcp_is_westwood(&(sk->tp_pinfo.af_tcp))) __tcp_westwood_fast_bw(sk, skb); } static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb) { - if (sysctl_tcp_westwood) + if (tcp_is_westwood(&(sk->tp_pinfo.af_tcp))) __tcp_westwood_slow_bw(sk, skb); } @@ -2035,7 +2037,7 @@ { __u32 ret = 0; - if (sysctl_tcp_westwood) + if (tcp_is_westwood(tp)) ret = (__u32) (max(__tcp_westwood_bw_rttmin(tp), 2U)); return ret; @@ -2046,7 +2048,7 @@ int ret = 0; __u32 ssthresh; - if (sysctl_tcp_westwood) { + if (tcp_is_westwood(tp)) { if (!(ssthresh = tcp_westwood_bw_rttmin(tp))) return ret; @@ -2062,7 +2064,7 @@ int ret = 0; __u32 cwnd; - if (sysctl_tcp_westwood) { + if (tcp_is_westwood(tp)) { if (!(cwnd = tcp_westwood_bw_rttmin(tp))) return ret; @@ -2077,7 +2079,7 @@ { int ret = 0; - if (sysctl_tcp_westwood) { + if (tcp_is_westwood(tp)) { if (tcp_westwood_cwnd(tp)) { tp->snd_ssthresh = tp->snd_cwnd; ret = 1; diff -urN linux-2.4.27/include/pcmcia/mem_op.h linux-2.4.28/include/pcmcia/mem_op.h --- linux-2.4.27/include/pcmcia/mem_op.h 2001-02-16 16:02:37.000000000 -0800 +++ linux-2.4.28/include/pcmcia/mem_op.h 2004-11-17 03:54:22.089418082 -0800 @@ -81,7 +81,9 @@ n -= odd; while (n) { *(u_short *)to = __raw_readw(from); - (char *)to += 2; (char *)from += 2; n -= 2; + to = (void *)((long)to + 2); + from = (const void *)((long)from + 2); + n -= 2; } if (odd) *(u_char *)to = readb(from); @@ -93,7 +95,9 @@ n -= odd; while (n) { __raw_writew(*(u_short *)from, to); - (char *)to += 2; (char *)from += 2; n -= 2; + to = (void *)((long)to + 2); + from = (const void *)((long)from + 2); + n -= 2; } if (odd) writeb(*(u_char *)from, to); @@ -105,7 +109,9 @@ n -= odd; while (n) { put_user(__raw_readw(from), (short *)to); - (char *)to += 2; (char *)from += 2; n -= 2; + to = (void *)((long)to + 2); + from = (const void *)((long)from + 2); + n -= 2; } if (odd) put_user(readb(from), (char *)to); @@ -120,7 +126,9 @@ while (n) { get_user(s, (short *)from); __raw_writew(s, to); - (char *)to += 2; (char *)from += 2; n -= 2; + to = (void *)((long)to + 2); + from = (const void *)((long)from + 2); + n -= 2; } if (odd) { get_user(c, (char *)from); diff -urN linux-2.4.27/include/scsi/scsi.h linux-2.4.28/include/scsi/scsi.h --- linux-2.4.27/include/scsi/scsi.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/include/scsi/scsi.h 2004-11-17 03:54:22.090418123 -0800 @@ -91,6 +91,7 @@ #define WRITE_LONG_2 0xea #define READ_16 0x88 #define WRITE_16 0x8a +#define VERIFY_16 0x8f #define SERVICE_ACTION_IN 0x9e /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 diff -urN linux-2.4.27/init/main.c linux-2.4.28/init/main.c --- linux-2.4.27/init/main.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/init/main.c 2004-11-17 03:54:22.090418123 -0800 @@ -101,6 +101,11 @@ extern int init_pcmcia_ds(void); extern void free_initmem(void); +#ifdef CONFIG_ACPI_BUS +extern void acpi_early_init(void); +#else +static inline void acpi_early_init(void) { } +#endif #ifdef CONFIG_TC extern void tc_init(void); @@ -426,6 +431,7 @@ proc_root_init(); #endif check_bugs(); + acpi_early_init(); /* before LAPIC and SMP init */ printk("POSIX conformance testing by UNIFIX\n"); /* diff -urN linux-2.4.27/kernel/fork.c linux-2.4.28/kernel/fork.c --- linux-2.4.27/kernel/fork.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/kernel/fork.c 2004-11-17 03:54:22.091418164 -0800 @@ -39,7 +39,7 @@ struct task_struct *pidhash[PIDHASH_SZ]; -void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -49,7 +49,7 @@ wq_write_unlock_irqrestore(&q->lock, flags); } -void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -59,7 +59,7 @@ wq_write_unlock_irqrestore(&q->lock, flags); } -void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -264,7 +264,7 @@ * is dropped: either by a lazy thread or by * mmput. Free the page directory and the mm. */ -inline void __mmdrop(struct mm_struct *mm) +void fastcall __mmdrop(struct mm_struct *mm) { BUG_ON(mm == &init_mm); pgd_free(mm->pgd); diff -urN linux-2.4.27/kernel/panic.c linux-2.4.28/kernel/panic.c --- linux-2.4.27/kernel/panic.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/kernel/panic.c 2004-11-17 03:54:22.092418205 -0800 @@ -59,7 +59,7 @@ bust_spinlocks(1); va_start(args, fmt); - vsprintf(buf, fmt, args); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); printk(KERN_EMERG "Kernel panic: %s\n",buf); if (in_interrupt()) diff -urN linux-2.4.27/kernel/printk.c linux-2.4.28/kernel/printk.c --- linux-2.4.27/kernel/printk.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/kernel/printk.c 2004-11-17 03:54:22.092418205 -0800 @@ -95,6 +95,7 @@ static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; +static int selected_console = -1; static int preferred_console = -1; /* Flag: console code may call schedule() */ @@ -140,12 +141,12 @@ for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) if (strcmp(console_cmdline[i].name, name) == 0 && console_cmdline[i].index == idx) { - preferred_console = i; + selected_console = i; return 1; } if (i == MAX_CMDLINECONSOLES) return 1; - preferred_console = i; + selected_console = i; c = &console_cmdline[i]; memcpy(c->name, name, sizeof(c->name)); c->options = options; @@ -586,6 +587,9 @@ int i; unsigned long flags; + if (preferred_console < 0) + preferred_console = selected_console; + /* * See if we want to use this console driver. If we * didn't select a console we take the first one @@ -675,7 +679,7 @@ * would prevent fbcon from taking over. */ if (console_drivers == NULL) - preferred_console = -1; + preferred_console = selected_console; release_console_sem(); diff -urN linux-2.4.27/kernel/sched.c linux-2.4.28/kernel/sched.c --- linux-2.4.27/kernel/sched.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/kernel/sched.c 2004-11-17 03:54:22.094418287 -0800 @@ -209,7 +209,7 @@ */ static FASTCALL(void reschedule_idle(struct task_struct * p)); -static void reschedule_idle(struct task_struct * p) +static void fastcall reschedule_idle(struct task_struct * p) { #ifdef CONFIG_SMP int this_cpu = smp_processor_id(); @@ -367,7 +367,7 @@ return success; } -inline int wake_up_process(struct task_struct * p) +inline int fastcall wake_up_process(struct task_struct * p) { return try_to_wake_up(p, 0); } @@ -405,7 +405,7 @@ * * In all cases the return value is guaranteed to be non-negative. */ -signed long schedule_timeout(signed long timeout) +signed long fastcall schedule_timeout(signed long timeout) { struct timer_list timer; unsigned long expire; @@ -735,7 +735,7 @@ } } -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr) +void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode, int nr) { if (q) { unsigned long flags; @@ -745,7 +745,7 @@ } } -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr) +void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr) { if (q) { unsigned long flags; @@ -755,7 +755,7 @@ } } -void complete(struct completion *x) +void fastcall complete(struct completion *x) { unsigned long flags; @@ -765,7 +765,7 @@ spin_unlock_irqrestore(&x->wait.lock, flags); } -void wait_for_completion(struct completion *x) +void fastcall wait_for_completion(struct completion *x) { spin_lock_irq(&x->wait.lock); if (!x->done) { @@ -800,7 +800,7 @@ __remove_wait_queue(q, &wait); \ wq_write_unlock_irqrestore(&q->lock,flags); -void interruptible_sleep_on(wait_queue_head_t *q) +void fastcall interruptible_sleep_on(wait_queue_head_t *q) { SLEEP_ON_VAR @@ -811,7 +811,7 @@ SLEEP_ON_TAIL } -long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) +long fastcall interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR @@ -824,7 +824,7 @@ return timeout; } -void sleep_on(wait_queue_head_t *q) +void fastcall sleep_on(wait_queue_head_t *q) { SLEEP_ON_VAR @@ -835,7 +835,7 @@ SLEEP_ON_TAIL } -long sleep_on_timeout(wait_queue_head_t *q, long timeout) +long fastcall sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR diff -urN linux-2.4.27/kernel/softirq.c linux-2.4.28/kernel/softirq.c --- linux-2.4.27/kernel/softirq.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/kernel/softirq.c 2004-11-17 03:54:22.094418287 -0800 @@ -111,7 +111,7 @@ /* * This function must run with irq disabled! */ -inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) +inline fastcall void cpu_raise_softirq(unsigned int cpu, unsigned int nr) { __cpu_raise_softirq(cpu, nr); @@ -128,7 +128,7 @@ wakeup_softirqd(cpu); } -void raise_softirq(unsigned int nr) +void fastcall raise_softirq(unsigned int nr) { unsigned long flags; @@ -149,7 +149,7 @@ struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned; struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned; -void __tasklet_schedule(struct tasklet_struct *t) +void fastcall __tasklet_schedule(struct tasklet_struct *t) { int cpu = smp_processor_id(); unsigned long flags; @@ -161,7 +161,7 @@ local_irq_restore(flags); } -void __tasklet_hi_schedule(struct tasklet_struct *t) +void fastcall __tasklet_hi_schedule(struct tasklet_struct *t) { int cpu = smp_processor_id(); unsigned long flags; diff -urN linux-2.4.27/kernel/sysctl.c linux-2.4.28/kernel/sysctl.c --- linux-2.4.27/kernel/sysctl.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/kernel/sysctl.c 2004-11-17 03:54:22.095418329 -0800 @@ -879,7 +879,7 @@ if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -1032,7 +1032,7 @@ if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -1133,7 +1133,7 @@ if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; diff -urN linux-2.4.27/lib/brlock.c linux-2.4.28/lib/brlock.c --- linux-2.4.27/lib/brlock.c 2001-11-09 14:11:15.000000000 -0800 +++ linux-2.4.28/lib/brlock.c 2004-11-17 03:54:22.096418370 -0800 @@ -20,7 +20,7 @@ brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] = { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = RW_LOCK_UNLOCKED } }; -void __br_write_lock (enum brlock_indices idx) +void fastcall __br_write_lock (enum brlock_indices idx) { int i; @@ -28,7 +28,7 @@ write_lock(&__brlock_array[cpu_logical_map(i)][idx]); } -void __br_write_unlock (enum brlock_indices idx) +void fastcall __br_write_unlock (enum brlock_indices idx) { int i; @@ -44,7 +44,7 @@ struct br_wrlock __br_write_locks[__BR_IDX_MAX] = { [0 ... __BR_IDX_MAX-1] = { SPIN_LOCK_UNLOCKED } }; -void __br_write_lock (enum brlock_indices idx) +void fastcall __br_write_lock (enum brlock_indices idx) { int i; @@ -59,7 +59,7 @@ } } -void __br_write_unlock (enum brlock_indices idx) +void fastcall __br_write_unlock (enum brlock_indices idx) { spin_unlock(&__br_write_locks[idx].lock); } diff -urN linux-2.4.27/lib/crc32.c linux-2.4.28/lib/crc32.c --- linux-2.4.27/lib/crc32.c 2004-04-14 06:05:40.000000000 -0700 +++ linux-2.4.28/lib/crc32.c 2004-11-17 03:54:22.097418411 -0800 @@ -99,7 +99,9 @@ /* Align it */ if(unlikely(((long)b)&3 && len)){ do { - DO_CRC(*((u8 *)b)++); + u8 *p = (u8 *)b; + DO_CRC(*p++); + b = (void *)p; } while ((--len) && ((long)b)&3 ); } if(likely(len >= 4)){ @@ -120,7 +122,9 @@ /* And the last few bytes */ if(len){ do { - DO_CRC(*((u8 *)b)++); + u8 *p = (u8 *)b; + DO_CRC(*p++); + b = (void *)p; } while (--len); } @@ -200,7 +204,9 @@ /* Align it */ if(unlikely(((long)b)&3 && len)){ do { - DO_CRC(*((u8 *)b)++); + u8 *p = (u8 *)b; + DO_CRC(*p++); + b = (u32 *)p; } while ((--len) && ((long)b)&3 ); } if(likely(len >= 4)){ @@ -221,7 +227,9 @@ /* And the last few bytes */ if(len){ do { - DO_CRC(*((u8 *)b)++); + u8 *p = (u8 *)b; + DO_CRC(*p++); + b = (void *)p; } while (--len); } return __be32_to_cpu(crc); diff -urN linux-2.4.27/lib/rbtree.c linux-2.4.28/lib/rbtree.c --- linux-2.4.27/lib/rbtree.c 2002-08-02 17:39:46.000000000 -0700 +++ linux-2.4.28/lib/rbtree.c 2004-11-17 03:54:22.097418411 -0800 @@ -294,3 +294,74 @@ __rb_erase_color(child, parent, root); } EXPORT_SYMBOL(rb_erase); + +/* + * This function returns the first node (in sort order) of the tree. + */ +rb_node_t *rb_first(rb_root_t *root) +{ + rb_node_t *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} +EXPORT_SYMBOL(rb_first); + +rb_node_t *rb_last(rb_root_t *root) +{ + rb_node_t *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} +EXPORT_SYMBOL(rb_last); + +rb_node_t *rb_next(rb_node_t *node) +{ + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node = node->rb_left; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while (node->rb_parent && node == node->rb_parent->rb_right) + node = node->rb_parent; + + return node->rb_parent; +} +EXPORT_SYMBOL(rb_next); + +rb_node_t *rb_prev(rb_node_t *node) +{ + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node = node->rb_right; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while (node->rb_parent && node == node->rb_parent->rb_left) + node = node->rb_parent; + + return node->rb_parent; +} +EXPORT_SYMBOL(rb_prev); diff -urN linux-2.4.27/lib/rwsem.c linux-2.4.28/lib/rwsem.c --- linux-2.4.27/lib/rwsem.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/lib/rwsem.c 2004-11-17 03:54:22.098418452 -0800 @@ -160,7 +160,7 @@ /* * wait for the read lock to be granted */ -struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_down_read_failed(struct rw_semaphore *sem) { struct rwsem_waiter waiter; @@ -176,7 +176,7 @@ /* * wait for the write lock to be granted */ -struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_down_write_failed(struct rw_semaphore *sem) { struct rwsem_waiter waiter; @@ -193,7 +193,7 @@ * handle waking up a waiter on the semaphore * - up_read has decremented the active part of the count if we come here */ -struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering rwsem_wake"); diff -urN linux-2.4.27/lib/string.c linux-2.4.28/lib/string.c --- linux-2.4.27/lib/string.c 2002-08-02 17:39:46.000000000 -0700 +++ linux-2.4.28/lib/string.c 2004-11-17 03:54:22.098418452 -0800 @@ -380,14 +380,13 @@ * 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) +void bcopy(const void * srcp, void * destp, size_t count) { - char *tmp = dest; + const char *src = srcp; + char *dest = destp; while (count--) - *tmp++ = *src++; - - return dest; + *dest++ = *src++; } #endif diff -urN linux-2.4.27/mm/filemap.c linux-2.4.28/mm/filemap.c --- linux-2.4.27/mm/filemap.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/mm/filemap.c 2004-11-17 03:54:22.101418575 -0800 @@ -68,7 +68,7 @@ #define CLUSTER_OFFSET(x) (((x) >> page_cluster) << page_cluster) static void FASTCALL(add_page_to_hash_queue(struct page * page, struct page **p)); -static void add_page_to_hash_queue(struct page * page, struct page **p) +static void fastcall add_page_to_hash_queue(struct page * page, struct page **p) { struct page *next = *p; @@ -151,7 +151,7 @@ /* * Add a page to the dirty page list. */ -void set_page_dirty(struct page *page) +void fastcall set_page_dirty(struct page *page) { if (!test_and_set_bit(PG_dirty, &page->flags)) { struct address_space *mapping = page->mapping; @@ -260,7 +260,7 @@ } static int FASTCALL(truncate_list_pages(struct list_head *, unsigned long, unsigned *)); -static int truncate_list_pages(struct list_head *head, unsigned long start, unsigned *partial) +static int fastcall truncate_list_pages(struct list_head *head, unsigned long start, unsigned *partial) { struct list_head *curr; struct page * page; @@ -382,7 +382,7 @@ } static int FASTCALL(invalidate_list_pages2(struct list_head *)); -static int invalidate_list_pages2(struct list_head *head) +static int fastcall invalidate_list_pages2(struct list_head *head) { struct list_head *curr; struct page * page; @@ -755,7 +755,7 @@ * and schedules an I/O to read in its contents from disk. */ static int FASTCALL(page_cache_read(struct file * file, unsigned long offset)); -static int page_cache_read(struct file * file, unsigned long offset) +static int fastcall page_cache_read(struct file * file, unsigned long offset) { struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct page **hash = page_hash(mapping, offset); @@ -790,7 +790,7 @@ */ static int FASTCALL(read_cluster_nonblocking(struct file * file, unsigned long offset, unsigned long filesize)); -static int read_cluster_nonblocking(struct file * file, unsigned long offset, +static int fastcall read_cluster_nonblocking(struct file * file, unsigned long offset, unsigned long filesize) { unsigned long pages = CLUSTER_PAGES; @@ -871,7 +871,7 @@ * callbacks that would result into the blkdev layer waking * up the page after a queue unplug. */ -void wakeup_page_waiters(struct page * page) +void fastcall wakeup_page_waiters(struct page * page) { wait_queue_head_t * head; @@ -927,7 +927,7 @@ * of the waiters for all of the pages in the appropriate * wait queue are woken. */ -void unlock_page(struct page *page) +void fastcall unlock_page(struct page *page) { wait_queue_head_t *waitqueue = page_waitqueue(page); ClearPageLaunder(page); @@ -974,7 +974,7 @@ * Get an exclusive lock on the page, optimistically * assuming it's not locked.. */ -void lock_page(struct page *page) +void fastcall lock_page(struct page *page) { if (TryLockPage(page)) __lock_page(page); @@ -1025,7 +1025,7 @@ * during blocking operations.. */ static struct page * FASTCALL(__find_lock_page_helper(struct address_space *, unsigned long, struct page *)); -static struct page * __find_lock_page_helper(struct address_space *mapping, +static struct page * fastcall __find_lock_page_helper(struct address_space *mapping, unsigned long offset, struct page *hash) { struct page *page; @@ -1388,7 +1388,7 @@ * If it was already so marked, move it to the active queue and drop * the referenced bit. Otherwise, just mark it for future action.. */ -void mark_page_accessed(struct page *page) +void fastcall mark_page_accessed(struct page *page) { if (!PageActive(page) && PageReferenced(page)) { activate_page(page); @@ -1639,8 +1639,9 @@ static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, size_t count, loff_t offset) { - ssize_t retval; - int new_iobuf, chunk_size, blocksize_mask, blocksize, blocksize_bits, iosize, progress; + ssize_t retval, progress; + int new_iobuf, chunk_size, blocksize_mask, blocksize, blocksize_bits; + ssize_t iosize; struct kiobuf * iobuf; struct address_space * mapping = filp->f_dentry->d_inode->i_mapping; struct inode * inode = mapping->host; diff -urN linux-2.4.27/mm/highmem.c linux-2.4.28/mm/highmem.c --- linux-2.4.27/mm/highmem.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.28/mm/highmem.c 2004-11-17 03:54:22.101418575 -0800 @@ -129,7 +129,7 @@ return vaddr; } -void *kmap_high(struct page *page, int nonblocking) +void fastcall *kmap_high(struct page *page, int nonblocking) { unsigned long vaddr; @@ -154,7 +154,7 @@ return (void*) vaddr; } -void kunmap_high(struct page *page) +void fastcall kunmap_high(struct page *page) { unsigned long vaddr; unsigned long nr; diff -urN linux-2.4.27/mm/memory.c linux-2.4.28/mm/memory.c --- linux-2.4.27/mm/memory.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/mm/memory.c 2004-11-17 03:54:22.102418616 -0800 @@ -1396,7 +1396,7 @@ * On a two-level page table, this ends up actually being entirely * optimized away. */ -pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) +pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) { pmd_t *new; @@ -1430,7 +1430,7 @@ * We've already handled the fast-path in-line, and we own the * page table lock. */ -pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +pte_t fastcall *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) { if (pmd_none(*pmd)) { pte_t *new; diff -urN linux-2.4.27/mm/oom_kill.c linux-2.4.28/mm/oom_kill.c --- linux-2.4.27/mm/oom_kill.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/mm/oom_kill.c 2004-11-17 03:54:22.103418657 -0800 @@ -141,7 +141,7 @@ * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that * we select a process with CAP_SYS_RAW_IO set). */ -void oom_kill_task(struct task_struct *p) +static void __oom_kill_task(struct task_struct *p) { printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm); @@ -161,6 +161,26 @@ } } +static struct mm_struct *oom_kill_task(struct task_struct *p) +{ + struct mm_struct *mm; + + task_lock(p); + mm = p->mm; + if (mm) { + spin_lock(&mmlist_lock); + if (atomic_read(&mm->mm_users)) + atomic_inc(&mm->mm_users); + else + mm = NULL; + spin_unlock(&mmlist_lock); + } + task_unlock(p); + if (mm) + __oom_kill_task(p); + return mm; +} + /** * oom_kill - kill the "best" process when we run out of memory * @@ -172,21 +192,27 @@ static void oom_kill(void) { struct task_struct *p, *q; + struct mm_struct *mm; +retry: read_lock(&tasklist_lock); p = select_bad_process(); /* Found nothing?!?! Either we hang forever, or we panic. */ if (p == NULL) panic("Out of memory and no killable processes...\n"); - + mm = oom_kill_task(p); + if (!mm) { + read_unlock(&tasklist_lock); + goto retry; + } /* kill all processes that share the ->mm (i.e. all threads) */ for_each_task(q) { - if (q->mm == p->mm) - oom_kill_task(q); + if (q->mm == mm) + __oom_kill_task(q); } read_unlock(&tasklist_lock); - + mmput(mm); /* * Make kswapd go out of the way, so "p" has a good chance of * killing itself before someone else gets the chance to ask @@ -263,7 +289,7 @@ spin_lock(&oom_lock); reset: - if (first < now) + if ((long)first - (long)now < 0) first = now; count = 0; diff -urN linux-2.4.27/mm/page_alloc.c linux-2.4.28/mm/page_alloc.c --- linux-2.4.27/mm/page_alloc.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/mm/page_alloc.c 2004-11-17 03:54:22.104418699 -0800 @@ -109,7 +109,7 @@ * -- wli */ -static void __free_pages_ok (struct page *page, unsigned int order) +static void fastcall __free_pages_ok (struct page *page, unsigned int order) { unsigned long index, page_idx, mask, flags; free_area_t *area; @@ -239,7 +239,7 @@ } static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order)); -static struct page * rmqueue(zone_t *zone, unsigned int order) +static struct page * fastcall rmqueue(zone_t *zone, unsigned int order) { free_area_t * area = zone->free_area + order; unsigned int curr_order = order; @@ -285,7 +285,7 @@ } #ifndef CONFIG_DISCONTIGMEM -struct page *_alloc_pages(unsigned int gfp_mask, unsigned int order) +struct page * fastcall _alloc_pages(unsigned int gfp_mask, unsigned int order) { return __alloc_pages(gfp_mask, order, contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK)); @@ -293,7 +293,7 @@ #endif static struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *)); -static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed) +static struct page * fastcall balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed) { struct page * page = NULL; int __freed; @@ -371,7 +371,7 @@ /* * This is the 'heart' of the zoned buddy allocator: */ -struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist) +struct page * fastcall __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist) { zone_t **zone, * classzone; struct page * page; @@ -484,7 +484,7 @@ /* * Common helper functions. */ -unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order) +fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order) { struct page * page; @@ -494,7 +494,7 @@ return (unsigned long) page_address(page); } -unsigned long get_zeroed_page(unsigned int gfp_mask) +fastcall unsigned long get_zeroed_page(unsigned int gfp_mask) { struct page * page; @@ -507,13 +507,13 @@ return 0; } -void __free_pages(struct page *page, unsigned int order) +fastcall void __free_pages(struct page *page, unsigned int order) { if (!PageReserved(page) && put_page_testzero(page)) __free_pages_ok(page, order); } -void free_pages(unsigned long addr, unsigned int order) +fastcall void free_pages(unsigned long addr, unsigned int order) { if (addr != 0) __free_pages(virt_to_page(addr), order); diff -urN linux-2.4.27/mm/shmem.c linux-2.4.28/mm/shmem.c --- linux-2.4.27/mm/shmem.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/mm/shmem.c 2004-11-17 03:54:22.105418740 -0800 @@ -973,7 +973,7 @@ struct inode *inode = file->f_dentry->d_inode; loff_t pos; unsigned long written; - int err; + ssize_t err; if ((ssize_t) count < 0) return -EINVAL; @@ -1174,13 +1174,27 @@ } /* + * Retaining negative dentries for an in-memory filesystem just wastes + * memory and lookup time: arrange for them to be deleted immediately. + */ +static int shmem_delete_dentry(struct dentry *dentry) +{ + return 1; +} + +/* * Lookup the data. This is trivial - if the dentry didn't already - * exist, we know it is negative. + * exist, we know it is negative. Set d_op to delete negative dentries. */ static struct dentry *shmem_lookup(struct inode *dir, struct dentry *dentry) { + static struct dentry_operations shmem_dentry_operations = { + .d_delete = shmem_delete_dentry, + }; + if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); + dentry->d_op = &shmem_dentry_operations; d_add(dentry, NULL); return NULL; } diff -urN linux-2.4.27/mm/slab.c linux-2.4.28/mm/slab.c --- linux-2.4.27/mm/slab.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/mm/slab.c 2004-11-17 03:54:22.106418781 -0800 @@ -1735,7 +1735,7 @@ * * Called from do_try_to_free_pages() and __alloc_pages() */ -int kmem_cache_reap (int gfp_mask) +int fastcall kmem_cache_reap (int gfp_mask) { slab_t *slabp; kmem_cache_t *searchp; diff -urN linux-2.4.27/mm/swap.c linux-2.4.28/mm/swap.c --- linux-2.4.27/mm/swap.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/mm/swap.c 2004-11-17 03:54:22.107418822 -0800 @@ -44,7 +44,7 @@ } } -void activate_page(struct page * page) +void fastcall activate_page(struct page * page) { spin_lock(&pagemap_lru_lock); activate_page_nolock(page); @@ -55,7 +55,7 @@ * lru_cache_add: add a page to the page lists * @page: the page to add */ -void lru_cache_add(struct page * page) +void fastcall lru_cache_add(struct page * page) { if (!PageLRU(page)) { spin_lock(&pagemap_lru_lock); @@ -72,7 +72,7 @@ * This function is for when the caller already holds * the pagemap_lru_lock. */ -void __lru_cache_del(struct page * page) +void fastcall __lru_cache_del(struct page * page) { if (TestClearPageLRU(page)) { if (PageActive(page)) { @@ -87,7 +87,7 @@ * lru_cache_del: remove a page from the page lists * @page: the page to remove */ -void lru_cache_del(struct page * page) +void fastcall lru_cache_del(struct page * page) { spin_lock(&pagemap_lru_lock); __lru_cache_del(page); diff -urN linux-2.4.27/mm/swapfile.c linux-2.4.28/mm/swapfile.c --- linux-2.4.27/mm/swapfile.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/mm/swapfile.c 2004-11-17 03:54:22.108418863 -0800 @@ -256,7 +256,7 @@ * work, but we opportunistically check whether * we need to get all the locks first.. */ -int can_share_swap_page(struct page *page) +int fastcall can_share_swap_page(struct page *page) { int retval = 0; @@ -284,7 +284,7 @@ * Work out if there are any other processes sharing this * swap cache page. Free it if you can. Return success. */ -int remove_exclusive_swap_page(struct page *page) +int fastcall remove_exclusive_swap_page(struct page *page) { int retval; struct swap_info_struct * p; diff -urN linux-2.4.27/mm/vmscan.c linux-2.4.28/mm/vmscan.c --- linux-2.4.27/mm/vmscan.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/mm/vmscan.c 2004-11-17 03:54:22.109418904 -0800 @@ -323,7 +323,7 @@ } static int FASTCALL(swap_out(zone_t * classzone)); -static int swap_out(zone_t * classzone) +static int fastcall swap_out(zone_t * classzone) { int counter, nr_pages = SWAP_CLUSTER_MAX; struct mm_struct *mm; @@ -366,7 +366,7 @@ static void FASTCALL(refill_inactive(int nr_pages, zone_t * classzone)); static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout)); -static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout) +static int fastcall shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout) { struct list_head * entry; int max_scan = (classzone->nr_inactive_pages + classzone->nr_active_pages) / vm_cache_scan_ratio; @@ -577,7 +577,7 @@ * We move them the other way when we see the * reference bit on the page. */ -static void refill_inactive(int nr_pages, zone_t * classzone) +static void fastcall refill_inactive(int nr_pages, zone_t * classzone) { struct list_head * entry; unsigned long ratio; @@ -610,7 +610,7 @@ } static int FASTCALL(shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout)); -static int shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout) +static int fastcall shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout) { nr_pages -= kmem_cache_reap(gfp_mask); if (nr_pages <= 0) @@ -627,7 +627,7 @@ static int check_classzone_need_balance(zone_t * classzone); -int try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask) +int fastcall try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask) { gfp_mask = pf_gfp_mask(gfp_mask); @@ -665,7 +665,7 @@ return 0; } -int try_to_free_pages(unsigned int gfp_mask) +int fastcall try_to_free_pages(unsigned int gfp_mask) { pg_data_t *pgdat; zonelist_t *zonelist; diff -urN linux-2.4.27/net/appletalk/ddp.c linux-2.4.28/net/appletalk/ddp.c --- linux-2.4.27/net/appletalk/ddp.c 2001-09-10 07:57:00.000000000 -0700 +++ linux-2.4.28/net/appletalk/ddp.c 2004-11-17 03:54:22.110418945 -0800 @@ -106,8 +106,8 @@ #endif /* APPLETALK_DEBUG */ #ifdef CONFIG_SYSCTL -extern inline void atalk_register_sysctl(void); -extern inline void atalk_unregister_sysctl(void); +extern void atalk_register_sysctl(void); +extern void atalk_unregister_sysctl(void); #endif /* CONFIG_SYSCTL */ struct datalink_proto *ddp_dl, *aarp_dl; diff -urN linux-2.4.27/net/atm/clip.c linux-2.4.28/net/atm/clip.c --- linux-2.4.27/net/atm/clip.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/atm/clip.c 2004-11-17 03:54:22.111418986 -0800 @@ -1,6 +1,10 @@ /* net/atm/clip.c - RFC1577 Classical IP over ATM */ -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA + * + * Changes: + * Harald Welte : + * - backport DaveM's generalized neighbour cache from 2.6.9-rcX */ #include @@ -24,6 +28,7 @@ #include /* for IFF_UP */ #include #include +#include #include /* for struct rtable and routing */ #include /* icmp_send */ #include /* for HZ */ @@ -119,64 +124,49 @@ spin_unlock_bh(&entry->neigh->dev->xmit_lock); } - -static void idle_timer_check(unsigned long dummy) +/* The neighbour entry n->lock is held. */ +static int neigh_check_cb(struct neighbour *n) { - int i; + struct atmarp_entry *entry = NEIGH2ENTRY(n); + struct clip_vcc *cv; - /*DPRINTK("idle_timer_check\n");*/ - write_lock(&clip_tbl.lock); - for (i = 0; i <= NEIGH_HASHMASK; i++) { - struct neighbour **np; + for (cv = entry->vccs; cv; cv = cv->next) { + unsigned long exp = cv->last_use + cv->idle_timeout; - for (np = &clip_tbl.hash_buckets[i]; *np;) { - struct neighbour *n = *np; - struct atmarp_entry *entry = NEIGH2ENTRY(n); - struct clip_vcc *clip_vcc; - - write_lock(&n->lock); - - for (clip_vcc = entry->vccs; clip_vcc; - clip_vcc = clip_vcc->next) - if (clip_vcc->idle_timeout && - time_after(jiffies, clip_vcc->last_use+ - clip_vcc->idle_timeout)) { - DPRINTK("releasing vcc %p->%p of " - "entry %p\n",clip_vcc,clip_vcc->vcc, - entry); - vcc_release_async(clip_vcc->vcc, - -ETIMEDOUT); - } - if (entry->vccs || - time_before(jiffies, entry->expires)) { - np = &n->next; - write_unlock(&n->lock); - continue; - } - if (atomic_read(&n->refcnt) > 1) { - struct sk_buff *skb; - - DPRINTK("destruction postponed with ref %d\n", - atomic_read(&n->refcnt)); - while ((skb = skb_dequeue(&n->arp_queue)) != - NULL) - dev_kfree_skb(skb); - np = &n->next; - write_unlock(&n->lock); - continue; - } - *np = n->next; - DPRINTK("expired neigh %p\n",n); - n->dead = 1; - write_unlock(&n->lock); - neigh_release(n); + if (cv->idle_timeout && time_after(jiffies, exp)) { + DPRINTK("releasing vcc %p->%p of entry %p\n", + cv, cv->vcc, entry); + vcc_release_async(cv->vcc, -ETIMEDOUT); } } + + if (entry->vccs || time_before(jiffies, entry->expires)) + return 0; + + if (atomic_read(&n->refcnt) > 1) { + struct sk_buff *skb; + + DPRINTK("destruction postponed with ref %d\n", + atomic_read(&n->refcnt)); + + while ((skb = skb_dequeue(&n->arp_queue)) != NULL) + dev_kfree_skb(skb); + + return 0; + } + + DPRINTK("expired neigh %p\n",n); + return 1; +} + +static void idle_timer_check(unsigned long dummy) +{ + write_lock(&clip_tbl.lock); + __neigh_for_each_release(&clip_tbl, neigh_check_cb); mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ); write_unlock(&clip_tbl.lock); } - static int clip_arp_rcv(struct sk_buff *skb) { struct atm_vcc *vcc; @@ -320,15 +310,7 @@ static u32 clip_hash(const void *pkey, const struct net_device *dev) { - u32 hash_val; - - hash_val = *(u32*)pkey; - hash_val ^= (hash_val>>16); - hash_val ^= hash_val>>8; - hash_val ^= hash_val>>3; - hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; - - return hash_val; + return jhash_2words(*(u32 *)pkey, dev->ifindex, clip_tbl.hash_rnd); } @@ -768,19 +750,7 @@ static int __init atm_clip_init(void) { - /* we should use neigh_table_init() */ - clip_tbl.lock = RW_LOCK_UNLOCKED; - clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id, - clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - - if (!clip_tbl.kmem_cachep) - return -ENOMEM; - - /* so neigh_ifdown() doesn't complain */ - clip_tbl.proxy_timer.data = 0; - clip_tbl.proxy_timer.function = 0; - init_timer(&clip_tbl.proxy_timer); - skb_queue_head_init(&clip_tbl.proxy_queue); + neigh_table_init(&clip_tbl); clip_tbl_hook = &clip_tbl; atm_clip_ops_set(&__atm_clip_ops); @@ -794,7 +764,18 @@ atm_clip_ops_set(NULL); + /* First, stop the idle timer, so it stops banging + * on the table. + */ + if (start_timer == 0) + del_timer(&idle_timer); + + /* Next, purge the table, so that the device + * unregister loop below does not hang due to + * device references remaining in the table. + */ neigh_ifdown(&clip_tbl, NULL); + dev = clip_devs; while (dev) { next = PRIV(dev)->next; @@ -802,9 +783,9 @@ kfree(dev); dev = next; } - if (start_timer == 0) del_timer(&idle_timer); - kmem_cache_destroy(clip_tbl.kmem_cachep); + /* Now it is safe to fully shutdown whole table. */ + neigh_table_clear(&clip_tbl); clip_tbl_hook = NULL; } diff -urN linux-2.4.27/net/atm/lec.c linux-2.4.28/net/atm/lec.c --- linux-2.4.27/net/atm/lec.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/atm/lec.c 2004-11-17 03:54:22.113419069 -0800 @@ -71,9 +71,9 @@ static int lec_close(struct net_device *dev); static struct net_device_stats *lec_get_stats(struct net_device *dev); static void lec_init(struct net_device *dev); -static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv, +static struct lec_arp_table* lec_arp_find(struct lec_priv *priv, unsigned char *mac_addr); -static inline int lec_arp_remove(struct lec_priv *priv, +static int lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove); /* LANE2 functions */ static void lane2_associate_ind (struct net_device *dev, u8 *mac_address, @@ -1137,7 +1137,7 @@ /* * Remove entry from lec_arp_table */ -static inline int +static int lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) { @@ -1424,7 +1424,7 @@ /* * Find entry by mac_address */ -static inline struct lec_arp_table* +static struct lec_arp_table* lec_arp_find(struct lec_priv *priv, unsigned char *mac_addr) { diff -urN linux-2.4.27/net/atm/proc.c linux-2.4.28/net/atm/proc.c --- linux-2.4.27/net/atm/proc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/atm/proc.c 2004-11-17 03:54:22.114419110 -0800 @@ -90,74 +90,202 @@ #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) +#define SEQ_NO_VCC_TOKEN ((void *) 2) -static int svc_addr(char *buf,struct sockaddr_atmsvc *addr) +static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr) { static int code[] = { 1,2,10,6,1,0 }; static int e164[] = { 1,8,4,6,1,0 }; - int *fields; - int len,i,j,pos; - len = 0; if (*addr->sas_addr.pub) { - strcpy(buf,addr->sas_addr.pub); - len = strlen(addr->sas_addr.pub); - buf += len; - if (*addr->sas_addr.prv) { - *buf++ = '+'; - len++; - } + seq_printf(seq, "%s", addr->sas_addr.pub); + if (*addr->sas_addr.prv) + seq_putc(seq, '+'); + } else if (!*addr->sas_addr.prv) { + seq_printf(seq, "%s", "(none)"); + return; } - else if (!*addr->sas_addr.prv) { - strcpy(buf,"(none)"); - return strlen(buf); - } if (*addr->sas_addr.prv) { - len += 44; - pos = 0; - fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code; + unsigned char *prv = addr->sas_addr.prv; + int *fields; + int i, j; + + fields = *prv == ATM_AFI_E164 ? e164 : code; for (i = 0; fields[i]; i++) { - for (j = fields[i]; j; j--) { - sprintf(buf,"%02X",addr->sas_addr.prv[pos++]); - buf += 2; - } - if (fields[i+1]) *buf++ = '.'; + for (j = fields[i]; j; j--) + seq_printf(seq, "%02X", *prv++); + if (fields[i+1]) + seq_putc(seq, '.'); } } - return len; } -static void atmarp_info(struct net_device *dev,struct atmarp_entry *entry, - struct clip_vcc *clip_vcc,char *buf) -{ - unsigned char *ip; - int svc,off,ip_len; - - svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC; - off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC", - !clip_vcc || clip_vcc->encap ? "LLC" : "NULL", - (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/ - HZ); - ip = (unsigned char *) &entry->ip; - ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); - off += ip_len; - while (ip_len++ < 16) buf[off++] = ' '; - if (!clip_vcc) +static void atmarp_info(struct seq_file *seq, struct net_device *dev,struct + atmarp_entry *entry, struct clip_vcc *clip_vcc) { + unsigned long exp; + char buf[17]; + int svc, llc, off; + + svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || + (clip_vcc->vcc->sk->family == AF_ATMSVC)); + + llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || + (clip_vcc->encap)); + + if (clip_vcc == SEQ_NO_VCC_TOKEN) + exp = entry->neigh->used; + else + exp = clip_vcc->last_use; + + exp = (jiffies - exp) / HZ; + + seq_printf(seq, "%-6s%-4s%-4s%5ld ", + dev->name, + svc ? "SVC" : "PVC", + llc ? "LLC" : "NULL", + exp); + + off = snprintf(buf, sizeof(buf)-1, "%d.%d.%d.%d", NIPQUAD(entry->ip)); + while (off < 16) + buf[off++] = ' '; + buf[off] = '\0'; + seq_printf(seq, "%s", buf); + + if (clip_vcc == SEQ_NO_VCC_TOKEN) { if (time_before(jiffies, entry->expires)) - strcpy(buf+off,"(resolving)\n"); - else sprintf(buf+off,"(expired, ref %d)\n", - atomic_read(&entry->neigh->refcnt)); - else if (!svc) - sprintf(buf+off,"%d.%d.%d\n",clip_vcc->vcc->dev->number, - clip_vcc->vcc->vpi,clip_vcc->vcc->vci); - else { - off += svc_addr(buf+off,&clip_vcc->vcc->remote); - strcpy(buf+off,"\n"); + seq_printf(seq, "(resolving)\n"); + else + seq_printf(seq, "(expired, ref %d)\n", + atomic_read(&entry->neigh->refcnt)); + } else if (!svc) { + seq_printf(seq, "%d.%d.%d\n", + clip_vcc->vcc->dev->number, + clip_vcc->vcc->vpi, + clip_vcc->vcc->vci); + } else { + svc_addr(seq, &clip_vcc->vcc->remote); + seq_putc(seq, '\n'); + } +} + +struct clip_seq_state { + /* This member must be first. */ + struct neigh_seq_state ns; + + /* Local to clip specific iteration. */ + struct clip_vcc *vcc; +}; + +static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e, + struct clip_vcc *curr) +{ + if (!curr) { + curr = e->vccs; + if (!curr) + return SEQ_NO_VCC_TOKEN; + return curr; + } + + if (curr == SEQ_NO_VCC_TOKEN) + return NULL; + + curr = curr->next; + + return curr; +} + +static void *clip_seq_vcc_walk(struct clip_seq_state *state, + struct atmarp_entry *e, loff_t *pos) +{ + struct clip_vcc *vcc = state->vcc; + + vcc = clip_seq_next_vcc(e, vcc); + if (vcc && pos != NULL) { + while (*pos) { + vcc = clip_seq_next_vcc(e, vcc); + if (!vcc) + break; + --(*pos); } + } + state->vcc = vcc; + + return vcc; +} + +static void *clip_seq_sub_iter(struct neigh_seq_state *_state, + struct neighbour *n, loff_t *pos) +{ + struct clip_seq_state *state = (struct clip_seq_state *) _state; + + return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos); } +static void *clip_seq_start(struct seq_file *seq, loff_t *pos) +{ + return neigh_seq_start(seq, pos, clip_tbl_hook, NEIGH_SEQ_NEIGH_ONLY); +} +static int clip_seq_show(struct seq_file *seq, void *v) +{ + static char atm_arp_banner[] = + "IPitf TypeEncp Idle IP address ATM address\n"; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, atm_arp_banner); + } else { + struct clip_seq_state *state = seq->private; + struct neighbour *n = v; + struct clip_vcc *vcc = state->vcc; + + atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc); + } + return 0; +} + +static struct seq_operations arp_seq_ops = { + .start = clip_seq_start, + .next = neigh_seq_next, + .stop = neigh_seq_stop, + .show = clip_seq_show, +}; + +static int arp_seq_open(struct inode *inode, struct file *file) +{ + struct clip_seq_state *state; + struct seq_file *seq; + int rc = -EAGAIN; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) { + rc = -ENOMEM; + goto out_kfree; + } + memset(state, 0, sizeof(*state)); + state->ns.neigh_sub_iter = clip_seq_sub_iter; + + rc = seq_open(file, &arp_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; + seq->private = state; +out: + return rc; + +out_kfree: + kfree(state); + goto out; +} + +static struct file_operations arp_seq_fops = { + .open = arp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, + .owner = THIS_MODULE, +}; #endif @@ -416,50 +544,6 @@ return 0; } -#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) -static int atm_arp_info(loff_t pos,char *buf) -{ - struct neighbour *n; - int i,count; - - if (!pos) { - return sprintf(buf,"IPitf TypeEncp Idle IP address " - "ATM address\n"); - } - if (!try_atm_clip_ops()) - return 0; - count = pos; - read_lock_bh(&clip_tbl_hook->lock); - for (i = 0; i <= NEIGH_HASHMASK; i++) - for (n = clip_tbl_hook->hash_buckets[i]; n; n = n->next) { - struct atmarp_entry *entry = NEIGH2ENTRY(n); - struct clip_vcc *vcc; - - if (!entry->vccs) { - if (--count) continue; - atmarp_info(n->dev,entry,NULL,buf); - read_unlock_bh(&clip_tbl_hook->lock); - if (atm_clip_ops->owner) - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); - return strlen(buf); - } - for (vcc = entry->vccs; vcc; - vcc = vcc->next) { - if (--count) continue; - atmarp_info(n->dev,entry,vcc,buf); - read_unlock_bh(&clip_tbl_hook->lock); - if (atm_clip_ops->owner) - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); - return strlen(buf); - } - } - read_unlock_bh(&clip_tbl_hook->lock); - if (atm_clip_ops->owner) - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); - return 0; -} -#endif - #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) static int atm_lec_info(loff_t pos,char *buf) { @@ -666,7 +750,10 @@ CREATE_ENTRY(svc); CREATE_ENTRY(vc); #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) - CREATE_ENTRY(arp); + arp = create_proc_entry("arp", S_IRUGO, atm_proc_root); + if (!arp) + goto cleanup; + arp->proc_fops = &arp_seq_fops; #endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) CREATE_ENTRY(lec); diff -urN linux-2.4.27/net/bluetooth/l2cap.c linux-2.4.28/net/bluetooth/l2cap.c --- linux-2.4.27/net/bluetooth/l2cap.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/bluetooth/l2cap.c 2004-11-17 03:54:22.116419192 -0800 @@ -70,7 +70,7 @@ static int l2cap_conn_del(struct hci_conn *conn, int err); -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); static void l2cap_chan_del(struct sock *sk, int err); static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); @@ -420,6 +420,14 @@ return err; } +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + write_lock(&l->lock); + __l2cap_chan_add(conn, sk, parent); + write_unlock(&l->lock); +} + static int l2cap_do_connect(struct sock *sk) { bdaddr_t *src = &bluez_pi(sk)->src; @@ -897,14 +905,6 @@ bluez_accept_enqueue(parent, sk); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) -{ - struct l2cap_chan_list *l = &conn->chan_list; - write_lock(&l->lock); - __l2cap_chan_add(conn, sk, parent); - write_unlock(&l->lock); -} - /* Delete channel. * Must be called on the locked socket. */ static void l2cap_chan_del(struct sock *sk, int err) diff -urN linux-2.4.27/net/bluetooth/rfcomm/core.c linux-2.4.28/net/bluetooth/rfcomm/core.c --- linux-2.4.27/net/bluetooth/rfcomm/core.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/bluetooth/rfcomm/core.c 2004-11-17 03:54:22.117419233 -0800 @@ -406,7 +406,7 @@ return len; } -void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) +void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); @@ -417,7 +417,7 @@ rfcomm_schedule(RFCOMM_SCHED_TX); } -void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff -urN linux-2.4.27/net/bluetooth/sco.c linux-2.4.28/net/bluetooth/sco.c --- linux-2.4.27/net/bluetooth/sco.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/bluetooth/sco.c 2004-11-17 03:54:22.118419274 -0800 @@ -67,9 +67,8 @@ lock: RW_LOCK_UNLOCKED }; -static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); +static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -static inline struct sock * sco_chan_get(struct sco_conn *conn); static int sco_conn_del(struct hci_conn *conn, int err); @@ -150,6 +149,15 @@ return conn; } +static inline struct sock * sco_chan_get(struct sco_conn *conn) +{ + struct sock *sk = NULL; + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); + return sk; +} + static int sco_conn_del(struct hci_conn *hcon, int err) { struct sco_conn *conn; @@ -176,6 +184,20 @@ return 0; } +static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + int err = 0; + + sco_conn_lock(conn); + if (conn->sk) { + err = -EBUSY; + } else { + __sco_chan_add(conn, sk, parent); + } + sco_conn_unlock(conn); + return err; +} + int sco_connect(struct sock *sk) { bdaddr_t *src = &bluez_pi(sk)->src; @@ -743,29 +765,6 @@ bluez_accept_enqueue(parent, sk); } -static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) -{ - int err = 0; - - sco_conn_lock(conn); - if (conn->sk) { - err = -EBUSY; - } else { - __sco_chan_add(conn, sk, parent); - } - sco_conn_unlock(conn); - return err; -} - -static inline struct sock * sco_chan_get(struct sco_conn *conn) -{ - struct sock *sk = NULL; - sco_conn_lock(conn); - sk = conn->sk; - sco_conn_unlock(conn); - return sk; -} - /* Delete channel. * Must be called on the locked socket. */ static void sco_chan_del(struct sock *sk, int err) diff -urN linux-2.4.27/net/core/Makefile linux-2.4.28/net/core/Makefile --- linux-2.4.27/net/core/Makefile 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/core/Makefile 2004-11-17 03:54:22.118419274 -0800 @@ -9,7 +9,7 @@ O_TARGET := core.o -export-objs := netfilter.o profile.o ethtool.o +export-objs := netfilter.o profile.o ethtool.o neighbour.o obj-y := sock.o skbuff.o iovec.o datagram.o scm.o diff -urN linux-2.4.27/net/core/neighbour.c linux-2.4.28/net/core/neighbour.c --- linux-2.4.27/net/core/neighbour.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/core/neighbour.c 2004-11-17 03:54:22.121419398 -0800 @@ -2,7 +2,7 @@ * Generic address resolution entity * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * This program is free software; you can redistribute it and/or @@ -12,14 +12,18 @@ * * Fixes: * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. + * Harald Welte Add neighbour cache statistics like rtstat + * Harald Welte port neighbour cache rework from 2.6.9-rcX */ #include #include #include +#include #include #include #include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -27,6 +31,8 @@ #include #include #include +#include +#include #define NEIGH_DEBUG 1 @@ -45,6 +51,8 @@ #define NEIGH_PRINTK2 NEIGH_PRINTK #endif +#define PNEIGH_HASHMASK 0xF + static void neigh_timer_handler(unsigned long arg); #ifdef CONFIG_ARPD static void neigh_app_notify(struct neighbour *n); @@ -54,6 +62,7 @@ static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; +static struct file_operations neigh_stat_seq_fops; /* Neighbour hash table buckets are protected with rwlock tbl->lock. @@ -111,27 +120,21 @@ int shrunk = 0; int i; - for (i=0; i<=NEIGH_HASHMASK; i++) { + NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); + + write_lock_bh(&tbl->lock); + for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; np = &tbl->hash_buckets[i]; - write_lock_bh(&tbl->lock); while ((n = *np) != NULL) { /* Neighbour record may be discarded if: - - nobody refers to it. - - it is not permanent - - (NEW and probably wrong) - INCOMPLETE entries are kept at least for - n->parms->retrans_time, otherwise we could - flood network with resolution requests. - It is not clear, what is better table overflow - or flooding. + * - nobody refers to it. + * - it is not permanent */ write_lock(&n->lock); if (atomic_read(&n->refcnt) == 1 && - !(n->nud_state&NUD_PERMANENT) && - (n->nud_state != NUD_INCOMPLETE || - jiffies - n->used > n->parms->retrans_time)) { + !(n->nud_state&NUD_PERMANENT)) { *np = n->next; n->dead = 1; shrunk = 1; @@ -142,10 +145,12 @@ write_unlock(&n->lock); np = &n->next; } - write_unlock_bh(&tbl->lock); } tbl->last_flush = jiffies; + + write_unlock_bh(&tbl->lock); + return shrunk; } @@ -176,7 +181,7 @@ write_lock_bh(&tbl->lock); - for (i=0; i <= NEIGH_HASHMASK; i++) { + for (i=0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; np = &tbl->hash_buckets[i]; @@ -203,7 +208,7 @@ write_lock_bh(&tbl->lock); - for (i=0; i<=NEIGH_HASHMASK; i++) { + for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; np = &tbl->hash_buckets[i]; @@ -254,11 +259,11 @@ struct neighbour *n; unsigned long now = jiffies; - if (tbl->entries > tbl->gc_thresh3 || - (tbl->entries > tbl->gc_thresh2 && + if (atomic_read(&tbl->entries) > tbl->gc_thresh3 || + (atomic_read(&tbl->entries) > tbl->gc_thresh2 && now - tbl->last_flush > 5*HZ)) { if (neigh_forced_gc(tbl) == 0 && - tbl->entries > tbl->gc_thresh3) + atomic_read(&tbl->entries) > tbl->gc_thresh3) return NULL; } @@ -277,29 +282,113 @@ init_timer(&n->timer); n->timer.function = neigh_timer_handler; n->timer.data = (unsigned long)n; - tbl->stats.allocs++; + NEIGH_CACHE_STAT_INC(tbl, allocs); neigh_glbl_allocs++; - tbl->entries++; + atomic_inc(&tbl->entries); n->tbl = tbl; atomic_set(&n->refcnt, 1); n->dead = 1; return n; } +static struct neighbour **neigh_hash_alloc(unsigned int entries) +{ + unsigned long size = entries * sizeof(struct neighbour *); + struct neighbour **ret; + + if (size <= PAGE_SIZE) { + ret = kmalloc(size, GFP_ATOMIC); + } else { + ret = (struct neighbour **) + __get_free_pages(GFP_ATOMIC, get_order(size)); + } + if (ret) + memset(ret, 0, size); + + return ret; +} + +static void neigh_hash_free(struct neighbour **hash, unsigned int entries) +{ + unsigned long size = entries * sizeof(struct neighbour *); + + if (size <= PAGE_SIZE) + kfree(hash); + else + free_pages((unsigned long)hash, get_order(size)); +} + +static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries) +{ + struct neighbour **new_hash, **old_hash; + unsigned int i, new_hash_mask, old_entries; + + NEIGH_CACHE_STAT_INC(tbl, hash_grows); + + BUG_ON(new_entries & (new_entries - 1)); + new_hash = neigh_hash_alloc(new_entries); + if (!new_hash) + return; + + old_entries = tbl->hash_mask + 1; + new_hash_mask = new_entries - 1; + old_hash = tbl->hash_buckets; + + get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); + for (i = 0; i < old_entries; i++) { + struct neighbour *n, *next; + + for (n = old_hash[i]; n; n = next) { + unsigned int hash_val = tbl->hash(n->primary_key, n->dev); + + hash_val &= new_hash_mask; + next = n->next; + + n->next = new_hash[hash_val]; + new_hash[hash_val] = n; + } + } + tbl->hash_buckets = new_hash; + tbl->hash_mask = new_hash_mask; + + neigh_hash_free(old_hash, old_entries); +} + struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev) { struct neighbour *n; - u32 hash_val; int key_len = tbl->key_len; + u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; - hash_val = tbl->hash(pkey, dev); + NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (dev == n->dev && memcmp(n->primary_key, pkey, key_len) == 0) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); + break; + } + } + read_unlock_bh(&tbl->lock); + return n; +} + +struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey) +{ + struct neighbour *n; + int key_len = tbl->key_len; + u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; + + NEIGH_CACHE_STAT_INC(tbl, lookups); + + read_lock_bh(&tbl->lock); + for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { + if (!memcmp(n->primary_key, pkey, key_len)) { + neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -338,9 +427,11 @@ n->confirmed = jiffies - (n->parms->base_reachable_time<<1); - hash_val = tbl->hash(pkey, dev); + hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; write_lock_bh(&tbl->lock); + if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1)) + neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1); for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) { if (dev == n1->dev && memcmp(n1->primary_key, pkey, key_len) == 0) { @@ -418,9 +509,9 @@ hash_val ^= hash_val>>4; hash_val &= PNEIGH_HASHMASK; + write_lock_bh(&tbl->lock); for (np = &tbl->phash_buckets[hash_val]; (n=*np) != NULL; np = &n->next) { if (memcmp(n->key, pkey, key_len) == 0 && n->dev == dev) { - write_lock_bh(&tbl->lock); *np = n->next; write_unlock_bh(&tbl->lock); if (tbl->pdestructor) @@ -429,6 +520,7 @@ return 0; } } + write_unlock_bh(&tbl->lock); return -ENOENT; } @@ -462,6 +554,8 @@ { struct hh_cache *hh; + NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); + if (!neigh->dead) { printk("Destroying alive neighbour %p\n", neigh); dump_stack(); @@ -491,7 +585,7 @@ NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); neigh_glbl_allocs--; - neigh->tbl->entries--; + atomic_dec(&neigh->tbl->entries); kmem_cache_free(neigh->tbl->kmem_cachep, neigh); } @@ -566,9 +660,10 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg) { struct neigh_table *tbl = (struct neigh_table*)arg; - unsigned long now = jiffies; - int i; + struct neighbour *n, **np; + unsigned long expire, now = jiffies; + NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); write_lock(&tbl->lock); @@ -583,46 +678,49 @@ p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); } - for (i=0; i <= NEIGH_HASHMASK; i++) { - struct neighbour *n, **np; + np = &tbl->hash_buckets[tbl->hash_chain_gc]; + tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask); - np = &tbl->hash_buckets[i]; - while ((n = *np) != NULL) { - unsigned state; - - write_lock(&n->lock); - - state = n->nud_state; - if (state&(NUD_PERMANENT|NUD_IN_TIMER)) { - write_unlock(&n->lock); - goto next_elt; - } + while ((n = *np) != NULL) { + unsigned int state; - if ((long)(n->used - n->confirmed) < 0) - n->used = n->confirmed; + write_lock(&n->lock); + + state = n->nud_state; + if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { + write_unlock(&n->lock); + goto next_elt; + } - if (atomic_read(&n->refcnt) == 1 && - (state == NUD_FAILED || now - n->used > n->parms->gc_staletime)) { - *np = n->next; - n->dead = 1; - write_unlock(&n->lock); - neigh_release(n); - continue; - } + if (time_before(n->used, n->confirmed)) + n->used = n->confirmed; - if (n->nud_state&NUD_REACHABLE && - now - n->confirmed > n->parms->reachable_time) { - n->nud_state = NUD_STALE; - neigh_suspect(n); - } + if (atomic_read(&n->refcnt) == 1 && + (state == NUD_FAILED || + time_after(now, n->used + n->parms->gc_staletime))) { + *np = n->next; + n->dead = 1; write_unlock(&n->lock); + neigh_release(n); + continue; + } + write_unlock(&n->lock); next_elt: - np = &n->next; - } + np = &n->next; } + + /* Cycle through all hash buckets every base_reachable_time/2 ticks. + * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 + * base_reachable_time. + */ + expire = tbl->parms.base_reachable_time >> 1; + expire /= (tbl->hash_mask + 1); + if (!expire) + expire = 1; + + mod_timer(&tbl->gc_timer, now + expire); - mod_timer(&tbl->gc_timer, now + tbl->gc_interval); write_unlock(&tbl->lock); } @@ -648,6 +746,7 @@ { unsigned long now = jiffies; struct neighbour *neigh = (struct neighbour*)arg; + struct sk_buff *skb; unsigned state; int notify = 0; @@ -680,7 +779,7 @@ neigh->nud_state = NUD_FAILED; notify = 1; - neigh->tbl->stats.res_failed++; + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); NEIGH_PRINTK2("neigh %p is failed.\n", neigh); /* It is very thin place. report_unreachable is very complicated @@ -699,10 +798,20 @@ neigh->timer.expires = now + neigh->parms->retrans_time; add_timer(&neigh->timer); + + /* keep skb alive even if arp_queue overflows */ + skb = skb_peek(&neigh->arp_queue); + if (skb) + skb_get(skb); + write_unlock(&neigh->lock); - neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue)); + neigh->ops->solicit(neigh, skb); atomic_inc(&neigh->probes); + + if (skb) + kfree_skb(skb); + return; out: @@ -1132,6 +1241,7 @@ void neigh_table_init(struct neigh_table *tbl) { unsigned long now = jiffies; + unsigned long phsize; tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time); @@ -1141,6 +1251,30 @@ 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!tbl->kmem_cachep) + panic("cannot create neighbour cache"); + +#ifdef CONFIG_PROC_FS + tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat); + if (!tbl->pde) + panic("cannot create neighbour proc dir entry"); + tbl->pde->proc_fops = &neigh_stat_seq_fops; + tbl->pde->data = tbl; +#endif + + tbl->hash_mask = 1; + tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); + + phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *); + tbl->phash_buckets = kmalloc(phsize, GFP_KERNEL); + + if (!tbl->hash_buckets || !tbl->phash_buckets) + panic("cannot allocate neighbour cache hashes"); + + memset(tbl->phash_buckets, 0, phsize); + + get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); + #ifdef CONFIG_SMP tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer), (unsigned long)tbl); #endif @@ -1148,7 +1282,7 @@ tbl->lock = RW_LOCK_UNLOCKED; tbl->gc_timer.data = (unsigned long)tbl; tbl->gc_timer.function = neigh_periodic_timer; - tbl->gc_timer.expires = now + tbl->gc_interval + tbl->parms.reachable_time; + tbl->gc_timer.expires = now + 1; add_timer(&tbl->gc_timer); init_timer(&tbl->proxy_timer); @@ -1174,7 +1308,7 @@ del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); neigh_ifdown(tbl, NULL); - if (tbl->entries) + if (atomic_read(&tbl->entries)) printk(KERN_CRIT "neighbour leakage\n"); write_lock(&neigh_tbl_lock); for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { @@ -1184,6 +1318,13 @@ } } write_unlock(&neigh_tbl_lock); + + neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1); + tbl->hash_buckets = NULL; + + kfree(tbl->phash_buckets); + tbl->phash_buckets = NULL; + #ifdef CONFIG_SYSCTL neigh_sysctl_unregister(&tbl->parms); #endif @@ -1364,7 +1505,7 @@ s_h = cb->args[1]; s_idx = idx = cb->args[2]; - for (h=0; h <= NEIGH_HASHMASK; h++) { + for (h=0; h <= tbl->hash_mask; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; @@ -1415,6 +1556,361 @@ return skb->len; } +void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) +{ + int chain; + + read_lock_bh(&tbl->lock); + for (chain = 0; chain <= tbl->hash_mask; chain++) { + struct neighbour *n; + + for (n = tbl->hash_buckets[chain]; n; n = n->next) + cb(n, cookie); + } + read_unlock_bh(&tbl->lock); +} +EXPORT_SYMBOL(neigh_for_each); + +/* The tbl->lock must be held as a writer and BH disabled. */ +void __neigh_for_each_release(struct neigh_table *tbl, + int (*cb)(struct neighbour *)) +{ + int chain; + + for (chain = 0; chain <= tbl->hash_mask; chain++) { + struct neighbour *n, **np; + + np = &tbl->hash_buckets[chain]; + while ((n = *np) != NULL) { + int release; + + write_lock(&n->lock); + release = cb(n); + if (release) { + *np = n->next; + n->dead = 1; + } else + np = &n->next; + write_unlock(&n->lock); + if (release) + neigh_release(n); + } + } +} +EXPORT_SYMBOL(__neigh_for_each_release); + +#ifdef CONFIG_PROC_FS + +static struct neighbour *neigh_get_first(struct seq_file *seq) +{ + struct neigh_seq_state *state = seq->private; + struct neigh_table *tbl = state->tbl; + struct neighbour *n = NULL; + int bucket = state->bucket; + + state->flags &= ~NEIGH_SEQ_IS_PNEIGH; + for (bucket = 0; bucket <= tbl->hash_mask; bucket++) { + n = tbl->hash_buckets[bucket]; + + while (n) { + if (state->neigh_sub_iter) { + loff_t fakep = 0; + void *v; + + v = state->neigh_sub_iter(state, n, &fakep); + if (!v) + goto next; + } + if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) + break; + if (n->nud_state & ~NUD_NOARP) + break; + next: + n = n->next; + } + + if (n) + break; + } + state->bucket = bucket; + + return n; +} + +static struct neighbour *neigh_get_next(struct seq_file *seq, + struct neighbour *n, + loff_t *pos) +{ + struct neigh_seq_state *state = seq->private; + struct neigh_table *tbl = state->tbl; + + if (state->neigh_sub_iter) { + void *v = state->neigh_sub_iter(state, n, pos); + if (v) + return n; + } + n = n->next; + + while (1) { + while (n) { + if (state->neigh_sub_iter) { + void *v = state->neigh_sub_iter(state, n, pos); + if (v) + return n; + goto next; + } + if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) + break; + + if (n->nud_state & ~NUD_NOARP) + break; + next: + n = n->next; + } + + if (n) + break; + + if (++state->bucket > tbl->hash_mask) + break; + + n = tbl->hash_buckets[state->bucket]; + } + + if (n && pos) + --(*pos); + return n; +} + +static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) +{ + struct neighbour *n = neigh_get_first(seq); + + if (n) { + while (*pos) { + n = neigh_get_next(seq, n, pos); + if (!n) + break; + } + } + return *pos ? NULL : n; +} + +static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) +{ + struct neigh_seq_state *state = seq->private; + struct neigh_table *tbl = state->tbl; + struct pneigh_entry *pn = NULL; + int bucket = state->bucket; + + state->flags |= NEIGH_SEQ_IS_PNEIGH; + for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { + pn = tbl->phash_buckets[bucket]; + if (pn) + break; + } + state->bucket = bucket; + + return pn; +} + +static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, + struct pneigh_entry *pn, + loff_t *pos) +{ + struct neigh_seq_state *state = seq->private; + struct neigh_table *tbl = state->tbl; + + pn = pn->next; + while (!pn) { + if (++state->bucket > PNEIGH_HASHMASK) + break; + pn = tbl->phash_buckets[state->bucket]; + if (pn) + break; + } + + if (pn && pos) + --(*pos); + + return pn; +} + +static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos) +{ + struct pneigh_entry *pn = pneigh_get_first(seq); + + if (pn) { + while (*pos) { + pn = pneigh_get_next(seq, pn, pos); + if (!pn) + break; + } + } + return *pos ? NULL : pn; +} + +static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos) +{ + struct neigh_seq_state *state = seq->private; + void *rc; + + rc = neigh_get_idx(seq, pos); + if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY)) + rc = pneigh_get_idx(seq, pos); + + return rc; +} + +void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags) +{ + struct neigh_seq_state *state = seq->private; + loff_t pos_minus_one; + + state->tbl = tbl; + state->bucket = 0; + state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH); + + read_lock_bh(&tbl->lock); + + pos_minus_one = *pos - 1; + return *pos ? neigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN; +} + +void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct neigh_seq_state *state; + void *rc; + + if (v == SEQ_START_TOKEN) { + rc = neigh_get_idx(seq, pos); + goto out; + } + + state = seq->private; + if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) { + rc = neigh_get_next(seq, v, NULL); + if (rc) + goto out; + if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY)) + rc = pneigh_get_first(seq); + } else { + BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY); + rc = pneigh_get_next(seq, v, NULL); + } +out: + ++(*pos); + return rc; +} + +void neigh_seq_stop(struct seq_file *seq, void *v) +{ + struct neigh_seq_state *state = seq->private; + struct neigh_table *tbl = state->tbl; + + read_unlock_bh(&tbl->lock); +} + +/* statistics via seq_file */ + +static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int lcpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (lcpu = *pos-1; lcpu < smp_num_cpus; ++lcpu) { + int i = cpu_logical_map(lcpu); + *pos = lcpu+1; + return &tbl->stats[i]; + } + return NULL; +} + +static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int lcpu; + + for (lcpu = *pos; lcpu < smp_num_cpus; ++lcpu) { + int i = cpu_logical_map(lcpu); + *pos = lcpu+1; + return &tbl->stats[i]; + } + return NULL; +} + +static void neigh_stat_seq_stop(struct seq_file *seq, void *v) +{ + +} + +static int neigh_stat_seq_show(struct seq_file *seq, void *v) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + struct neigh_statistics *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); + return 0; + } + + seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " + "%08lx %08lx %08lx %08lx\n", + atomic_read(&tbl->entries), + + st->allocs, + st->destroys, + st->hash_grows, + + st->lookups, + st->hits, + + st->res_failed, + + st->rcv_probes_mcast, + st->rcv_probes_ucast, + + st->periodic_gc_runs, + st->forced_gc_runs + ); + + return 0; +} + +static struct seq_operations neigh_stat_seq_ops = { + .start = neigh_stat_seq_start, + .next = neigh_stat_seq_next, + .stop = neigh_stat_seq_stop, + .show = neigh_stat_seq_show, +}; + +static int neigh_stat_seq_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &neigh_stat_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +}; + +static struct file_operations neigh_stat_seq_fops = { + .owner = THIS_MODULE, + .open = neigh_stat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* CONFIG_PROC_FS */ + #ifdef CONFIG_ARPD void neigh_app_ns(struct neighbour *n) { diff -urN linux-2.4.27/net/decnet/dn_neigh.c linux-2.4.28/net/decnet/dn_neigh.c --- linux-2.4.27/net/decnet/dn_neigh.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/decnet/dn_neigh.c 2004-11-17 03:54:22.122419439 -0800 @@ -20,6 +20,7 @@ * Steve Whitehouse : Fixed neighbour states (for now anyway). * Steve Whitehouse : Made error_report functions dummies. This * is not the right place to return skbs. + * Harald Welte : Port to DaveM's generalized ncache from 2.6.x * */ @@ -33,6 +34,8 @@ #include #include #include +#include +#include #include #include #include @@ -118,13 +121,7 @@ static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) { - u32 hash_val; - - hash_val = *(dn_address *)pkey; - hash_val ^= (hash_val >> 10); - hash_val ^= (hash_val >> 3); - - return hash_val & NEIGH_HASHMASK; + return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd); } static int dn_neigh_construct(struct neighbour *neigh) @@ -322,33 +319,6 @@ } /* - * Unfortunately, the neighbour code uses the device in its hash - * function, so we don't get any advantage from it. This function - * basically does a neigh_lookup(), but without comparing the device - * field. This is required for the On-Ethernet cache - */ -struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr) -{ - struct neighbour *neigh; - u32 hash_val; - - hash_val = tbl->hash(ptr, NULL); - - read_lock_bh(&tbl->lock); - for(neigh = tbl->hash_buckets[hash_val]; neigh != NULL; neigh = neigh->next) { - if (memcmp(neigh->primary_key, ptr, tbl->key_len) == 0) { - atomic_inc(&neigh->refcnt); - read_unlock_bh(&tbl->lock); - return neigh; - } - } - read_unlock_bh(&tbl->lock); - - return NULL; -} - - -/* * Any traffic on a pointopoint link causes the timer to be reset * for the entry in the neighbour table. */ @@ -484,113 +454,146 @@ return (*min < priority) ? (min - 6) : NULL; } -int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) +struct elist_cb_state { + struct net_device *dev; + unsigned char *ptr; + unsigned char *rs; + int t, n; +}; + +static void neigh_elist_cb(struct neighbour *neigh, void *_info) { - int t = 0; - int i; - struct neighbour *neigh; + struct elist_cb_state *s = _info; + struct dn_dev *dn_db; struct dn_neigh *dn; - struct neigh_table *tbl = &dn_neigh_table; - unsigned char *rs = ptr; - struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; - read_lock_bh(&tbl->lock); + if (neigh->dev != s->dev) + return; - for(i = 0; i < NEIGH_HASHMASK; i++) { - for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) { - if (neigh->dev != dev) - continue; - dn = (struct dn_neigh *)neigh; - if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) - continue; - if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) - continue; - if (t == n) - rs = dn_find_slot(ptr, n, dn->priority); - else - t++; - if (rs == NULL) - continue; - dn_dn2eth(rs, dn->addr); - rs += 6; - *rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0; - *rs |= dn->priority; - rs++; - } - } + dn = (struct dn_neigh *) neigh; + if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) + return; + + dn_db = (struct dn_dev *) s->dev->dn_ptr; + if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) + return; - read_unlock_bh(&tbl->lock); + if (s->t == s->n) + s->rs = dn_find_slot(s->ptr, s->n, dn->priority); + else + s->t++; + if (s->rs == NULL) + return; + + dn_dn2eth(s->rs, dn->addr); + s->rs += 6; + *(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0; + *(s->rs) |= dn->priority; + s->rs++; +} + +int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) +{ + struct elist_cb_state state; + + state.dev = dev; + state.t = 0; + state.n = n; + state.ptr = ptr; + state.rs = ptr; + + neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state); - return t; + return state.t; } + #endif /* CONFIG_DECNET_ROUTER */ #ifdef CONFIG_PROC_FS -static int dn_neigh_get_info(char *buffer, char **start, off_t offset, int length) + +static inline void dn_neigh_format_entry(struct seq_file *seq, + struct neighbour *n) { - int len = 0; - off_t pos = 0; - off_t begin = 0; - struct neighbour *n; - int i; + struct dn_neigh *dn = (struct dn_neigh *) n; char buf[DN_ASCBUF_LEN]; - len += sprintf(buffer + len, "Addr Flags State Use Blksize Dev\n"); - - for(i=0;i <= NEIGH_HASHMASK; i++) { - read_lock_bh(&dn_neigh_table.lock); - n = dn_neigh_table.hash_buckets[i]; - for(; n != NULL; n = n->next) { - struct dn_neigh *dn = (struct dn_neigh *)n; - - read_lock(&n->lock); - len += sprintf(buffer+len, "%-7s %s%s%s %02x %02d %07ld %-8s\n", - dn_addr2asc(dn_ntohs(dn->addr), buf), - (dn->flags&DN_NDFLAG_R1) ? "1" : "-", - (dn->flags&DN_NDFLAG_R2) ? "2" : "-", - (dn->flags&DN_NDFLAG_P3) ? "3" : "-", - dn->n.nud_state, - atomic_read(&dn->n.refcnt), - dn->blksize, - (dn->n.dev) ? dn->n.dev->name : "?"); - read_unlock(&n->lock); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) { - read_unlock_bh(&dn_neigh_table.lock); - goto done; - } - } - read_unlock_bh(&dn_neigh_table.lock); + read_lock(&n->lock); + seq_printf(seq, "%-7s %s%s%s %02x %02d %07ld %-8s\n", + dn_addr2asc(dn_ntohs(dn->addr), buf), + (dn->flags&DN_NDFLAG_R1) ? "1" : "-", + (dn->flags&DN_NDFLAG_R2) ? "2" : "-", + (dn->flags&DN_NDFLAG_P3) ? "3" : "-", + dn->n.nud_state, + atomic_read(&dn->n.refcnt), + dn->blksize, + (dn->n.dev) ? dn->n.dev->name : "?"); + read_unlock(&n->lock); +} + +static int dn_neigh_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Addr Flags State Use Blksize Dev\n"); + } else { + dn_neigh_format_entry(seq, v); } -done: + return 0; +} - *start = buffer + (offset - begin); - len -= offset - begin; +static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos) +{ + return neigh_seq_start(seq, pos, &dn_neigh_table, + NEIGH_SEQ_NEIGH_ONLY); +} - if (len > length) len = length; +static struct seq_operations dn_neigh_seq_ops = { + .start = dn_neigh_seq_start, + .next = neigh_seq_next, + .stop = neigh_seq_stop, + .show = dn_neigh_seq_show, +}; - return len; -} +static int dn_neigh_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (!s) + goto out; + + memset(s, 0, sizeof(*s)); + rc = seq_open(file, &dn_neigh_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); +out: + return rc; +out_kfree: + kfree(s); + goto out; +} + +static struct file_operations dn_neigh_seq_fops = { + .owner = THIS_MODULE, + .open = dn_neigh_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; #endif void __init dn_neigh_init(void) { neigh_table_init(&dn_neigh_table); - -#ifdef CONFIG_PROC_FS - proc_net_create("decnet_neigh",0,dn_neigh_get_info); -#endif /* CONFIG_PROC_FS */ + proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); } void __exit dn_neigh_cleanup(void) diff -urN linux-2.4.27/net/decnet/dn_route.c linux-2.4.28/net/decnet/dn_route.c --- linux-2.4.27/net/decnet/dn_route.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.28/net/decnet/dn_route.c 2004-11-17 03:54:22.123419480 -0800 @@ -761,7 +761,7 @@ /* Look in On-Ethernet cache first */ if (!(flags & MSG_TRYHARD)) { - if ((neigh = dn_neigh_lookup(&dn_neigh_table, &dst)) != NULL) + if ((neigh = neigh_lookup_nodev(&dn_neigh_table, &dst)) != NULL) goto got_route; } diff -urN linux-2.4.27/net/ipv4/arp.c linux-2.4.28/net/ipv4/arp.c --- linux-2.4.27/net/ipv4/arp.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv4/arp.c 2004-11-17 03:54:22.124419521 -0800 @@ -70,11 +70,13 @@ * arp_xmit so intermediate drivers like * bonding can change the skb before * sending (e.g. insert 8021q tag). + * Harald Welte : convert to make use of jenkins hash */ #include #include #include +#include #include #include #include @@ -92,6 +94,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -218,15 +222,7 @@ static u32 arp_hash(const void *pkey, const struct net_device *dev) { - u32 hash_val; - - hash_val = *(u32*)pkey; - hash_val ^= (hash_val>>16); - hash_val ^= hash_val>>8; - hash_val ^= hash_val>>3; - hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; - - return hash_val; + return jhash_2words(*(u32 *)pkey, dev->ifindex, arp_tbl.hash_rnd); } static int arp_constructor(struct neighbour *neigh) @@ -1024,8 +1020,26 @@ if (!dev) return -EINVAL; } - if (r->arp_ha.sa_family != dev->type) - return -EINVAL; + switch (dev->type) { +#ifdef CONFIG_FDDI + case ARPHRD_FDDI: + /* + * According to RFC 1390, FDDI devices should accept ARP + * hardware types of 1 (Ethernet). However, to be more + * robust, we'll accept hardware types of either 1 (Ethernet) + * or 6 (IEEE 802.2). + */ + if (r->arp_ha.sa_family != ARPHRD_FDDI && + r->arp_ha.sa_family != ARPHRD_ETHER && + r->arp_ha.sa_family != ARPHRD_IEEE802) + return -EINVAL; + break; +#endif + default: + if (r->arp_ha.sa_family != dev->type) + return -EINVAL; + break; + } neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); err = PTR_ERR(neigh); @@ -1185,129 +1199,155 @@ return err; } +#ifdef CONFIG_PROC_FS +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + +/* ------------------------------------------------------------------------ */ /* - * Write the contents of the ARP cache to a PROCfs file. + * ax25 -> ASCII conversion */ -#ifndef CONFIG_PROC_FS -static int arp_get_info(char *buffer, char **start, off_t offset, int length) { return 0; } -#else -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) -static char *ax2asc2(ax25_address *a, char *buf); -#endif +static char *ax2asc2(ax25_address *a, char *buf) +{ + char c, *s; + int n; + + for (n = 0, s = buf; n < 6; n++) { + c = (a->ax25_call[n] >> 1) & 0x7F; + + if (c != ' ') *s++ = c; + } + + *s++ = '-'; + + if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { + *s++ = '1'; + n -= 10; + } + + *s++ = n + '0'; + *s++ = '\0'; + + if (*buf == '\0' || *buf == '-') + return "*"; + + return buf; + +} +#endif /* CONFIG_AX25 */ + #define HBUFFERLEN 30 -static int arp_get_info(char *buffer, char **start, off_t offset, int length) +static void arp_format_neigh_entry(struct seq_file *seq, + struct neighbour *n) { - int len=0; - off_t pos=0; - int size; char hbuffer[HBUFFERLEN]; - int i,j,k; const char hexbuf[] = "0123456789ABCDEF"; + int k, j; + char tbuf[16]; + struct net_device *dev = n->dev; + int hatype = dev->type; - size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n"); + read_lock(&n->lock); - pos+=size; - len+=size; - - for(i=0; i<=NEIGH_HASHMASK; i++) { - struct neighbour *n; - read_lock_bh(&arp_tbl.lock); - for (n=arp_tbl.hash_buckets[i]; n; n=n->next) { - struct net_device *dev = n->dev; - int hatype = dev->type; - - /* Do not confuse users "arp -a" with magic entries */ - if (!(n->nud_state&~NUD_NOARP)) - continue; - - read_lock(&n->lock); - -/* - * Convert hardware address to XX:XX:XX:XX ... form. - */ + /* Convert hardware address to XX:XX:XX:XX ... form. */ #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) - ax2asc2((ax25_address *)n->ha, hbuffer); - else { -#endif - for (k=0,j=0;kaddr_len;j++) { - hbuffer[k++]=hexbuf[(n->ha[j]>>4)&15 ]; - hbuffer[k++]=hexbuf[n->ha[j]&15 ]; - hbuffer[k++]=':'; - } - hbuffer[--k]=0; - + if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) + ax2asc2((ax25_address *)n->ha, hbuffer); + else { +#endif + for (k=0,j=0;kaddr_len;j++) { + hbuffer[k++]=hexbuf[(n->ha[j]>>4)&15 ]; + hbuffer[k++]=hexbuf[n->ha[j]&15 ]; + hbuffer[k++]=':'; + } + hbuffer[--k]=0; #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - } + } #endif + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); + seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", + tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); + read_unlock(&n->lock); +} - { - char tbuf[16]; - sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); - size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" - " * %s\n", - tbuf, - hatype, - arp_state_to_flags(n), - hbuffer, - dev->name); - } +static void arp_format_pneigh_entry(struct seq_file *seq, + struct pneigh_entry *n) +{ + struct net_device *dev = n->dev; + int hatype = dev ? dev->type : 0; + char tbuf[16]; - read_unlock(&n->lock); + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); + seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", + tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", + dev ? dev->name : "*"); +} - len += size; - pos += size; - - if (pos <= offset) - len=0; - if (pos >= offset+length) { - read_unlock_bh(&arp_tbl.lock); - goto done; - } - } - read_unlock_bh(&arp_tbl.lock); +static int arp_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "IP address HW type Flags " + "HW address Mask Device\n"); + } else { + struct neigh_seq_state *state = seq->private; + + if (state->flags & NEIGH_SEQ_IS_PNEIGH) + arp_format_pneigh_entry(seq, v); + else + arp_format_neigh_entry(seq, v); } - for (i=0; i<=PNEIGH_HASHMASK; i++) { - struct pneigh_entry *n; - for (n=arp_tbl.phash_buckets[i]; n; n=n->next) { - struct net_device *dev = n->dev; - int hatype = dev ? dev->type : 0; - - { - char tbuf[16]; - sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); - size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" - " * %s\n", - tbuf, - hatype, - ATF_PUBL|ATF_PERM, - "00:00:00:00:00:00", - dev ? dev->name : "*"); - } + return 0; +} - len += size; - pos += size; - - if (pos <= offset) - len=0; - if (pos >= offset+length) - goto done; - } - } +static void *arp_seq_start(struct seq_file *seq, loff_t *pos) +{ + /* Don't want to confuse "arp -a" w/ magic entries, + * so we tell the generic iterator to skip NUD_NOARP. + */ + return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); +} + +/* ------------------------------------------------------------------------ */ + +static struct seq_operations arp_seq_ops = { + .start = arp_seq_start, + .next = neigh_seq_next, + .stop = neigh_seq_stop, + .show = arp_seq_show, +}; -done: - - *start = buffer+len-(pos-offset); /* Start of wanted data */ - len = pos-offset; /* Start slop */ - if (len>length) - len = length; /* Ending slop */ - if (len<0) - len = 0; - return len; +static int arp_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (!s) + goto out; + + memset(s, 0, sizeof(*s)); + rc = seq_open(file, &arp_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; + seq->private = s; +out: + return rc; +out_kfree: + kfree(s); + goto out; } -#endif + +static struct file_operations arp_seq_fops = { + .owner = THIS_MODULE, + .open = arp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; +#endif /* CONFIG_PROC_FS */ static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -1355,8 +1395,10 @@ dev_add_pack(&arp_packet_type); - proc_net_create ("arp", 0, arp_get_info); - +#ifdef CONFIG_PROC_FS + if (!proc_net_fops_create("arp", S_IRUGO, &arp_seq_fops)) + panic("unable to create arp proc entry"); +#endif #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4"); #endif @@ -1364,39 +1406,3 @@ } -#ifdef CONFIG_PROC_FS -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - -/* - * ax25 -> ASCII conversion - */ -char *ax2asc2(ax25_address *a, char *buf) -{ - char c, *s; - int n; - - for (n = 0, s = buf; n < 6; n++) { - c = (a->ax25_call[n] >> 1) & 0x7F; - - if (c != ' ') *s++ = c; - } - - *s++ = '-'; - - if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { - *s++ = '1'; - n -= 10; - } - - *s++ = n + '0'; - *s++ = '\0'; - - if (*buf == '\0' || *buf == '-') - return "*"; - - return buf; - -} - -#endif -#endif diff -urN linux-2.4.27/net/ipv4/ip_fragment.c linux-2.4.28/net/ipv4/ip_fragment.c --- linux-2.4.27/net/ipv4/ip_fragment.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.28/net/ipv4/ip_fragment.c 2004-11-17 03:54:22.125419562 -0800 @@ -168,14 +168,18 @@ atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */ /* Memory Tracking Functions. */ -static __inline__ void frag_kfree_skb(struct sk_buff *skb) +static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) { + if (work) + *work -= skb->truesize; atomic_sub(skb->truesize, &ip_frag_mem); kfree_skb(skb); } -static __inline__ void frag_free_queue(struct ipq *qp) +static __inline__ void frag_free_queue(struct ipq *qp, int *work) { + if (work) + *work -= sizeof(struct ipq); atomic_sub(sizeof(struct ipq), &ip_frag_mem); kfree(qp); } @@ -194,7 +198,7 @@ /* Destruction primitives. */ /* Complete destruction of ipq. */ -static void ip_frag_destroy(struct ipq *qp) +static void ip_frag_destroy(struct ipq *qp, int *work) { struct sk_buff *fp; @@ -206,18 +210,18 @@ while (fp) { struct sk_buff *xp = fp->next; - frag_kfree_skb(fp); + frag_kfree_skb(fp, work); fp = xp; } /* Finally, release the queue descriptor itself. */ - frag_free_queue(qp); + frag_free_queue(qp, work); } -static __inline__ void ipq_put(struct ipq *ipq) +static __inline__ void ipq_put(struct ipq *ipq, int *work) { if (atomic_dec_and_test(&ipq->refcnt)) - ip_frag_destroy(ipq); + ip_frag_destroy(ipq, work); } /* Kill ipq entry. It is not destroyed immediately, @@ -236,16 +240,19 @@ } /* Memory limiting on fragments. Evictor trashes the oldest - * fragment queue until we are back under the low threshold. + * fragment queue until we are back under the threshold. */ -static void ip_evictor(void) +static void __ip_evictor(int threshold) { struct ipq *qp; struct list_head *tmp; + int work; - for(;;) { - if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh) - return; + work = atomic_read(&ip_frag_mem) - threshold; + if (work <= 0) + return; + + while (work > 0) { read_lock(&ipfrag_lock); if (list_empty(&ipq_lru_list)) { read_unlock(&ipfrag_lock); @@ -261,11 +268,16 @@ ipq_kill(qp); spin_unlock(&qp->lock); - ipq_put(qp); + ipq_put(qp, &work); IP_INC_STATS_BH(IpReasmFails); } } +static inline void ip_evictor(void) +{ + __ip_evictor(sysctl_ipfrag_low_thresh); +} + /* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -293,7 +305,7 @@ } out: spin_unlock(&qp->lock); - ipq_put(qp); + ipq_put(qp, NULL); } /* Creation primitives. */ @@ -316,7 +328,7 @@ atomic_inc(&qp->refcnt); write_unlock(&ipfrag_lock); qp_in->last_in |= COMPLETE; - ipq_put(qp_in); + ipq_put(qp_in, NULL); return qp; } } @@ -505,7 +517,7 @@ qp->fragments = next; qp->meat -= free_it->len; - frag_kfree_skb(free_it); + frag_kfree_skb(free_it, NULL); } } @@ -656,7 +668,7 @@ ret = ip_frag_reasm(qp, dev); spin_unlock(&qp->lock); - ipq_put(qp); + ipq_put(qp, NULL); return ret; } @@ -675,3 +687,8 @@ ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval; add_timer(&ipfrag_secret_timer); } + +void ipfrag_flush(void) +{ + __ip_evictor(0); +} diff -urN linux-2.4.27/net/ipv4/ip_output.c linux-2.4.28/net/ipv4/ip_output.c --- linux-2.4.27/net/ipv4/ip_output.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/ip_output.c 2004-11-17 03:54:22.126419603 -0800 @@ -184,7 +184,7 @@ return -EINVAL; } -__inline__ int ip_finish_output(struct sk_buff *skb) +static __inline__ int __ip_finish_output(struct sk_buff *skb) { struct net_device *dev = skb->dst->dev; @@ -195,6 +195,11 @@ ip_finish_output2); } +int ip_finish_output(struct sk_buff *skb) +{ + return __ip_finish_output(skb); +} + int ip_mc_output(struct sk_buff *skb) { struct sock *sk = skb->sk; @@ -253,7 +258,7 @@ newskb->dev, ip_dev_loopback_xmit); } - return ip_finish_output(skb); + return __ip_finish_output(skb); } int ip_output(struct sk_buff *skb) @@ -269,7 +274,7 @@ ip_do_nat(skb); #endif - return ip_finish_output(skb); + return __ip_finish_output(skb); } /* Queues a packet to be sent, and starts the transmitter if necessary. diff -urN linux-2.4.27/net/ipv4/ipconfig.c linux-2.4.28/net/ipv4/ipconfig.c --- linux-2.4.27/net/ipv4/ipconfig.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/ipconfig.c 2004-11-17 03:54:22.127419644 -0800 @@ -689,6 +689,8 @@ b->htype = dev->type; else if (dev->type == ARPHRD_IEEE802_TR) /* fix for token ring */ b->htype = ARPHRD_IEEE802; + else if (dev->type == ARPHRD_FDDI) + b->htype = ARPHRD_ETHER; else { printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name); b->htype = dev->type; /* can cause undefined behavior */ @@ -899,6 +901,9 @@ break; case DHCPACK: + if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0) + goto drop; + /* Yeah! */ break; diff -urN linux-2.4.27/net/ipv4/ipvs/ip_vs_sync.c linux-2.4.28/net/ipv4/ipvs/ip_vs_sync.c --- linux-2.4.27/net/ipv4/ipvs/ip_vs_sync.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv4/ipvs/ip_vs_sync.c 2004-11-17 03:54:22.128419685 -0800 @@ -11,6 +11,9 @@ * * ip_vs_sync: sync connection info from master load balancer to backups * through multicast + * + * Changes: + * Justin Ossevoort : Fix endian problem on sync message size. */ #include @@ -254,6 +257,9 @@ char *p; int i; + /* Convert size back to host byte order */ + m->size = ntohs(m->size); + if (buflen != m->size) { IP_VS_ERR("bogus message\n"); return; @@ -517,6 +523,19 @@ return len; } +static void +ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg) +{ + int msize; + + msize = msg->size; + + /* Put size in network byte order */ + msg->size = htons(msg->size); + + if (ip_vs_send_async(sock, (char *)msg, msize) != msize) + IP_VS_ERR("ip_vs_send_async error\n"); +} static int ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen) @@ -561,7 +580,6 @@ { struct socket *sock; struct ip_vs_sync_buff *sb; - struct ip_vs_sync_mesg *m; /* create the sending multicast socket */ sock = make_send_sock(); @@ -570,19 +588,13 @@ for (;;) { while ((sb=sb_dequeue())) { - m = sb->mesg; - if (ip_vs_send_async(sock, (char *)m, - m->size) != m->size) - IP_VS_ERR("ip_vs_send_async error\n"); + ip_vs_send_sync_msg(sock, sb->mesg); ip_vs_sync_buff_release(sb); } /* check if entries stay in curr_sb for 2 seconds */ if ((sb = get_curr_sync_buff(2*HZ))) { - m = sb->mesg; - if (ip_vs_send_async(sock, (char *)m, - m->size) != m->size) - IP_VS_ERR("ip_vs_send_async error\n"); + ip_vs_send_sync_msg(sock, sb->mesg); ip_vs_sync_buff_release(sb); } diff -urN linux-2.4.27/net/ipv4/netfilter/arp_tables.c linux-2.4.28/net/ipv4/netfilter/arp_tables.c --- linux-2.4.27/net/ipv4/netfilter/arp_tables.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/arp_tables.c 2004-11-17 03:54:22.129419727 -0800 @@ -101,7 +101,7 @@ { char *arpptr = (char *)(arphdr + 1); char *src_devaddr, *tgt_devaddr; - u32 *src_ipaddr, *tgt_ipaddr; + u32 src_ipaddr, tgt_ipaddr; int i, ret; #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg)) @@ -140,11 +140,11 @@ src_devaddr = arpptr; arpptr += dev->addr_len; - src_ipaddr = (u32 *) arpptr; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); arpptr += sizeof(u32); tgt_devaddr = arpptr; arpptr += dev->addr_len; - tgt_ipaddr = (u32 *) arpptr; + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), ARPT_INV_SRCDEVADDR) || @@ -155,19 +155,19 @@ return 0; } - if (FWINV(((*src_ipaddr) & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, + if (FWINV(((src_ipaddr) & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, ARPT_INV_SRCIP) || - FWINV((((*tgt_ipaddr) & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), + FWINV((((tgt_ipaddr) & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), ARPT_INV_TGTIP)) { dprintf("Source or target IP address mismatch.\n"); dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", - NIPQUAD(*src_ipaddr), + NIPQUAD(src_ipaddr), NIPQUAD(arpinfo->smsk.s_addr), NIPQUAD(arpinfo->src.s_addr), arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", - NIPQUAD(*tgt_ipaddr), + NIPQUAD(tgt_ipaddr), NIPQUAD(arpinfo->tmsk.s_addr), NIPQUAD(arpinfo->tgt.s_addr), arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); @@ -188,7 +188,10 @@ } for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { - ret |= (((const unsigned long *)outdev)[i] + unsigned long odev; + memcpy(&odev, outdev + i*sizeof(unsigned long), + sizeof(unsigned long)); + ret |= (odev ^ ((const unsigned long *)arpinfo->outiface)[i]) & ((const unsigned long *)arpinfo->outiface_mask)[i]; } diff -urN linux-2.4.27/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.28/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.4.27/net/ipv4/netfilter/ip_conntrack_core.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-17 03:54:22.130419768 -0800 @@ -1183,6 +1183,8 @@ WRITE_UNLOCK(&ip_conntrack_lock); } +int ip_ct_no_defrag; + /* Returns new sk_buff, or NULL */ struct sk_buff * ip_ct_gather_frags(struct sk_buff *skb) @@ -1191,6 +1193,12 @@ #ifdef CONFIG_NETFILTER_DEBUG unsigned int olddebug = skb->nf_debug; #endif + + if (unlikely(ip_ct_no_defrag)) { + kfree_skb(skb); + return NULL; + } + if (sk) { sock_hold(sk); skb_orphan(skb); diff -urN linux-2.4.27/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.28/net/ipv4/netfilter/ip_conntrack_ftp.c --- linux-2.4.27/net/ipv4/netfilter/ip_conntrack_ftp.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-11-17 03:54:22.131419809 -0800 @@ -11,7 +11,7 @@ #include #include -DECLARE_LOCK(ip_ftp_lock); +static DECLARE_LOCK(ip_ftp_lock); struct module *ip_conntrack_ftp = THIS_MODULE; #define MAX_PORTS 8 @@ -338,7 +338,6 @@ memset(&expect, 0, sizeof(expect)); /* Update the ftp info */ - LOCK_BH(&ip_ftp_lock); if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) == ct->tuplehash[dir].tuple.src.ip) { exp->seq = ntohl(tcph->seq) + matchoff; @@ -358,7 +357,8 @@ for reporting this potential problem (DMZ machines opening holes to internal networks, or the packet filter itself). */ - if (!loose) goto out; + if (!loose) + return NF_ACCEPT; } exp->tuple = ((struct ip_conntrack_tuple) @@ -376,9 +376,6 @@ /* Ignore failure; should only happen with NAT */ ip_conntrack_expect_related(ct, &expect); - out: - UNLOCK_BH(&ip_ftp_lock); - return NF_ACCEPT; } diff -urN linux-2.4.27/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.28/net/ipv4/netfilter/ip_conntrack_irc.c --- linux-2.4.27/net/ipv4/netfilter/ip_conntrack_irc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/netfilter/ip_conntrack_irc.c 2004-11-17 03:54:22.132419850 -0800 @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -61,7 +60,6 @@ }; #define MINMATCHLEN 5 -DECLARE_LOCK(ip_irc_lock); struct module *ip_conntrack_irc = THIS_MODULE; #if 0 @@ -208,8 +206,6 @@ memset(&expect, 0, sizeof(expect)); - LOCK_BH(&ip_irc_lock); - /* save position of address in dcc string, * neccessary for NAT */ DEBUGP("tcph->seq = %u\n", tcph->seq); @@ -236,8 +232,6 @@ ntohs(exp->tuple.dst.u.tcp.port)); ip_conntrack_expect_related(ct, &expect); - UNLOCK_BH(&ip_irc_lock); - return NF_ACCEPT; } /* for .. NUM_DCCPROTO */ } /* while data < ... */ @@ -315,7 +309,5 @@ } } -EXPORT_SYMBOL(ip_irc_lock); - module_init(init); module_exit(fini); diff -urN linux-2.4.27/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.28/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.4.27/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-11-17 03:54:22.132419850 -0800 @@ -393,6 +393,13 @@ cleanup_inandlocalops: nf_unregister_hook(&ip_conntrack_local_out_ops); cleanup_inops: + /* Frag queues may hold fragments with skb->dst == NULL */ + ip_ct_no_defrag = 1; + local_bh_disable(); + br_write_lock(BR_NETPROTO_LOCK); + br_write_unlock(BR_NETPROTO_LOCK); + ipfrag_flush(); + local_bh_enable(); nf_unregister_hook(&ip_conntrack_in_ops); cleanup_proc: proc_net_remove("ip_conntrack"); diff -urN linux-2.4.27/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.28/net/ipv4/netfilter/ip_nat_ftp.c --- linux-2.4.27/net/ipv4/netfilter/ip_nat_ftp.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/ip_nat_ftp.c 2004-11-17 03:54:22.133419891 -0800 @@ -24,8 +24,6 @@ MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); #endif -DECLARE_LOCK_EXTERN(ip_ftp_lock); - /* FIXME: Time out? --RR */ static unsigned int @@ -48,8 +46,6 @@ DEBUGP("nat_expected: We have a connection!\n"); exp_ftp_info = &ct->master->help.exp_ftp_info; - LOCK_BH(&ip_ftp_lock); - if (exp_ftp_info->ftptype == IP_CT_FTP_PORT || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) { /* PORT command: make connection go to the client. */ @@ -64,7 +60,6 @@ DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } - UNLOCK_BH(&ip_ftp_lock); if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) newip = newsrcip; @@ -100,8 +95,6 @@ { char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; - MUST_BE_LOCKED(&ip_ftp_lock); - sprintf(buffer, "%u,%u,%u,%u,%u,%u", NIPQUAD(newip), port>>8, port&0xFF); @@ -123,8 +116,6 @@ { char buffer[sizeof("|1|255.255.255.255|65535|")]; - MUST_BE_LOCKED(&ip_ftp_lock); - sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); DEBUGP("calling ip_nat_mangle_tcp_packet\n"); @@ -145,8 +136,6 @@ { char buffer[sizeof("|||65535|")]; - MUST_BE_LOCKED(&ip_ftp_lock); - sprintf(buffer, "|||%u|", port); DEBUGP("calling ip_nat_mangle_tcp_packet\n"); @@ -166,7 +155,7 @@ [IP_CT_FTP_EPSV] mangle_epsv_packet }; -static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info, +static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info, struct ip_conntrack *ct, struct sk_buff **pskb, enum ip_conntrack_info ctinfo, @@ -178,15 +167,14 @@ u_int16_t port; struct ip_conntrack_tuple newtuple; - MUST_BE_LOCKED(&ip_ftp_lock); DEBUGP("FTP_NAT: seq %u + %u in %u\n", - expect->seq, ct_ftp_info->len, + expect->seq, exp_ftp_info->len, ntohl(tcph->seq)); /* Change address inside packet to match way we're mapping this connection. */ - if (ct_ftp_info->ftptype == IP_CT_FTP_PASV - || ct_ftp_info->ftptype == IP_CT_FTP_EPSV) { + if (exp_ftp_info->ftptype == IP_CT_FTP_PASV + || exp_ftp_info->ftptype == IP_CT_FTP_EPSV) { /* PASV/EPSV response: must be where client thinks server is */ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; @@ -208,7 +196,7 @@ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; /* Try to get same port: if not, try to change it. */ - for (port = ct_ftp_info->port; port != 0; port++) { + for (port = exp_ftp_info->port; port != 0; port++) { newtuple.dst.u.tcp.port = htons(port); if (ip_conntrack_change_expect(expect, &newtuple) == 0) @@ -217,9 +205,9 @@ if (port == 0) return 0; - if (!mangle[ct_ftp_info->ftptype](pskb, newip, port, + if (!mangle[exp_ftp_info->ftptype](pskb, newip, port, expect->seq - ntohl(tcph->seq), - ct_ftp_info->len, ct, ctinfo)) + exp_ftp_info->len, ct, ctinfo)) return 0; return 1; @@ -236,12 +224,12 @@ struct tcphdr *tcph = (void *)iph + iph->ihl*4; unsigned int datalen; int dir; - struct ip_ct_ftp_expect *ct_ftp_info; + struct ip_ct_ftp_expect *exp_ftp_info; if (!exp) DEBUGP("ip_nat_ftp: no exp!!"); - ct_ftp_info = &exp->help.exp_ftp_info; + exp_ftp_info = &exp->help.exp_ftp_info; /* Only mangle things once: original direction in POST_ROUTING and reply direction on PRE_ROUTING. */ @@ -257,29 +245,23 @@ } datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; - LOCK_BH(&ip_ftp_lock); /* If it's in the right range... */ - if (between(exp->seq + ct_ftp_info->len, + if (between(exp->seq + exp_ftp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) { - if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) { - UNLOCK_BH(&ip_ftp_lock); + if (!ftp_data_fixup(exp_ftp_info, ct, pskb, ctinfo, exp)) return NF_DROP; - } } else { /* Half a match? This means a partial retransmisison. It's a cracker being funky. */ if (net_ratelimit()) { printk("FTP_NAT: partial packet %u/%u in %u/%u\n", - exp->seq, ct_ftp_info->len, + exp->seq, exp_ftp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); } - UNLOCK_BH(&ip_ftp_lock); return NF_DROP; } - UNLOCK_BH(&ip_ftp_lock); - return NF_ACCEPT; } diff -urN linux-2.4.27/net/ipv4/netfilter/ip_nat_irc.c linux-2.4.28/net/ipv4/netfilter/ip_nat_irc.c --- linux-2.4.27/net/ipv4/netfilter/ip_nat_irc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/netfilter/ip_nat_irc.c 2004-11-17 03:54:22.134419932 -0800 @@ -46,9 +46,6 @@ MODULE_PARM_DESC(ports, "port numbers of IRC servers"); #endif -/* protects irc part of conntracks */ -DECLARE_LOCK_EXTERN(ip_irc_lock); - /* FIXME: Time out? --RR */ static unsigned int @@ -89,7 +86,7 @@ return ip_nat_setup_info(ct, &mr, hooknum); } -static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info, +static int irc_data_fixup(const struct ip_ct_irc_expect *exp_irc_info, struct ip_conntrack *ct, struct sk_buff **pskb, enum ip_conntrack_info ctinfo, @@ -104,23 +101,16 @@ /* "4294967296 65635 " */ char buffer[18]; - MUST_BE_LOCKED(&ip_irc_lock); - DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", - expect->seq, ct_irc_info->len, + expect->seq, exp_irc_info->len, ntohl(tcph->seq)); newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; /* Alter conntrack's expectations. */ - - /* We can read expect here without conntrack lock, since it's - only set in ip_conntrack_irc, with ip_irc_lock held - writable */ - t = expect->tuple; t.dst.ip = newip; - for (port = ct_irc_info->port; port != 0; port++) { + for (port = exp_irc_info->port; port != 0; port++) { t.dst.u.tcp.port = htons(port); if (ip_conntrack_change_expect(expect, &t) == 0) { DEBUGP("using port %d", port); @@ -150,7 +140,7 @@ return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, expect->seq - ntohl(tcph->seq), - ct_irc_info->len, buffer, + exp_irc_info->len, buffer, strlen(buffer)); } @@ -165,12 +155,12 @@ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; unsigned int datalen; int dir; - struct ip_ct_irc_expect *ct_irc_info; + struct ip_ct_irc_expect *exp_irc_info; if (!exp) DEBUGP("ip_nat_irc: no exp!!"); - ct_irc_info = &exp->help.exp_irc_info; + exp_irc_info = &exp->help.exp_irc_info; /* Only mangle things once: original direction in POST_ROUTING and reply direction on PRE_ROUTING. */ @@ -187,30 +177,24 @@ DEBUGP("got beyond not touching\n"); datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; - LOCK_BH(&ip_irc_lock); /* Check wether the whole IP/address pattern is carried in the payload */ - if (between(exp->seq + ct_irc_info->len, + if (between(exp->seq + exp_irc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) { - if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) { - UNLOCK_BH(&ip_irc_lock); + if (!irc_data_fixup(exp_irc_info, ct, pskb, ctinfo, exp)) return NF_DROP; - } } else { /* Half a match? This means a partial retransmisison. It's a cracker being funky. */ if (net_ratelimit()) { printk ("IRC_NAT: partial packet %u/%u in %u/%u\n", - exp->seq, ct_irc_info->len, + exp->seq, exp_irc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); } - UNLOCK_BH(&ip_irc_lock); return NF_DROP; } - UNLOCK_BH(&ip_irc_lock); - return NF_ACCEPT; } diff -urN linux-2.4.27/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.28/net/ipv4/netfilter/ip_nat_snmp_basic.c --- linux-2.4.27/net/ipv4/netfilter/ip_nat_snmp_basic.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/netfilter/ip_nat_snmp_basic.c 2004-11-17 03:54:22.135419973 -0800 @@ -862,6 +862,77 @@ return 1; } +/* + * Fast checksum update for possibly oddly-aligned UDP byte, from the + * code example in the draft. + */ +static void fast_csum(unsigned char *csum, + const unsigned char *optr, + const unsigned char *nptr, + int odd) +{ + long x, old, new; + + x = csum[0] * 256 + csum[1]; + + x =~ x & 0xFFFF; + + if (odd) old = optr[0] * 256; + else old = optr[0]; + + x -= old & 0xFFFF; + if (x <= 0) { + x--; + x &= 0xFFFF; + } + + if (odd) new = nptr[0] * 256; + else new = nptr[0]; + + x += new & 0xFFFF; + if (x & 0x10000) { + x++; + x &= 0xFFFF; + } + + x =~ x & 0xFFFF; + csum[0] = x / 256; + csum[1] = x & 0xFF; +} + +/* + * Mangle IP address. + * - begin points to the start of the snmp messgae + * - addr points to the start of the address + */ +static void inline mangle_address(unsigned char *begin, + unsigned char *addr, + const struct oct1_map *map, + u_int16_t *check) +{ + if (map->from == NOCT1(*addr)) { + u_int32_t old; + + if (debug) + memcpy(&old, (unsigned char *)addr, sizeof(old)); + + *addr = map->to; + + /* Update UDP checksum if being used */ + if (*check) { + unsigned char odd = !((addr - begin) % 2); + + fast_csum((unsigned char *)check, + &map->from, &map->to, odd); + + } + + if (debug) + printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " + "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); + } +} + static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, struct snmp_v1_trap *trap, const struct oct1_map *map, @@ -952,77 +1023,6 @@ printk("\n"); } -/* - * Fast checksum update for possibly oddly-aligned UDP byte, from the - * code example in the draft. - */ -static void fast_csum(unsigned char *csum, - const unsigned char *optr, - const unsigned char *nptr, - int odd) -{ - long x, old, new; - - x = csum[0] * 256 + csum[1]; - - x =~ x & 0xFFFF; - - if (odd) old = optr[0] * 256; - else old = optr[0]; - - x -= old & 0xFFFF; - if (x <= 0) { - x--; - x &= 0xFFFF; - } - - if (odd) new = nptr[0] * 256; - else new = nptr[0]; - - x += new & 0xFFFF; - if (x & 0x10000) { - x++; - x &= 0xFFFF; - } - - x =~ x & 0xFFFF; - csum[0] = x / 256; - csum[1] = x & 0xFF; -} - -/* - * Mangle IP address. - * - begin points to the start of the snmp messgae - * - addr points to the start of the address - */ -static void inline mangle_address(unsigned char *begin, - unsigned char *addr, - const struct oct1_map *map, - u_int16_t *check) -{ - if (map->from == NOCT1(*addr)) { - u_int32_t old; - - if (debug) - memcpy(&old, (unsigned char *)addr, sizeof(old)); - - *addr = map->to; - - /* Update UDP checksum if being used */ - if (*check) { - unsigned char odd = !((addr - begin) % 2); - - fast_csum((unsigned char *)check, - &map->from, &map->to, odd); - - } - - if (debug) - printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " - "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); - } -} - /* * Parse and mangle SNMP message according to mapping. * (And this is the fucking 'basic' method). diff -urN linux-2.4.27/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.28/net/ipv4/netfilter/ipt_ULOG.c --- linux-2.4.27/net/ipv4/netfilter/ipt_ULOG.c 2004-08-07 16:26:06.000000000 -0700 +++ linux-2.4.28/net/ipv4/netfilter/ipt_ULOG.c 2004-11-17 03:54:22.135419973 -0800 @@ -1,7 +1,7 @@ /* * netfilter module for userspace packet logging daemons * - * (C) 2000-2002 by Harald Welte + * (C) 2000-2004 by Harald Welte * * 2000/09/22 ulog-cprange feature added * 2001/01/04 in-kernel queue as proposed by Sebastian Zander @@ -13,6 +13,8 @@ * 2002/07/07 remove broken nflog_rcv() function -HW * 2002/08/29 fix shifted/unshifted nlgroup bug -HW * 2002/10/30 fix uninitialized mac_len field - + * 2004/10/25 fix erroneous calculation of 'len' parameter to NLMSG_PUT + * resulting in bogus 'error during NLMSG_PUT' messages. * * Released under the terms of the GPL * @@ -203,7 +205,7 @@ /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, - size - sizeof(*nlh)); + sizeof(*pm)+copy_len); ub->qlen++; pm = NLMSG_DATA(nlh); diff -urN linux-2.4.27/net/ipv4/route.c linux-2.4.28/net/ipv4/route.c --- linux-2.4.27/net/ipv4/route.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv4/route.c 2004-11-17 03:54:22.137420055 -0800 @@ -284,6 +284,7 @@ int i, lcpu; int len = 0; + len += sprintf(buffer+len, "entries in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) { i = cpu_logical_map(lcpu); @@ -2625,7 +2626,8 @@ add_timer(&rt_secret_timer); proc_net_create ("rt_cache", 0, rt_cache_get_info); - proc_net_create ("rt_cache_stat", 0, rt_cache_stat_get_info); + create_proc_info_entry ("rt_cache", 0, proc_net_stat, + rt_cache_stat_get_info); #ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read, NULL); #endif diff -urN linux-2.4.27/net/ipv4/tcp_diag.c linux-2.4.28/net/ipv4/tcp_diag.c --- linux-2.4.27/net/ipv4/tcp_diag.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv4/tcp_diag.c 2004-11-17 03:54:22.138420097 -0800 @@ -49,6 +49,7 @@ struct nlmsghdr *nlh; struct tcp_info *info = NULL; struct tcpdiag_meminfo *minfo = NULL; + struct tcpvegas_info *vinfo = NULL; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); @@ -58,6 +59,10 @@ minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo)); if (ext & (1<<(TCPDIAG_INFO-1))) info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info)); + + if ((tcp_is_westwood(tp) || tcp_is_vegas(tp)) + && (ext & (1<<(TCPDIAG_VEGASINFO-1)))) + vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo)); } r->tcpdiag_family = sk->family; r->tcpdiag_state = sk->state; @@ -186,6 +191,20 @@ info->tcpi_reordering = tp->reordering; } + if (vinfo) { + if (tcp_is_vegas(tp)) { + vinfo->tcpv_enabled = tp->vegas.doing_vegas_now; + vinfo->tcpv_rttcnt = tp->vegas.cntRTT; + vinfo->tcpv_rtt = (1000000*tp->vegas.baseRTT)/HZ; + vinfo->tcpv_minrtt = (1000000*tp->vegas.minRTT)/HZ; + } else { + vinfo->tcpv_enabled = 0; + vinfo->tcpv_rttcnt = 0; + vinfo->tcpv_rtt = (1000000*tp->westwood.rtt)/HZ; + vinfo->tcpv_minrtt = (1000000*tp->westwood.rtt_min)/HZ; + } + } + nlh->nlmsg_len = skb->tail - b; return skb->len; diff -urN linux-2.4.27/net/ipv4/tcp_input.c linux-2.4.28/net/ipv4/tcp_input.c --- linux-2.4.27/net/ipv4/tcp_input.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv4/tcp_input.c 2004-11-17 03:54:22.141420220 -0800 @@ -549,17 +549,20 @@ tcp_grow_window(sk, tp, skb); } -/* Set up a new TCP connection, depending on whether it should be - * using Vegas or not. - */ -void tcp_vegas_init(struct tcp_opt *tp) +/* When starting a new connection, pin down the current choice of + * congestion algorithm. + */ +void tcp_ca_init(struct tcp_opt *tp) { - if (sysctl_tcp_vegas_cong_avoid) { - tp->vegas.do_vegas = 1; + if (sysctl_tcp_westwood) + tp->adv_cong = TCP_WESTWOOD; + else if (sysctl_tcp_bic) + tp->adv_cong = TCP_BIC; + else if (sysctl_tcp_vegas_cong_avoid) { + tp->adv_cong = TCP_VEGAS; tp->vegas.baseRTT = 0x7fffffff; tcp_vegas_enable(tp); - } else - tcp_vegas_disable(tp); + } } /* Do RTT sampling needed for Vegas. @@ -851,8 +854,10 @@ * to low value, and then abruptly stops to do it and starts to delay * ACKs, wait for troubles. */ - if (dst->rtt > tp->srtt) + if (dst->rtt > tp->srtt) { tp->srtt = dst->rtt; + tp->rtt_seq = tp->snd_nxt; + } if (dst->rttvar > tp->mdev) { tp->mdev = dst->rttvar; tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN); @@ -2005,7 +2010,7 @@ static inline __u32 bictcp_cwnd(struct tcp_opt *tp) { /* orignal Reno behaviour */ - if (!sysctl_tcp_bic) + if (!tcp_is_bic(tp)) return tp->snd_cwnd; if (tp->bictcp.last_cwnd == tp->snd_cwnd && @@ -2551,15 +2556,13 @@ * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN! */ -static inline __u32 westwood_update_rttmin(struct sock *sk) +static inline __u32 westwood_update_rttmin(const struct sock *sk) { - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); __u32 rttmin = tp->westwood.rtt_min; - if (tp->westwood.rtt == 0) - return rttmin; - - if (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin) + if (tp->westwood.rtt != 0 && + (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin)) rttmin = tp->westwood.rtt; return rttmin; @@ -2570,9 +2573,9 @@ * Evaluate increases for dk. */ -static __u32 westwood_acked(struct sock *sk) +static __u32 westwood_acked(const struct sock *sk) { - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); return ((tp->snd_una) - (tp->westwood.snd_una)); } @@ -2586,9 +2589,9 @@ * window, 1 if the sample has to be considered in the next window. */ -static int westwood_new_window(struct sock *sk) +static int westwood_new_window(const struct sock *sk) { - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); __u32 left_bound; __u32 rtt; int ret = 0; @@ -2622,14 +2625,13 @@ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); __u32 delta = now - tp->westwood.rtt_win_sx; - if (!delta) - return; + if (delta) { + if (tp->westwood.rtt) + westwood_filter(sk, delta); - if (tp->westwood.rtt) - westwood_filter(sk, delta); - - tp->westwood.bk = 0; - tp->westwood.rtt_win_sx = tcp_time_stamp; + tp->westwood.bk = 0; + tp->westwood.rtt_win_sx = tcp_time_stamp; + } } static void westwood_update_window(struct sock *sk, __u32 now) @@ -2683,7 +2685,7 @@ static inline int westwood_may_change_cumul(struct tcp_opt *tp) { - return ((tp->westwood.cumul_ack) > westwood_mss(tp)); + return (tp->westwood.cumul_ack > westwood_mss(tp)); } static inline void westwood_partial_update(struct tcp_opt *tp) @@ -2704,7 +2706,7 @@ * delayed or partial acks. */ -static __u32 westwood_acked_count(struct sock *sk) +static inline __u32 westwood_acked_count(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -2718,7 +2720,7 @@ if (westwood_may_change_cumul(tp)) { /* Partial or delayed ack */ - if ((tp->westwood.accounted) >= (tp->westwood.cumul_ack)) + if (tp->westwood.accounted >= tp->westwood.cumul_ack) westwood_partial_update(tp); else westwood_complete_update(tp); diff -urN linux-2.4.27/net/ipv4/tcp_ipv4.c linux-2.4.28/net/ipv4/tcp_ipv4.c --- linux-2.4.27/net/ipv4/tcp_ipv4.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv4/tcp_ipv4.c 2004-11-17 03:54:22.143420302 -0800 @@ -1025,11 +1025,7 @@ switch (type) { case ICMP_SOURCE_QUENCH: - /* This is deprecated, but if someone generated it, - * we have no reasons to ignore it. - */ - if (sk->lock.users == 0) - tcp_enter_cwr(tp); + /* Just silently ignore these. */ goto out; case ICMP_PARAMETERPROB: err = EPROTO; diff -urN linux-2.4.27/net/ipv4/tcp_minisocks.c linux-2.4.28/net/ipv4/tcp_minisocks.c --- linux-2.4.27/net/ipv4/tcp_minisocks.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv4/tcp_minisocks.c 2004-11-17 03:54:22.144420343 -0800 @@ -788,7 +788,7 @@ newtp->mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); - tcp_vegas_init(newtp); + tcp_ca_init(newtp); TCP_INC_STATS_BH(TcpPassiveOpens); } return newsk; diff -urN linux-2.4.27/net/ipv4/tcp_output.c linux-2.4.28/net/ipv4/tcp_output.c --- linux-2.4.27/net/ipv4/tcp_output.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv4/tcp_output.c 2004-11-17 03:54:22.145420384 -0800 @@ -1197,7 +1197,7 @@ tp->window_clamp = dst->window; tp->advmss = dst->advmss; tcp_initialize_rcv_mss(sk); - tcp_vegas_init(tp); + tcp_ca_init(tp); tcp_select_initial_window(tcp_full_space(sk), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), @@ -1248,7 +1248,7 @@ TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; - tcp_vegas_init(tp); + tcp_ca_init(tp); /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; diff -urN linux-2.4.27/net/ipv6/addrconf.c linux-2.4.28/net/ipv6/addrconf.c --- linux-2.4.27/net/ipv6/addrconf.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/ipv6/addrconf.c 2004-11-17 03:54:22.146420425 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $ diff -urN linux-2.4.27/net/ipv6/af_inet6.c linux-2.4.28/net/ipv6/af_inet6.c --- linux-2.4.27/net/ipv6/af_inet6.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/af_inet6.c 2004-11-17 03:54:22.147420467 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Adapted from linux/net/ipv4/af_inet.c * diff -urN linux-2.4.27/net/ipv6/datagram.c linux-2.4.28/net/ipv6/datagram.c --- linux-2.4.27/net/ipv6/datagram.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.28/net/ipv6/datagram.c 2004-11-17 03:54:22.148420508 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: datagram.c,v 1.23 2001/09/01 00:31:50 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/exthdrs.c linux-2.4.28/net/ipv6/exthdrs.c --- linux-2.4.27/net/ipv6/exthdrs.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv6/exthdrs.c 2004-11-17 03:54:22.148420508 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Andi Kleen * Alexey Kuznetsov * @@ -293,9 +293,11 @@ dst_release(xchg(&skb->dst, NULL)); ip6_route_input(skb); if (skb->dst->error) { + skb_push(skb, skb->data - skb->nh.raw); skb->dst->input(skb); 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, @@ -307,6 +309,7 @@ goto looped_back; } + skb_push(skb, skb->data - skb->nh.raw); skb->dst->input(skb); return -1; } diff -urN linux-2.4.27/net/ipv6/icmp.c linux-2.4.28/net/ipv6/icmp.c --- linux-2.4.27/net/ipv6/icmp.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/icmp.c 2004-11-17 03:54:22.149420549 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/ip6_fib.c linux-2.4.28/net/ipv6/ip6_fib.c --- linux-2.4.27/net/ipv6/ip6_fib.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv6/ip6_fib.c 2004-11-17 03:54:22.150420590 -0800 @@ -3,7 +3,7 @@ * Forwarding Information Database * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/ip6_input.c linux-2.4.28/net/ipv6/ip6_input.c --- linux-2.4.27/net/ipv6/ip6_input.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv6/ip6_input.c 2004-11-17 03:54:22.150420590 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Ian P. Morris * * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $ diff -urN linux-2.4.27/net/ipv6/ip6_output.c linux-2.4.28/net/ipv6/ip6_output.c --- linux-2.4.27/net/ipv6/ip6_output.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv6/ip6_output.c 2004-11-17 03:54:22.151420631 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ip6_output.c,v 1.33 2001/09/20 00:35:35 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/ipv6_sockglue.c linux-2.4.28/net/ipv6/ipv6_sockglue.c --- linux-2.4.27/net/ipv6/ipv6_sockglue.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv6/ipv6_sockglue.c 2004-11-17 03:54:22.152420672 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Based on linux/net/ipv4/ip_sockglue.c * diff -urN linux-2.4.27/net/ipv6/mcast.c linux-2.4.28/net/ipv6/mcast.c --- linux-2.4.27/net/ipv6/mcast.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/mcast.c 2004-11-17 03:54:22.153420713 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/ndisc.c linux-2.4.28/net/ipv6/ndisc.c --- linux-2.4.27/net/ipv6/ndisc.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/ipv6/ndisc.c 2004-11-17 03:54:22.154420754 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Mike Shaver * * This program is free software; you can redistribute it and/or @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -240,15 +241,14 @@ static u32 ndisc_hash(const void *pkey, const struct net_device *dev) { - u32 hash_val; + const u32 *p32 = pkey; + u32 addr_hash, i; - hash_val = *(u32*)(pkey + sizeof(struct in6_addr) - 4); - hash_val ^= (hash_val>>16); - hash_val ^= hash_val>>8; - hash_val ^= hash_val>>3; - hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + addr_hash = 0; + for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) + addr_hash ^= *p32++; - return hash_val; + return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd); } static int ndisc_constructor(struct neighbour *neigh) @@ -696,9 +696,9 @@ int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST; if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); /* * update / create cache entry @@ -741,9 +741,9 @@ if (addr_type & IPV6_ADDR_UNICAST) { int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST; if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); /* * update / create cache entry @@ -775,9 +775,11 @@ inc == 0 || in6_dev->nd_parms->proxy_delay == 0) { if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, + rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, + rcv_probes_ucast); neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev); diff -urN linux-2.4.27/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.28/net/ipv6/netfilter/ip6t_LOG.c --- linux-2.4.27/net/ipv6/netfilter/ip6t_LOG.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv6/netfilter/ip6t_LOG.c 2004-11-17 03:54:22.155420796 -0800 @@ -56,7 +56,7 @@ repeatedly...with a large stick...no, an even LARGER stick...no, you're still not thinking big enough */ nexthdr = **hdrptr; - hdrlen = *hdrptr[1] * 4 + 8; + hdrlen = (*hdrptr)[1] * 4 + 8; *hdrptr = *hdrptr + hdrlen; break; /*stupid rfc2402 */ @@ -64,7 +64,7 @@ case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: nexthdr = **hdrptr; - hdrlen = *hdrptr[1] * 8 + 8; + hdrlen = (*hdrptr)[1] * 8 + 8; *hdrptr = *hdrptr + hdrlen; break; case IPPROTO_FRAGMENT: diff -urN linux-2.4.27/net/ipv6/protocol.c linux-2.4.28/net/ipv6/protocol.c --- linux-2.4.27/net/ipv6/protocol.c 2001-05-19 17:56:43.000000000 -0700 +++ linux-2.4.28/net/ipv6/protocol.c 2004-11-17 03:54:22.156420837 -0800 @@ -7,7 +7,7 @@ * * Version: $Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $ * - * Authors: Pedro Roque + * Authors: Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -urN linux-2.4.27/net/ipv6/raw.c linux-2.4.28/net/ipv6/raw.c --- linux-2.4.27/net/ipv6/raw.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/raw.c 2004-11-17 03:54:22.156420837 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Adapted from linux/net/ipv4/raw.c * diff -urN linux-2.4.27/net/ipv6/reassembly.c linux-2.4.28/net/ipv6/reassembly.c --- linux-2.4.27/net/ipv6/reassembly.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/ipv6/reassembly.c 2004-11-17 03:54:22.157420878 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $ * @@ -191,14 +191,18 @@ atomic_t ip6_frag_mem = ATOMIC_INIT(0); /* Memory Tracking Functions. */ -static inline void frag_kfree_skb(struct sk_buff *skb) +static inline void frag_kfree_skb(struct sk_buff *skb, int *work) { + if (work) + *work -= skb->truesize; atomic_sub(skb->truesize, &ip6_frag_mem); kfree_skb(skb); } -static inline void frag_free_queue(struct frag_queue *fq) +static inline void frag_free_queue(struct frag_queue *fq, int *work) { + if (work) + *work -= sizeof(struct frag_queue); atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem); kfree(fq); } @@ -216,7 +220,7 @@ /* Destruction primitives. */ /* Complete destruction of fq. */ -static void ip6_frag_destroy(struct frag_queue *fq) +static void ip6_frag_destroy(struct frag_queue *fq, int *work) { struct sk_buff *fp; @@ -228,17 +232,17 @@ while (fp) { struct sk_buff *xp = fp->next; - frag_kfree_skb(fp); + frag_kfree_skb(fp, work); fp = xp; } - frag_free_queue(fq); + frag_free_queue(fq, work); } -static __inline__ void fq_put(struct frag_queue *fq) +static __inline__ void fq_put(struct frag_queue *fq, int *work) { if (atomic_dec_and_test(&fq->refcnt)) - ip6_frag_destroy(fq); + ip6_frag_destroy(fq, work); } /* Kill fq entry. It is not destroyed immediately, @@ -260,10 +264,13 @@ { struct frag_queue *fq; struct list_head *tmp; + int work; - for(;;) { - if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) - return; + work = atomic_read(&ip6_frag_mem) - sysctl_ip6frag_low_thresh; + if (work <= 0) + return; + + while(work > 0) { read_lock(&ip6_frag_lock); if (list_empty(&ip6_frag_lru_list)) { read_unlock(&ip6_frag_lock); @@ -279,7 +286,7 @@ fq_kill(fq); spin_unlock(&fq->lock); - fq_put(fq); + fq_put(fq, &work); IP6_INC_STATS_BH(Ip6ReasmFails); } } @@ -316,7 +323,7 @@ } out: spin_unlock(&fq->lock); - fq_put(fq); + fq_put(fq, NULL); } /* Creation primitives. */ @@ -336,7 +343,7 @@ atomic_inc(&fq->refcnt); write_unlock(&ip6_frag_lock); fq_in->last_in |= COMPLETE; - fq_put(fq_in); + fq_put(fq_in, NULL); return fq; } } @@ -533,7 +540,7 @@ fq->fragments = next; fq->meat -= free_it->len; - frag_kfree_skb(free_it); + frag_kfree_skb(free_it, NULL); } } @@ -733,7 +740,7 @@ ret = ip6_frag_reasm(fq, skbp, dev); spin_unlock(&fq->lock); - fq_put(fq); + fq_put(fq, NULL); return ret; } diff -urN linux-2.4.27/net/ipv6/route.c linux-2.4.28/net/ipv6/route.c --- linux-2.4.27/net/ipv6/route.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/ipv6/route.c 2004-11-17 03:54:22.158420919 -0800 @@ -3,7 +3,7 @@ * FIB front-end. * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $ * diff -urN linux-2.4.27/net/ipv6/sit.c linux-2.4.28/net/ipv6/sit.c --- linux-2.4.27/net/ipv6/sit.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/sit.c 2004-11-17 03:54:22.159420960 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * $Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $ @@ -500,6 +500,7 @@ goto tx_error_icmp; } if (rt->rt_type != RTN_UNICAST) { + ip_rt_put(rt); tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; } diff -urN linux-2.4.27/net/ipv6/tcp_ipv6.c linux-2.4.28/net/ipv6/tcp_ipv6.c --- linux-2.4.27/net/ipv6/tcp_ipv6.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/tcp_ipv6.c 2004-11-17 03:54:22.161421042 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: tcp_ipv6.c,v 1.142.2.1 2001/12/21 05:06:08 davem Exp $ * @@ -978,11 +978,11 @@ * and then put it into the queue to be sent. */ - buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC); + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr), GFP_ATOMIC); if (buff == NULL) return; - skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr)); + skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)); t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr)); @@ -1037,14 +1037,14 @@ struct flowi fl; int tot_len = sizeof(struct tcphdr); - buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC); + if (ts) + tot_len += 3*4; + + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (buff == NULL) return; - skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr)); - - if (ts) - tot_len += 3*4; + skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); t1 = (struct tcphdr *) skb_push(buff,tot_len); diff -urN linux-2.4.27/net/ipv6/udp.c linux-2.4.28/net/ipv6/udp.c --- linux-2.4.27/net/ipv6/udp.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/ipv6/udp.c 2004-11-17 03:54:22.161421042 -0800 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Based on linux/ipv4/udp.c * diff -urN linux-2.4.27/net/ipx/af_ipx.c linux-2.4.28/net/ipx/af_ipx.c --- linux-2.4.27/net/ipx/af_ipx.c 2001-09-30 12:26:13.000000000 -0700 +++ linux-2.4.28/net/ipx/af_ipx.c 2004-11-17 03:54:22.163421124 -0800 @@ -1544,7 +1544,8 @@ ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr)); IPX_SKB_CB(skb)->ipx_tctrl = 0; ipx->ipx_type = usipx->sipx_type; - skb->h.raw = (void *)skb->nh.ipxh = ipx; + skb->nh.ipxh = ipx; + skb->h.raw = (void *)skb->nh.ipxh; IPX_SKB_CB(skb)->last_hop.index = -1; #ifdef CONFIG_IPX_INTERN diff -urN linux-2.4.27/net/irda/ircomm/ircomm_param.c linux-2.4.28/net/irda/ircomm/ircomm_param.c --- linux-2.4.27/net/irda/ircomm/ircomm_param.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/irda/ircomm/ircomm_param.c 2004-11-17 03:54:22.164421166 -0800 @@ -198,7 +198,7 @@ IRDA_DEBUG(2, "%s(), No common service type to use!\n", __FUNCTION__); return -1; } - IRDA_DEBUG(0, __FUNCTION__ "%s(), services in common=%02x\n", __FUNCTION__, + IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ , service_type); /* diff -urN linux-2.4.27/net/irda/irlmp.c linux-2.4.28/net/irda/irlmp.c --- linux-2.4.27/net/irda/irlmp.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.28/net/irda/irlmp.c 2004-11-17 03:54:22.165421207 -0800 @@ -1241,7 +1241,7 @@ /* Get the number of lsap. That's the only safe way to know * that we have looped around... - Jean II */ lsap_todo = HASHBIN_GET_SIZE(self->lsaps); - IRDA_DEBUG(4, __FUNCTION__ "() : %d lsaps to scan\n", lsap_todo); + IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __FUNCTION__ , lsap_todo); /* Poll lsap in order until the queue is full or until we * tried them all. @@ -1255,7 +1255,7 @@ /* Note that if there is only one LSAP on the LAP * (most common case), self->flow_next is always NULL, * so we always avoid this loop. - Jean II */ - IRDA_DEBUG(4, __FUNCTION__ "() : searching my LSAP\n"); + IRDA_DEBUG(4, "%s() : searching my LSAP\n", __FUNCTION__ ); /* We look again in hashbins, because the lsap * might have gone away... - Jean II */ @@ -1274,14 +1274,14 @@ /* Next time, we will get the next one (or the first one) */ self->flow_next = (struct lsap_cb *) hashbin_get_next(self->lsaps); - IRDA_DEBUG(4, __FUNCTION__ "() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); + IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __FUNCTION__ , curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); /* Inform lsap user that it can send one more packet. */ if (curr->notify.flow_indication != NULL) curr->notify.flow_indication(curr->notify.instance, curr, flow); else - IRDA_DEBUG(1, __FUNCTION__ "(), no handler\n"); + IRDA_DEBUG(1, "%s(), no handler\n", __FUNCTION__ ); } } diff -urN linux-2.4.27/net/irda/wrapper.c linux-2.4.28/net/irda/wrapper.c --- linux-2.4.27/net/irda/wrapper.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/irda/wrapper.c 2004-11-17 03:54:22.166421248 -0800 @@ -37,8 +37,6 @@ #include #include -static inline int stuff_byte(__u8 byte, __u8 *buf); - static void state_outside_frame(struct net_device *dev, struct net_device_stats *stats, iobuff_t *rx_buff, __u8 byte); @@ -62,6 +60,32 @@ }; /* + * Function stuff_byte (byte, buf) + * + * Byte stuff one single byte and put the result in buffer pointed to by + * buf. The buffer must at all times be able to have two bytes inserted. + * + */ +static inline int stuff_byte(__u8 byte, __u8 *buf) +{ + switch (byte) { + case BOF: /* FALLTHROUGH */ + case EOF: /* FALLTHROUGH */ + case CE: + /* Insert transparently coded */ + buf[0] = CE; /* Send link escape */ + buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */ + return 2; + /* break; */ + default: + /* Non-special value, no transparency required */ + buf[0] = byte; + return 1; + /* break; */ + } +} + +/* * Function async_wrap (skb, *tx_buff, buffsize) * * Makes a new buffer with wrapping and stuffing, should check that @@ -140,32 +164,6 @@ } /* - * Function stuff_byte (byte, buf) - * - * Byte stuff one single byte and put the result in buffer pointed to by - * buf. The buffer must at all times be able to have two bytes inserted. - * - */ -static inline int stuff_byte(__u8 byte, __u8 *buf) -{ - switch (byte) { - case BOF: /* FALLTHROUGH */ - case EOF: /* FALLTHROUGH */ - case CE: - /* Insert transparently coded */ - buf[0] = CE; /* Send link escape */ - buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */ - return 2; - /* break; */ - default: - /* Non-special value, no transparency required */ - buf[0] = byte; - return 1; - /* break; */ - } -} - -/* * Function async_bump (buf, len, stats) * * Got a frame, make a copy of it, and pass it up the stack! We can try diff -urN linux-2.4.27/net/netsyms.c linux-2.4.28/net/netsyms.c --- linux-2.4.27/net/netsyms.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/netsyms.c 2004-11-17 03:54:22.167421289 -0800 @@ -179,9 +179,13 @@ EXPORT_SYMBOL(neigh_update); EXPORT_SYMBOL(neigh_create); EXPORT_SYMBOL(neigh_lookup); +EXPORT_SYMBOL(neigh_lookup_nodev); EXPORT_SYMBOL(__neigh_event_send); EXPORT_SYMBOL(neigh_event_ns); EXPORT_SYMBOL(neigh_ifdown); +EXPORT_SYMBOL(neigh_seq_start); +EXPORT_SYMBOL(neigh_seq_next); +EXPORT_SYMBOL(neigh_seq_stop); #ifdef CONFIG_ARPD EXPORT_SYMBOL(neigh_app_ns); #endif @@ -283,6 +287,7 @@ EXPORT_SYMBOL(inetdev_by_index); EXPORT_SYMBOL(in_dev_finish_destroy); EXPORT_SYMBOL(ip_defrag); +EXPORT_SYMBOL(ipfrag_flush); /* Route manipulation */ EXPORT_SYMBOL(ip_rt_ioctl); diff -urN linux-2.4.27/net/packet/af_packet.c linux-2.4.28/net/packet/af_packet.c --- linux-2.4.27/net/packet/af_packet.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/packet/af_packet.c 2004-11-17 03:54:22.168421330 -0800 @@ -1777,6 +1777,7 @@ atomic_inc(&po->mapped); start = vma->vm_start; + vma->vm_flags |= VM_IO; err = -EAGAIN; for (i=0; ipg_vec_len; i++) { if (remap_page_range(start, __pa(po->pg_vec[i]), diff -urN linux-2.4.27/net/sched/cls_fw.c linux-2.4.28/net/sched/cls_fw.c --- linux-2.4.27/net/sched/cls_fw.c 2001-12-21 09:42:06.000000000 -0800 +++ linux-2.4.28/net/sched/cls_fw.c 2004-11-17 03:54:22.168421330 -0800 @@ -292,7 +292,7 @@ } if (arg->fn(tp, (unsigned long)f, arg) < 0) { arg->stop = 1; - break; + return; } arg->count++; } diff -urN linux-2.4.27/net/sched/cls_route.c linux-2.4.28/net/sched/cls_route.c --- linux-2.4.27/net/sched/cls_route.c 2001-12-21 09:42:06.000000000 -0800 +++ linux-2.4.28/net/sched/cls_route.c 2004-11-17 03:54:22.169421371 -0800 @@ -541,7 +541,7 @@ } if (arg->fn(tp, (unsigned long)f, arg) < 0) { arg->stop = 1; - break; + return; } arg->count++; } diff -urN linux-2.4.27/net/sched/cls_rsvp.h linux-2.4.28/net/sched/cls_rsvp.h --- linux-2.4.27/net/sched/cls_rsvp.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.28/net/sched/cls_rsvp.h 2004-11-17 03:54:22.170421412 -0800 @@ -604,7 +604,7 @@ } if (arg->fn(tp, (unsigned long)f, arg) < 0) { arg->stop = 1; - break; + return; } arg->count++; } diff -urN linux-2.4.27/net/sched/cls_u32.c linux-2.4.28/net/sched/cls_u32.c --- linux-2.4.27/net/sched/cls_u32.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.28/net/sched/cls_u32.c 2004-11-17 03:54:22.170421412 -0800 @@ -73,7 +73,6 @@ struct tc_u_common *tp_c; int refcnt; unsigned divisor; - u32 hgenerator; struct tc_u_knode *ht[1]; }; diff -urN linux-2.4.27/net/sched/estimator.c linux-2.4.28/net/sched/estimator.c --- linux-2.4.27/net/sched/estimator.c 1999-06-09 14:45:37.000000000 -0700 +++ linux-2.4.28/net/sched/estimator.c 2004-11-17 03:54:22.171421453 -0800 @@ -66,15 +66,11 @@ * Minimal interval is HZ/4=250msec (it is the greatest common divisor for HZ=100 and HZ=1024 8)), maximal interval - is (HZ/4)*2^EST_MAX_INTERVAL = 8sec. Shorter intervals + is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals are too expensive, longer ones can be implemented at user level painlessly. */ -#if (HZ%4) != 0 -#error Bad HZ value. -#endif - #define EST_MAX_INTERVAL 5 struct qdisc_estimator @@ -127,7 +123,7 @@ spin_unlock(st->lock); } - mod_timer(&elist[idx].timer, jiffies + ((HZ/4)<next == NULL) { init_timer(&elist[est->interval].timer); elist[est->interval].timer.data = est->interval; - elist[est->interval].timer.expires = jiffies + ((HZ/4)<interval); + elist[est->interval].timer.expires = jiffies + ((HZ<interval)/4); elist[est->interval].timer.function = est_timer; add_timer(&elist[est->interval].timer); } diff -urN linux-2.4.27/net/sched/sch_api.c linux-2.4.28/net/sched/sch_api.c --- linux-2.4.27/net/sched/sch_api.c 2002-11-28 15:53:16.000000000 -0800 +++ linux-2.4.28/net/sched/sch_api.c 2004-11-17 03:54:22.172421494 -0800 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -193,7 +194,7 @@ { struct Qdisc *q; - for (q = dev->qdisc_list; q; q = q->next) { + list_for_each_entry(q, &dev->qdisc_list, list) { if (q->handle == handle) return q; } @@ -306,7 +307,7 @@ write_lock(&qdisc_tree_lock); spin_lock_bh(&dev->queue_lock); - if (qdisc && qdisc->flags&TCQ_F_INGRES) { + if (qdisc && qdisc->flags&TCQ_F_INGRESS) { oqdisc = dev->qdisc_ingress; /* Prune old scheduler */ if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) { @@ -356,7 +357,7 @@ if (parent == NULL) { - if (q && q->flags&TCQ_F_INGRES) { + if (q && q->flags&TCQ_F_INGRESS) { *old = dev_graft_qdisc(dev, q); } else { *old = dev_graft_qdisc(dev, new); @@ -370,6 +371,8 @@ unsigned long cl = cops->get(parent, classid); if (cl) { err = cops->graft(parent, cl, new, old); + if (new) + new->parent = classid; cops->put(parent, cl); } } @@ -424,10 +427,11 @@ memset(sch, 0, size); + INIT_LIST_HEAD(&sch->list); skb_queue_head_init(&sch->q); if (handle == TC_H_INGRESS) - sch->flags |= TCQ_F_INGRES; + sch->flags |= TCQ_F_INGRESS; sch->ops = ops; sch->enqueue = ops->enqueue; @@ -449,8 +453,7 @@ if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) { write_lock(&qdisc_tree_lock); - sch->next = dev->qdisc_list; - dev->qdisc_list = sch; + list_add_tail(&sch->list, &dev->qdisc_list); write_unlock(&qdisc_tree_lock); #ifdef CONFIG_NET_ESTIMATOR if (tca[TCA_RATE-1]) @@ -805,15 +808,18 @@ if (idx > s_idx) s_q_idx = 0; read_lock(&qdisc_tree_lock); - for (q = dev->qdisc_list, q_idx = 0; q; - q = q->next, q_idx++) { - if (q_idx < s_q_idx) + q_idx = 0; + list_for_each_entry(q, &dev->qdisc_list, list) { + if (q_idx < s_q_idx) { + q_idx++; continue; - if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid, + } + if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { read_unlock(&qdisc_tree_lock); goto done; } + q_idx++; } read_unlock(&qdisc_tree_lock); } @@ -1024,13 +1030,16 @@ return 0; s_t = cb->args[0]; + t = 0; read_lock(&qdisc_tree_lock); - for (q=dev->qdisc_list, t=0; q; q = q->next, t++) { - if (t < s_t) continue; - if (!q->ops->cl_ops) continue; - if (tcm->tcm_parent && TC_H_MAJ(tcm->tcm_parent) != q->handle) + list_for_each_entry(q, &dev->qdisc_list, list) { + if (t < s_t || !q->ops->cl_ops || + (tcm->tcm_parent && + TC_H_MAJ(tcm->tcm_parent) != q->handle)) { + t++; continue; + } if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); arg.w.fn = qdisc_class_dump; @@ -1043,6 +1052,7 @@ cb->args[1] = arg.w.count; if (arg.w.stop) break; + t++; } read_unlock(&qdisc_tree_lock); diff -urN linux-2.4.27/net/sched/sch_atm.c linux-2.4.28/net/sched/sch_atm.c --- linux-2.4.27/net/sched/sch_atm.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/sched/sch_atm.c 2004-11-17 03:54:22.173421536 -0800 @@ -566,7 +566,6 @@ struct atm_qdisc_data *p = PRIV(sch); DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - memset(p,0,sizeof(*p)); p->flows = &p->link; if(!(p->link.q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops))) p->link.q = &noop_qdisc; diff -urN linux-2.4.27/net/sched/sch_cbq.c linux-2.4.28/net/sched/sch_cbq.c --- linux-2.4.27/net/sched/sch_cbq.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sched/sch_cbq.c 2004-11-17 03:54:22.174421577 -0800 @@ -1641,7 +1641,6 @@ cl->xstats.undertime = 0; if (!PSCHED_IS_PASTPERFECT(cl->undertime)) cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now); - q->link.xstats.avgidle = q->link.avgidle; if (cbq_copy_xstats(skb, &cl->xstats)) { spin_unlock_bh(&sch->dev->queue_lock); goto rtattr_failure; @@ -1712,15 +1711,20 @@ } } -static void cbq_destroy_class(struct cbq_class *cl) +static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl) { + struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; + + BUG_TRAP(!cl->filters); + cbq_destroy_filters(cl); qdisc_destroy(cl->q); qdisc_put_rtab(cl->R_tab); #ifdef CONFIG_NET_ESTIMATOR qdisc_kill_estimator(&cl->stats); #endif - kfree(cl); + if (cl != &q->link) + kfree(cl); } static void @@ -1733,22 +1737,24 @@ #ifdef CONFIG_NET_CLS_POLICE q->rx_class = NULL; #endif - for (h = 0; h < 16; h++) { + /* + * Filters must be destroyed first because we don't destroy the + * classes from root to leafs which means that filters can still + * be bound to classes which have been destroyed already. --TGR '04 + */ + for (h = 0; h < 16; h++) for (cl = q->classes[h]; cl; cl = cl->next) cbq_destroy_filters(cl); - } for (h = 0; h < 16; h++) { struct cbq_class *next; for (cl = q->classes[h]; cl; cl = next) { next = cl->next; - if (cl != &q->link) - cbq_destroy_class(cl); + cbq_destroy_class(sch, cl); } } - qdisc_put_rtab(q->link.R_tab); MOD_DEC_USE_COUNT; } @@ -1766,7 +1772,7 @@ spin_unlock_bh(&sch->dev->queue_lock); #endif - cbq_destroy_class(cl); + cbq_destroy_class(sch, cl); } } @@ -2000,7 +2006,7 @@ sch_tree_unlock(sch); if (--cl->refcnt == 0) - cbq_destroy_class(cl); + cbq_destroy_class(sch, cl); return 0; } diff -urN linux-2.4.27/net/sched/sch_dsmark.c linux-2.4.28/net/sched/sch_dsmark.c --- linux-2.4.27/net/sched/sch_dsmark.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sched/sch_dsmark.c 2004-11-17 03:54:22.175421618 -0800 @@ -329,8 +329,6 @@ !tb[TCA_DSMARK_INDICES-1] || RTA_PAYLOAD(tb[TCA_DSMARK_INDICES-1]) < sizeof(__u16)) return -EINVAL; - memset(p,0,sizeof(*p)); - p->filter_list = NULL; p->indices = *(__u16 *) RTA_DATA(tb[TCA_DSMARK_INDICES-1]); if (!p->indices) return -EINVAL; diff -urN linux-2.4.27/net/sched/sch_generic.c linux-2.4.28/net/sched/sch_generic.c --- linux-2.4.27/net/sched/sch_generic.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/sched/sch_generic.c 2004-11-17 03:54:22.175421618 -0800 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -391,6 +392,7 @@ return NULL; memset(sch, 0, size); + INIT_LIST_HEAD(&sch->list); skb_queue_head_init(&sch->q); sch->ops = ops; sch->enqueue = ops->enqueue; @@ -420,22 +422,11 @@ void qdisc_destroy(struct Qdisc *qdisc) { struct Qdisc_ops *ops = qdisc->ops; - struct net_device *dev; - if (!atomic_dec_and_test(&qdisc->refcnt)) + if (qdisc->flags&TCQ_F_BUILTIN || + !atomic_dec_and_test(&qdisc->refcnt)) return; - - dev = qdisc->dev; - - if (dev) { - struct Qdisc *q, **qp; - for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) { - if (q == qdisc) { - *qp = q->next; - break; - } - } - } + list_del(&qdisc->list); #ifdef CONFIG_NET_ESTIMATOR qdisc_kill_estimator(&qdisc->stats); #endif @@ -443,8 +434,7 @@ ops->reset(qdisc); if (ops->destroy) ops->destroy(qdisc); - if (!(qdisc->flags&TCQ_F_BUILTIN)) - kfree(qdisc); + kfree(qdisc); } @@ -464,10 +454,8 @@ printk(KERN_INFO "%s: activation failed\n", dev->name); return; } - write_lock(&qdisc_tree_lock); - qdisc->next = dev->qdisc_list; - dev->qdisc_list = qdisc; + list_add_tail(&qdisc->list, &dev->qdisc_list); write_unlock(&qdisc_tree_lock); } else { @@ -513,7 +501,7 @@ dev->qdisc = &noop_qdisc; spin_unlock_bh(&dev->queue_lock); dev->qdisc_sleeping = &noop_qdisc; - dev->qdisc_list = NULL; + INIT_LIST_HEAD(&dev->qdisc_list); write_unlock(&qdisc_tree_lock); dev_watchdog_init(dev); @@ -535,9 +523,8 @@ qdisc_destroy(qdisc); } #endif - BUG_TRAP(dev->qdisc_list == NULL); + BUG_TRAP(list_empty(&dev->qdisc_list)); BUG_TRAP(!timer_pending(&dev->watchdog_timer)); - dev->qdisc_list = NULL; spin_unlock_bh(&dev->queue_lock); write_unlock(&qdisc_tree_lock); } diff -urN linux-2.4.27/net/sched/sch_hfsc.c linux-2.4.28/net/sched/sch_hfsc.c --- linux-2.4.27/net/sched/sch_hfsc.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sched/sch_hfsc.c 2004-11-17 03:54:22.178421741 -0800 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -131,9 +132,11 @@ struct list_head children; /* child classes */ struct Qdisc *qdisc; /* leaf qdisc */ - struct list_head actlist; /* active children list */ - struct list_head alist; /* active children list member */ - struct list_head ellist; /* eligible list member */ + rb_node_t el_node; /* qdisc's eligible tree member */ + rb_root_t vt_tree; /* active children sorted by cl_vt */ + rb_node_t vt_node; /* parent's vt_tree member */ + rb_root_t cf_tree; /* active children sorted by cl_f */ + rb_node_t cf_node; /* parent's cf_heap member */ struct list_head hlist; /* hash list member */ struct list_head dlist; /* drop list member */ @@ -159,6 +162,9 @@ adjustment */ u64 cl_vtoff; /* inter-period cumulative vt offset */ u64 cl_cvtmax; /* max child's vt in the last period */ + u64 cl_cvtoff; /* cumulative cvtmax of all periods */ + u64 cl_pcvtoff; /* parent's cvtoff at initalization + time */ struct internal_sc cl_rsc; /* internal real-time service curve */ struct internal_sc cl_fsc; /* internal fair service curve */ @@ -181,7 +187,7 @@ u16 defcls; /* default class id */ struct hfsc_class root; /* root class */ struct list_head clhash[HFSC_HSIZE]; /* class hash */ - struct list_head eligible; /* eligible list */ + rb_root_t eligible; /* eligible tree */ struct list_head droplist; /* active leaf class list (for dropping) */ struct sk_buff_head requeue; /* requeued packet */ @@ -217,82 +223,51 @@ /* - * eligible list holds backlogged classes being sorted by their eligible times. - * there is one eligible list per hfsc instance. + * eligible tree holds backlogged classes being sorted by their eligible times. + * there is one eligible tree per hfsc instance. */ static void -ellist_insert(struct hfsc_class *cl) +eltree_insert(struct hfsc_class *cl) { - struct list_head *head = &cl->sched->eligible; - struct hfsc_class *p; - - /* check the last entry first */ - if (list_empty(head) || - ((p = list_entry(head->prev, struct hfsc_class, ellist)) && - p->cl_e <= cl->cl_e)) { - list_add_tail(&cl->ellist, head); - return; - } - - list_for_each_entry(p, head, ellist) { - if (cl->cl_e < p->cl_e) { - /* insert cl before p */ - list_add_tail(&cl->ellist, &p->ellist); - return; - } + rb_node_t **p = &cl->sched->eligible.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, el_node); + if (cl->cl_e >= cl1->cl_e) + p = &parent->rb_right; + else + p = &parent->rb_left; } - ASSERT(0); /* should not reach here */ + rb_link_node(&cl->el_node, parent, p); + rb_insert_color(&cl->el_node, &cl->sched->eligible); } static inline void -ellist_remove(struct hfsc_class *cl) +eltree_remove(struct hfsc_class *cl) { - list_del(&cl->ellist); + rb_erase(&cl->el_node, &cl->sched->eligible); } -static void -ellist_update(struct hfsc_class *cl) +static inline void +eltree_update(struct hfsc_class *cl) { - struct list_head *head = &cl->sched->eligible; - struct hfsc_class *p, *last; - - /* - * the eligible time of a class increases monotonically. - * if the next entry has a larger eligible time, nothing to do. - */ - if (cl->ellist.next == head || - ((p = list_entry(cl->ellist.next, struct hfsc_class, ellist)) && - cl->cl_e <= p->cl_e)) - return; - - /* check the last entry */ - last = list_entry(head->prev, struct hfsc_class, ellist); - if (last->cl_e <= cl->cl_e) { - list_move_tail(&cl->ellist, head); - return; - } - - /* - * the new position must be between the next entry - * and the last entry - */ - list_for_each_entry_continue(p, head, ellist) { - if (cl->cl_e < p->cl_e) { - list_move_tail(&cl->ellist, &p->ellist); - return; - } - } - ASSERT(0); /* should not reach here */ + eltree_remove(cl); + eltree_insert(cl); } /* find the class with the minimum deadline among the eligible classes */ static inline struct hfsc_class * -ellist_get_mindl(struct list_head *head, u64 cur_time) +eltree_get_mindl(struct hfsc_sched *q, u64 cur_time) { struct hfsc_class *p, *cl = NULL; + rb_node_t *n; - list_for_each_entry(p, head, ellist) { + for (n = rb_first(&q->eligible); n != NULL; n = rb_next(n)) { + p = rb_entry(n, struct hfsc_class, el_node); if (p->cl_e > cur_time) break; if (cl == NULL || p->cl_d < cl->cl_d) @@ -303,92 +278,62 @@ /* find the class with minimum eligible time among the eligible classes */ static inline struct hfsc_class * -ellist_get_minel(struct list_head *head) +eltree_get_minel(struct hfsc_sched *q) { - if (list_empty(head)) + rb_node_t *n; + + n = rb_first(&q->eligible); + if (n == NULL) return NULL; - return list_entry(head->next, struct hfsc_class, ellist); + return rb_entry(n, struct hfsc_class, el_node); } /* - * active children list holds backlogged child classes being sorted - * by their virtual time. each intermediate class has one active - * children list. + * vttree holds holds backlogged child classes being sorted by their virtual + * time. each intermediate class has one vttree. */ static void -actlist_insert(struct hfsc_class *cl) +vttree_insert(struct hfsc_class *cl) { - struct list_head *head = &cl->cl_parent->actlist; - struct hfsc_class *p; - - /* check the last entry first */ - if (list_empty(head) || - ((p = list_entry(head->prev, struct hfsc_class, alist)) && - p->cl_vt <= cl->cl_vt)) { - list_add_tail(&cl->alist, head); - return; - } - - list_for_each_entry(p, head, alist) { - if (cl->cl_vt < p->cl_vt) { - /* insert cl before p */ - list_add_tail(&cl->alist, &p->alist); - return; - } + rb_node_t **p = &cl->cl_parent->vt_tree.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, vt_node); + if (cl->cl_vt >= cl1->cl_vt) + p = &parent->rb_right; + else + p = &parent->rb_left; } - ASSERT(0); /* should not reach here */ + rb_link_node(&cl->vt_node, parent, p); + rb_insert_color(&cl->vt_node, &cl->cl_parent->vt_tree); } static inline void -actlist_remove(struct hfsc_class *cl) +vttree_remove(struct hfsc_class *cl) { - list_del(&cl->alist); + rb_erase(&cl->vt_node, &cl->cl_parent->vt_tree); } -static void -actlist_update(struct hfsc_class *cl) +static inline void +vttree_update(struct hfsc_class *cl) { - struct list_head *head = &cl->cl_parent->actlist; - struct hfsc_class *p, *last; - - /* - * the virtual time of a class increases monotonically. - * if the next entry has a larger virtual time, nothing to do. - */ - if (cl->alist.next == head || - ((p = list_entry(cl->alist.next, struct hfsc_class, alist)) && - cl->cl_vt <= p->cl_vt)) - return; - - /* check the last entry */ - last = list_entry(head->prev, struct hfsc_class, alist); - if (last->cl_vt <= cl->cl_vt) { - list_move_tail(&cl->alist, head); - return; - } - - /* - * the new position must be between the next entry - * and the last entry - */ - list_for_each_entry_continue(p, head, alist) { - if (cl->cl_vt < p->cl_vt) { - list_move_tail(&cl->alist, &p->alist); - return; - } - } - ASSERT(0); /* should not reach here */ + vttree_remove(cl); + vttree_insert(cl); } static inline struct hfsc_class * -actlist_firstfit(struct hfsc_class *cl, u64 cur_time) +vttree_firstfit(struct hfsc_class *cl, u64 cur_time) { struct hfsc_class *p; + rb_node_t *n; - list_for_each_entry(p, &cl->actlist, alist) { - if (p->cl_f <= cur_time) { + for (n = rb_first(&cl->vt_tree); n != NULL; n = rb_next(n)) { + p = rb_entry(n, struct hfsc_class, vt_node); + if (p->cl_f <= cur_time) return p; - } } return NULL; } @@ -397,14 +342,14 @@ * get the leaf class with the minimum vt in the hierarchy */ static struct hfsc_class * -actlist_get_minvt(struct hfsc_class *cl, u64 cur_time) +vttree_get_minvt(struct hfsc_class *cl, u64 cur_time) { /* if root-class's cfmin is bigger than cur_time nothing to do */ if (cl->cl_cfmin > cur_time) return NULL; while (cl->level > 0) { - cl = actlist_firstfit(cl, cur_time); + cl = vttree_firstfit(cl, cur_time); if (cl == NULL) return NULL; /* @@ -416,6 +361,38 @@ return cl; } +static void +cftree_insert(struct hfsc_class *cl) +{ + rb_node_t **p = &cl->cl_parent->cf_tree.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, cf_node); + if (cl->cl_f >= cl1->cl_f) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&cl->cf_node, parent, p); + rb_insert_color(&cl->cf_node, &cl->cl_parent->cf_tree); +} + +static inline void +cftree_remove(struct hfsc_class *cl) +{ + rb_erase(&cl->cf_node, &cl->cl_parent->cf_tree); +} + +static inline void +cftree_update(struct hfsc_class *cl) +{ + cftree_remove(cl); + cftree_insert(cl); +} + /* * service curve support functions * @@ -709,7 +686,7 @@ cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); - ellist_insert(cl); + eltree_insert(cl); } static void @@ -718,7 +695,7 @@ cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); - ellist_update(cl); + eltree_update(cl); } static inline void @@ -727,32 +704,25 @@ cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); } -static void +static inline void update_cfmin(struct hfsc_class *cl) { + rb_node_t *n = rb_first(&cl->cf_tree); struct hfsc_class *p; - u64 cfmin; - if (list_empty(&cl->actlist)) { + if (n == NULL) { cl->cl_cfmin = 0; return; } - cfmin = HT_INFINITY; - list_for_each_entry(p, &cl->actlist, alist) { - if (p->cl_f == 0) { - cl->cl_cfmin = 0; - return; - } - if (p->cl_f < cfmin) - cfmin = p->cl_f; - } - cl->cl_cfmin = cfmin; + p = rb_entry(n, struct hfsc_class, cf_node); + cl->cl_cfmin = p->cl_f; } static void init_vf(struct hfsc_class *cl, unsigned int len) { - struct hfsc_class *max_cl, *p; + struct hfsc_class *max_cl; + rb_node_t *n; u64 vt, f, cur_time; int go_active; @@ -765,9 +735,9 @@ go_active = 0; if (go_active) { - if (!list_empty(&cl->cl_parent->actlist)) { - max_cl = list_entry(cl->cl_parent->actlist.prev, - struct hfsc_class, alist); + n = rb_last(&cl->cl_parent->vt_tree); + if (n != NULL) { + max_cl = rb_entry(n, struct hfsc_class,vt_node); /* * set vt to the average of the min and max * classes. if the parent's period didn't @@ -783,19 +753,20 @@ } else { /* * first child for a new parent backlog period. - * add parent's cvtmax to vtoff of children - * to make a new vt (vtoff + vt) larger than - * the vt in the last period for all children. + * add parent's cvtmax to cvtoff to make a new + * vt (vtoff + vt) larger than the vt in the + * last period for all children. */ vt = cl->cl_parent->cl_cvtmax; - list_for_each_entry(p, &cl->cl_parent->children, - siblings) - p->cl_vtoff += vt; - cl->cl_vt = 0; + cl->cl_parent->cl_cvtoff += vt; cl->cl_parent->cl_cvtmax = 0; cl->cl_parent->cl_cvtmin = 0; + cl->cl_vt = 0; } + cl->cl_vtoff = cl->cl_parent->cl_cvtoff - + cl->cl_pcvtoff; + /* update the virtual curve */ vt = cl->cl_vt + cl->cl_vtoff; rtsc_min(&cl->cl_virtual, &cl->cl_fsc, vt, @@ -812,7 +783,8 @@ cl->cl_parentperiod++; cl->cl_f = 0; - actlist_insert(cl); + vttree_insert(cl); + cftree_insert(cl); if (cl->cl_flags & HFSC_USC) { /* class has upper limit curve */ @@ -832,6 +804,7 @@ f = max(cl->cl_myf, cl->cl_cfmin); if (f != cl->cl_f) { cl->cl_f = f; + cftree_update(cl); update_cfmin(cl->cl_parent); } } @@ -864,9 +837,10 @@ if (cl->cl_vt > cl->cl_parent->cl_cvtmax) cl->cl_parent->cl_cvtmax = cl->cl_vt; - /* remove this class from the vt list */ - actlist_remove(cl); + /* remove this class from the vt tree */ + vttree_remove(cl); + cftree_remove(cl); update_cfmin(cl->cl_parent); continue; @@ -888,8 +862,8 @@ cl->cl_vt = cl->cl_parent->cl_cvtmin; } - /* update the vt list */ - actlist_update(cl); + /* update the vt tree */ + vttree_update(cl); if (cl->cl_flags & HFSC_USC) { cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit, @@ -919,6 +893,7 @@ f = max(cl->cl_myf, cl->cl_cfmin); if (f != cl->cl_f) { cl->cl_f = f; + cftree_update(cl); update_cfmin(cl->cl_parent); } } @@ -939,13 +914,13 @@ set_passive(struct hfsc_class *cl) { if (cl->cl_flags & HFSC_RSC) - ellist_remove(cl); + eltree_remove(cl); list_del(&cl->dlist); /* - * actlist is now handled in update_vf() so that update_vf(cl, 0, 0) - * needs to be called explicitly to remove a class from actlist + * vttree is now handled in update_vf() so that update_vf(cl, 0, 0) + * needs to be called explicitly to remove a class from vttree. */ } @@ -1168,7 +1143,8 @@ cl->qdisc = &noop_qdisc; cl->stats.lock = &sch->dev->queue_lock; INIT_LIST_HEAD(&cl->children); - INIT_LIST_HEAD(&cl->actlist); + cl->vt_tree = RB_ROOT; + cl->cf_tree = RB_ROOT; sch_tree_lock(sch); list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); @@ -1176,6 +1152,7 @@ if (parent->level == 0) hfsc_purge_queue(sch, parent); hfsc_adjust_levels(parent); + cl->cl_pcvtoff = parent->cl_cvtoff; sch_tree_unlock(sch); #ifdef CONFIG_NET_ESTIMATOR @@ -1500,7 +1477,7 @@ u64 next_time = 0; long delay; - if ((cl = ellist_get_minel(&q->eligible)) != NULL) + if ((cl = eltree_get_minel(q)) != NULL) next_time = cl->cl_e; if (q->root.cl_cfmin != 0) { if (next_time == 0 || next_time > q->root.cl_cfmin) @@ -1525,13 +1502,12 @@ return -EINVAL; qopt = RTA_DATA(opt); - memset(q, 0, sizeof(struct hfsc_sched)); sch->stats.lock = &sch->dev->queue_lock; q->defcls = qopt->defcls; for (i = 0; i < HFSC_HSIZE; i++) INIT_LIST_HEAD(&q->clhash[i]); - INIT_LIST_HEAD(&q->eligible); + q->eligible = RB_ROOT; INIT_LIST_HEAD(&q->droplist); skb_queue_head_init(&q->requeue); @@ -1543,7 +1519,8 @@ q->root.qdisc = &noop_qdisc; q->root.stats.lock = &sch->dev->queue_lock; INIT_LIST_HEAD(&q->root.children); - INIT_LIST_HEAD(&q->root.actlist); + q->root.vt_tree = RB_ROOT; + q->root.cf_tree = RB_ROOT; list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); @@ -1584,6 +1561,8 @@ cl->cl_vtoff = 0; cl->cl_cvtmin = 0; cl->cl_cvtmax = 0; + cl->cl_cvtoff = 0; + cl->cl_pcvtoff = 0; cl->cl_vtperiod = 0; cl->cl_parentperiod = 0; cl->cl_f = 0; @@ -1591,7 +1570,9 @@ cl->cl_myfadj = 0; cl->cl_cfmin = 0; cl->cl_nactive = 0; - INIT_LIST_HEAD(&cl->actlist); + + cl->vt_tree = RB_ROOT; + cl->cf_tree = RB_ROOT; qdisc_reset(cl->qdisc); if (cl->cl_flags & HFSC_RSC) @@ -1614,7 +1595,7 @@ hfsc_reset_class(cl); } __skb_queue_purge(&q->requeue); - INIT_LIST_HEAD(&q->eligible); + q->eligible = RB_ROOT; INIT_LIST_HEAD(&q->droplist); del_timer(&q->wd_timer); sch->flags &= ~TCQ_F_THROTTLED; @@ -1647,10 +1628,6 @@ qopt.defcls = q->defcls; RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); - sch->stats.qlen = sch->q.qlen; - if (qdisc_copy_stats(skb, &sch->stats) < 0) - goto rtattr_failure; - return skb->len; rtattr_failure: @@ -1712,14 +1689,14 @@ * find the class with the minimum deadline among * the eligible classes. */ - if ((cl = ellist_get_mindl(&q->eligible, cur_time)) != NULL) { + if ((cl = eltree_get_mindl(q, cur_time)) != NULL) { realtime = 1; } else { /* * use link-sharing criteria * get the class with the minimum vt in the hierarchy */ - cl = actlist_get_minvt(&q->root, cur_time); + cl = vttree_get_minvt(&q->root, cur_time); if (cl == NULL) { sch->stats.overlimits++; hfsc_schedule_watchdog(sch, cur_time); diff -urN linux-2.4.27/net/sched/sch_htb.c linux-2.4.28/net/sched/sch_htb.c --- linux-2.4.27/net/sched/sch_htb.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sched/sch_htb.c 2004-11-17 03:54:22.179421782 -0800 @@ -77,7 +77,7 @@ #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x30010 /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" @@ -172,6 +172,11 @@ struct htb_class_inner { rb_root_t feed[TC_HTB_NUMPRIO]; /* feed trees */ rb_node_t *ptr[TC_HTB_NUMPRIO]; /* current class ptr */ + /* When class changes from state 1->2 and disconnects from + parent's feed then we lost ptr value and start from the + first child again. Here we store classid of the + last valid ptr (used when ptr is NULL). */ + u32 last_ptr_id[TC_HTB_NUMPRIO]; } inner; } un; rb_node_t node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ @@ -218,6 +223,7 @@ rb_root_t row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; int row_mask[TC_HTB_MAXDEPTH]; rb_node_t *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; + u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; /* self wait list - roots of wait PQs per row */ rb_root_t wait_pq[TC_HTB_MAXDEPTH]; @@ -576,8 +582,13 @@ int prio = ffz(~m); m &= ~(1 << prio); - if (p->un.inner.ptr[prio] == cl->node+prio) - htb_next_rb_node(p->un.inner.ptr + prio); + if (p->un.inner.ptr[prio] == cl->node+prio) { + /* we are removing child which is pointed to from + parent feed - forget the pointer but remember + classid */ + p->un.inner.last_ptr_id[prio] = cl->classid; + p->un.inner.ptr[prio] = NULL; + } htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio); @@ -908,25 +919,56 @@ return HZ/10; } +/* Returns class->node+prio from id-tree where classe's id is >= id. NULL + is no such one exists. */ +static rb_node_t * +htb_id_find_next_upper(int prio,rb_node_t *n,u32 id) +{ + rb_node_t *r = NULL; + while (n) { + struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]); + if (id == cl->classid) return n; + + if (id > cl->classid) { + n = n->rb_right; + } else { + r = n; + n = n->rb_left; + } + } + return r; +} + /** * htb_lookup_leaf - returns next leaf class in DRR order * * Find leaf where current feed pointers points to. */ static struct htb_class * -htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr) +htb_lookup_leaf(HTB_ARGQ rb_root_t *tree,int prio,rb_node_t **pptr,u32 *pid) { int i; struct { rb_node_t *root; rb_node_t **pptr; + u32 *pid; } stk[TC_HTB_MAXDEPTH],*sp = stk; BUG_TRAP(tree->rb_node); sp->root = tree->rb_node; sp->pptr = pptr; + sp->pid = pid; for (i = 0; i < 65535; i++) { + HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid); + + if (!*sp->pptr && *sp->pid) { + /* ptr was invalidated but id is valid - try to recover + the original or next ptr */ + *sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid); + } + *sp->pid = 0; /* ptr is valid now so that remove this hint as it + can become out of date quickly */ if (!*sp->pptr) { /* we are at right end; rewind & go up */ *sp->pptr = sp->root; while ((*sp->pptr)->rb_left) @@ -944,6 +986,7 @@ return cl; (++sp)->root = cl->un.inner.feed[prio].rb_node; sp->pptr = cl->un.inner.ptr+prio; + sp->pid = cl->un.inner.last_ptr_id+prio; } } BUG_TRAP(0); @@ -958,7 +1001,8 @@ struct sk_buff *skb = NULL; struct htb_class *cl,*start; /* look initial class up in the row */ - start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio, + q->ptr[level]+prio,q->last_ptr_id[level]+prio); do { next: @@ -979,8 +1023,8 @@ if ((q->row_mask[level] & (1 << prio)) == 0) return NULL; - next = htb_lookup_leaf (q->row[level]+prio, - prio,q->ptr[level]+prio); + next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio, + prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio); if (cl == start) /* fix start if we just deleted it */ start = next; cl = next; @@ -995,7 +1039,8 @@ } q->nwc_hit++; htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio); - cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio, + q->last_ptr_id[level]+prio); } while (cl != start); if (likely(skb != NULL)) { @@ -1186,7 +1231,6 @@ HTB_VER >> 16,HTB_VER & 0xffff,gopt->version); return -EINVAL; } - memset(q,0,sizeof(*q)); q->debug = gopt->debug; HTB_DBG(0,1,"htb_init sch=%p handle=%X r2q=%d\n",sch,sch->handle,gopt->rate2quantum); @@ -1243,8 +1287,6 @@ RTA_PUT(skb, TCA_OPTIONS, 0, NULL); RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); rta->rta_len = skb->tail - b; - sch->stats.qlen = sch->q.qlen; - RTA_PUT(skb, TCA_STATS, sizeof(sch->stats), &sch->stats); HTB_QUNLOCK(sch); return skb->len; rtattr_failure: diff -urN linux-2.4.27/net/sched/sch_ingress.c linux-2.4.28/net/sched/sch_ingress.c --- linux-2.4.27/net/sched/sch_ingress.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/sched/sch_ingress.c 2004-11-17 03:54:22.180421823 -0800 @@ -254,8 +254,6 @@ } DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - memset(p, 0, sizeof(*p)); - p->filter_list = NULL; p->q = &noop_qdisc; MOD_INC_USE_COUNT; return 0; @@ -296,9 +294,6 @@ p->filter_list = tp->next; tcf_destroy(tp); } - memset(p, 0, sizeof(*p)); - p->filter_list = NULL; - #if 0 /* for future use */ qdisc_destroy(p->q); diff -urN linux-2.4.27/net/sched/sch_netem.c linux-2.4.28/net/sched/sch_netem.c --- linux-2.4.27/net/sched/sch_netem.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sched/sch_netem.c 2004-11-17 03:54:22.182421906 -0800 @@ -6,13 +6,15 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * + * Many of the algorithms and ideas for this came from + * NIST Net which is not copyrighted. + * * Authors: Stephen Hemminger * Catalin(ux aka Dino) BOIE */ #include #include -#include #include #include #include @@ -20,14 +22,37 @@ #include #include #include +#include #include -/* Network emulator - * - * This scheduler can alters spacing and order - * Similar to NISTnet and BSD Dummynet. - */ +#define qdisc_priv(q) ((void *)(q->data)) + +/* Network Emulation Queuing algorithm. + ==================================== + + Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based + Network Emulation Tool + [2] Luigi Rizzo, DummyNet for FreeBSD + + ---------------------------------------------------------------- + + This started out as a simple way to delay outgoing packets to + test TCP but has grown to include most of the functionality + of a full blown network emulator like NISTnet. It can delay + packets and add random jitter (and correlation). The random + distribution can be loaded from a table as well to provide + normal, Pareto, or experimental curves. Packet loss, + duplication, and reordering can also be emulated. + + This qdisc does not do classification that can be handled in + layering other disciplines. It does not need to do bandwidth + control either since that can be handled by using token + bucket or other rate control. + + The simulator is limited by the Linux timer resolution + and will create packet bursts on the HZ boundary (1ms). +*/ struct netem_sched_data { struct Qdisc *qdisc; @@ -40,6 +65,17 @@ u32 counter; u32 gap; u32 jitter; + u32 duplicate; + + struct crndstate { + unsigned long last; + unsigned long rho; + } delay_cor, loss_cor, dup_cor; + + struct disttable { + u32 size; + s16 table[0]; + } *delay_dist; }; /* Time stamp put into socket buffer control block */ @@ -47,576 +83,114 @@ psched_time_t time_to_send; }; -/* This is the distribution table for the normal distribution produced - * with NISTnet tools. - * The entries represent a scaled inverse of the cumulative distribution - * function. +/* init_crandom - initialize correlated random number generator + * Use entropy source for initial seed. */ -#define TABLESIZE 2048 -#define TABLEFACTOR 8192 +static void init_crandom(struct crndstate *state, unsigned long rho) +{ + state->rho = rho; + state->last = net_random(); +} -static const short disttable[TABLESIZE] = { - -31473, -26739, -25226, -24269, - -23560, -22993, -22518, -22109, - -21749, -21426, -21133, -20865, - -20618, -20389, -20174, -19972, - -19782, -19601, -19430, -19267, - -19112, -18962, -18819, -18681, - -18549, -18421, -18298, -18178, - -18062, -17950, -17841, -17735, - -17632, -17532, -17434, -17339, - -17245, -17155, -17066, -16979, - -16894, -16811, -16729, -16649, - -16571, -16494, -16419, -16345, - -16272, -16201, -16130, -16061, - -15993, -15926, -15861, -15796, - -15732, -15669, -15607, -15546, - -15486, -15426, -15368, -15310, - -15253, -15196, -15140, -15086, - -15031, -14977, -14925, -14872, - -14821, -14769, -14719, -14669, - -14619, -14570, -14522, -14473, - -14426, -14379, -14332, -14286, - -14241, -14196, -14150, -14106, - -14062, -14019, -13976, -13933, - -13890, -13848, -13807, -13765, - -13724, -13684, -13643, -13604, - -13564, -13525, -13486, -13447, - -13408, -13370, -13332, -13295, - -13258, -13221, -13184, -13147, - -13111, -13075, -13040, -13004, - -12969, -12934, -12899, -12865, - -12830, -12796, -12762, -12729, - -12695, -12662, -12629, -12596, - -12564, -12531, -12499, -12467, - -12435, -12404, -12372, -12341, - -12310, -12279, -12248, -12218, - -12187, -12157, -12127, -12097, - -12067, -12038, -12008, -11979, - -11950, -11921, -11892, -11863, - -11835, -11806, -11778, -11750, - -11722, -11694, -11666, -11639, - -11611, -11584, -11557, -11530, - -11503, -11476, -11450, -11423, - -11396, -11370, -11344, -11318, - -11292, -11266, -11240, -11214, - -11189, -11164, -11138, -11113, - -11088, -11063, -11038, -11013, - -10988, -10964, -10939, -10915, - -10891, -10866, -10843, -10818, - -10794, -10770, -10747, -10723, - -10700, -10676, -10652, -10630, - -10606, -10583, -10560, -10537, - -10514, -10491, -10469, -10446, - -10424, -10401, -10378, -10356, - -10334, -10312, -10290, -10267, - -10246, -10224, -10202, -10180, - -10158, -10137, -10115, -10094, - -10072, -10051, -10030, -10009, - -9988, -9967, -9945, -9925, - -9904, -9883, -9862, -9842, - -9821, -9800, -9780, -9760, - -9739, -9719, -9699, -9678, - -9658, -9638, -9618, -9599, - -9578, -9559, -9539, -9519, - -9499, -9480, -9461, -9441, - -9422, -9402, -9383, -9363, - -9344, -9325, -9306, -9287, - -9268, -9249, -9230, -9211, - -9192, -9173, -9155, -9136, - -9117, -9098, -9080, -9062, - -9043, -9025, -9006, -8988, - -8970, -8951, -8933, -8915, - -8897, -8879, -8861, -8843, - -8825, -8807, -8789, -8772, - -8754, -8736, -8718, -8701, - -8683, -8665, -8648, -8630, - -8613, -8595, -8578, -8561, - -8543, -8526, -8509, -8492, - -8475, -8458, -8441, -8423, - -8407, -8390, -8373, -8356, - -8339, -8322, -8305, -8289, - -8272, -8255, -8239, -8222, - -8206, -8189, -8172, -8156, - -8140, -8123, -8107, -8090, - -8074, -8058, -8042, -8025, - -8009, -7993, -7977, -7961, - -7945, -7929, -7913, -7897, - -7881, -7865, -7849, -7833, - -7817, -7802, -7786, -7770, - -7754, -7739, -7723, -7707, - -7692, -7676, -7661, -7645, - -7630, -7614, -7599, -7583, - -7568, -7553, -7537, -7522, - -7507, -7492, -7476, -7461, - -7446, -7431, -7416, -7401, - -7385, -7370, -7356, -7340, - -7325, -7311, -7296, -7281, - -7266, -7251, -7236, -7221, - -7207, -7192, -7177, -7162, - -7148, -7133, -7118, -7104, - -7089, -7075, -7060, -7046, - -7031, -7016, -7002, -6988, - -6973, -6959, -6944, -6930, - -6916, -6901, -6887, -6873, - -6859, -6844, -6830, -6816, - -6802, -6788, -6774, -6760, - -6746, -6731, -6717, -6704, - -6690, -6675, -6661, -6647, - -6633, -6620, -6606, -6592, - -6578, -6564, -6550, -6537, - -6523, -6509, -6495, -6482, - -6468, -6454, -6441, -6427, - -6413, -6400, -6386, -6373, - -6359, -6346, -6332, -6318, - -6305, -6291, -6278, -6264, - -6251, -6238, -6224, -6211, - -6198, -6184, -6171, -6158, - -6144, -6131, -6118, -6105, - -6091, -6078, -6065, -6052, - -6039, -6025, -6012, -5999, - -5986, -5973, -5960, -5947, - -5934, -5921, -5908, -5895, - -5882, -5869, -5856, -5843, - -5830, -5817, -5804, -5791, - -5779, -5766, -5753, -5740, - -5727, -5714, -5702, -5689, - -5676, -5663, -5650, -5638, - -5625, -5612, -5600, -5587, - -5575, -5562, -5549, -5537, - -5524, -5512, -5499, -5486, - -5474, -5461, -5449, -5436, - -5424, -5411, -5399, -5386, - -5374, -5362, -5349, -5337, - -5324, -5312, -5299, -5287, - -5275, -5263, -5250, -5238, - -5226, -5213, -5201, -5189, - -5177, -5164, -5152, -5140, - -5128, -5115, -5103, -5091, - -5079, -5067, -5055, -5043, - -5030, -5018, -5006, -4994, - -4982, -4970, -4958, -4946, - -4934, -4922, -4910, -4898, - -4886, -4874, -4862, -4850, - -4838, -4826, -4814, -4803, - -4791, -4778, -4767, -4755, - -4743, -4731, -4719, -4708, - -4696, -4684, -4672, -4660, - -4649, -4637, -4625, -4613, - -4601, -4590, -4578, -4566, - -4554, -4543, -4531, -4520, - -4508, -4496, -4484, -4473, - -4461, -4449, -4438, -4427, - -4415, -4403, -4392, -4380, - -4368, -4357, -4345, -4334, - -4322, -4311, -4299, -4288, - -4276, -4265, -4253, -4242, - -4230, -4219, -4207, -4196, - -4184, -4173, -4162, -4150, - -4139, -4128, -4116, -4105, - -4094, -4082, -4071, -4060, - -4048, -4037, -4026, -4014, - -4003, -3992, -3980, -3969, - -3958, -3946, -3935, -3924, - -3913, -3901, -3890, -3879, - -3868, -3857, -3845, -3834, - -3823, -3812, -3801, -3790, - -3779, -3767, -3756, -3745, - -3734, -3723, -3712, -3700, - -3689, -3678, -3667, -3656, - -3645, -3634, -3623, -3612, - -3601, -3590, -3579, -3568, - -3557, -3545, -3535, -3524, - -3513, -3502, -3491, -3480, - -3469, -3458, -3447, -3436, - -3425, -3414, -3403, -3392, - -3381, -3370, -3360, -3348, - -3337, -3327, -3316, -3305, - -3294, -3283, -3272, -3262, - -3251, -3240, -3229, -3218, - -3207, -3197, -3185, -3175, - -3164, -3153, -3142, -3132, - -3121, -3110, -3099, -3088, - -3078, -3067, -3056, -3045, - -3035, -3024, -3013, -3003, - -2992, -2981, -2970, -2960, - -2949, -2938, -2928, -2917, - -2906, -2895, -2885, -2874, - -2864, -2853, -2842, -2832, - -2821, -2810, -2800, -2789, - -2778, -2768, -2757, -2747, - -2736, -2725, -2715, -2704, - -2694, -2683, -2673, -2662, - -2651, -2641, -2630, -2620, - -2609, -2599, -2588, -2578, - -2567, -2556, -2546, -2535, - -2525, -2515, -2504, -2493, - -2483, -2472, -2462, -2451, - -2441, -2431, -2420, -2410, - -2399, -2389, -2378, -2367, - -2357, -2347, -2336, -2326, - -2315, -2305, -2295, -2284, - -2274, -2263, -2253, -2243, - -2232, -2222, -2211, -2201, - -2191, -2180, -2170, -2159, - -2149, -2139, -2128, -2118, - -2107, -2097, -2087, -2076, - -2066, -2056, -2046, -2035, - -2025, -2014, -2004, -1994, - -1983, -1973, -1963, -1953, - -1942, -1932, -1921, -1911, - -1901, -1891, -1880, -1870, - -1860, -1849, -1839, -1829, - -1819, -1808, -1798, -1788, - -1778, -1767, -1757, -1747, - -1736, -1726, -1716, -1706, - -1695, -1685, -1675, -1665, - -1654, -1644, -1634, -1624, - -1613, -1603, -1593, -1583, - -1573, -1563, -1552, -1542, - -1532, -1522, -1511, -1501, - -1491, -1481, -1471, -1461, - -1450, -1440, -1430, -1420, - -1409, -1400, -1389, -1379, - -1369, -1359, -1348, -1339, - -1328, -1318, -1308, -1298, - -1288, -1278, -1267, -1257, - -1247, -1237, -1227, -1217, - -1207, -1196, -1186, -1176, - -1166, -1156, -1146, -1135, - -1126, -1115, -1105, -1095, - -1085, -1075, -1065, -1055, - -1044, -1034, -1024, -1014, - -1004, -994, -984, -974, - -964, -954, -944, -933, - -923, -913, -903, -893, - -883, -873, -863, -853, - -843, -833, -822, -812, - -802, -792, -782, -772, - -762, -752, -742, -732, - -722, -712, -702, -691, - -682, -671, -662, -651, - -641, -631, -621, -611, - -601, -591, -581, -571, - -561, -551, -541, -531, - -521, -511, -501, -491, - -480, -471, -460, -451, - -440, -430, -420, -410, - -400, -390, -380, -370, - -360, -350, -340, -330, - -320, -310, -300, -290, - -280, -270, -260, -250, - -240, -230, -220, -210, - -199, -190, -179, -170, - -159, -150, -139, -129, - -119, -109, -99, -89, - -79, -69, -59, -49, - -39, -29, -19, -9, - 1, 11, 21, 31, - 41, 51, 61, 71, - 81, 91, 101, 111, - 121, 131, 141, 152, - 161, 172, 181, 192, - 202, 212, 222, 232, - 242, 252, 262, 272, - 282, 292, 302, 312, - 322, 332, 342, 352, - 362, 372, 382, 392, - 402, 412, 422, 433, - 442, 453, 462, 473, - 483, 493, 503, 513, - 523, 533, 543, 553, - 563, 573, 583, 593, - 603, 613, 623, 633, - 643, 653, 664, 673, - 684, 694, 704, 714, - 724, 734, 744, 754, - 764, 774, 784, 794, - 804, 815, 825, 835, - 845, 855, 865, 875, - 885, 895, 905, 915, - 925, 936, 946, 956, - 966, 976, 986, 996, - 1006, 1016, 1026, 1037, - 1047, 1057, 1067, 1077, - 1087, 1097, 1107, 1117, - 1128, 1138, 1148, 1158, - 1168, 1178, 1188, 1198, - 1209, 1219, 1229, 1239, - 1249, 1259, 1269, 1280, - 1290, 1300, 1310, 1320, - 1330, 1341, 1351, 1361, - 1371, 1381, 1391, 1402, - 1412, 1422, 1432, 1442, - 1452, 1463, 1473, 1483, - 1493, 1503, 1513, 1524, - 1534, 1544, 1554, 1565, - 1575, 1585, 1595, 1606, - 1616, 1626, 1636, 1647, - 1656, 1667, 1677, 1687, - 1697, 1708, 1718, 1729, - 1739, 1749, 1759, 1769, - 1780, 1790, 1800, 1810, - 1821, 1831, 1841, 1851, - 1862, 1872, 1883, 1893, - 1903, 1913, 1923, 1934, - 1944, 1955, 1965, 1975, - 1985, 1996, 2006, 2016, - 2027, 2037, 2048, 2058, - 2068, 2079, 2089, 2099, - 2110, 2120, 2130, 2141, - 2151, 2161, 2172, 2182, - 2193, 2203, 2213, 2224, - 2234, 2245, 2255, 2265, - 2276, 2286, 2297, 2307, - 2318, 2328, 2338, 2349, - 2359, 2370, 2380, 2391, - 2401, 2412, 2422, 2433, - 2443, 2454, 2464, 2475, - 2485, 2496, 2506, 2517, - 2527, 2537, 2548, 2559, - 2569, 2580, 2590, 2601, - 2612, 2622, 2632, 2643, - 2654, 2664, 2675, 2685, - 2696, 2707, 2717, 2728, - 2738, 2749, 2759, 2770, - 2781, 2791, 2802, 2813, - 2823, 2834, 2845, 2855, - 2866, 2877, 2887, 2898, - 2909, 2919, 2930, 2941, - 2951, 2962, 2973, 2984, - 2994, 3005, 3015, 3027, - 3037, 3048, 3058, 3069, - 3080, 3091, 3101, 3113, - 3123, 3134, 3145, 3156, - 3166, 3177, 3188, 3199, - 3210, 3220, 3231, 3242, - 3253, 3264, 3275, 3285, - 3296, 3307, 3318, 3329, - 3340, 3351, 3362, 3373, - 3384, 3394, 3405, 3416, - 3427, 3438, 3449, 3460, - 3471, 3482, 3493, 3504, - 3515, 3526, 3537, 3548, - 3559, 3570, 3581, 3592, - 3603, 3614, 3625, 3636, - 3647, 3659, 3670, 3681, - 3692, 3703, 3714, 3725, - 3736, 3747, 3758, 3770, - 3781, 3792, 3803, 3814, - 3825, 3837, 3848, 3859, - 3870, 3881, 3893, 3904, - 3915, 3926, 3937, 3949, - 3960, 3971, 3983, 3994, - 4005, 4017, 4028, 4039, - 4051, 4062, 4073, 4085, - 4096, 4107, 4119, 4130, - 4141, 4153, 4164, 4175, - 4187, 4198, 4210, 4221, - 4233, 4244, 4256, 4267, - 4279, 4290, 4302, 4313, - 4325, 4336, 4348, 4359, - 4371, 4382, 4394, 4406, - 4417, 4429, 4440, 4452, - 4464, 4475, 4487, 4499, - 4510, 4522, 4533, 4545, - 4557, 4569, 4581, 4592, - 4604, 4616, 4627, 4639, - 4651, 4663, 4674, 4686, - 4698, 4710, 4722, 4734, - 4746, 4758, 4769, 4781, - 4793, 4805, 4817, 4829, - 4841, 4853, 4865, 4877, - 4889, 4900, 4913, 4925, - 4936, 4949, 4961, 4973, - 4985, 4997, 5009, 5021, - 5033, 5045, 5057, 5070, - 5081, 5094, 5106, 5118, - 5130, 5143, 5155, 5167, - 5179, 5191, 5204, 5216, - 5228, 5240, 5253, 5265, - 5278, 5290, 5302, 5315, - 5327, 5340, 5352, 5364, - 5377, 5389, 5401, 5414, - 5426, 5439, 5451, 5464, - 5476, 5489, 5502, 5514, - 5527, 5539, 5552, 5564, - 5577, 5590, 5603, 5615, - 5628, 5641, 5653, 5666, - 5679, 5691, 5704, 5717, - 5730, 5743, 5756, 5768, - 5781, 5794, 5807, 5820, - 5833, 5846, 5859, 5872, - 5885, 5897, 5911, 5924, - 5937, 5950, 5963, 5976, - 5989, 6002, 6015, 6028, - 6042, 6055, 6068, 6081, - 6094, 6108, 6121, 6134, - 6147, 6160, 6174, 6187, - 6201, 6214, 6227, 6241, - 6254, 6267, 6281, 6294, - 6308, 6321, 6335, 6348, - 6362, 6375, 6389, 6403, - 6416, 6430, 6443, 6457, - 6471, 6485, 6498, 6512, - 6526, 6540, 6554, 6567, - 6581, 6595, 6609, 6623, - 6637, 6651, 6665, 6679, - 6692, 6706, 6721, 6735, - 6749, 6763, 6777, 6791, - 6805, 6819, 6833, 6848, - 6862, 6876, 6890, 6905, - 6919, 6933, 6948, 6962, - 6976, 6991, 7005, 7020, - 7034, 7049, 7064, 7078, - 7093, 7107, 7122, 7136, - 7151, 7166, 7180, 7195, - 7210, 7225, 7240, 7254, - 7269, 7284, 7299, 7314, - 7329, 7344, 7359, 7374, - 7389, 7404, 7419, 7434, - 7449, 7465, 7480, 7495, - 7510, 7526, 7541, 7556, - 7571, 7587, 7602, 7618, - 7633, 7648, 7664, 7680, - 7695, 7711, 7726, 7742, - 7758, 7773, 7789, 7805, - 7821, 7836, 7852, 7868, - 7884, 7900, 7916, 7932, - 7948, 7964, 7981, 7997, - 8013, 8029, 8045, 8061, - 8078, 8094, 8110, 8127, - 8143, 8160, 8176, 8193, - 8209, 8226, 8242, 8259, - 8276, 8292, 8309, 8326, - 8343, 8360, 8377, 8394, - 8410, 8428, 8444, 8462, - 8479, 8496, 8513, 8530, - 8548, 8565, 8582, 8600, - 8617, 8634, 8652, 8670, - 8687, 8704, 8722, 8740, - 8758, 8775, 8793, 8811, - 8829, 8847, 8865, 8883, - 8901, 8919, 8937, 8955, - 8974, 8992, 9010, 9029, - 9047, 9066, 9084, 9103, - 9121, 9140, 9159, 9177, - 9196, 9215, 9234, 9253, - 9272, 9291, 9310, 9329, - 9349, 9368, 9387, 9406, - 9426, 9445, 9465, 9484, - 9504, 9524, 9544, 9563, - 9583, 9603, 9623, 9643, - 9663, 9683, 9703, 9723, - 9744, 9764, 9785, 9805, - 9826, 9846, 9867, 9888, - 9909, 9930, 9950, 9971, - 9993, 10013, 10035, 10056, - 10077, 10099, 10120, 10142, - 10163, 10185, 10207, 10229, - 10251, 10273, 10294, 10317, - 10339, 10361, 10384, 10406, - 10428, 10451, 10474, 10496, - 10519, 10542, 10565, 10588, - 10612, 10635, 10658, 10682, - 10705, 10729, 10752, 10776, - 10800, 10824, 10848, 10872, - 10896, 10921, 10945, 10969, - 10994, 11019, 11044, 11069, - 11094, 11119, 11144, 11169, - 11195, 11221, 11246, 11272, - 11298, 11324, 11350, 11376, - 11402, 11429, 11456, 11482, - 11509, 11536, 11563, 11590, - 11618, 11645, 11673, 11701, - 11728, 11756, 11785, 11813, - 11842, 11870, 11899, 11928, - 11957, 11986, 12015, 12045, - 12074, 12104, 12134, 12164, - 12194, 12225, 12255, 12286, - 12317, 12348, 12380, 12411, - 12443, 12475, 12507, 12539, - 12571, 12604, 12637, 12670, - 12703, 12737, 12771, 12804, - 12839, 12873, 12907, 12942, - 12977, 13013, 13048, 13084, - 13120, 13156, 13192, 13229, - 13267, 13304, 13341, 13379, - 13418, 13456, 13495, 13534, - 13573, 13613, 13653, 13693, - 13734, 13775, 13817, 13858, - 13901, 13943, 13986, 14029, - 14073, 14117, 14162, 14206, - 14252, 14297, 14343, 14390, - 14437, 14485, 14533, 14582, - 14631, 14680, 14731, 14782, - 14833, 14885, 14937, 14991, - 15044, 15099, 15154, 15210, - 15266, 15324, 15382, 15441, - 15500, 15561, 15622, 15684, - 15747, 15811, 15877, 15943, - 16010, 16078, 16148, 16218, - 16290, 16363, 16437, 16513, - 16590, 16669, 16749, 16831, - 16915, 17000, 17088, 17177, - 17268, 17362, 17458, 17556, - 17657, 17761, 17868, 17977, - 18090, 18207, 18328, 18452, - 18581, 18715, 18854, 18998, - 19149, 19307, 19472, 19645, - 19828, 20021, 20226, 20444, - 20678, 20930, 21204, 21503, - 21835, 22206, 22630, 23124, - 23721, 24478, 25529, 27316, -}; +/* get_crandom - correlated random number generator + * Next number depends on last value. + * rho is scaled to avoid floating point. + */ +static unsigned long get_crandom(struct crndstate *state) +{ + u64 value, rho; + unsigned long answer; + + if (state->rho == 0) /* no correllation */ + return net_random(); + + value = net_random(); + rho = (u64)state->rho + 1; + answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32; + state->last = answer; + return answer; +} /* tabledist - return a pseudo-randomly distributed value with mean mu and * std deviation sigma. Uses table lookup to approximate the desired * distribution, and a uniformly-distributed pseudo-random source. */ -static inline int tabledist(int mu, int sigma) +static long tabledist(unsigned long mu, long sigma, + struct crndstate *state, const struct disttable *dist) { - int x; - int index; - int sigmamod, sigmadiv; + long t, x; + unsigned long rnd; if (sigma == 0) return mu; - index = (net_random() & (TABLESIZE-1)); - sigmamod = sigma%TABLEFACTOR; - sigmadiv = sigma/TABLEFACTOR; - x = sigmamod*disttable[index]; + rnd = get_crandom(state); + + /* default uniform distribution */ + if (dist == NULL) + return (rnd % (2*sigma)) - sigma + mu; + t = dist->table[rnd % dist->size]; + x = (sigma % NETEM_DIST_SCALE) * t; if (x >= 0) - x += TABLEFACTOR/2; + x += NETEM_DIST_SCALE/2; else - x -= TABLEFACTOR/2; + x -= NETEM_DIST_SCALE/2; - x /= TABLEFACTOR; - x += sigmadiv*disttable[index]; - x += mu; - return x; + return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu; } -/* Enqueue packets with underlying discipline (fifo) - * but mark them with current time first. - */ -static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) +/* Put skb in the private delayed queue. */ +static int delay_skb(struct Qdisc *sch, struct sk_buff *skb) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; - psched_time_t now; - long delay; + psched_tdiff_t td; + psched_time_t now; + + PSCHED_GET_TIME(now); + td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist); + PSCHED_TADD2(now, td, cb->time_to_send); + + /* Always queue at tail to keep packets in order */ + if (likely(q->delayed.qlen < q->limit)) { + __skb_queue_tail(&q->delayed, skb); + sch->stats.bytes += skb->len; + sch->stats.packets++; + + if (!timer_pending(&q->timer)) { + q->timer.expires = jiffies + PSCHED_US2JIFFIE(td); + add_timer(&q->timer); + } + return NET_XMIT_SUCCESS; + } + + sch->stats.drops++; + kfree_skb(skb); + return NET_XMIT_DROP; +} + +static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct netem_sched_data *q = qdisc_priv(sch); pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); /* Random packet drop 0 => none, ~0 => all */ - if (q->loss && q->loss >= net_random()) { + if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { + pr_debug("netem_enqueue: random loss\n"); sch->stats.drops++; return 0; /* lie about loss so TCP doesn't know */ } + /* Random duplication */ + if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + + pr_debug("netem_enqueue: dup %p\n", skb2); + if (skb2) + delay_skb(sch, skb2); + } /* If doing simple delay then gap == 0 so all packets * go into the delayed holding queue @@ -628,39 +202,24 @@ ++q->counter; ret = q->qdisc->enqueue(skb, q->qdisc); - if (ret) + if (likely(ret == NET_XMIT_SUCCESS)) { + sch->q.qlen++; + sch->stats.bytes += skb->len; + sch->stats.packets++; + } else sch->stats.drops++; return ret; } q->counter = 0; - - PSCHED_GET_TIME(now); - if (q->jitter) - delay = tabledist(q->latency, q->jitter); - else - delay = q->latency; - PSCHED_TADD2(now, delay, cb->time_to_send); - - /* Always queue at tail to keep packets in order */ - if (likely(q->delayed.qlen < q->limit)) { - __skb_queue_tail(&q->delayed, skb); - sch->q.qlen++; - sch->stats.bytes += skb->len; - sch->stats.packets++; - return 0; - } - - sch->stats.drops++; - kfree_skb(skb); - return NET_XMIT_DROP; + return delay_skb(sch, skb); } /* Requeue packets but don't change time stamp */ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); int ret; if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) @@ -671,7 +230,7 @@ static unsigned int netem_drop(struct Qdisc* sch) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); unsigned int len; if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { @@ -687,17 +246,33 @@ */ static struct sk_buff *netem_dequeue(struct Qdisc *sch) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); + struct sk_buff *skb; + + skb = q->qdisc->dequeue(q->qdisc); + if (skb) + sch->q.qlen--; + return skb; +} + +static void netem_watchdog(unsigned long arg) +{ + struct Qdisc *sch = (struct Qdisc *)arg; + struct netem_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; psched_time_t now; + pr_debug("netem_watchdog: fired @%lu\n", jiffies); + + spin_lock_bh(&sch->dev->queue_lock); PSCHED_GET_TIME(now); + while ((skb = skb_peek(&q->delayed)) != NULL) { const struct netem_skb_cb *cb = (const struct netem_skb_cb *)skb->cb; long delay = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); - pr_debug("netem_dequeue: delay queue %p@%lu %ld\n", + pr_debug("netem_watchdog: skb %p@%lu %ld\n", skb, jiffies, delay); /* if more time remaining? */ @@ -710,24 +285,12 @@ if (q->qdisc->enqueue(skb, q->qdisc)) sch->stats.drops++; } - - skb = q->qdisc->dequeue(q->qdisc); - if (skb) - sch->q.qlen--; - return skb; -} - -static void netem_watchdog(unsigned long arg) -{ - struct Qdisc *sch = (struct Qdisc *)arg; - - pr_debug("netem_watchdog: fired @%lu\n", jiffies); - netif_schedule(sch->dev); + spin_unlock_bh(&sch->dev->queue_lock); } static void netem_reset(struct Qdisc *sch) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); qdisc_reset(q->qdisc); skb_queue_purge(&q->delayed); @@ -753,92 +316,163 @@ return ret; } -static int netem_change(struct Qdisc *sch, struct rtattr *opt) +/* + * Distribution data is a variable size payload containing + * signed 16 bit values. + */ +static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; - struct tc_netem_qopt *qopt = RTA_DATA(opt); - struct Qdisc *child; - int ret; + struct netem_sched_data *q = qdisc_priv(sch); + unsigned long n = RTA_PAYLOAD(attr)/sizeof(__s16); + const __s16 *data = RTA_DATA(attr); + struct disttable *d; + int i; + + if (n > 65536) + return -EINVAL; + + d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->size = n; + for (i = 0; i < n; i++) + d->table[i] = data[i]; + + spin_lock_bh(&sch->dev->queue_lock); + d = xchg(&q->delay_dist, d); + spin_unlock_bh(&sch->dev->queue_lock); + + kfree(d); + return 0; +} - if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) +static int get_correlation(struct Qdisc *sch, const struct rtattr *attr) +{ + struct netem_sched_data *q = qdisc_priv(sch); + const struct tc_netem_corr *c = RTA_DATA(attr); + + if (RTA_PAYLOAD(attr) != sizeof(*c)) return -EINVAL; - child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); - if (!child) + init_crandom(&q->delay_cor, c->delay_corr); + init_crandom(&q->loss_cor, c->loss_corr); + init_crandom(&q->dup_cor, c->dup_corr); + return 0; +} + +static int netem_change(struct Qdisc *sch, struct rtattr *opt) +{ + struct netem_sched_data *q = qdisc_priv(sch); + struct tc_netem_qopt *qopt; + int ret; + + if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) return -EINVAL; - ret = set_fifo_limit(child, qopt->limit); + qopt = RTA_DATA(opt); + ret = set_fifo_limit(q->qdisc, qopt->limit); if (ret) { - qdisc_destroy(child); + pr_debug("netem: can't set fifo limit\n"); return ret; } - - sch_tree_lock(sch); - if (child) { - child = xchg(&q->qdisc, child); - if (child != &noop_qdisc) - qdisc_destroy(child); - q->latency = qopt->latency; - q->jitter = qopt->jitter; - q->limit = qopt->limit; - q->gap = qopt->gap; - q->loss = qopt->loss; + q->latency = qopt->latency; + q->jitter = qopt->jitter; + q->limit = qopt->limit; + q->gap = qopt->gap; + q->loss = qopt->loss; + q->duplicate = qopt->duplicate; + + /* Handle nested options after initial queue options. + * Should have put all options in nested format but too late now. + */ + if (RTA_PAYLOAD(opt) > sizeof(*qopt)) { + struct rtattr *tb[TCA_NETEM_MAX]; + if (rtattr_parse(tb, TCA_NETEM_MAX, + RTA_DATA(opt) + sizeof(*qopt), + RTA_PAYLOAD(opt) - sizeof(*qopt))) + return -EINVAL; + + if (tb[TCA_NETEM_CORR-1]) { + ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]); + if (ret) + return ret; + } + + if (tb[TCA_NETEM_DELAY_DIST-1]) { + ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]); + if (ret) + return ret; + } } - sch_tree_unlock(sch); + return 0; } static int netem_init(struct Qdisc *sch, struct rtattr *opt) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; - int err; + struct netem_sched_data *q = qdisc_priv(sch); + int ret; if (!opt) return -EINVAL; MOD_INC_USE_COUNT; skb_queue_head_init(&q->delayed); - q->qdisc = &noop_qdisc; - init_timer(&q->timer); q->timer.function = netem_watchdog; q->timer.data = (unsigned long) sch; q->counter = 0; - err = netem_change(sch, opt); - if (err != 0) + q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (!q->qdisc) { + pr_debug("netem: qdisc create failed\n"); + return -ENOMEM; + } + + ret = netem_change(sch, opt); + if (ret) { + pr_debug("netem: change failed\n"); + qdisc_destroy(q->qdisc); MOD_DEC_USE_COUNT; - return err; + } + return ret; } static void netem_destroy(struct Qdisc *sch) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; - - del_timer(&q->timer); + struct netem_sched_data *q = qdisc_priv(sch); + del_timer_sync(&q->timer); qdisc_destroy(q->qdisc); - q->qdisc = &noop_qdisc; - + kfree(q->delay_dist); MOD_DEC_USE_COUNT; } static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + const struct netem_sched_data *q = qdisc_priv(sch); unsigned char *b = skb->tail; + struct rtattr *rta = (struct rtattr *) b; struct tc_netem_qopt qopt; + struct tc_netem_corr cor; qopt.latency = q->latency; qopt.jitter = q->jitter; qopt.limit = q->limit; qopt.loss = q->loss; qopt.gap = q->gap; - + qopt.duplicate = q->duplicate; RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); + cor.delay_corr = q->delay_cor.rho; + cor.loss_corr = q->loss_cor.rho; + cor.dup_corr = q->dup_cor.rho; + RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); + rta->rta_len = skb->tail - b; + return skb->len; rtattr_failure: @@ -849,7 +483,7 @@ static int netem_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { - struct netem_sched_data *q = (struct netem_sched_data*)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); if (cl != 1) /* only one class */ return -ENOENT; @@ -863,7 +497,7 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); if (new == NULL) new = &noop_qdisc; @@ -871,7 +505,7 @@ sch_tree_lock(sch); *old = xchg(&q->qdisc, new); qdisc_reset(*old); - sch->q.qlen = 0; + sch->q.qlen = q->delayed.qlen; sch_tree_unlock(sch); return 0; @@ -879,7 +513,7 @@ static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg) { - struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + struct netem_sched_data *q = qdisc_priv(sch); return q->qdisc; } diff -urN linux-2.4.27/net/sctp/associola.c linux-2.4.28/net/sctp/associola.c --- linux-2.4.27/net/sctp/associola.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/associola.c 2004-11-17 03:54:22.183421947 -0800 @@ -478,14 +478,15 @@ /* 7.2.1 Slow-Start * - * o The initial cwnd before data transmission or after a - * sufficiently long idle period MUST be <= 2*MTU. + * o The initial cwnd before DATA transmission or after a sufficiently + * long idle period MUST be set to + * min(4*MTU, max(2*MTU, 4380 bytes)) * * o The initial value of ssthresh MAY be arbitrarily high * (for example, implementations MAY use the size of the * receiver advertised window). */ - peer->cwnd = asoc->pmtu * 2; + peer->cwnd = min(4*asoc->pmtu, max_t(__u32, 2*asoc->pmtu, 4380)); /* At this point, we may not have the receiver's advertised window, * so initialize ssthresh to the default value and it will be set @@ -1108,6 +1109,7 @@ case SCTP_STATE_ESTABLISHED: case SCTP_STATE_SHUTDOWN_PENDING: case SCTP_STATE_SHUTDOWN_RECEIVED: + case SCTP_STATE_SHUTDOWN_SENT: if ((asoc->rwnd > asoc->a_rwnd) && ((asoc->rwnd - asoc->a_rwnd) >= min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) diff -urN linux-2.4.27/net/sctp/inqueue.c linux-2.4.28/net/sctp/inqueue.c --- linux-2.4.27/net/sctp/inqueue.c 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.28/net/sctp/inqueue.c 2004-11-17 03:54:22.184421988 -0800 @@ -81,7 +81,7 @@ struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL) sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, diff -urN linux-2.4.27/net/sctp/ipv6.c linux-2.4.28/net/sctp/ipv6.c --- linux-2.4.27/net/sctp/ipv6.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/ipv6.c 2004-11-17 03:54:22.185422029 -0800 @@ -78,7 +78,10 @@ #include -extern struct notifier_block sctp_inetaddr_notifier; +extern int sctp_inetaddr_event(struct notifier_block *, unsigned long, void *); +static struct notifier_block sctp_inet6addr_notifier = { + .notifier_call = sctp_inetaddr_event, +}; /* FIXME: This macro needs to be moved to a common header file. */ #define NIP6(addr) \ @@ -980,7 +983,7 @@ sctp_register_af(&sctp_ipv6_specific); /* Register notifier for inet6 address additions/deletions. */ - register_inet6addr_notifier(&sctp_inetaddr_notifier); + register_inet6addr_notifier(&sctp_inet6addr_notifier); return 0; } @@ -992,5 +995,5 @@ inet6_del_protocol(&sctpv6_protocol); inet6_unregister_protosw(&sctpv6_seqpacket_protosw); inet6_unregister_protosw(&sctpv6_stream_protosw); - unregister_inet6addr_notifier(&sctp_inetaddr_notifier); + unregister_inet6addr_notifier(&sctp_inet6addr_notifier); } diff -urN linux-2.4.27/net/sctp/output.c linux-2.4.28/net/sctp/output.c --- linux-2.4.27/net/sctp/output.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/output.c 2004-11-17 03:54:22.186422070 -0800 @@ -133,7 +133,7 @@ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) sctp_chunk_free(chunk); if (packet->malloced) @@ -370,7 +370,7 @@ * [This whole comment explains WORD_ROUND() below.] */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (sctp_chunk_is_data(chunk)) { if (!chunk->has_tsn) { @@ -511,7 +511,7 @@ * will get resent or dropped later. */ - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (!sctp_chunk_is_data(chunk)) sctp_chunk_free(chunk); } diff -urN linux-2.4.27/net/sctp/outqueue.c linux-2.4.28/net/sctp/outqueue.c --- linux-2.4.27/net/sctp/outqueue.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/outqueue.c 2004-11-17 03:54:22.187422111 -0800 @@ -245,7 +245,7 @@ /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { + while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); /* Mark as part of a failed message. */ @@ -282,7 +282,7 @@ } /* Throw away any leftover data chunks. */ - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* Mark as send failure. */ sctp_chunk_fail(chunk, q->error); @@ -292,7 +292,7 @@ q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL) sctp_chunk_free(chunk); } @@ -525,10 +525,10 @@ int rtx_timeout, int *start_timer) { struct list_head *lqueue; - struct list_head *lchunk; + struct list_head *lchunk, *lchunk1; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; - struct sctp_chunk *chunk; + struct sctp_chunk *chunk, *chunk1; struct sctp_association *asoc; int error = 0; @@ -615,6 +615,12 @@ * the transmitted list. */ list_add_tail(lchunk, &transport->transmitted); + + /* Mark the chunk as ineligible for fast retransmit + * after it is retransmitted. + */ + chunk->fast_retransmit = 0; + *start_timer = 1; q->empty = 0; @@ -622,6 +628,18 @@ lchunk = sctp_list_dequeue(lqueue); break; }; + + /* If we are here due to a retransmit timeout or a fast + * retransmit and if there are any chunks left in the retransmit + * queue that could not fit in the PMTU sized packet, they need * to be marked as ineligible for a subsequent fast retransmit. + */ + if (rtx_timeout && !lchunk) { + list_for_each(lchunk1, lqueue) { + chunk1 = list_entry(lchunk1, struct sctp_chunk, + transmitted_list); + chunk1->fast_retransmit = 0; + } + } } return error; @@ -681,17 +699,26 @@ */ queue = &q->control; - while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) { /* Pick the right transport to use. */ new_transport = chunk->transport; if (!new_transport) { new_transport = asoc->peer.active_path; } else if (!new_transport->active) { - /* If the chunk is Heartbeat, send it to - * chunk->transport, even it's inactive. + /* If the chunk is Heartbeat or Heartbeat Ack, + * send it to chunk->transport, even if it's + * inactive. + * + * 3.3.6 Heartbeat Acknowledgement: + * ... + * A HEARTBEAT ACK is always sent to the source IP + * address of the IP datagram containing the + * HEARTBEAT chunk to which this ack is responding. + * ... */ - if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) + if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT && + chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK) new_transport = asoc->peer.active_path; } @@ -812,7 +839,7 @@ start_timer = 0; queue = &q->out; - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid * stream identifier. */ @@ -866,7 +893,7 @@ SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head " "%p skb->users %d.\n", ntohl(chunk->subh.data_hdr->tsn), - chunk->skb ?chunk->skb->head : 0, + chunk->skb ?chunk->skb->head : NULL, chunk->skb ? atomic_read(&chunk->skb->users) : -1); diff -urN linux-2.4.27/net/sctp/protocol.c linux-2.4.28/net/sctp/protocol.c --- linux-2.4.27/net/sctp/protocol.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/protocol.c 2004-11-17 03:54:22.188422152 -0800 @@ -97,7 +97,7 @@ { if (!proc_net_sctp) { struct proc_dir_entry *ent; - ent = proc_mkdir("net/sctp", 0); + ent = proc_mkdir("net/sctp", NULL); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; @@ -621,8 +621,8 @@ /* Event handler for inet address addition/deletion events. * Basically, whenever there is an event, we re-build our local address list. */ -static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, - void *ptr) +int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, + void *ptr) { unsigned long flags; @@ -823,7 +823,7 @@ }; /* Notifier for inetaddr addition/deletion events. */ -struct notifier_block sctp_inetaddr_notifier = { +static struct notifier_block sctp_inetaddr_notifier = { .notifier_call = sctp_inetaddr_event, }; diff -urN linux-2.4.27/net/sctp/sm_make_chunk.c linux-2.4.28/net/sctp/sm_make_chunk.c --- linux-2.4.27/net/sctp/sm_make_chunk.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/sm_make_chunk.c 2004-11-17 03:54:22.190422235 -0800 @@ -171,6 +171,7 @@ struct sctp_opt *sp; sctp_supported_addrs_param_t sat; __u16 types[2]; + sctp_adaption_ind_param_t aiparam; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -196,6 +197,7 @@ chunksize += sizeof(ecap_param); if (sctp_prsctp_enable) chunksize += sizeof(prsctp_param); + chunksize += sizeof(aiparam); chunksize += vparam_len; /* RFC 2960 3.3.2 Initiation (INIT) (1) @@ -234,6 +236,10 @@ sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); if (sctp_prsctp_enable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); + aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND; + aiparam.param_hdr.length = htons(sizeof(aiparam)); + aiparam.adaption_ind = htonl(sp->adaption_ind); + sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); nodata: if (addrs.v) kfree(addrs.v); @@ -251,6 +257,7 @@ sctp_cookie_param_t *cookie; int cookie_len; size_t chunksize; + sctp_adaption_ind_param_t aiparam; retval = NULL; @@ -284,6 +291,8 @@ if (asoc->peer.prsctp_capable) chunksize += sizeof(prsctp_param); + chunksize += sizeof(aiparam); + /* Now allocate and fill out the chunk. */ retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); if (!retval) @@ -302,6 +311,11 @@ if (asoc->peer.prsctp_capable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); + aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND; + aiparam.param_hdr.length = htons(sizeof(aiparam)); + aiparam.adaption_ind = htonl(sctp_sk(asoc->base.sk)->adaption_ind); + sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); + /* We need to remove the const qualifier at this point. */ retval->asoc = (struct sctp_association *) asoc; @@ -1297,6 +1311,9 @@ /* Remember PR-SCTP capability. */ cookie->c.prsctp_capable = asoc->peer.prsctp_capable; + /* Save adaption indication in the cookie. */ + cookie->c.adaption_ind = asoc->peer.adaption_ind; + /* Set an expiration time for the cookie. */ do_gettimeofday(&cookie->c.expiration); TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); @@ -1455,6 +1472,7 @@ retval->addip_serial = retval->c.initial_tsn; retval->adv_peer_ack_point = retval->ctsn_ack_point; retval->peer.prsctp_capable = retval->c.prsctp_capable; + retval->peer.adaption_ind = retval->c.adaption_ind; /* The INIT stuff will be done by the side effects. */ return retval; @@ -1661,6 +1679,7 @@ case SCTP_PARAM_HEARTBEAT_INFO: case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_ECN_CAPABLE: + case SCTP_PARAM_ADAPTION_LAYER_IND: break; case SCTP_PARAM_HOST_NAME_ADDRESS: @@ -1973,6 +1992,10 @@ asoc->peer.ecn_capable = 1; break; + case SCTP_PARAM_ADAPTION_LAYER_IND: + asoc->peer.adaption_ind = param.aind->adaption_ind; + break; + case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) { asoc->peer.prsctp_capable = 1; @@ -2443,6 +2466,8 @@ union sctp_addr addr; struct sctp_bind_addr *bp = &asoc->base.bind_addr; union sctp_addr_param *addr_param; + struct list_head *pos; + struct sctp_transport *transport; int retval = 0; addr_param = (union sctp_addr_param *) @@ -2466,6 +2491,12 @@ retval = sctp_del_bind_addr(bp, &addr); sctp_write_unlock(&asoc->base.addr_lock); sctp_local_bh_enable(); + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + sctp_transport_route(transport, NULL, + sctp_sk(asoc->base.sk)); + } break; default: break; diff -urN linux-2.4.27/net/sctp/sm_sideeffect.c linux-2.4.28/net/sctp/sm_sideeffect.c --- linux-2.4.27/net/sctp/sm_sideeffect.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/sm_sideeffect.c 2004-11-17 03:54:22.192422317 -0800 @@ -529,6 +529,23 @@ } } +/* Helper function to stop any pending T3-RTX timers */ +static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc) +{ + struct sctp_transport *t; + struct list_head *pos; + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, struct sctp_transport, transports); + if (timer_pending(&t->T3_rtx_timer) && + del_timer(&t->T3_rtx_timer)) { + sctp_transport_put(t); + } + } +} + + /* Helper function to update the heartbeat timer. */ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, @@ -749,6 +766,26 @@ return; } +/* Helper function to remove the association non-primary peer + * transports. + */ +static void sctp_cmd_del_non_primary(struct sctp_association *asoc) +{ + struct sctp_transport *t; + struct list_head *pos; + struct list_head *temp; + + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + t = list_entry(pos, struct sctp_transport, transports); + if (!sctp_cmp_addr_exact(&t->ipaddr, + &asoc->peer.primary_addr)) { + sctp_assoc_del_peer(asoc, &t->ipaddr); + } + } + + return; +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1048,6 +1085,27 @@ if (cmd->obj.ptr) sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(cmd->obj.ptr)); + + /* FIXME - Eventually come up with a cleaner way to + * enabling COOKIE-ECHO + DATA bundling during + * multihoming stale cookie scenarios, the following + * command plays with asoc->peer.retran_path to + * avoid the problem of sending the COOKIE-ECHO and + * DATA in different paths, which could result + * in the association being ABORTed if the DATA chunk + * is processed first by the server. Checking the + * init error counter simply causes this command + * to be executed only during failed attempts of + * association establishment. + */ + if ((asoc->peer.retran_path != + asoc->peer.primary_path) && + (asoc->counters[SCTP_COUNTER_INIT_ERROR] > 0)) { + sctp_add_cmd_sf(commands, + SCTP_CMD_FORCE_PRIM_RETRAN, + SCTP_NULL()); + } + break; case SCTP_CMD_GEN_SHUTDOWN: @@ -1282,6 +1340,19 @@ case SCTP_CMD_CLEAR_INIT_TAG: asoc->peer.i.init_tag = 0; break; + case SCTP_CMD_DEL_NON_PRIMARY: + sctp_cmd_del_non_primary(asoc); + break; + case SCTP_CMD_T3_RTX_TIMERS_STOP: + sctp_cmd_t3_rtx_timers_stop(commands, asoc); + break; + case SCTP_CMD_FORCE_PRIM_RETRAN: + t = asoc->peer.retran_path; + asoc->peer.retran_path = asoc->peer.primary_path; + error = sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + asoc->peer.retran_path = t; + break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", cmd->verb, cmd->obj.ptr); diff -urN linux-2.4.27/net/sctp/sm_statefuns.c linux-2.4.28/net/sctp/sm_statefuns.c --- linux-2.4.27/net/sctp/sm_statefuns.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/sm_statefuns.c 2004-11-17 03:54:22.196422481 -0800 @@ -472,8 +472,6 @@ */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, - SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -631,6 +629,21 @@ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (new_asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(new_asoc, + GFP_ATOMIC); + if (!ev) + goto nomem_ev; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem_ev: @@ -674,6 +687,15 @@ if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Reset init error count upon receipt of COOKIE-ACK, + * to avoid problems with the managemement of this + * counter in stale cookie situations when a transition back + * from the COOKIE-ECHOED state to the COOKIE-WAIT + * state is performed. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, + SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + /* RFC 2960 5.1 Normal Establishment of an Association * * E) Upon reception of the COOKIE ACK, endpoint "A" will move @@ -706,6 +728,20 @@ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem: return SCTP_DISPOSITION_NOMEM; @@ -995,7 +1031,7 @@ /* Search through all current addresses and make sure * we aren't adding any new ones. */ - new_addr = 0; + new_addr = NULL; found = 0; list_for_each(pos, &new_asoc->peer.transport_addr_list) { @@ -1525,6 +1561,21 @@ goto nomem_ev; sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC); + if (!ev) + goto nomem_ev; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem_ev: @@ -1605,6 +1656,21 @@ goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter, + * SCTP delivers this notification to inform the application + * that of the peers requested adaption layer. + */ + if (new_asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(new_asoc, + GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } } sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); @@ -1872,8 +1938,6 @@ time_t stale; sctp_cookie_preserve_param_t bht; sctp_errhdr_t *err; - struct list_head *pos; - struct sctp_transport *t; struct sctp_chunk *reply; struct sctp_bind_addr *bp; int attempts; @@ -1920,20 +1984,27 @@ /* Clear peer's init_tag cached in assoc as we are sending a new INIT */ sctp_add_cmd_sf(commands, SCTP_CMD_CLEAR_INIT_TAG, SCTP_NULL()); + /* Stop pending T3-rtx and heartbeat timers */ + sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL()); + + /* Delete non-primary peer ip addresses since we are transitioning + * back to the COOKIE-WAIT state + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + + /* If we've sent any data bundled with COOKIE-ECHO we will need to + * resend + */ + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, + SCTP_TRANSPORT(asoc->peer.primary_path)); + /* Cast away the const modifier, as we want to just * rerun it through as a sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC, SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); - /* If we've sent any data bundled with COOKIE-ECHO we need to - * resend. - */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); - sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(t)); - } - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -2321,12 +2392,7 @@ sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; - sctp_datahdr_t *data_hdr; - struct sctp_chunk *err; - size_t datalen; - sctp_verb_t deliver; - int tmp; - __u32 tsn; + int error; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -2334,158 +2400,22 @@ return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); - - tsn = ntohl(data_hdr->tsn); - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - - /* ASSERT: Now skb->data is really the user data. */ - - /* Process ECN based congestion. - * - * Since the chunk structure is reused for all chunks within - * a packet, we use ecn_ce_done to track if we've already - * done CE processing for this packet. - * - * We need to do ECN processing even if we plan to discard the - * chunk later. - */ - - if (!chunk->ecn_ce_done) { - struct sctp_af *af; - chunk->ecn_ce_done = 1; - - af = sctp_get_af_specific( - ipver2af(chunk->skb->nh.iph->version)); - - if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { - /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, - SCTP_U32(tsn)); - } - } - - tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); - if (tmp < 0) { - /* The TSN is too high--silently discard the chunk and - * count on it getting retransmitted later. - */ + error = sctp_eat_data(asoc, chunk, commands ); + switch (error) { + case SCTP_IERROR_NO_ERROR: + break; + case SCTP_IERROR_HIGH_TSN: + case SCTP_IERROR_BAD_STREAM: goto discard_noforce; - } else if (tmp > 0) { - /* This is a duplicate. Record it. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + case SCTP_IERROR_DUP_TSN: + case SCTP_IERROR_IGNORE_TSN: goto discard_force; + case SCTP_IERROR_NO_DATA: + goto consume; + default: + BUG(); } - /* This is a new TSN. */ - - /* Discard if there is no room in the receive window. - * Actually, allow a little bit of overflow (up to a MTU). - */ - datalen = ntohs(chunk->chunk_hdr->length); - datalen -= sizeof(sctp_data_chunk_t); - - deliver = SCTP_CMD_CHUNK_ULP; - - /* Think about partial delivery. */ - if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { - - /* Even if we don't accept this chunk there is - * memory pressure. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL()); - } - - /* Spill over rwnd a little bit. Note: While allowed, this spill over - * seems a bit troublesome in that frag_point varies based on - * PMTU. In cases, such as loopback, this might be a rather - * large spill over. - */ - if (!asoc->rwnd || asoc->rwnd_over || - (datalen > asoc->rwnd + asoc->frag_point)) { - - /* If this is the next TSN, consider reneging to make - * room. Note: Playing nice with a confused sender. A - * malicious sender can still eat up all our buffer - * space and in the future we may want to detect and - * do more drastic reneging. - */ - if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && - (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { - SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); - deliver = SCTP_CMD_RENEGE; - } else { - SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, " - "rwnd: %d\n", tsn, datalen, - asoc->rwnd); - goto discard_force; - } - } - - /* - * Section 3.3.10.9 No User Data (9) - * - * Cause of error - * --------------- - * No User Data: This error cause is returned to the originator of a - * DATA chunk if a received DATA chunk has no user data. - */ - if (unlikely(0 == datalen)) { - err = sctp_make_abort_no_data(asoc, chunk, tsn); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } - /* We are going to ABORT, so we might as well stop - * processing the rest of the chunks in the packet. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_U32(SCTP_ERROR_NO_DATA)); - SCTP_INC_STATS(SctpAborteds); - SCTP_DEC_STATS(SctpCurrEstab); - return SCTP_DISPOSITION_CONSUME; - } - - /* If definately accepting the DATA chunk, record its TSN, otherwise - * wait for renege processing. - */ - if (SCTP_CMD_CHUNK_ULP == deliver) - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); - - /* Note: Some chunks may get overcounted (if we drop) or overcounted - * if we renege and the chunk arrives again. - */ - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) - SCTP_INC_STATS(SctpInUnorderChunks); - else - SCTP_INC_STATS(SctpInOrderChunks); - - /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream - * identifier, it shall acknowledge the reception of the DATA chunk - * following the normal procedure, immediately send an ERROR chunk - * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. - */ - if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, - sizeof(data_hdr->stream)); - if (err) - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - goto discard_noforce; - } - - /* Send the data up to the user. Note: Schedule the - * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK - * chunk needs the updated rwnd. - */ - sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk)); - if (asoc->autoclose) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); @@ -2551,6 +2481,9 @@ SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); } return SCTP_DISPOSITION_DISCARD; +consume: + return SCTP_DISPOSITION_CONSUME; + } /* @@ -2576,11 +2509,7 @@ sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; - sctp_datahdr_t *data_hdr; - struct sctp_chunk *err; - size_t datalen; - int tmp; - __u32 tsn; + int error; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -2588,110 +2517,23 @@ return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *) chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); - - tsn = ntohl(data_hdr->tsn); - - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - - /* ASSERT: Now skb->data is really the user data. */ - - /* Process ECN based congestion. - * - * Since the chunk structure is reused for all chunks within - * a packet, we use ecn_ce_done to track if we've already - * done CE processing for this packet. - * - * We need to do ECN processing even if we plan to discard the - * chunk later. - */ - if (!chunk->ecn_ce_done) { - struct sctp_af *af; - chunk->ecn_ce_done = 1; - - af = sctp_get_af_specific( - ipver2af(chunk->skb->nh.iph->version)); - - if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { - /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, - SCTP_U32(tsn)); - } - } - - tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); - if (tmp < 0) { - /* The TSN is too high--silently discard the chunk and - * count on it getting retransmitted later. - */ - goto gen_shutdown; - } else if (tmp > 0) { - /* This is a duplicate. Record it. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); - goto gen_shutdown; - } - - /* This is a new TSN. */ - - datalen = ntohs(chunk->chunk_hdr->length); - datalen -= sizeof(sctp_data_chunk_t); - - /* - * Section 3.3.10.9 No User Data (9) - * - * Cause of error - * --------------- - * No User Data: This error cause is returned to the originator of a - * DATA chunk if a received DATA chunk has no user data. - */ - if (unlikely(0 == datalen)) { - err = sctp_make_abort_no_data(asoc, chunk, tsn); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } - /* We are going to ABORT, so we might as well stop - * processing the rest of the chunks in the packet. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_U32(SCTP_ERROR_NO_DATA)); - SCTP_INC_STATS(SctpAborteds); - SCTP_DEC_STATS(SctpCurrEstab); - return SCTP_DISPOSITION_CONSUME; - } - - /* We are accepting this DATA chunk. */ - - /* Record the fact that we have received this TSN. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); - - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) - SCTP_INC_STATS(SctpInUnorderChunks); - else - SCTP_INC_STATS(SctpInOrderChunks); - /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream - * identifier, it shall acknowledge the reception of the DATA chunk - * following the normal procedure, immediately send an ERROR chunk - * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. - */ - if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, - sizeof(data_hdr->stream)); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } + error = sctp_eat_data(asoc, chunk, commands ); + switch (error) { + case SCTP_IERROR_NO_ERROR: + case SCTP_IERROR_HIGH_TSN: + case SCTP_IERROR_DUP_TSN: + case SCTP_IERROR_IGNORE_TSN: + case SCTP_IERROR_BAD_STREAM: + break; + case SCTP_IERROR_NO_DATA: + goto consume; + default: + BUG(); } /* Go a head and force a SACK, since we are shutting down. */ -gen_shutdown: + /* Implementor's Guide. * * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately @@ -2707,6 +2549,8 @@ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); } + +consume: return SCTP_DISPOSITION_CONSUME; } @@ -4709,7 +4553,7 @@ num_blocks = ntohs(sack->num_gap_ack_blocks); num_dup_tsns = ntohs(sack->num_dup_tsns); len = sizeof(struct sctp_sackhdr); - len = (num_blocks + num_dup_tsns) * sizeof(__u32); + len += (num_blocks + num_dup_tsns) * sizeof(__u32); if (len > chunk->skb->len) return NULL; @@ -4848,3 +4692,171 @@ sctp_chunk_free (err_chunk); } } + + +/* Process a data chunk */ +int sctp_eat_data(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands) +{ + sctp_datahdr_t *data_hdr; + struct sctp_chunk *err; + size_t datalen; + sctp_verb_t deliver; + int tmp; + __u32 tsn; + + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + + tsn = ntohl(data_hdr->tsn); + SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); + + /* ASSERT: Now skb->data is really the user data. */ + + /* Process ECN based congestion. + * + * Since the chunk structure is reused for all chunks within + * a packet, we use ecn_ce_done to track if we've already + * done CE processing for this packet. + * + * We need to do ECN processing even if we plan to discard the + * chunk later. + */ + + if (!chunk->ecn_ce_done) { + struct sctp_af *af; + chunk->ecn_ce_done = 1; + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { + /* Do real work as sideffect. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + SCTP_U32(tsn)); + } + } + + tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); + if (tmp < 0) { + /* The TSN is too high--silently discard the chunk and + * count on it getting retransmitted later. + */ + return SCTP_IERROR_HIGH_TSN; + } else if (tmp > 0) { + /* This is a duplicate. Record it. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + return SCTP_IERROR_DUP_TSN; + } + + /* This is a new TSN. */ + + /* Discard if there is no room in the receive window. + * Actually, allow a little bit of overflow (up to a MTU). + */ + datalen = ntohs(chunk->chunk_hdr->length); + datalen -= sizeof(sctp_data_chunk_t); + + deliver = SCTP_CMD_CHUNK_ULP; + + /* Think about partial delivery. */ + if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { + + /* Even if we don't accept this chunk there is + * memory pressure. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL()); + } + + /* Spill over rwnd a little bit. Note: While allowed, this spill over + * seems a bit troublesome in that frag_point varies based on + * PMTU. In cases, such as loopback, this might be a rather + * large spill over. + */ + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point)) { + + /* If this is the next TSN, consider reneging to make + * room. Note: Playing nice with a confused sender. A + * malicious sender can still eat up all our buffer + * space and in the future we may want to detect and + * do more drastic reneging. + */ + if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && + (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { + SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); + deliver = SCTP_CMD_RENEGE; + } else { + SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, " + "rwnd: %d\n", tsn, datalen, + asoc->rwnd); + return SCTP_IERROR_IGNORE_TSN; + } + } + + /* + * Section 3.3.10.9 No User Data (9) + * + * Cause of error + * --------------- + * No User Data: This error cause is returned to the originator of a + * DATA chunk if a received DATA chunk has no user data. + */ + if (unlikely(0 == datalen)) { + err = sctp_make_abort_no_data(asoc, chunk, tsn); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_U32(SCTP_ERROR_NO_DATA)); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); + return SCTP_IERROR_NO_DATA; + } + + /* If definately accepting the DATA chunk, record its TSN, otherwise + * wait for renege processing. + */ + if (SCTP_CMD_CHUNK_ULP == deliver) + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + + /* Note: Some chunks may get overcounted (if we drop) or overcounted + * if we renege and the chunk arrives again. + */ + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + SCTP_INC_STATS(SctpInUnorderChunks); + else + SCTP_INC_STATS(SctpInOrderChunks); + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * If an endpoint receive a DATA chunk with an invalid stream + * identifier, it shall acknowledge the reception of the DATA chunk + * following the normal procedure, immediately send an ERROR chunk + * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) + * and discard the DATA chunk. + */ + if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, + sizeof(data_hdr->stream)); + if (err) + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + return SCTP_IERROR_BAD_STREAM; + } + + /* Send the data up to the user. Note: Schedule the + * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK + * chunk needs the updated rwnd. + */ + sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk)); + + return SCTP_IERROR_NO_ERROR; +} diff -urN linux-2.4.27/net/sctp/socket.c linux-2.4.28/net/sctp/socket.c --- linux-2.4.27/net/sctp/socket.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/socket.c 2004-11-17 03:54:22.199422605 -0800 @@ -86,8 +86,6 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); -static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, size_t msg_len); @@ -95,7 +93,8 @@ static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); static void sctp_wait_for_close(struct sock *sk, long timeo); -static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); +static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, + union sctp_addr *addr, int len); static int sctp_bindx_add(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); @@ -111,6 +110,64 @@ extern kmem_cache_t *sctp_bucket_cachep; extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc); +/* Get the sndbuf space available at the time on the association. */ +static inline int sctp_wspace(struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (amt < 0) + amt = 0; + return amt; +} + +/* Increment the used sndbuf space count of the corresponding association by + * the size of the outgoing data chunk. + * Also, set the skb destructor for sndbuf accounting later. + * + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * destructor in the data chunk skb for the purpose of the sndbuf space + * tracking. + */ +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) +{ + struct sctp_association *asoc = chunk->asoc; + struct sock *sk = asoc->base.sk; + + /* The sndbuf space is tracked per association. */ + sctp_association_hold(asoc); + + chunk->skb->destructor = sctp_wfree; + /* Save the chunk pointer in skb for sctp_wfree to use later. */ + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); +} + +/* Verify that this is a valid address. */ +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, + int len) +{ + struct sctp_af *af; + + /* Verify basic sockaddr. */ + af = sctp_sockaddr_af(sctp_sk(sk), addr, len); + if (!af) + return -EINVAL; + + /* Is this a valid SCTP address? */ + if (!af->addr_valid(addr, sctp_sk(sk))) + return -EINVAL; + + if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) + return -EINVAL; + + return 0; +} + /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ @@ -999,7 +1056,7 @@ struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = NULL; - sctp_cmsgs_t cmsgs = { 0 }; + sctp_cmsgs_t cmsgs = { NULL }; int err; sctp_scope_t scope; long timeo; @@ -1630,6 +1687,32 @@ if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; + /* + * API 7. Socket Options (setting the default value for the endpoint) + * All options that support specific settings on an association by + * filling in either an association id variable or a sockaddr_storage + * SHOULD also support setting of the same value for the entire endpoint + * (i.e. future associations). To accomplish this the following logic is + * used when setting one of these options: + + * c) If neither the sockaddr_storage or association identification is + * set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and + * the association identification is 0, the settings are a default + * and to be applied to the endpoint (all future associations). + */ + + /* update default value for endpoint (all future associations) */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + if (params.spp_hbinterval) + sctp_sk(sk)->paddrparam.spp_hbinterval = + params.spp_hbinterval; + if (sctp_max_retrans_path) + sctp_sk(sk)->paddrparam.spp_pathmaxrxt = + params.spp_pathmaxrxt; + return 0; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -2028,6 +2111,20 @@ return err; } +static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, + int optlen) +{ + __u32 val; + + if (optlen < sizeof(__u32)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(__u32))) + return -EFAULT; + + sctp_sk(sk)->adaption_ind = val; + + return 0; +} /* API 6.2 setsockopt(), getsockopt() * @@ -2127,6 +2224,10 @@ case SCTP_MAXSEG: retval = sctp_setsockopt_maxseg(sk, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_setsockopt_adaption_layer(sk, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -2426,6 +2527,8 @@ /* User specified fragmentation limit. */ sp->user_frag = 0; + sp->adaption_ind = 0; + sp->pf = sctp_get_pf_specific(sk->sk_family); /* Control variables for partial data delivery. */ @@ -2795,6 +2898,17 @@ if (copy_from_user(¶ms, optval, *optlen)) return -EFAULT; + /* If no association id is specified retrieve the default value + * for the endpoint that will be used for all future associations + */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + params.spp_hbinterval = sctp_sk(sk)->paddrparam.spp_hbinterval; + params.spp_pathmaxrxt = sctp_sk(sk)->paddrparam.spp_pathmaxrxt; + + goto done; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -2814,6 +2928,7 @@ */ params.spp_pathmaxrxt = trans->error_threshold; +done: if (copy_to_user(optval, ¶ms, len)) return -EFAULT; @@ -3053,6 +3168,29 @@ } /* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +static int sctp_getsockopt_adaption_layer(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + __u32 val; + + if (len < sizeof(__u32)) + return -EINVAL; + + len = sizeof(__u32); + val = sctp_sk(sk)->adaption_ind; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; +} + +/* * * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) * @@ -3405,6 +3543,10 @@ retval = sctp_getsockopt_peer_addr_info(sk, len, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_getsockopt_adaption_layer(sk, len, optval, + optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -4138,64 +4280,6 @@ return NULL; } -/* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, - int len) -{ - struct sctp_af *af; - - /* Verify basic sockaddr. */ - af = sctp_sockaddr_af(sctp_sk(sk), addr, len); - if (!af) - return -EINVAL; - - /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr, sctp_sk(sk))) - return -EINVAL; - - if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) - return -EINVAL; - - return 0; -} - -/* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(struct sctp_association *asoc) -{ - struct sock *sk = asoc->base.sk; - int amt = 0; - - amt = sk->sk_sndbuf - asoc->sndbuf_used; - if (amt < 0) - amt = 0; - return amt; -} - -/* Increment the used sndbuf space count of the corresponding association by - * the size of the outgoing data chunk. - * Also, set the skb destructor for sndbuf accounting later. - * - * Since it is always 1-1 between chunk and skb, and also a new skb is always - * allocated for chunk bundling in sctp_packet_transmit(), we can use the - * destructor in the data chunk skb for the purpose of the sndbuf space - * tracking. - */ -static inline void sctp_set_owner_w(struct sctp_chunk *chunk) -{ - struct sctp_association *asoc = chunk->asoc; - struct sock *sk = asoc->base.sk; - - /* The sndbuf space is tracked per association. */ - sctp_association_hold(asoc); - - chunk->skb->destructor = sctp_wfree; - /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); -} - /* If sndbuf has changed, wake up per association sndbuf waiters. */ static void __sctp_write_space(struct sctp_association *asoc) { diff -urN linux-2.4.27/net/sctp/transport.c linux-2.4.28/net/sctp/transport.c --- linux-2.4.27/net/sctp/transport.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/transport.c 2004-11-17 03:54:22.200422646 -0800 @@ -421,15 +421,15 @@ { switch (reason) { case SCTP_LOWER_CWND_T3_RTX: - /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 + /* RFC 2960 Section 7.2.3, sctpimpguide * When the T3-rtx timer expires on an address, SCTP should * perform slow start by: - * ssthresh = max(cwnd/2, 2*MTU) + * ssthresh = max(cwnd/2, 4*MTU) * cwnd = 1*MTU * partial_bytes_acked = 0 */ transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->asoc->pmtu; break; @@ -439,15 +439,15 @@ * were last sent, according to the formula described in * Section 7.2.3. * - * RFC 2960 7.2.3, sctpimpguide-05 2.9.2 Upon detection of - * packet losses from SACK (see Section 7.2.4), An endpoint + * RFC 2960 7.2.3, sctpimpguide Upon detection of packet + * losses from SACK (see Section 7.2.4), An endpoint * should do the following: - * ssthresh = max(cwnd/2, 2*MTU) + * ssthresh = max(cwnd/2, 4*MTU) * cwnd = ssthresh * partial_bytes_acked = 0 */ transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; break; @@ -467,23 +467,24 @@ if ((jiffies - transport->last_time_ecne_reduced) > transport->rtt) { transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; transport->last_time_ecne_reduced = jiffies; } break; case SCTP_LOWER_CWND_INACTIVE: - /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2 - * When the association does not transmit data on a given - * transport address within an RTO, the cwnd of the transport - * address should be adjusted to 2*MTU. + /* RFC 2960 Section 7.2.1, sctpimpguide + * When the endpoint does not transmit data on a given + * transport address, the cwnd of the transport address + * should be adjusted to max(cwnd/2, 4*MTU) per RTO. * NOTE: Although the draft recommends that this check needs * to be done every RTO interval, we do it every hearbeat * interval. */ if ((jiffies - transport->last_time_used) > transport->rto) - transport->cwnd = 2*transport->asoc->pmtu; + transport->cwnd = max(transport->cwnd/2, + 4*transport->asoc->pmtu); break; }; diff -urN linux-2.4.27/net/sctp/ulpevent.c linux-2.4.28/net/sctp/ulpevent.c --- linux-2.4.27/net/sctp/ulpevent.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/ulpevent.c 2004-11-17 03:54:22.201422687 -0800 @@ -48,13 +48,23 @@ #include #include -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc); -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, struct sctp_association *asoc); static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); +/* Stub skb destructor. */ +static void sctp_stub_rfree(struct sk_buff *skb) +{ +/* WARNING: This function is just a warning not to use the + * skb destructor. If the skb is shared, we may get the destructor + * callback on some processor that does not own the sock_lock. This + * was occuring with PACKET socket applications that were monitoring + * our skbs. We can't take the sock_lock, because we can't risk + * recursing if we do really own the sock lock. Instead, do all + * of our rwnd manipulation while we own the sock_lock outright. + */ +} + /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) { @@ -87,6 +97,30 @@ return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION); } +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) +{ + struct sk_buff *skb; + + /* Cast away the const, as we are just wanting to + * bump the reference count. + */ + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); + skb->sk = asoc->base.sk; + event->asoc = (struct sctp_association *)asoc; + skb->destructor = sctp_stub_rfree; +} + +/* A simple destructor to give up the reference to the association. */ +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) +{ + sctp_association_put(event->asoc); +} + /* Create and initialize an SCTP_ASSOC_CHANGE event. * * 5.3.1.1 SCTP_ASSOC_CHANGE @@ -528,7 +562,7 @@ struct sctp_shutdown_event *sse; struct sk_buff *skb; - event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event), MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -579,6 +613,40 @@ return NULL; } +/* Create and initialize a SCTP_ADAPTION_INDICATION notification. + * + * Socket Extensions for SCTP + * 5.3.1.6 SCTP_ADAPTION_INDICATION + */ +struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication( + const struct sctp_association *asoc, int gfp) +{ + struct sctp_ulpevent *event; + struct sctp_adaption_event *sai; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_adaption_event), + MSG_NOTIFICATION, gfp); + if (!event) + goto fail; + + skb = sctp_event2skb(event); + sai = (struct sctp_adaption_event *) + skb_put(skb, sizeof(struct sctp_adaption_event)); + + sai->sai_type = SCTP_ADAPTION_INDICATION; + sai->sai_flags = 0; + sai->sai_length = sizeof(struct sctp_adaption_event); + sai->sai_adaption_ind = asoc->peer.adaption_ind; + sctp_ulpevent_set_owner(event, asoc); + sai->sai_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail: + return NULL; +} + /* A message has been received. Package this message as a notification * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo * even if filtered out later. @@ -655,7 +723,7 @@ struct sctp_pdapi_event *pd; struct sk_buff *skb; - event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event), MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -789,43 +857,6 @@ sizeof(struct sctp_sndrcvinfo), (void *)&sinfo); } -/* Stub skb destructor. */ -static void sctp_stub_rfree(struct sk_buff *skb) -{ -/* WARNING: This function is just a warning not to use the - * skb destructor. If the skb is shared, we may get the destructor - * callback on some processor that does not own the sock_lock. This - * was occuring with PACKET socket applications that were monitoring - * our skbs. We can't take the sock_lock, because we can't risk - * recursing if we do really own the sock lock. Instead, do all - * of our rwnd manipulation while we own the sock_lock outright. - */ -} - -/* Hold the association in case the msg_name needs read out of - * the association. - */ -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc) -{ - struct sk_buff *skb; - - /* Cast away the const, as we are just wanting to - * bump the reference count. - */ - sctp_association_hold((struct sctp_association *)asoc); - skb = sctp_event2skb(event); - skb->sk = asoc->base.sk; - event->asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_stub_rfree; -} - -/* A simple destructor to give up the reference to the association. */ -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) -{ - sctp_association_put(event->asoc); -} - /* Do accounting for bytes received and hold a reference to the association * for each skb. */ diff -urN linux-2.4.27/net/sctp/ulpqueue.c linux-2.4.28/net/sctp/ulpqueue.c --- linux-2.4.27/net/sctp/ulpqueue.c 2004-08-07 16:26:07.000000000 -0700 +++ linux-2.4.28/net/sctp/ulpqueue.c 2004-11-17 03:54:22.202422728 -0800 @@ -49,10 +49,10 @@ #include /* Forward declarations for internal helpers. */ -static inline struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *); -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, - struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *, + struct sctp_ulpevent *); /* 1st Level Abstractions */ @@ -97,12 +97,12 @@ struct sk_buff *skb; struct sctp_ulpevent *event; - while ((skb = __skb_dequeue(&ulpq->lobby))) { + while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } - while ((skb = __skb_dequeue(&ulpq->reasm))) { + while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } @@ -466,8 +466,8 @@ /* Helper function to reassemble chunks. Hold chunks on the reasm queue that * need reassembling. */ -static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { struct sctp_ulpevent *retval = NULL; @@ -645,8 +645,8 @@ } -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { __u16 sid, ssn; struct sctp_stream *in; @@ -756,7 +756,7 @@ tsnmap = &ulpq->asoc->peer.tsn_map; - while ((skb = __skb_dequeue_tail(&ulpq->lobby))) { + while ((skb = __skb_dequeue_tail(&ulpq->lobby)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn; @@ -782,7 +782,7 @@ tsnmap = &ulpq->asoc->peer.tsn_map; /* Walk backwards through the list, reneges the newest tsns. */ - while ((skb = __skb_dequeue_tail(&ulpq->reasm))) { + while ((skb = __skb_dequeue_tail(&ulpq->reasm)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn; diff -urN linux-2.4.27/net/socket.c linux-2.4.28/net/socket.c --- linux-2.4.27/net/socket.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.28/net/socket.c 2004-11-17 03:54:22.203422769 -0800 @@ -1055,7 +1055,7 @@ if (!sock) goto out; - err = -EMFILE; + err = -ENFILE; if (!(newsock = sock_alloc())) goto out_put; diff -urN linux-2.4.27/net/sunrpc/xprt.c linux-2.4.28/net/sunrpc/xprt.c --- linux-2.4.27/net/sunrpc/xprt.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.28/net/sunrpc/xprt.c 2004-11-17 03:54:22.205422851 -0800 @@ -1244,19 +1244,6 @@ /* * Reserve an RPC call slot. */ -void -xprt_reserve(struct rpc_task *task) -{ - struct rpc_xprt *xprt = task->tk_xprt; - - task->tk_status = -EIO; - if (!xprt->shutdown) { - spin_lock(&xprt->xprt_lock); - do_xprt_reserve(task); - spin_unlock(&xprt->xprt_lock); - } -} - static inline void do_xprt_reserve(struct rpc_task *task) { @@ -1279,6 +1266,19 @@ rpc_sleep_on(&xprt->backlog, task, NULL, NULL); } +void +xprt_reserve(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + + task->tk_status = -EIO; + if (!xprt->shutdown) { + spin_lock(&xprt->xprt_lock); + do_xprt_reserve(task); + spin_unlock(&xprt->xprt_lock); + } +} + /* * Allocate a 'unique' XID */ diff -urN linux-2.4.27/net/unix/af_unix.c linux-2.4.28/net/unix/af_unix.c --- linux-2.4.27/net/unix/af_unix.c 2002-11-28 15:53:16.000000000 -0800 +++ linux-2.4.28/net/unix/af_unix.c 2004-11-17 03:54:22.206422892 -0800 @@ -178,18 +178,7 @@ return -EINVAL; if (!sunaddr || sunaddr->sun_family != AF_UNIX) return -EINVAL; - if (sunaddr->sun_path[0]) - { - /* - * This may look like an off by one error but it is - * a bit more subtle. 108 is the longest valid AF_UNIX - * path for a binding. sun_path[108] doesn't as such - * exist. However in kernel space we are guaranteed that - * it is a valid memory location in our kernel - * address buffer. - */ - if (len > sizeof(*sunaddr)) - len = sizeof(*sunaddr); + if (sunaddr->sun_path[0]) { ((char *)sunaddr)[len]=0; len = strlen(sunaddr->sun_path)+1+sizeof(short); return len; @@ -1414,9 +1403,11 @@ msg->msg_namelen = 0; + down(&sk->protinfo.af_unix.readsem); + skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) - goto out; + goto out_unlock; wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); @@ -1460,6 +1451,8 @@ out_free: skb_free_datagram(sk,skb); +out_unlock: + up(&sk->protinfo.af_unix.readsem); out: return err; } diff -urN linux-2.4.27/scripts/Menuconfig linux-2.4.28/scripts/Menuconfig --- linux-2.4.27/scripts/Menuconfig 2002-08-02 17:39:46.000000000 -0700 +++ linux-2.4.28/scripts/Menuconfig 2004-11-17 03:54:22.207422934 -0800 @@ -714,7 +714,7 @@ function parser(ifile,menu) { - while (getline 0) { if ($1 == "mainmenu_option") { comment_is_option = "1" } @@ -761,7 +761,7 @@ function parser(ifile,menu) { - while (getline 0) { if ($0 ~ /^#|$MAKE|mainmenu_name/) { printf("") >>menu }