diff -Nru a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl --- a/Documentation/DocBook/kernel-hacking.tmpl Sat Aug 31 15:06:00 2002 +++ b/Documentation/DocBook/kernel-hacking.tmpl Sat Aug 31 15:06:00 2002 @@ -1085,18 +1085,17 @@ Initializing structure members - The preferred method of initializing structures is to use the - gcc Labeled Elements extension, eg: + The preferred method of initializing structures is to use + designated initialisers, as defined by ISO C99, eg: static struct block_device_operations opt_fops = { - open: opt_open, - release: opt_release, - ioctl: opt_ioctl, - check_media_change: opt_media_change, + .open = opt_open, + .release = opt_release, + .ioctl = opt_ioctl, + .check_media_change = opt_media_change, }; - This makes it easy to grep for, and makes it clear which structure fields are set. You should do this because it looks diff -Nru a/Documentation/cciss.txt b/Documentation/cciss.txt --- a/Documentation/cciss.txt Sat Aug 31 15:05:54 2002 +++ b/Documentation/cciss.txt Sat Aug 31 15:05:54 2002 @@ -86,7 +86,7 @@ Hot plugging of SCSI tape drives is supported, with some caveats. The cciss driver must be informed that changes to the SCSI bus -have been made, in addition to and prior to informing the the SCSI +have been made, in addition to and prior to informing the SCSI mid layer. This may be done via the /proc filesystem. For example: echo "rescan" > /proc/scsi/cciss0/1 diff -Nru a/Documentation/cdrom/sonycd535 b/Documentation/cdrom/sonycd535 --- a/Documentation/cdrom/sonycd535 Sat Aug 31 15:05:59 2002 +++ b/Documentation/cdrom/sonycd535 Sat Aug 31 15:05:59 2002 @@ -63,8 +63,8 @@ Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding me to place this code into the mainstream Linux source tree (as of Linux version 1.1.91), as well as some patches to make -it a better device citizen. Further thanks to "S. Joel Katz" - for his MODULE patches (see details below), +it a better device citizen. Further thanks to Joel Katz + for his MODULE patches (see details below), Porfiri Claudio for patches to make the driver work with the older CDU-510/515 series, and Heiko Eissfeldt for pointing out that @@ -79,7 +79,7 @@ ken@halcyon.com ------------------------------------------------------------------------------ -(The following is from Joel Katz .) +(The following is from Joel Katz .) To build a version of sony535.o that can be installed as a module, use the following command: @@ -103,7 +103,7 @@ I have an external drive, and I usually leave it powered off. I used to have to reboot if I needed to use the CDROM drive. Now I don't. - Even if you have an internal drive, why waste the 268K of memory + Even if you have an internal drive, why waste the 96K of memory (unswappable) that the driver uses if you use your CD-ROM drive infrequently? This driver will not install (whether compiled in or loaded as a diff -Nru a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog --- a/Documentation/filesystems/devfs/ChangeLog Sat Aug 31 15:05:54 2002 +++ b/Documentation/filesystems/devfs/ChangeLog Sat Aug 31 15:05:54 2002 @@ -1957,3 +1957,11 @@ - Removed deprecated +=============================================================================== +Changes for patch v217 + +- Exported and to modules + +- Updated README from master HTML file + +- Fixed module unload race in diff -Nru a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README --- a/Documentation/filesystems/devfs/README Sat Aug 31 15:05:59 2002 +++ b/Documentation/filesystems/devfs/README Sat Aug 31 15:05:59 2002 @@ -3,7 +3,7 @@ Linux Devfs (Device File System) FAQ Richard Gooch -21-JUL-2002 +20-AUG-2002 Document languages: @@ -1509,6 +1509,16 @@ +Devfsd doesn't start + +Make sure you have compiled and installed devfsd +Make sure devfsd is being started from your boot +scripts +Make sure you have configured your kernel to enable devfs (see +below) +Make sure devfs is mounted (see below) + + Devfsd is not managing all my permissions Make sure you are capturing the appropriate events. For example, @@ -1777,7 +1787,7 @@ First, remember that no naming scheme will please everybody. You hate the scheme, others love it. Who's to say who's right and who's wrong? Ultimately, the person who writes the code gets to choose, and what -exists now is a combination of the the choices made by the +exists now is a combination of the choices made by the devfs author and the kernel maintainer (Linus). diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt Sat Aug 31 15:06:00 2002 +++ b/Documentation/filesystems/ntfs.txt Sat Aug 31 15:06:00 2002 @@ -247,6 +247,12 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.0: + - Add configuration option for developmental write support. + - Initial implementation of file overwriting. (Writes to resident files + are not written out to disk yet, so avoid writing to files smaller + than about 1kiB.) + - Intercept/abort changes in file size as they are not implemented yet. 2.0.25: - Minor bugfixes in error code paths and small cleanups. 2.0.24: diff -Nru a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt --- a/Documentation/networking/8139too.txt Sat Aug 31 15:06:00 2002 +++ b/Documentation/networking/8139too.txt Sat Aug 31 15:06:00 2002 @@ -185,9 +185,22 @@ Change History -------------- -Version 0.9.23 - In progress +Version 0.9.26 - August 9, 2002 -* New, compile-time conditional for testing better RX reset +* Fix MII ioctl phy id corruption. +* Fix big-endian multicast bug. +* Support register dumps via ethtool. +* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit +* Replace several "magic numbers" with their proper representation + constants in linux/mii.h. +* Support ethtool media interface via generic kernel MII API +* Export NIC-specific statistics via ethtool. +* Proper support for RTL8139 rev K. (can be disabled via + compile-time conditional) +* Add PCI ids for new 8139 boards. +* Use ethernet crc via generic linux/crc32.h kernel API. +* Better RX reset. Old rx-reset method still available via + a compile-time conditional. * Only account specific RX errors if rx_status is !OK diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt --- a/Documentation/networking/bonding.txt Sat Aug 31 15:05:55 2002 +++ b/Documentation/networking/bonding.txt Sat Aug 31 15:05:55 2002 @@ -266,7 +266,7 @@ If not explicitly configured with ifconfig, the MAC address of the bonding device is taken from its first slave device. This MAC address is then passed to all following slaves and remains persistent (even if - the the first slave is removed) until the bonding device is brought + the first slave is removed) until the bonding device is brought down or reconfigured. If you wish to change the MAC address, you can set it with ifconfig: diff -Nru a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt --- a/Documentation/networking/e1000.txt Sat Aug 31 15:05:55 2002 +++ b/Documentation/networking/e1000.txt Sat Aug 31 15:05:55 2002 @@ -1,7 +1,7 @@ Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters =============================================================== -June 11, 2002 +August 6, 2002 Contents @@ -20,12 +20,12 @@ =============== This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family -of Adapters, version 4.2.x. This driver includes support for +of Adapters, version 4.3.x. This driver includes support for Itanium(TM)-based systems. This release version includes the following: - - Support for the ethtool 1.5 interface. A third-party application can use + - Support for the ethtool 1.6 interface. A third-party application can use the ethtool interface to get and set driver parameters. - Zero copy. This feature provides faster data throughput. Enabled by @@ -113,12 +113,12 @@ Default Value: 0x2F This parameter is a bit mask that specifies which speed and duplex settings the board advertises. When this parameter is used, the Speed and - Duplex parameters must not be specified. + Duplex parameters must not be specified. Duplex (adapters using copper connections only) Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full) Default Value: 0 - Defines the direction in which data is allowed to flow. Can by either one + Defines the direction in which data is allowed to flow. Can by either one or two-directional. If both Duplex and the link partner are set to auto- negotiate, the board auto-detects the correct duplex. If the link partner is forced (either full or half), Duplex defaults to half-duplex. @@ -126,45 +126,58 @@ FlowControl Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) Default: Read flow control settings from the EEPROM - This parameter controls the automatic generation(Tx) and response(Rx) to + This parameter controls the automatic generation(Tx) and response(Rx) to Ethernet PAUSE frames. RxDescriptors Valid Range: 80-256 for 82542 and 82543-based adapters 80-4096 for 82540, 82544, 82545, and 82546-based adapters Default Value: 80 - This value is the number of receive descriptors allocated by the driver. - Increasing this value allows the driver to buffer more incoming packets. + This value is the number of receive descriptors allocated by the driver. + Increasing this value allows the driver to buffer more incoming packets. Each descriptor is 16 bytes. A receive buffer is also allocated for each - descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending + descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending on the MTU setting. The maximum MTU size is 16110. + NOTE: MTU designates the frame size. It only needs to be set for Jumbo + Frames. + RxIntDelay Valid Range: 0-65535 (0=off) Default Value: 0 (82542, 82543, and 82544-based adapters) 128 (82540, 82545, and 82546-based adapters) - This value delays the generation of receive interrupts in units of 1.024 - microseconds. Receive interrupt reduction can improve CPU efficiency if - properly tuned for specific network traffic. Increasing this value adds - extra latency to frame reception and can end up decreasing the throughput - of TCP traffic. If the system is reporting dropped receives, this value - may be set too high, causing the driver to run out of available receive + This value delays the generation of receive interrupts in units of 1.024 + microseconds. Receive interrupt reduction can improve CPU efficiency if + properly tuned for specific network traffic. Increasing this value adds + extra latency to frame reception and can end up decreasing the throughput + of TCP traffic. If the system is reporting dropped receives, this value + may be set too high, causing the driver to run out of available receive descriptors. - CAUTION: When setting RxIntDelay to a value other than 0, adapters based - on the Intel 82543 and 82544 LAN controllers may hang (stop + CAUTION: When setting RxIntDelay to a value other than 0, adapters based + on the Intel 82543 and 82544 LAN controllers may hang (stop transmitting) under certain network conditions. If this occurs a - message is logged in the system event log. In addition, the - controller is automatically reset, restoring the network - connection. To eliminate the potential for the hang ensure that + message is logged in the system event log. In addition, the + controller is automatically reset, restoring the network + connection. To eliminate the potential for the hang ensure that RxIntDelay is set to 0. +RxAbsIntDelay (82540, 82545, and 82546-based adapters only) +Valid Range: 0-65535 (0=off) +Default Value: 128 + This value, in units of 1.024 microseconds, limits the delay in which a + transmit interrupt is generated. Useful only if RxIntDelay is non-zero, + this value ensures that an interrupt is generated after the initial + packet is received within the set amount of time. Proper tuning, + along with RxIntDelay, may improve traffic throughput in specific network + conditions. + Speed (adapters using copper connections only) Valid Settings: 0, 10, 100, 1000 Default Value: 0 (auto-negotiate at all supported speeds) Speed forces the line speed to the specified value in megabits per second - (Mbps). If this parameter is not specified or is set to 0 and the link - partner is set to auto-negotiate, the board will auto-detect the correct + (Mbps). If this parameter is not specified or is set to 0 and the link + partner is set to auto-negotiate, the board will auto-detect the correct speed. Duplex must also be set when Speed is set to either 10 or 100. TxDescriptors @@ -172,8 +185,27 @@ 80-4096 for 82540, 82544, 82545, and 82546-based adapters Default Value: 256 This value is the number of transmit descriptors allocated by the driver. - Increasing this value allows the driver to queue more transmits. Each + Increasing this value allows the driver to queue more transmits. Each descriptor is 16 bytes. + +TxIntDelay +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value delays the generation of transmit interrupts in units of + 1.024 microseconds. Transmit interrupt reduction can improve CPU + efficiency if properly tuned for specific network traffic. If the + system is reporting dropped transmits, this value may be set too high + causing the driver to run out of available transmit descriptors. + +TxAbsIntDelay (82540, 82545, and 82546-based adapters only) +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value, in units of 1.024 microseconds, limits the delay in which a + transmit interrupt is generated. Useful only if TxIntDelay is non-zero, + this value ensures that an interrupt is generated after the initial + packet is sent on the wire within the set amount of time. Proper tuning, + along with TxIntDelay, may improve traffic throughput in specific + network conditions. XsumRX (not available on the PRO/1000 Gigabit Server Adapter) Valid Range: 0-1 diff -Nru a/Documentation/networking/sctp.txt b/Documentation/networking/sctp.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/networking/sctp.txt Sat Aug 31 15:06:06 2002 @@ -0,0 +1,38 @@ +Linux Kernel SCTP + +This is the current BETA release of the Linux Kernel SCTP reference +implementation. + +SCTP (Stream Control Transmission Protocol) is a IP based, message oriented, +reliable transport protocol, with congestion control, support for +transparent multi-homing, and multiple ordered streams of messages. +RFC2960 defines the core protocol. The IETF SIGTRAN working group originally +developed the SCTP protocol and later handed the protocol over to the +Transport Area (TSVWG) working group for the continued evolvement of SCTP as a +general purpose transport. + +See the IETF website (http://www.ietf.org) for further documents on SCTP. +See http://www.ietf.org/rfc/rfc2960.txt + +The initial project goal is to create an Linux kernel reference implementation +of SCTP that is RFC 2960 compliant and provides an programming interface +referred to as the UDP-style API of the Sockets Extensions for SCTP, as +proposed in IETF Internet-Drafts. + + +Caveats: + +-lksctp can be built as statically or as a module. However, be aware that +module removal of lksctp is not yet a safe activity. + +-There is tentative support for IPv6, but most work has gone towards +implementation and testing lksctp on IPv4. + + +For more information, please visit the lksctp project website: + http://www.sf.net/projects/lksctp + +Or contact the lksctp developers through the mailing list: + + + diff -Nru a/Documentation/preempt-locking.txt b/Documentation/preempt-locking.txt --- a/Documentation/preempt-locking.txt Sat Aug 31 15:05:54 2002 +++ b/Documentation/preempt-locking.txt Sat Aug 31 15:05:54 2002 @@ -1,7 +1,7 @@ Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe - Robert Love - Last Updated: 22 Jan 2002 + Robert Love + Last Updated: 28 Aug 2002 INTRODUCTION @@ -112,3 +112,24 @@ This code is not preempt-safe, but see how easily we can fix it by simply moving the spin_lock up two lines. + + +PREVENTING PREEMPTION USING INTERRUPT DISABLING + + +It is possible to prevent a preemption event using local_irq_disable and +local_irq_save. Note, when doing so, you must be very careful to not cause +an event that would set need_resched and result in a preemption check. When +in doubt, rely on locking or explicit preemption disabling. + +Note in 2.5 interrupt disabling is now only per-CPU (e.g. local). + +An additional concern is proper usage of local_irq_disable and local_irq_save. +These may be used to protect from preemption, however, on exit, if preemption +may be enabled, a test to see if preemption is required should be done. If +these are called from the spin_lock and read/write lock macros, the right thing +is done. They may also be called within a spin-lock protected region, however, +if they are ever called outside of this context, a test for preemption should +be made. Do note that calls from interrupt context or bottom half/ tasklets +are also protected by preemption locks and so may use the versions which do +not check preemption. diff -Nru a/Documentation/usb/ehci.txt b/Documentation/usb/ehci.txt --- a/Documentation/usb/ehci.txt Sat Aug 31 15:06:00 2002 +++ b/Documentation/usb/ehci.txt Sat Aug 31 15:06:00 2002 @@ -1,4 +1,4 @@ -26-Apr-2002 +23-Aug-2002 The EHCI driver is used to talk to high speed USB 2.0 devices using USB 2.0-capable host controller hardware. The USB 2.0 standard is @@ -21,11 +21,15 @@ At this writing, this driver has been seen to work with implementations of EHCI from (in alphabetical order): Intel, NEC, Philips, and VIA. +Other EHCI implementations are becoming available from other vendors; +you should expect this driver to work with them too. -At this writing, high speed devices are finally beginning to appear. -While usb-storage devices have been available for some time (working +While usb-storage devices have been available since mid-2001 (working quite speedily on the 2.4 version of this driver), hubs have only -very recently become available. +been available since late 2001, and other kinds of high speed devices +appear to be on hold until more systems come with USB 2.0 built-in. +Such new systems have been available since early 2002, and became much +more typical in the second half of 2002. Note that USB 2.0 support involves more than just EHCI. It requires other changes to the Linux-USB core APIs, including the hub driver, @@ -43,26 +47,25 @@ It's believed to do all the right PCI magic so that I/O works even on systems with interesting DMA mapping issues. -At this writing the driver should comfortably handle all control and bulk -transfers, including requests to USB 1.1 devices through transaction -translators (TTs) in USB 2.0 hubs. However, there some situations where -the hub driver needs to clear TT error state, which it doesn't yet do. - -Interrupt transfer support is newly functional and not yet as robust as -control and bulk traffic. As yet there is no support for split transaction -scheduling for interrupt transfers, which means among other things that -connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work. -Connect them to USB 1.1 hubs, or to a root hub. - -Isochronous (ISO) transfer support is also newly functional. No production -high speed devices are available which would need it (though high quality -webcams are in the works!). Note that split transaction support for ISO +At this writing the driver should comfortably handle all control, bulk, +and interrupt transfers, including requests to USB 1.1 devices through +transaction translators (TTs) in USB 2.0 hubs. + +High Speed Isochronous (ISO) transfer support is also functional, but +at this writing no Linux drivers have been using that support. + +Full Speed Isochronous transfer support, through transaction translators, +is not yet available. Note that split transaction support for ISO transfers can't share much code with the code for high speed ISO transfers, since EHCI represents these with a different data structure. So for now, -most USB audio and video devices have the same restrictions as hubs, mice, -and keyboards: don't connect them using high speed USB hubs. +most USB audio and video devices can't be connected to high speed buses. + +Transfers of all types can be queued. This means that control transfers +from a driver on one interface (or through usbfs) won't interfere with +ones from another driver, and that interrupt transfers can use periods +of one frame without risking data loss due to interrupt processing costs. -The EHCI root hub code should hand off USB 1.1 devices to its companion +The EHCI root hub code hands off USB 1.1 devices to its companion controller. This driver doesn't need to know anything about those drivers; a OHCI or UHCI driver that works already doesn't need to change just because the EHCI driver is also present. @@ -70,6 +73,11 @@ There are some issues with power management; suspend/resume doesn't behave quite right at the moment. +Also, some shortcuts have been taken with the scheduling periodic +transactions (interrupt and isochronous transfers). These place some +limits on the number of periodic transactions that can be scheduled, +and prevent use of polling intervals of less than one frame. + USE BY @@ -83,10 +91,10 @@ # rmmod ehci-hcd You should also have a driver for a "companion controller", such as -"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci". In case of any trouble -with the EHCI driver, remove its module and then the driver for that -companion controller will take over (at lower speed) all the devices -that were previously handled by the EHCI driver. +"ohci-hcd" or "uhci-hcd". In case of any trouble with the EHCI driver, +remove its module and then the driver for that companion controller will +take over (at lower speed) all the devices that were previously handled +by the EHCI driver. Module parameters (pass to "modprobe") include: @@ -122,13 +130,18 @@ and at most 13 of those fit into one USB 2.0 microframe. Eight USB 2.0 microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec. +So more than 50 MByte/sec is available for bulk transfers, when both +hardware and device driver software allow it. Periodic transfer modes +(isochronous and interrupt) allow the larger packet sizes which let you +approach the quoted 480 MBit/sec transfer rate. + Hardware Performance At this writing, individual USB 2.0 devices tend to max out at around 20 MByte/sec transfer rates. This is of course subject to change; and some devices now go faster, while others go slower. -The NEC implementation of EHCI seems to have a hardware bottleneck +The first NEC implementation of EHCI seems to have a hardware bottleneck at around 28 MByte/sec aggregate transfer rate. While this is clearly enough for a single device at 20 MByte/sec, putting three such devices onto one bus does not get you 60 MByte/sec. The issue appears to be @@ -136,9 +149,11 @@ so that it's only trying six (or maybe seven) USB transactions each microframe rather than thirteen. (Seems like a reasonable trade off for a product that beat all the others to market by over a year!) + It's expected that newer implementations will better this, throwing more silicon real estate at the problem so that new motherboard chip -sets will get closer to that 60 MByte/sec target. +sets will get closer to that 60 MByte/sec target. That includes an +updated implementation from NEC, as well as other vendors' silicon. There's a minimum latency of one microframe (125 usec) for the host to receive interrupts from the EHCI controller indicating completion diff -Nru a/Documentation/usb/ohci.txt b/Documentation/usb/ohci.txt --- a/Documentation/usb/ohci.txt Sat Aug 31 15:06:06 2002 +++ b/Documentation/usb/ohci.txt Sat Aug 31 15:06:06 2002 @@ -1,98 +1,32 @@ +23-Aug-2002 -The OHCI HCD layer is a simple but nearly complete implementation of what the -USB people would call a HCD for the OHCI. - (ISO coming soon, Bulk, INT u. CTRL transfers enabled) -It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree). -The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. - -- Roman Weissgaerber - - * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers - * v2.1 1999/05/09 ep_addr correction, code cleanup - * v0.2.0 1999/05/04 - * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers) - * virtual root hub is now an option, - * memory allocation based on kmalloc and kfree now, simple Bus error handling, - * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion - * - * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff - * from Greg Smith (ohci.c): better reset ohci-controller handling, hub - * - * v0.1.0 1999/04/27 initial release - -to remove the module try: -rmmod usb-ohci - -Features: -- virtual root hub, all basic hub descriptors and commands (state: complete) - this is an option now (v0.2.0) - #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB) - default is with. - (at the moment: the Virtual Root Hub is included automatically) - - files: ohci-root-hub.c, ohci-root-hub.h - - -- Endpoint Descriptor (ED) handling more static approach - (EDs should be allocated in parallel to the SET CONFIGURATION command and they live - as long as the function (device) is alive or another configuration is chosen. - In the HCD layer the EDs has to be allocated manually either by calling a subroutine - or by sending a USB root hub vendor specific command to the virtual root hub. - At the alternate linux usb stack EDs will be added (allocated) at their first use. - ED will be unlinked from the HC chains if they are not busy. - - files: ohci-hcd.c ohci-hcd.h - routines: (do not use for drivers, use the top layer alternate usb commands instead) - - int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, - int interval, int load, f_handler handler, int ep_size, int speed) - adds an endpoint, (if the endpoint already exists some parameters will be updated) - - int usb_ohci_rm_ep( ) - removes an endpoint and all pending TDs of that EP - - usb_ohci_rm_function( ) - removes all Endpoints of a function (device) - -- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers - The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has - to take care of buffer allocation. - files: ohci-hcd.c ohci-hcd.h - - There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL): - - int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) - - CTRL: ctrl, ctrl_len ... cmd buffer - data, data_len ... data buffer (in or out) - INT, BULK: ctrl = NULL, ctrl_len=0, - data, data_len ... data buffer (in or out) - ISO: tbd - - There is no buffer reinsertion done by the internal HCD function. - (The interface layer does this for a INT-pipe on request.) - If you want a transfer then you have to - provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED - you can send as many as you like. They should come back by the callback f_handler in - the same order (for each endpoint, not globally) If an error occurs all - queued transfers of an endpoint will return unsent. They will be marked with an error status. - - e.g double-buffering for int transfers: - - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - and when a data0 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - and when a data1 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - lw0, lw1 are private fields for upper layers for ids or fine grained handlers. - The alternate usb uses them for dev_id and usb_device_irq handler. - - -- Done list handling: returns the requests (callback f_handler in ED) and does - some error handling, root-hub request dequeuing - (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0)) +The "ohci-hcd" driver is a USB Host Controller Driver (HCD) that is derived +from the "usb-ohci" driver from the 2.4 kernel series. The "usb-ohci" code +was written primarily by Roman Weissgaerber but with +contributions from many others (read its copyright/licencing header). + +It supports the "Open Host Controller Interface" (OHCI), which standardizes +hardware register protocols used to talk to USB 1.1 host controllers. As +compared to the earlier "Universal Host Controller Interface" (UHCI) from +Intel, it pushes more intelligence into the hardware. USB 1.1 controllers +from vendors other than Intel and VIA generally use OHCI. + +Changes since the 2.4 kernel include + + - improved robustness; bugfixes; and less overhead + - supports the updated and simplified usbcore APIs + - interrupt transfers can be larger, and can be queued + - less code, by using the upper level "hcd" framework + - supports some non-PCI implementations of OHCI + - ... more + +The "ohci-hcd" driver handles all USB 1.1 transfer types. Transfers of all +types can be queued. That was also true in "usb-ohci", except for interrupt +transfers. Previously, using periods of one frame would risk data loss due +to overhead in IRQ processing. When interrupt transfers are queued, those +risks can be minimized by making sure the hardware always has transfers to +work on while the OS is getting around to the relevant IRQ processing. + +- David Brownell + - diff -Nru a/Documentation/watchdog-api.txt b/Documentation/watchdog-api.txt --- a/Documentation/watchdog-api.txt Sat Aug 31 15:05:54 2002 +++ b/Documentation/watchdog-api.txt Sat Aug 31 15:05:54 2002 @@ -278,7 +278,7 @@ when the timeout runs out which can be 0 = RESET (default), 1 = SMI, 2 = NMI, 3 = SCI. - Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character + Supports CONFIG_WATCHDOG_NOWAYOUT and the magic character 'V' close handling. GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Sat Aug 31 15:06:01 2002 +++ b/MAINTAINERS Sat Aug 31 15:06:01 2002 @@ -1406,7 +1406,7 @@ SCHEDULER P: Ingo Molnar M: mingo@elte.hu -P: Robert Love +P: Robert Love [the preemptible kernel bits] M: rml@tech9.net L: linux-kernel@vger.kernel.org S: Maintained @@ -1888,7 +1888,6 @@ VIDEO FOR LINUX P: Gerd Knorr M: kraxel@bytesex.org -W: http://roadrunner.swansea.linux.org.uk/v4l.shtml S: Maintained WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) diff -Nru a/Makefile b/Makefile --- a/Makefile Sat Aug 31 15:05:54 2002 +++ b/Makefile Sat Aug 31 15:05:54 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 32 +SUBLEVEL = 33 EXTRAVERSION = # *DOCUMENTATION* diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in --- a/arch/alpha/config.in Sat Aug 31 15:05:55 2002 +++ b/arch/alpha/config.in Sat Aug 31 15:05:55 2002 @@ -338,6 +338,7 @@ fi endmenu +source drivers/input/Config.in source drivers/char/Config.in #source drivers/misc/Config.in @@ -373,7 +374,6 @@ endmenu source drivers/usb/Config.in -source drivers/input/Config.in source net/bluetooth/Config.in diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig --- a/arch/alpha/defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/alpha/defconfig Sat Aug 31 15:06:00 2002 @@ -572,6 +572,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c --- a/arch/alpha/kernel/core_apecs.c Sat Aug 31 15:05:55 2002 +++ b/arch/alpha/kernel/core_apecs.c Sat Aug 31 15:05:55 2002 @@ -90,12 +90,11 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, - unsigned char *type1) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," " pci_addr=0x%p, type1=0x%p)\n", @@ -273,87 +272,66 @@ } static int -apecs_read_config_byte(struct pci_dev *dev, int where, u8 *value) +apecs_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, + u8 *value) { unsigned long addr, pci_addr; unsigned char type1; + long mask; + int shift; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr = (pci_addr << 5) + 0x00 + APECS_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -apecs_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x08 + APECS_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -apecs_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x18 + APECS_CONF; - *value = conf_read(addr, type1); + switch (size) { + case 1: + mask = 0x00; + shift = (where & 3) * 8; + break; + case 2: + mask = 0x08; + shift = (where & 3) * 8; + break; + case 4: + mask = 0x18; + shift = 0; + break; + } + addr = (pci_addr << 5) + mask + APECS_CONF; + *value = conf_read(addr, type1) >> (shift); return PCIBIOS_SUCCESSFUL; } static int -apecs_write_config(struct pci_dev *dev, int where, u32 value, long mask) +apecs_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { unsigned long addr, pci_addr; unsigned char type1; + long mask; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; + switch (size) { + case 1: + mask = 0x00; + break; + case 2: + mask = 0x08; + break; + case 4: + mask = 0x18; + break; + } addr = (pci_addr << 5) + mask + APECS_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -static int -apecs_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return apecs_write_config(dev, where, value, 0x00); -} - -static int -apecs_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return apecs_write_config(dev, where, value, 0x08); -} - -static int -apecs_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return apecs_write_config(dev, where, value, 0x18); -} - struct pci_ops apecs_pci_ops = { - read_byte: apecs_read_config_byte, - read_word: apecs_read_config_word, - read_dword: apecs_read_config_dword, - write_byte: apecs_write_config_byte, - write_word: apecs_write_config_word, - write_dword: apecs_write_config_dword + .read = apecs_read_config, + .write = apecs_write_config, }; void diff -Nru a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c --- a/arch/alpha/kernel/core_cia.c Sat Aug 31 15:06:00 2002 +++ b/arch/alpha/kernel/core_cia.c Sat Aug 31 15:06:00 2002 @@ -89,11 +89,10 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, - unsigned char *type1) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr, unsigned char *type1) { - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; *type1 = (bus != 0); *pci_addr = (bus << 16) | (device_fn << 8) | where; @@ -208,88 +207,70 @@ DBGC(("done\n")); } -static int -cia_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x00 + CIA_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - static int -cia_read_config_word(struct pci_dev *dev, int where, u16 *value) +cia_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, + u32 *value) { unsigned long addr, pci_addr; + long mask; unsigned char type1; + int shift; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr = (pci_addr << 5) + 0x08 + CIA_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -cia_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + switch (size) { + case 1: + mask = 0x00; + shift = (where & 3) * 8; + break; + case 2: + mask = 0x08; + shift = (where & 3) * 8; + break; + case 4: + mase = 0x18; + shift = 0; + break; + } addr = (pci_addr << 5) + 0x18 + CIA_CONF; - *value = conf_read(addr, type1); + *value = conf_read(addr, type1) >> (shift); return PCIBIOS_SUCCESSFUL; } static int -cia_write_config(struct pci_dev *dev, int where, u32 value, long mask) +cia_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, + u32 value) { unsigned long addr, pci_addr; + long mask; unsigned char type1; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; + switch (size) { + case 1: + mask = 0x00; + break; + case 2: + mask = 0x08; + break; + case 4: + mase = 0x18; + break; + } + addr = (pci_addr << 5) + mask + CIA_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -static int -cia_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return cia_write_config(dev, where, value, 0x00); -} - -static int -cia_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return cia_write_config(dev, where, value, 0x08); -} - -static int -cia_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return cia_write_config(dev, where, value, 0x18); -} - struct pci_ops cia_pci_ops = { - read_byte: cia_read_config_byte, - read_word: cia_read_config_word, - read_dword: cia_read_config_dword, - write_byte: cia_write_config_byte, - write_word: cia_write_config_word, - write_dword: cia_write_config_dword + .read = cia_read_config, + .write = cia_write_config, }; /* diff -Nru a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c --- a/arch/alpha/kernel/core_irongate.c Sat Aug 31 15:05:54 2002 +++ b/arch/alpha/kernel/core_irongate.c Sat Aug 31 15:05:54 2002 @@ -83,12 +83,11 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, - unsigned char *type1) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " "pci_addr=0x%p, type1=0x%p)\n", @@ -105,12 +104,13 @@ } static int -irongate_read_config_byte(struct pci_dev *dev, int where, u8 *value) +irongate_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(dev, where, &addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldbu(*(vucp)addr); @@ -118,38 +118,13 @@ } static int -irongate_read_config_word(struct pci_dev *dev, int where, u16 *value) +irongate_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(dev, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *value = __kernel_ldwu(*(vusp)addr); - return PCIBIOS_SUCCESSFUL; -} - -static int -irongate_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *value = *(vuip)addr; - return PCIBIOS_SUCCESSFUL; -} - -static int -irongate_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stb(value, *(vucp)addr); @@ -158,45 +133,11 @@ return PCIBIOS_SUCCESSFUL; } -static int -irongate_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - __kernel_stw(value, *(vusp)addr); - mb(); - __kernel_ldwu(*(vusp)addr); - return PCIBIOS_SUCCESSFUL; -} - -static int -irongate_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *(vuip)addr = value; - mb(); - *(vuip)addr; - return PCIBIOS_SUCCESSFUL; -} - struct pci_ops irongate_pci_ops = { - read_byte: irongate_read_config_byte, - read_word: irongate_read_config_word, - read_dword: irongate_read_config_dword, - write_byte: irongate_write_config_byte, - write_word: irongate_write_config_word, - write_dword: irongate_write_config_dword + .read = irongate_read_config, + .write = irongate_write_config, }; #ifdef DEBUG_IRONGATE diff -Nru a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c --- a/arch/alpha/kernel/core_lca.c Sat Aug 31 15:05:55 2002 +++ b/arch/alpha/kernel/core_lca.c Sat Aug 31 15:05:55 2002 @@ -99,11 +99,11 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr) { unsigned long addr; - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; if (bus == 0) { int device = device_fn >> 3; @@ -199,83 +199,65 @@ } static int -lca_read_config_byte(struct pci_dev *dev, int where, u8 *value) +lca_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) { unsigned long addr, pci_addr; + long mask; + int shift - if (mk_conf_addr(dev, where, &pci_addr)) + if (mk_conf_addr(bus, devfn, dev, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; - addr = (pci_addr << 5) + 0x00 + LCA_CONF; - *value = conf_read(addr) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -lca_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long addr, pci_addr; - - if (mk_conf_addr(dev, where, &pci_addr)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x08 + LCA_CONF; - *value = conf_read(addr) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -lca_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr, pci_addr; - - if (mk_conf_addr(dev, where, &pci_addr)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x18 + LCA_CONF; - *value = conf_read(addr); + switch (size) { + case 1: + shift = (where & 3) * 8; + mask = 0x00; + break; + case 2: + shift = (where & 3) * 8; + mask = 0x08 + break; + case 4: + shift = 0; + mask = 0x18 + break; + } + addr = (pci_addr << 5) + mask + LCA_CONF; + *value = conf_read(addr) >> (shift); return PCIBIOS_SUCCESSFUL; } static int -lca_write_config(struct pci_dev *dev, int where, u32 value, long mask) +lca_write_config(struct pci_bus *dev, unsigned int devfn, int where, int size, + u32 value) { unsigned long addr, pci_addr; + long mask; - if (mk_conf_addr(dev, where, &pci_addr)) + if (mk_conf_addr(bus, devfn, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; + switch (size) { + case 1: + mask = 0x00; + break; + case 2: + mask = 0x08 + break; + case 4: + mask = 0x18 + break; + } addr = (pci_addr << 5) + mask + LCA_CONF; conf_write(addr, value << ((where & 3) * 8)); return PCIBIOS_SUCCESSFUL; } -static int -lca_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return lca_write_config(dev, where, value, 0x00); -} - -static int -lca_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return lca_write_config(dev, where, value, 0x08); -} - -static int -lca_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return lca_write_config(dev, where, value, 0x18); -} - struct pci_ops lca_pci_ops = { - read_byte: lca_read_config_byte, - read_word: lca_read_config_word, - read_dword: lca_read_config_dword, - write_byte: lca_write_config_byte, - write_word: lca_write_config_word, - write_dword: lca_write_config_dword + .read = lca_read_config, + .write = lca_write_config, }; void diff -Nru a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c --- a/arch/alpha/kernel/core_polaris.c Sat Aug 31 15:05:55 2002 +++ b/arch/alpha/kernel/core_polaris.c Sat Aug 31 15:05:55 2002 @@ -65,10 +65,10 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, u8 *type1) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr, u8 *type1) { - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; *type1 = (bus == 0) ? 0 : 1; *pci_addr = (bus << 16) | (device_fn << 8) | (where) | @@ -82,51 +82,28 @@ } static int -polaris_read_config_byte(struct pci_dev *dev, int where, u8 *value) +polaris_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldbu(*(vucp)pci_addr); return PCIBIOS_SUCCESSFUL; } -static int -polaris_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *value = __kernel_ldwu(*(vusp)pci_addr); - return PCIBIOS_SUCCESSFUL; -} - -int -polaris_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *value = *(vuip)pci_addr; - return PCIBIOS_SUCCESSFUL; -} static int -polaris_write_config_byte(struct pci_dev *dev, int where, u8 value) +polaris_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stb(value, *(vucp)pci_addr); @@ -135,44 +112,10 @@ return PCIBIOS_SUCCESSFUL; } -static int -polaris_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - __kernel_stw(value, *(vusp)pci_addr); - mb(); - __kernel_ldwu(*(vusp)pci_addr); - return PCIBIOS_SUCCESSFUL; -} - -int -polaris_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - *(vuip)pci_addr = value; - mb(); - *(vuip)pci_addr; - return PCIBIOS_SUCCESSFUL; -} - struct pci_ops polaris_pci_ops = { - read_byte: polaris_read_config_byte, - read_word: polaris_read_config_word, - read_dword: polaris_read_config_dword, - write_byte: polaris_write_config_byte, - write_word: polaris_write_config_word, - write_dword: polaris_write_config_dword + .read = polaris_read_config, + .write = polaris_write_config, }; void __init diff -Nru a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c --- a/arch/alpha/kernel/core_t2.c Sat Aug 31 15:05:54 2002 +++ b/arch/alpha/kernel/core_t2.c Sat Aug 31 15:05:54 2002 @@ -89,12 +89,11 @@ */ static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, - unsigned char *type1) +mk_conf_addr(struct pci_bus *bus_dev, unsigned int device_fn, int where, + unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; + u8 bus = bus_dev->number; DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x," " addr=0x%lx, type1=0x%x)\n", @@ -238,87 +237,67 @@ } static int -t2_read_config_byte(struct pci_dev *dev, int where, u8 *value) +t2_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) { unsigned long addr, pci_addr; unsigned char type1; + int shift; + long mask; - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x00 + T2_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -t2_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x08 + T2_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -t2_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) + if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr = (pci_addr << 5) + 0x18 + T2_CONF; - *value = conf_read(addr, type1); + switch (size) { + case 1: + mask = 0x00; + shift = (where & 3) * 8; + break; + case 2: + mask = 0x08; + shift = (where & 3) * 8; + break; + case 4: + mask = 0x18; + shift = 0; + break; + } + addr = (pci_addr << 5) + mask + T2_CONF; + *value = conf_read(addr, type1) >> (shift); return PCIBIOS_SUCCESSFUL; } static int -t2_write_config(struct pci_dev *dev, int where, u32 value, long mask) +t2_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, + u32 value) { unsigned long addr, pci_addr; unsigned char type1; + long mask; if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; + switch (size) { + case 1: + mask = 0x00; + break; + case 2: + mask = 0x08; + break; + case 4: + mask = 0x18; + break; + } addr = (pci_addr << 5) + mask + T2_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -static int -t2_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return t2_write_config(dev, where, value, 0x00); -} - -static int -t2_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return t2_write_config(dev, where, value, 0x08); -} - -static int -t2_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return t2_write_config(dev, where, value, 0x18); -} - struct pci_ops t2_pci_ops = { - read_byte: t2_read_config_byte, - read_word: t2_read_config_word, - read_dword: t2_read_config_dword, - write_byte: t2_write_config_byte, - write_word: t2_write_config_word, - write_dword: t2_write_config_dword + .read = t2_read_config, + .write = t2_write_config, }; void __init diff -Nru a/arch/arm/def-configs/a5k b/arch/arm/def-configs/a5k --- a/arch/arm/def-configs/a5k Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/a5k Sat Aug 31 15:05:59 2002 @@ -385,6 +385,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/adi_evb b/arch/arm/def-configs/adi_evb --- a/arch/arm/def-configs/adi_evb Sat Aug 31 15:06:00 2002 +++ b/arch/arm/def-configs/adi_evb Sat Aug 31 15:06:00 2002 @@ -529,6 +529,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/adsbitsy b/arch/arm/def-configs/adsbitsy --- a/arch/arm/def-configs/adsbitsy Sat Aug 31 15:06:04 2002 +++ b/arch/arm/def-configs/adsbitsy Sat Aug 31 15:06:04 2002 @@ -479,6 +479,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/anakin b/arch/arm/def-configs/anakin --- a/arch/arm/def-configs/anakin Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/anakin Sat Aug 31 15:05:54 2002 @@ -509,6 +509,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/assabet b/arch/arm/def-configs/assabet --- a/arch/arm/def-configs/assabet Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/assabet Sat Aug 31 15:05:59 2002 @@ -658,6 +658,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/badge4 b/arch/arm/def-configs/badge4 --- a/arch/arm/def-configs/badge4 Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/badge4 Sat Aug 31 15:06:06 2002 @@ -844,6 +844,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/arm/def-configs/brutus b/arch/arm/def-configs/brutus --- a/arch/arm/def-configs/brutus Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/brutus Sat Aug 31 15:05:55 2002 @@ -223,6 +223,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/cerfcube b/arch/arm/def-configs/cerfcube --- a/arch/arm/def-configs/cerfcube Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/cerfcube Sat Aug 31 15:05:54 2002 @@ -647,6 +647,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/cerfpda b/arch/arm/def-configs/cerfpda --- a/arch/arm/def-configs/cerfpda Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/cerfpda Sat Aug 31 15:05:55 2002 @@ -685,6 +685,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/cerfpod b/arch/arm/def-configs/cerfpod --- a/arch/arm/def-configs/cerfpod Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/cerfpod Sat Aug 31 15:06:06 2002 @@ -649,6 +649,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/clps7500 b/arch/arm/def-configs/clps7500 --- a/arch/arm/def-configs/clps7500 Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/clps7500 Sat Aug 31 15:05:54 2002 @@ -420,6 +420,8 @@ # CONFIG_ISO9660_FS is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/ebsa110 b/arch/arm/def-configs/ebsa110 --- a/arch/arm/def-configs/ebsa110 Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/ebsa110 Sat Aug 31 15:05:54 2002 @@ -531,6 +531,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/edb7211 b/arch/arm/def-configs/edb7211 --- a/arch/arm/def-configs/edb7211 Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/edb7211 Sat Aug 31 15:05:54 2002 @@ -330,6 +330,7 @@ CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/empeg b/arch/arm/def-configs/empeg --- a/arch/arm/def-configs/empeg Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/empeg Sat Aug 31 15:05:55 2002 @@ -1,4 +1,5 @@ # +# # Example empeg-car kernel configuration file. # CONFIG_ARM=y diff -Nru a/arch/arm/def-configs/epxa10db b/arch/arm/def-configs/epxa10db --- a/arch/arm/def-configs/epxa10db Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/epxa10db Sat Aug 31 15:05:55 2002 @@ -544,6 +544,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/flexanet b/arch/arm/def-configs/flexanet --- a/arch/arm/def-configs/flexanet Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/flexanet Sat Aug 31 15:06:06 2002 @@ -642,6 +642,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge --- a/arch/arm/def-configs/footbridge Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/footbridge Sat Aug 31 15:05:59 2002 @@ -615,6 +615,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/fortunet b/arch/arm/def-configs/fortunet --- a/arch/arm/def-configs/fortunet Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/fortunet Sat Aug 31 15:06:06 2002 @@ -455,6 +455,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/freebird b/arch/arm/def-configs/freebird --- a/arch/arm/def-configs/freebird Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/freebird Sat Aug 31 15:05:55 2002 @@ -492,6 +492,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/freebird_new b/arch/arm/def-configs/freebird_new --- a/arch/arm/def-configs/freebird_new Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/freebird_new Sat Aug 31 15:05:54 2002 @@ -512,6 +512,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/graphicsclient b/arch/arm/def-configs/graphicsclient --- a/arch/arm/def-configs/graphicsclient Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/graphicsclient Sat Aug 31 15:06:06 2002 @@ -585,6 +585,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/graphicsmaster b/arch/arm/def-configs/graphicsmaster --- a/arch/arm/def-configs/graphicsmaster Sat Aug 31 15:05:53 2002 +++ b/arch/arm/def-configs/graphicsmaster Sat Aug 31 15:05:53 2002 @@ -560,6 +560,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/h3600 b/arch/arm/def-configs/h3600 --- a/arch/arm/def-configs/h3600 Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/h3600 Sat Aug 31 15:05:55 2002 @@ -650,6 +650,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/huw_webpanel b/arch/arm/def-configs/huw_webpanel --- a/arch/arm/def-configs/huw_webpanel Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/huw_webpanel Sat Aug 31 15:05:54 2002 @@ -336,6 +336,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/integrator b/arch/arm/def-configs/integrator --- a/arch/arm/def-configs/integrator Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/integrator Sat Aug 31 15:05:54 2002 @@ -543,6 +543,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310 --- a/arch/arm/def-configs/iq80310 Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/iq80310 Sat Aug 31 15:05:55 2002 @@ -638,6 +638,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/jornada720 b/arch/arm/def-configs/jornada720 --- a/arch/arm/def-configs/jornada720 Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/jornada720 Sat Aug 31 15:05:55 2002 @@ -667,6 +667,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/arm/def-configs/lart b/arch/arm/def-configs/lart --- a/arch/arm/def-configs/lart Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/lart Sat Aug 31 15:05:59 2002 @@ -655,6 +655,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/lubbock b/arch/arm/def-configs/lubbock --- a/arch/arm/def-configs/lubbock Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/lubbock Sat Aug 31 15:05:54 2002 @@ -702,6 +702,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/lusl7200 b/arch/arm/def-configs/lusl7200 --- a/arch/arm/def-configs/lusl7200 Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/lusl7200 Sat Aug 31 15:05:55 2002 @@ -417,6 +417,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/neponset b/arch/arm/def-configs/neponset --- a/arch/arm/def-configs/neponset Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/neponset Sat Aug 31 15:05:59 2002 @@ -762,6 +762,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/omnimeter b/arch/arm/def-configs/omnimeter --- a/arch/arm/def-configs/omnimeter Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/omnimeter Sat Aug 31 15:05:59 2002 @@ -422,6 +422,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pangolin b/arch/arm/def-configs/pangolin --- a/arch/arm/def-configs/pangolin Sat Aug 31 15:06:00 2002 +++ b/arch/arm/def-configs/pangolin Sat Aug 31 15:06:00 2002 @@ -559,6 +559,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pfs168_mqtft b/arch/arm/def-configs/pfs168_mqtft --- a/arch/arm/def-configs/pfs168_mqtft Sat Aug 31 15:06:00 2002 +++ b/arch/arm/def-configs/pfs168_mqtft Sat Aug 31 15:06:00 2002 @@ -598,6 +598,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pfs168_mqvga b/arch/arm/def-configs/pfs168_mqvga --- a/arch/arm/def-configs/pfs168_mqvga Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/pfs168_mqvga Sat Aug 31 15:05:54 2002 @@ -598,6 +598,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pfs168_sastn b/arch/arm/def-configs/pfs168_sastn --- a/arch/arm/def-configs/pfs168_sastn Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/pfs168_sastn Sat Aug 31 15:05:54 2002 @@ -591,6 +591,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pfs168_satft b/arch/arm/def-configs/pfs168_satft --- a/arch/arm/def-configs/pfs168_satft Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/pfs168_satft Sat Aug 31 15:05:54 2002 @@ -598,6 +598,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/pleb b/arch/arm/def-configs/pleb --- a/arch/arm/def-configs/pleb Sat Aug 31 15:05:55 2002 +++ b/arch/arm/def-configs/pleb Sat Aug 31 15:05:55 2002 @@ -460,6 +460,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/rpc b/arch/arm/def-configs/rpc --- a/arch/arm/def-configs/rpc Sat Aug 31 15:05:53 2002 +++ b/arch/arm/def-configs/rpc Sat Aug 31 15:05:53 2002 @@ -620,6 +620,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/shannon b/arch/arm/def-configs/shannon --- a/arch/arm/def-configs/shannon Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/shannon Sat Aug 31 15:05:54 2002 @@ -534,6 +534,8 @@ CONFIG_MINIX_FS=y # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/def-configs/shark b/arch/arm/def-configs/shark --- a/arch/arm/def-configs/shark Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/shark Sat Aug 31 15:05:54 2002 @@ -681,6 +681,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/arm/def-configs/sherman b/arch/arm/def-configs/sherman --- a/arch/arm/def-configs/sherman Sat Aug 31 15:05:54 2002 +++ b/arch/arm/def-configs/sherman Sat Aug 31 15:05:54 2002 @@ -151,6 +151,8 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_QNX4FS_FS is not set diff -Nru a/arch/arm/def-configs/stork b/arch/arm/def-configs/stork --- a/arch/arm/def-configs/stork Sat Aug 31 15:06:06 2002 +++ b/arch/arm/def-configs/stork Sat Aug 31 15:06:06 2002 @@ -649,6 +649,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/arm/def-configs/system3 b/arch/arm/def-configs/system3 --- a/arch/arm/def-configs/system3 Sat Aug 31 15:05:59 2002 +++ b/arch/arm/def-configs/system3 Sat Aug 31 15:05:59 2002 @@ -684,6 +684,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/arm/defconfig b/arch/arm/defconfig --- a/arch/arm/defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/arm/defconfig Sat Aug 31 15:05:55 2002 @@ -421,6 +421,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/cris/defconfig b/arch/cris/defconfig --- a/arch/cris/defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/cris/defconfig Sat Aug 31 15:05:55 2002 @@ -441,6 +441,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig --- a/arch/i386/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/i386/defconfig Sat Aug 31 15:05:54 2002 @@ -657,9 +657,85 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y # CONFIG_SERIAL_NONSTANDARD is not set # +# Serial drivers +# +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_INTEL_RNG=y +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_GAMMA is not set +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_I830 is not set +# CONFIG_DRM_MGA is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_MWAVE is not set +# CONFIG_RAW_DRIVER is not set + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -703,6 +779,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c --- a/arch/i386/kernel/cpu/common.c Sat Aug 31 15:05:54 2002 +++ b/arch/i386/kernel/cpu/common.c Sat Aug 31 15:05:54 2002 @@ -454,7 +454,7 @@ /* * Set up the per-thread TLS descriptor cache: */ - memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_MAX * 8); + memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); __asm__ __volatile__("lgdt %0": "=m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Sat Aug 31 15:06:00 2002 +++ b/arch/i386/kernel/i386_ksyms.c Sat Aug 31 15:06:00 2002 @@ -58,6 +58,9 @@ EXPORT_SYMBOL(EISA_bus); #endif EXPORT_SYMBOL(MCA_bus); +#ifdef CONFIG_MULTIQUAD +EXPORT_SYMBOL(xquad_portio); +#endif EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); @@ -169,7 +172,3 @@ EXPORT_SYMBOL(is_sony_vaio_laptop); EXPORT_SYMBOL(__PAGE_KERNEL); - -#ifdef CONFIG_MULTIQUAD -EXPORT_SYMBOL(xquad_portio); -#endif diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c --- a/arch/i386/kernel/ioport.c Sat Aug 31 15:06:00 2002 +++ b/arch/i386/kernel/ioport.c Sat Aug 31 15:06:00 2002 @@ -55,12 +55,16 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { struct thread_struct * t = ¤t->thread; - struct tss_struct * tss = init_tss + smp_processor_id(); + struct tss_struct * tss; + int ret = 0; if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; + + tss = init_tss + get_cpu(); + /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -69,8 +73,11 @@ if (!t->ts_io_bitmap) { unsigned long *bitmap; bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); - if (!bitmap) - return -ENOMEM; + if (!bitmap) { + ret = -ENOMEM; + goto out; + } + /* * just in case ... */ @@ -88,7 +95,9 @@ set_bitmap(t->ts_io_bitmap, from, num, !turn_on); set_bitmap(tss->io_bitmap, from, num, !turn_on); - return 0; +out: + put_cpu(); + return ret; } /* diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c --- a/arch/i386/kernel/ldt.c Sat Aug 31 15:05:54 2002 +++ b/arch/i386/kernel/ldt.c Sat Aug 31 15:05:54 2002 @@ -49,17 +49,20 @@ memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); oldldt = pc->ldt; memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - wmb(); pc->ldt = newldt; + wmb(); pc->size = mincount; + wmb(); + if (reload) { load_LDT(pc); #ifdef CONFIG_SMP - if (current->mm->cpu_vm_mask != (1<mm->cpu_vm_mask != (1 << smp_processor_id())) smp_call_function(flush_ldt, 0, 1, 1); + preempt_enable(); #endif } - wmb(); if (oldsize) { if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) vfree(oldldt); @@ -72,11 +75,8 @@ static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { int err = alloc_ldt(new, old->size, 0); - if (err < 0) { - printk(KERN_WARNING "ldt allocation failed\n"); - new->size = 0; + if (err < 0) return err; - } memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); return 0; } diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Sat Aug 31 15:05:53 2002 +++ b/arch/i386/kernel/process.c Sat Aug 31 15:05:53 2002 @@ -504,7 +504,7 @@ regs.eflags = 0x286; /* Ok, create the new process.. */ - p = do_fork(flags | CLONE_VM, 0, ®s, 0); + p = do_fork(flags | CLONE_VM, 0, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -588,11 +588,6 @@ } /* - * The common fastpath: - */ - if (!(clone_flags & (CLONE_SETTLS | CLONE_SETTID | CLONE_CLEARTID))) - return 0; - /* * Set a new TLS for the child thread? */ if (clone_flags & CLONE_SETTLS) { @@ -613,19 +608,6 @@ desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } - - /* - * Notify the child of the TID? - */ - if (clone_flags & CLONE_SETTID) - if (put_user(p->pid, (pid_t *)childregs->edx)) - return -EFAULT; - - /* - * Does the userspace VM want the TID cleared on mm_release()? - */ - if (clone_flags & CLONE_CLEARTID) - p->user_tid = (int *) childregs->edx; return 0; } @@ -779,7 +761,7 @@ { struct task_struct *p; - p = do_fork(SIGCHLD, regs.esp, ®s, 0); + p = do_fork(SIGCHLD, regs.esp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -788,12 +770,14 @@ struct task_struct *p; unsigned long clone_flags; unsigned long newsp; + int *user_tid; clone_flags = regs.ebx; newsp = regs.ecx; + user_tid = (int *)regs.edx; if (!newsp) newsp = regs.esp; - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, user_tid); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -811,7 +795,7 @@ { struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Sat Aug 31 15:06:00 2002 +++ b/arch/i386/kernel/setup.c Sat Aug 31 15:06:00 2002 @@ -46,6 +46,8 @@ unsigned long mmu_cr4_features; +int acpi_disabled __initdata = 0; + int MCA_bus; /* for MCA, but anyone else can use it if they want */ unsigned int machine_id; @@ -522,7 +524,7 @@ } /* setup_memory_region */ -static void __init parse_mem_cmdline (char ** cmdline_p) +static void __init parse_cmdline_early (char ** cmdline_p) { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; @@ -569,6 +571,11 @@ } } } + + /* "acpi=off" disables both ACPI table parsing and interpreter init */ + if (c == ' ' && !memcmp(from, "acpi=off", 8)) + acpi_disabled = 1; + /* * highmem=size forces highmem to be exactly 'size' bytes. * This works even on boxes that have no highmem otherwise. @@ -637,7 +644,7 @@ data_resource.start = virt_to_phys(&_etext); data_resource.end = virt_to_phys(&_edata)-1; - parse_mem_cmdline(cmdline_p); + parse_cmdline_early(cmdline_p); #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) @@ -840,7 +847,8 @@ /* * Parse the ACPI tables for possible boot-time SMP configuration. */ - acpi_boot_init(*cmdline_p); + if (!acpi_disabled) + acpi_boot_init(*cmdline_p); #endif #ifdef CONFIG_X86_LOCAL_APIC if (smp_found_config) diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Sat Aug 31 15:06:00 2002 +++ b/arch/i386/kernel/smpboot.c Sat Aug 31 15:06:00 2002 @@ -395,7 +395,7 @@ Dprintk("CALLIN, before setup_local_APIC().\n"); /* * Because we use NMIs rather than the INIT-STARTUP sequence to - * bootstrap the CPUs, the APIC may be in a wierd state. Kick it. + * bootstrap the CPUs, the APIC may be in a weird state. Kick it. */ if (clustered_apic_mode) clear_local_APIC(); @@ -495,7 +495,7 @@ * don't care about the eip and regs settings since * we'll never reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0); + return do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL); } /* which physical APIC ID maps to which logical CPU number */ diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Sat Aug 31 15:05:55 2002 +++ b/arch/i386/kernel/traps.c Sat Aug 31 15:05:55 2002 @@ -311,21 +311,6 @@ if (vm86 && regs->eflags & VM_MASK) goto vm86_trap; -#ifdef CONFIG_PNPBIOS - if (regs->xcs == 0x60 || regs->xcs == 0x68) - { - extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; - extern u32 pnp_bios_is_utter_crap; - pnp_bios_is_utter_crap = 1; - printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); - __asm__ volatile( - "movl %0, %%esp\n\t" - "jmp *%1\n\t" - : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); - panic("do_trap: can't hit this"); - } -#endif - if (!(regs->xcs & 3)) goto kernel_trap; @@ -341,7 +326,23 @@ } kernel_trap: { - unsigned long fixup = search_exception_table(regs->eip); + unsigned long fixup; +#ifdef CONFIG_PNPBIOS + if (unlikely((regs->xcs | 8) == 0x88)) /* 0x80 or 0x88 */ + { + extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; + extern u32 pnp_bios_is_utter_crap; + pnp_bios_is_utter_crap = 1; + printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); + __asm__ volatile( + "movl %0, %%esp\n\t" + "jmp *%1\n\t" + : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); + panic("do_trap: can't hit this"); + } +#endif + + fixup = search_exception_table(regs->eip); if (fixup) regs->eip = fixup; else diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c --- a/arch/i386/pci/common.c Sat Aug 31 15:05:59 2002 +++ b/arch/i386/pci/common.c Sat Aug 31 15:05:59 2002 @@ -25,9 +25,6 @@ struct pci_bus *pci_root_bus = NULL; struct pci_ops *pci_root_ops = NULL; -int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; -int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; - /* * legacy, numa, and acpi all want to call pcibios_scan_root * from their initcalls. This flag prevents that. diff -Nru a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c --- a/arch/i386/pci/direct.c Sat Aug 31 15:05:55 2002 +++ b/arch/i386/pci/direct.c Sat Aug 31 15:05:55 2002 @@ -13,7 +13,7 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -69,75 +69,23 @@ return 0; } - #undef PCI_CONF1_ADDRESS -static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) +static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - - *value = (u8)data; - - return result; + return __pci_conf1_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } -static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) +static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - - *value = (u16)data; - - return result; -} - -static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - if (!value) - return -EINVAL; - - return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); -} - -static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); -} - -static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_conf1_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } static struct pci_ops pci_direct_conf1 = { - pci_conf1_read_config_byte, - pci_conf1_read_config_word, - pci_conf1_read_config_dword, - pci_conf1_write_config_byte, - pci_conf1_write_config_word, - pci_conf1_write_config_dword + .read = pci_conf1_read, + .write = pci_conf1_write, }; @@ -147,7 +95,7 @@ #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -181,7 +129,7 @@ return 0; } -static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -217,57 +165,21 @@ #undef PCI_CONF2_ADDRESS -static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - int result; - u32 data; - result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - *value = (u8)data; - return result; -} - -static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - int result; - u32 data; - result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - *value = (u16)data; - return result; -} - -static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value) +static int pci_conf2_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); + return __pci_conf2_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } -static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value) +static int pci_conf2_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); -} - -static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_conf2_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } static struct pci_ops pci_direct_conf2 = { - pci_conf2_read_config_byte, - pci_conf2_read_config_word, - pci_conf2_read_config_dword, - pci_conf2_write_config_byte, - pci_conf2_write_config_word, - pci_conf2_write_config_dword + .read = pci_conf2_read, + .write = pci_conf2_write, }; @@ -283,7 +195,7 @@ */ static int __devinit pci_sanity_check(struct pci_ops *o) { - u16 x; + u32 x = 0; struct pci_bus bus; /* Fake bus and device */ struct pci_dev dev; @@ -292,16 +204,16 @@ bus.number = 0; dev.bus = &bus; for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++) - if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) && + if ((!o->read(&bus, dev.devfn, PCI_CLASS_DEVICE, 2, &x) && (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || - (!o->read_word(&dev, PCI_VENDOR_ID, &x) && + (!o->read(&bus, dev.devfn, PCI_VENDOR_ID, 2, &x) && (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) return 1; DBG("PCI: Sanity check failed\n"); return 0; } -static struct pci_ops * __devinit pci_check_direct(void) +static int __init pci_direct_init(void) { unsigned int tmp; unsigned long flags; @@ -321,8 +233,10 @@ local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) - return NULL; - return &pci_direct_conf1; + pci_root_ops = NULL; + else + pci_root_ops = &pci_direct_conf1; + return 0; } outl (tmp, 0xCF8); } @@ -339,28 +253,15 @@ local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) - return NULL; - return &pci_direct_conf2; + pci_root_ops = NULL; + else + pci_root_ops = &pci_direct_conf2; + return 0; } } local_irq_restore(flags); - return NULL; -} - -static int __init pci_direct_init(void) -{ - if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) - && (pci_root_ops = pci_check_direct())) { - if (pci_root_ops == &pci_direct_conf1) { - pci_config_read = pci_conf1_read; - pci_config_write = pci_conf1_write; - } - else { - pci_config_read = pci_conf2_read; - pci_config_write = pci_conf2_write; - } - } + pci_root_ops = NULL; return 0; } diff -Nru a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c --- a/arch/i386/pci/numa.c Sat Aug 31 15:05:55 2002 +++ b/arch/i386/pci/numa.c Sat Aug 31 15:05:55 2002 @@ -1,19 +1,19 @@ /* * numa.c - Low-level PCI access for NUMA-Q machines */ + #include #include - #include "pci.h" #define BUS2QUAD(global) (mp_bus_id_to_node[global]) #define BUS2LOCAL(global) (mp_bus_id_to_local[global]) #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) -#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ +#define PCI_CONF1_MQ_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -22,7 +22,7 @@ spin_lock_irqsave(&pci_config_lock, flags); - outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + outl_quad(PCI_CONF1_MQ_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); switch (len) { case 1: @@ -41,7 +41,7 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -50,7 +50,7 @@ spin_lock_irqsave(&pci_config_lock, flags); - outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + outl_quad(PCI_CONF1_MQ_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); switch (len) { case 1: @@ -69,6 +69,25 @@ return 0; } +#undef PCI_CONF1_MQ_ADDRESS + +static int pci_conf1_mq_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + return __pci_conf1_mq_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +static int pci_conf1_mq_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + return __pci_conf1_mq_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +static struct pci_ops pci_direct_conf1_mq = { + read: pci_conf1_mq_read, + write: pci_conf1_mq_write +}; + static void __devinit pci_fixup_i450nx(struct pci_dev *d) { @@ -102,8 +121,7 @@ { int quad; - pci_config_read = pci_conf1_read; - pci_config_write = pci_conf1_write; + pci_root_ops = &pci_direct_conf1_mq; if (pcibios_scanned++) return 0; diff -Nru a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c --- a/arch/i386/pci/pcbios.c Sat Aug 31 15:05:54 2002 +++ b/arch/i386/pci/pcbios.c Sat Aug 31 15:05:54 2002 @@ -185,7 +185,7 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long result = 0; unsigned long flags; @@ -240,7 +240,7 @@ return (int)((result & 0xff00) >> 8); } -static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long result = 0; unsigned long flags; @@ -295,63 +295,16 @@ return (int)((result & 0xff00) >> 8); } -static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value) +static int pci_bios_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - - *value = (u8)data; - - return result; -} - -static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - - *value = (u16)data; - - return result; -} - -static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - if (!value) - return -EINVAL; - - return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); -} - -static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); + return __pci_bios_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } -static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value) +static int pci_bios_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_bios_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } @@ -360,12 +313,8 @@ */ static struct pci_ops pci_bios_access = { - pci_bios_read_config_byte, - pci_bios_read_config_word, - pci_bios_read_config_dword, - pci_bios_write_config_byte, - pci_bios_write_config_word, - pci_bios_write_config_dword + .read = pci_bios_read, + .write = pci_bios_write }; /* @@ -551,8 +500,6 @@ && ((pci_root_ops = pci_find_bios()))) { pci_probe |= PCI_BIOS_SORT; pci_bios_present = 1; - pci_config_read = pci_bios_read; - pci_config_write = pci_bios_write; } return 0; } diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile --- a/arch/ia64/Makefile Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/Makefile Sat Aug 31 15:05:54 2002 @@ -96,7 +96,8 @@ vmlinux: arch/$(ARCH)/vmlinux.lds.s -CPPFLAGS_arch/ia64/vmlinux.lds.s := -traditional +arch/$(ARCH)/vmlinux.lds.s: arch/$(ARCH)/vmlinux.lds.S + $(CPP) $(CPPFLAGS) $(CPPFLAGS_$@) -D__ASSEMBLY__ -P -C -U$(ARCH) $< -o $@ compressed: vmlinux $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux-tmp diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig --- a/arch/ia64/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/defconfig Sat Aug 31 15:05:54 2002 @@ -628,6 +628,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/hp/common/sba_iommu.c Sat Aug 31 15:05:54 2002 @@ -30,11 +30,11 @@ #include #include #include +#include #include /* ia64_get_itc() */ #include #include /* PAGE_OFFSET */ -#include #define DRIVER_NAME "SBA" diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c --- a/arch/ia64/hp/sim/simeth.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/hp/sim/simeth.c Sat Aug 31 15:05:54 2002 @@ -213,7 +213,7 @@ memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - dev->irq = ia64_alloc_irq(); + dev->irq = ia64_alloc_vector(); /* * attach the interrupt in the simulator, this does enable interrupts diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/hp/sim/simserial.c Sat Aug 31 15:06:00 2002 @@ -1076,7 +1076,7 @@ if (state->type == PORT_UNKNOWN) continue; if (!state->irq) { - state->irq = ia64_alloc_irq(); + state->irq = ia64_alloc_vector(); ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); } diff -Nru a/arch/ia64/hp/zx1/hpzx1_misc.c b/arch/ia64/hp/zx1/hpzx1_misc.c --- a/arch/ia64/hp/zx1/hpzx1_misc.c Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/hp/zx1/hpzx1_misc.c Sat Aug 31 15:05:59 2002 @@ -12,9 +12,9 @@ #include #include #include +#include #include -#include #include extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Sat Aug 31 15:06:01 2002 +++ b/arch/ia64/ia32/sys_ia32.c Sat Aug 31 15:06:03 2002 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/acpi.c Sat Aug 31 15:06:00 2002 @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -47,9 +47,9 @@ #define PREFIX "ACPI: " -asm (".weak iosapic_register_irq"); -asm (".weak iosapic_register_legacy_irq"); -asm (".weak iosapic_register_platform_irq"); +asm (".weak iosapic_register_intr"); +asm (".weak iosapic_override_isa_irq"); +asm (".weak iosapic_register_platform_intr"); asm (".weak iosapic_init"); asm (".weak iosapic_version"); @@ -173,10 +173,10 @@ #ifdef CONFIG_ACPI_BOOT -#define ACPI_MAX_PLATFORM_IRQS 256 +#define ACPI_MAX_PLATFORM_INTERRUPTS 256 /* Array to record platform interrupt vectors for generic interrupt routing. */ -int platform_irq_list[ACPI_MAX_PLATFORM_IRQS] = { [0 ... ACPI_MAX_PLATFORM_IRQS - 1] = -1 }; +int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 }; enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC; @@ -189,9 +189,9 @@ { int vector = -1; - if (int_type < ACPI_MAX_PLATFORM_IRQS) { + if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) { /* correctable platform error interrupt */ - vector = platform_irq_list[int_type]; + vector = platform_intr_list[int_type]; } else printk("acpi_request_vector(): invalid interrupt type\n"); return vector; @@ -210,6 +210,7 @@ static int total_cpus __initdata; static int available_cpus __initdata; struct acpi_table_madt * acpi_madt __initdata; +static u8 has_8259; static int __init @@ -284,7 +285,7 @@ static int __init -acpi_find_iosapic (int global_vector, u32 *irq_base, char **iosapic_address) +acpi_find_iosapic (unsigned int gsi, u32 *gsi_base, char **iosapic_address) { struct acpi_table_iosapic *iosapic; int ver; @@ -292,7 +293,7 @@ char *p; char *end; - if (!irq_base || !iosapic_address) + if (!gsi_base || !iosapic_address) return -ENODEV; p = (char *) (acpi_madt + 1); @@ -302,13 +303,13 @@ if (*p == ACPI_MADT_IOSAPIC) { iosapic = (struct acpi_table_iosapic *) p; - *irq_base = iosapic->global_irq_base; + *gsi_base = iosapic->global_irq_base; *iosapic_address = ioremap(iosapic->address, 0); ver = iosapic_version(*iosapic_address); max_pin = (ver >> 16) & 0xff; - if ((global_vector - *irq_base) <= max_pin) + if ((gsi - *gsi_base) <= max_pin) return 0; /* Found it! */ } p += p[1]; @@ -347,7 +348,7 @@ { struct acpi_table_plat_int_src *plintsrc; int vector; - u32 irq_base; + u32 gsi_base; char *iosapic_address; plintsrc = (struct acpi_table_plat_int_src *) header; @@ -356,31 +357,31 @@ acpi_table_print_madt_entry(header); - if (!iosapic_register_platform_irq) { - printk(KERN_WARNING PREFIX "No ACPI platform IRQ support\n"); + if (!iosapic_register_platform_intr) { + printk(KERN_WARNING PREFIX "No ACPI platform interrupt support\n"); return -ENODEV; } - if (acpi_find_iosapic(plintsrc->global_irq, &irq_base, &iosapic_address)) { + if (acpi_find_iosapic(plintsrc->global_irq, &gsi_base, &iosapic_address)) { printk(KERN_WARNING PREFIX "IOSAPIC not found\n"); return -ENODEV; } /* - * Get vector assignment for this IRQ, set attributes, and program the - * IOSAPIC routing table. + * Get vector assignment for this interrupt, set attributes, + * and program the IOSAPIC routing table. */ - vector = iosapic_register_platform_irq(plintsrc->type, - plintsrc->global_irq, - plintsrc->iosapic_vector, - plintsrc->eid, - plintsrc->id, - (plintsrc->flags.polarity == 1) ? 1 : 0, - (plintsrc->flags.trigger == 1) ? 1 : 0, - irq_base, - iosapic_address); + vector = iosapic_register_platform_intr(plintsrc->type, + plintsrc->global_irq, + plintsrc->iosapic_vector, + plintsrc->eid, + plintsrc->id, + (plintsrc->flags.polarity == 1) ? 1 : 0, + (plintsrc->flags.trigger == 1) ? 1 : 0, + gsi_base, + iosapic_address); - platform_irq_list[plintsrc->type] = vector; + platform_intr_list[plintsrc->type] = vector; return 0; } @@ -397,12 +398,12 @@ acpi_table_print_madt_entry(header); /* Ignore if the platform doesn't support overrides */ - if (!iosapic_register_legacy_irq) + if (!iosapic_override_isa_irq) return 0; - iosapic_register_legacy_irq(p->bus_irq, p->global_irq, - (p->flags.polarity == 1) ? 1 : 0, - (p->flags.trigger == 1) ? 1 : 0); + iosapic_override_isa_irq(p->bus_irq, p->global_irq, + (p->flags.polarity == 1) ? 1 : 0, + (p->flags.trigger == 1) ? 1 : 0); return 0; } @@ -431,6 +432,9 @@ acpi_madt = (struct acpi_table_madt *) __va(phys_addr); + /* remember the value for reference after free_initmem() */ + has_8259 = acpi_madt->flags.pcat_compat; + /* Get base address of IPI Message Block */ if (acpi_madt->lapic_address) @@ -440,11 +444,14 @@ return 0; } + static int __init acpi_parse_fadt (unsigned long phys_addr, unsigned long size) { struct acpi_table_header *fadt_header; fadt_descriptor_rev2 *fadt; + u32 sci_irq, gsi_base; + char *iosapic_address; if (!phys_addr || !size) return -EINVAL; @@ -458,9 +465,20 @@ if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER)) acpi_kbd_controller_present = 0; + if (!iosapic_register_intr) + return 0; /* just ignore the rest */ + + sci_irq = fadt->sci_int; + + if (has_8259 && sci_irq < 16) + return 0; /* legacy, no setup required */ + + if (!acpi_find_iosapic(sci_irq, &gsi_base, &iosapic_address)) + iosapic_register_intr(sci_irq, 0, 0, gsi_base, iosapic_address); return 0; } + unsigned long __init acpi_find_rsdp (void) { @@ -482,12 +500,12 @@ acpi_parse_spcr (unsigned long phys_addr, unsigned long size) { acpi_ser_t *spcr; - unsigned long global_int; + unsigned int gsi; if (!phys_addr || !size) return -EINVAL; - if (!iosapic_register_irq) + if (!iosapic_register_intr) return -ENODEV; /* @@ -500,6 +518,7 @@ */ spcr = (acpi_ser_t *) __va(phys_addr); + setup_serial_acpi(spcr); if (spcr->length < sizeof(acpi_ser_t)) @@ -509,22 +528,22 @@ if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) && (spcr->int_type == ACPI_SERIAL_INT_SAPIC)) { - u32 irq_base; + u32 gsi_base; char *iosapic_address; int vector; /* We have a UART in memory space with an SAPIC interrupt */ - global_int = ((spcr->global_int[3] << 24) | - (spcr->global_int[2] << 16) | - (spcr->global_int[1] << 8) | - (spcr->global_int[0]) ); - - /* Which iosapic does this IRQ belong to? */ - - if (!acpi_find_iosapic(global_int, &irq_base, &iosapic_address)) - vector = iosapic_register_irq(global_int, 1, 1, - irq_base, iosapic_address); + gsi = ( (spcr->global_int[3] << 24) | + (spcr->global_int[2] << 16) | + (spcr->global_int[1] << 8) | + (spcr->global_int[0]) ); + + /* Which iosapic does this interrupt belong to? */ + + if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address)) + vector = iosapic_register_intr(gsi, 1, 1, + gsi_base, iosapic_address); } return 0; } @@ -583,7 +602,12 @@ printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); skip_madt: - /* FADT says whether a legacy keyboard controller is present. */ + /* + * FADT says whether a legacy keyboard controller is present. + * The FADT also contains an SCI_INT line, by which the system + * gets interrupts such as power and sleep buttons. If it's not + * on a Legacy interrupt, it needs to be setup. + */ if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1) printk(KERN_ERR PREFIX "Can't find FADT\n"); @@ -631,7 +655,7 @@ *count = 0; if (acpi_prt.count < 0) { - printk(KERN_ERR PREFIX "No PCI IRQ routing entries\n"); + printk(KERN_ERR PREFIX "No PCI interrupt routing entries\n"); return -ENODEV; } @@ -667,6 +691,15 @@ *type = ACPI_IRQ_MODEL_IOSAPIC; return 0; +} + +int +acpi_irq_to_vector (u32 irq) +{ + if (has_8259 && irq < 16) + return isa_irq_to_vector(irq); + + return gsi_to_vector(irq); } #endif /* CONFIG_ACPI_BOOT */ diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/kernel/efi.c Sat Aug 31 15:05:54 2002 @@ -24,8 +24,8 @@ #include #include #include +#include -#include #include #include #include diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c --- a/arch/ia64/kernel/efivars.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/efivars.c Sat Aug 31 15:06:00 2002 @@ -65,8 +65,8 @@ #include #include #include +#include -#include #include MODULE_AUTHOR("Matt Domsch "); diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/kernel/entry.S Sat Aug 31 15:05:55 2002 @@ -1229,11 +1229,11 @@ data8 ia64_ni_syscall // 1235 data8 ia64_ni_syscall data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1240 - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_io_setup + data8 sys_io_destroy + data8 sys_io_getevents // 1240 + data8 sys_io_submit + data8 sys_io_cancel data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall // 1245 diff -Nru a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c --- a/arch/ia64/kernel/fw-emu.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/kernel/fw-emu.c Sat Aug 31 15:05:54 2002 @@ -13,7 +13,7 @@ # include #endif -#include +#include #include #include #include diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c --- a/arch/ia64/kernel/ia64_ksyms.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/ia64_ksyms.c Sat Aug 31 15:06:00 2002 @@ -58,7 +58,7 @@ #include # ifndef CONFIG_NUMA -EXPORT_SYMBOL(cpu_info); +EXPORT_SYMBOL(cpu_info__per_cpu); # endif EXPORT_SYMBOL(kernel_thread); diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/iosapic.c Sat Aug 31 15:06:00 2002 @@ -26,9 +26,12 @@ * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping * error + * 02/07/29 T. Kochi Allocate interrupt vectors dynamically + * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, + * etc.) */ /* - * Here is what the interrupt logic between a PCI device and the CPU looks like: + * Here is what the interrupt logic between a PCI device and the kernel looks like: * * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The * device is uniquely identified by its bus--, and slot-number (the function @@ -37,19 +40,28 @@ * * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level - * triggered and use the same polarity). Each interrupt line has a unique IOSAPIC - * irq number which can be calculated as the sum of the controller's base irq number - * and the IOSAPIC pin number to which the line connects. + * triggered and use the same polarity). Each interrupt line has a unique Global + * System Interrupt (GSI) number which can be calculated as the sum of the controller's + * base GSI number and the IOSAPIC pin number to which the line connects. * - * (3) The IOSAPIC uses an internal table to map the IOSAPIC pin into the IA-64 interrupt - * vector. This interrupt vector is then sent to the CPU. + * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin + * into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. * - * In other words, there are two levels of indirections involved: + * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as + * architecture-independent interrupt handling mechanism in Linux. As an + * IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number + * mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and + * IRQ. A platform can implemnent platform_irq_to_vector(irq) and + * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. + * Please see also include/asm-ia64/hw_irq.h for those APIs. * - * pci pin -> iosapic irq -> IA-64 vector + * To sum up, there are three levels of mappings involved: * - * Note: outside this module, IA-64 vectors are called "irqs". This is because that's - * the traditional name Linux uses for interrupt vectors. + * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ + * + * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. + * Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this + * source code. */ #include @@ -72,49 +84,55 @@ #include -#undef DEBUG_IRQ_ROUTING +#undef DEBUG_INTERRUPT_ROUTING #undef OVERRIDE_DEBUG +#ifdef DEBUG_INTERRUPT_ROUTING +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif + static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; -/* PCI pin to IOSAPIC irq routing information. This info typically comes from ACPI. */ +/* PCI pin to GSI routing information. This info typically comes from ACPI. */ static struct { int num_routes; struct pci_vector_struct *route; } pci_irq; -/* This tables maps IA-64 vectors to the IOSAPIC pin that generates this vector. */ +/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ -static struct iosapic_irq { - char *addr; /* base address of IOSAPIC */ - unsigned int base_irq; /* first irq assigned to this IOSAPIC */ - char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ - unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ - unsigned char polarity : 1; /* interrupt polarity (see iosapic.h) */ - unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ -} iosapic_irq[IA64_NUM_VECTORS]; +static struct iosapic_intr_info { + char *addr; /* base address of IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ + char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ + unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ + unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ + unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ +} iosapic_intr_info[IA64_NUM_VECTORS]; static struct iosapic { - char *addr; /* base address of IOSAPIC */ - unsigned int base_irq; /* first irq assigned to this IOSAPIC */ - unsigned short max_pin; /* max input pin supported in this IOSAPIC */ + char *addr; /* base address of IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ + unsigned short num_rte; /* number of RTE in this IOSAPIC */ unsigned char pcat_compat; /* 8259 compatibility flag */ -} iosapic_lists[256] __initdata; +} iosapic_lists[256] __devinitdata; static int num_iosapic = 0; /* - * Find an IOSAPIC associated with an IRQ + * Find an IOSAPIC associated with a GSI */ -static inline int __init -find_iosapic (unsigned int irq) +static inline int __devinit +find_iosapic (unsigned int gsi) { int i; for (i = 0; i < num_iosapic; i++) { - if ((unsigned) (irq - iosapic_lists[i].base_irq) <= iosapic_lists[i].max_pin) + if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) return i; } @@ -122,60 +140,51 @@ } /* - * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no + * Translate GSI number to the corresponding IA-64 interrupt vector. If no * entry exists, return -1. */ -static int -iosapic_irq_to_vector (int irq) +int +gsi_to_vector (unsigned int gsi) { int vector; for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) - if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq) + if (iosapic_intr_info[vector].gsi_base + iosapic_intr_info[vector].rte_index == gsi) return vector; return -1; } -/* - * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, - * return -1. - */ -int -pci_pin_to_vector (int bus, int slot, int pci_pin) -{ - struct pci_vector_struct *r; - - for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r) - if (r->bus == bus && (r->pci_id >> 16) == slot && r->pin == pci_pin) - return iosapic_irq_to_vector(r->irq); - return -1; -} - static void -set_rte (unsigned int vector, unsigned long dest) +set_rte (unsigned int vector, unsigned int dest) { unsigned long pol, trigger, dmode; u32 low32, high32; char *addr; - int pin; + int rte_index; char redir; -#ifdef DEBUG_IRQ_ROUTING - printk(KERN_DEBUG "set_rte: routing vector 0x%02x to 0x%lx\n", vector, dest); -#endif + DBG(KERN_DEBUG "%s: routing vector %d to %x\n", __FUNCTION__, vector, dest); - pin = iosapic_irq[vector].pin; - if (pin < 0) + rte_index = iosapic_intr_info[vector].rte_index; + if (rte_index < 0) return; /* not an IOSAPIC interrupt */ - addr = iosapic_irq[vector].addr; - pol = iosapic_irq[vector].polarity; - trigger = iosapic_irq[vector].trigger; - dmode = iosapic_irq[vector].dmode; + addr = iosapic_intr_info[vector].addr; + pol = iosapic_intr_info[vector].polarity; + trigger = iosapic_intr_info[vector].trigger; + dmode = iosapic_intr_info[vector].dmode; redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; #ifdef CONFIG_SMP - set_irq_affinity_info(vector, (int)(dest & 0xffff), redir); + { + unsigned int irq; + + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == vector) { + set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); + break; + } + } #endif low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | @@ -186,9 +195,9 @@ /* dest contains both id and eid */ high32 = (dest << IOSAPIC_DEST_SHIFT); - writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); writel(low32, addr + IOSAPIC_WINDOW); } @@ -204,18 +213,18 @@ unsigned long flags; char *addr; u32 low32; - int pin; + int rte_index; ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vec].addr; - pin = iosapic_irq[vec].pin; + addr = iosapic_intr_info[vec].addr; + rte_index = iosapic_intr_info[vec].rte_index; - if (pin < 0) + if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 |= (1 << IOSAPIC_MASK_SHIFT); /* set only the mask bit */ @@ -230,17 +239,17 @@ unsigned long flags; char *addr; u32 low32; - int pin; + int rte_index; ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vec].addr; - pin = iosapic_irq[vec].pin; - if (pin < 0) + addr = iosapic_intr_info[vec].addr; + rte_index = iosapic_intr_info[vec].rte_index; + if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 &= ~(1 << IOSAPIC_MASK_SHIFT); /* clear only the mask bit */ @@ -256,24 +265,28 @@ #ifdef CONFIG_SMP unsigned long flags; u32 high32, low32; - int dest, pin; + int dest, rte_index; char *addr; - int redir = (irq & (1<<31)) ? 1 : 0; + int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; + ia64_vector vec; + + irq &= (~IA64_IRQ_REDIRECTED); + vec = irq_to_vector(irq); mask &= cpu_online_map; - if (!mask || irq >= IA64_NUM_VECTORS) + if (!mask || vec >= IA64_NUM_VECTORS) return; dest = cpu_physical_id(ffz(~mask)); - pin = iosapic_irq[irq].pin; - addr = iosapic_irq[irq].addr; + rte_index = iosapic_intr_info[vec].rte_index; + addr = iosapic_intr_info[vec].addr; - if (pin < 0) + if (rte_index < 0) return; /* not an IOSAPIC interrupt */ - set_irq_affinity_info(irq,dest,redir); + set_irq_affinity_info(irq, dest, redir); /* dest contains both id and eid */ high32 = dest << IOSAPIC_DEST_SHIFT; @@ -281,7 +294,7 @@ spin_lock_irqsave(&iosapic_lock, flags); { /* get current delivery mode by reading the low32 */ - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT); @@ -292,9 +305,9 @@ /* change delivery mode to fixed */ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); - writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); writel(low32, addr + IOSAPIC_WINDOW); } spin_unlock_irqrestore(&iosapic_lock, flags); @@ -317,7 +330,7 @@ { ia64_vector vec = irq_to_vector(irq); - writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI); + writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI); } #define iosapic_shutdown_level_irq mask_irq @@ -388,7 +401,7 @@ * { * unsigned int version : 8; * unsigned int reserved1 : 8; - * unsigned int pins : 8; + * unsigned int max_redir : 8; * unsigned int reserved2 : 8; * } */ @@ -405,70 +418,72 @@ { int new_vector; - if (iosapic_irq[vector].pin >= 0 || iosapic_irq[vector].addr - || iosapic_irq[vector].base_irq || iosapic_irq[vector].dmode - || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger) + if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr + || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode + || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger) { - new_vector = ia64_alloc_irq(); - printk("Reassigning vector 0x%x to 0x%x\n", vector, new_vector); - memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector], - sizeof(struct iosapic_irq)); - memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq)); - iosapic_irq[vector].pin = -1; + new_vector = ia64_alloc_vector(); + printk("Reassigning vector %d to %d\n", vector, new_vector); + memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], + sizeof(struct iosapic_intr_info)); + memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); + iosapic_intr_info[vector].rte_index = -1; } } static void -register_irq (u32 global_vector, int vector, int pin, unsigned char delivery, - unsigned long polarity, unsigned long edge_triggered, - u32 base_irq, char *iosapic_address) +register_intr (unsigned int gsi, int vector, unsigned char delivery, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { irq_desc_t *idesc; struct hw_interrupt_type *irq_type; + int rte_index; - gsi_to_vector(global_vector) = vector; - iosapic_irq[vector].pin = pin; - iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; - iosapic_irq[vector].dmode = delivery; + rte_index = gsi - gsi_base; + iosapic_intr_info[vector].rte_index = rte_index; + iosapic_intr_info[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + iosapic_intr_info[vector].dmode = delivery; /* - * In override, it does not provide addr/base_irq. global_vector is enough to - * locate iosapic addr, base_irq and pin by examining base_irq and max_pin of - * registered iosapics (tbd) + * In override, it may not provide addr/gsi_base. GSI is enough to + * locate iosapic addr, gsi_base and rte_index by examining + * gsi_base and num_rte of registered iosapics (tbd) */ #ifndef OVERRIDE_DEBUG if (iosapic_address) { - iosapic_irq[vector].addr = iosapic_address; - iosapic_irq[vector].base_irq = base_irq; + iosapic_intr_info[vector].addr = iosapic_address; + iosapic_intr_info[vector].gsi_base = gsi_base; } #else if (iosapic_address) { - if (iosapic_irq[vector].addr && (iosapic_irq[vector].addr != iosapic_address)) - printk("WARN: register_irq: diff IOSAPIC ADDRESS for gv %x, v %x\n", - global_vector, vector); - iosapic_irq[vector].addr = iosapic_address; - if (iosapic_irq[vector].base_irq && (iosapic_irq[vector].base_irq != base_irq)) { - printk("WARN: register_irq: diff BASE IRQ %x for gv %x, v %x\n", - base_irq, global_vector, vector); + if (iosapic_intr_info[vector].addr && (iosapic_intr_info[vector].addr != iosapic_address)) + printk("WARN: register_intr: diff IOSAPIC ADDRESS for GSI 0x%x, vector %d\n", + gsi, vector); + iosapic_intr_info[vector].addr = iosapic_address; + if (iosapic_intr_info[vector].gsi_base && (iosapic_intr_info[vector].gsi_base != gsi_base)) { + printk("WARN: register_intr: diff GSI base 0x%x for GSI 0x%x, vector %d\n", + gsi_base, gsi, vector); } - iosapic_irq[vector].base_irq = base_irq; - } else if (!iosapic_irq[vector].addr) - printk("WARN: register_irq: invalid override for gv %x, v %x\n", - global_vector, vector); + iosapic_intr_info[vector].gsi_base = gsi_base; + } else if (!iosapic_intr_info[vector].addr) + printk("WARN: register_intr: invalid override for GSI 0x%x, vector %d\n", + gsi, vector); #endif if (edge_triggered) { - iosapic_irq[vector].trigger = IOSAPIC_EDGE; + iosapic_intr_info[vector].trigger = IOSAPIC_EDGE; irq_type = &irq_type_iosapic_edge; } else { - iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + iosapic_intr_info[vector].trigger = IOSAPIC_LEVEL; irq_type = &irq_type_iosapic_level; } idesc = irq_desc(vector); if (idesc->handler != irq_type) { if (idesc->handler != &no_irq_type) - printk("register_irq(): changing vector 0x%02x from " - "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + printk("%s: changing vector %d from %s to %s\n", + __FUNCTION__, vector, idesc->handler->typename, + irq_type->typename); idesc->handler = irq_type; } } @@ -479,24 +494,26 @@ * program the IOSAPIC RTE. */ int -iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long - edge_triggered, u32 base_irq, char *iosapic_address) +iosapic_register_intr (unsigned int gsi, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { int vector; + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; - vector = iosapic_irq_to_vector(global_vector); + vector = gsi_to_vector(gsi); if (vector < 0) - vector = ia64_alloc_irq(); + vector = ia64_alloc_vector(); - register_irq (global_vector, vector, global_vector - base_irq, - IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, - base_irq, iosapic_address); + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, + polarity, edge_triggered, gsi_base, iosapic_address); - printk("IOSAPIC 0x%x(%s,%s) -> Vector 0x%x\n", global_vector, - (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector); + printk("GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n", + gsi, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); return vector; } @@ -505,12 +522,14 @@ * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */ int -iosapic_register_platform_irq (u32 int_type, u32 global_vector, - u32 iosapic_vector, u16 eid, u16 id, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, char *iosapic_address) +iosapic_register_platform_intr (u32 int_type, unsigned int gsi, + int iosapic_vector, u16 eid, u16 id, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { unsigned char delivery; int vector; + unsigned int dest = ((id << 8) | eid) & 0xffff; switch (int_type) { case ACPI_INTERRUPT_PMI: @@ -523,7 +542,7 @@ delivery = IOSAPIC_PMI; break; case ACPI_INTERRUPT_INIT: - vector = ia64_alloc_irq(); + vector = ia64_alloc_vector(); delivery = IOSAPIC_INIT; break; case ACPI_INTERRUPT_CPEI: @@ -535,56 +554,137 @@ return -1; } - register_irq(global_vector, vector, global_vector - base_irq, delivery, polarity, - edge_triggered, base_irq, iosapic_address); + register_intr(gsi, vector, delivery, polarity, + edge_triggered, gsi_base, iosapic_address); - printk("PLATFORM int 0x%x: IOSAPIC 0x%x(%s,%s) -> Vector 0x%x CPU %.02u:%.02u\n", - int_type, global_vector, (polarity ? "high" : "low"), - (edge_triggered ? "edge" : "level"), vector, eid, id); + printk("PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n", + int_type, gsi, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, ((id << 8) | eid) & 0xffff); + set_rte(vector, dest); return vector; } /* - * ACPI calls this when it finds an entry for a legacy ISA interrupt. - * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). + * ACPI calls this when it finds an entry for a legacy ISA IRQ override. + * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). */ void -iosapic_register_legacy_irq (unsigned long irq, - unsigned long pin, unsigned long polarity, - unsigned long edge_triggered) -{ - int vector = isa_irq_to_vector(irq); - - register_irq(irq, vector, (int)pin, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, - 0, NULL); /* ignored for override */ - -#ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n", - (unsigned) irq, (unsigned) pin, - polarity ? "high" : "low", edge_triggered ? "edge" : "level", - vector); -#endif +iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, + unsigned long polarity, + unsigned long edge_triggered) +{ + int index, vector; + unsigned int gsi_base; + char *addr; + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; + + index = find_iosapic(gsi); + + if (index < 0) { + printk("ISA: No corresponding IOSAPIC found : ISA IRQ %u -> GSI 0x%x\n", isa_irq, gsi); + return; + } + + vector = isa_irq_to_vector(isa_irq); + addr = iosapic_lists[index].addr; + gsi_base = iosapic_lists[index].gsi_base; + + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, + gsi_base, addr); + + DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n", + isa_irq, gsi, + polarity ? "high" : "low", edge_triggered ? "edge" : "level", + dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); +} + +/* + * Map PCI pin to the corresponding GSI. + * If no such mapping exists, return -1. + */ +static int +pci_pin_to_gsi (int bus, int slot, int pci_pin, unsigned int *gsi) +{ + struct pci_vector_struct *r; + + for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r) + if (r->bus == bus && + (r->pci_id >> 16) == slot && r->pin == pci_pin) { + *gsi = r->irq; + return 0; + } + + return -1; +} + +/* + * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, + * try to allocate a new vector. If it fails, return -1. + */ +static int +pci_pin_to_vector (int bus, int slot, int pci_pin) +{ + int index, vector; + int gsi_base, pcat_compat; + char *addr; + unsigned int gsi; + + if (pci_pin_to_gsi(bus, slot, pci_pin, &gsi) < 0) { + printk("PCI: no interrupt route for %02x:%02x pin %c\n", bus, slot, 'A' + pci_pin); + return -1; + } + + vector = gsi_to_vector(gsi); + + if (vector < 0) { + /* we should allocate a vector for this interrupt line */ + + index = find_iosapic(gsi); + + if (index < 0) { + printk("PCI: GSI 0x%x has no IOSAPIC mapping\n", gsi); + return -1; + } + + addr = iosapic_lists[index].addr; + gsi_base = iosapic_lists[index].gsi_base; + pcat_compat = iosapic_lists[index].pcat_compat; + + if (pcat_compat && (gsi < 16)) + vector = isa_irq_to_vector(gsi); + else { + /* new GSI; allocate a vector for it */ + vector = ia64_alloc_vector(); + } + + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, + 0, 0, gsi_base, addr); + + DBG("PCI: (%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n", + bus, slot, 'A' + pci_pin, gsi, vector); + } + + return vector; } -void __init -iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat) +void __devinit +iosapic_init (unsigned long phys_addr, unsigned int gsi_base, int pcat_compat) { - int irq, max_pin, vector, pin; - unsigned int ver; + int num_rte, vector; + unsigned int isa_irq, ver; char *addr; static int first_time = 1; if (first_time) { first_time = 0; for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) - iosapic_irq[vector].pin = -1; /* mark as unused */ + iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ } if (pcat_compat) { @@ -599,109 +699,148 @@ addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); - max_pin = (ver >> 16) & 0xff; + + /* + * The MAX_REDIR register holds the highest input pin + * number (starting from 0). + * We add 1 so that we can use it for number of pins (= RTEs) + */ + num_rte = ((ver >> 16) & 0xff) + 1; iosapic_lists[num_iosapic].addr = addr; iosapic_lists[num_iosapic].pcat_compat = pcat_compat; - iosapic_lists[num_iosapic].base_irq = base_irq; - iosapic_lists[num_iosapic].max_pin = max_pin; + iosapic_lists[num_iosapic].gsi_base = gsi_base; + iosapic_lists[num_iosapic].num_rte = num_rte; num_iosapic++; - printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", - (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); + printk("IOSAPIC: version %x.%x, address 0x%lx, GSIs 0x%x-0x%x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1); + + if ((gsi_base == 0) && pcat_compat) { + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; - if ((base_irq == 0) && pcat_compat) { /* * Map the legacy ISA devices into the IOSAPIC data. Some of these may * get reprogrammed later on with data from the ACPI Interrupt Source * Override table. */ - for (irq = 0; irq < 16; ++irq) { - vector = isa_irq_to_vector(irq); - if ((pin = iosapic_irq[vector].pin) == -1) - pin = irq; + for (isa_irq = 0; isa_irq < 16; ++isa_irq) { + vector = isa_irq_to_vector(isa_irq); - register_irq(irq, vector, pin, + register_intr(isa_irq, vector, IOSAPIC_LOWEST_PRIORITY, /* IOSAPIC_POL_HIGH, IOSAPIC_EDGE */ - IOSAPIC_LOWEST_PRIORITY, 1, 1, base_irq, addr); + 1, 1, gsi_base, addr); -#ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n", - irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, - vector); -#endif + DBG("ISA: IRQ %u -> GSI 0x%x (high,edge) -> CPU 0x%04x vector %d\n", + isa_irq, isa_irq, dest, vector); /* program the IOSAPIC routing table: */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); } } } -static void __init -iosapic_init_pci_irq (void) -{ - int i, index, vector, pin; - int base_irq, max_pin, pcat_compat; - unsigned int irq; - char *addr; - - if (acpi_get_prt(&pci_irq.route, &pci_irq.num_routes)) - return; - - for (i = 0; i < pci_irq.num_routes; i++) { - irq = pci_irq.route[i].irq; +/* + * Set allocated interrupt vector to dev->irq and + * program IOSAPIC to deliver interrupts + */ +void +iosapic_fixup_pci_interrupt (struct pci_dev *dev) +{ + unsigned char pci_pin; + int vector; + unsigned int dest; + struct hw_interrupt_type *irq_type; + irq_desc_t *idesc; - index = find_iosapic(irq); - if (index < 0) { - printk("PCI: IRQ %u has no IOSAPIC mapping\n", irq); - continue; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pci_pin); + if (pci_pin) { + pci_pin--; /* interrupt pins are numberd starting from 1 */ + + vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pci_pin); + + if (vector < 0 && dev->bus->parent) { + /* go back to the bridge */ + struct pci_dev *bridge = dev->bus->self; + + if (bridge) { + /* allow for multiple bridges on an adapter */ + do { + /* do the bridge swizzle... */ + pci_pin = (pci_pin + PCI_SLOT(dev->devfn)) % 4; + vector = pci_pin_to_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), + pci_pin); + } while (vector < 0 && (bridge = bridge->bus->self)); + } + if (vector >= 0) + printk(KERN_WARNING + "PCI: using PPB (%s INT%c) to get vector %d\n", + dev->slot_name, 'A' + pci_pin, + vector); + else + printk(KERN_WARNING + "PCI: Couldn't map irq for (%s INT%c)\n", + dev->slot_name, 'A' + pci_pin); } - addr = iosapic_lists[index].addr; - base_irq = iosapic_lists[index].base_irq; - max_pin = iosapic_lists[index].max_pin; - pcat_compat = iosapic_lists[index].pcat_compat; - pin = irq - base_irq; - - if ((unsigned) pin > max_pin) - /* the interrupt route is for another controller... */ - continue; + if (vector >= 0) { + dev->irq = vector; - if (pcat_compat && (irq < 16)) - vector = isa_irq_to_vector(irq); - else { - vector = iosapic_irq_to_vector(irq); - if (vector < 0) - /* new iosapic irq: allocate a vector for it */ - vector = ia64_alloc_irq(); - } - - register_irq(irq, vector, pin, IOSAPIC_LOWEST_PRIORITY, 0, 0, base_irq, addr); + irq_type = &irq_type_iosapic_level; + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("%s: changing vector %d from %s to %s\n", + __FUNCTION__, vector, + idesc->handler->typename, + irq_type->typename); + idesc->handler = irq_type; + } +#ifdef CONFIG_SMP + /* + * For platforms that do not support interrupt redirect + * via the XTP interface, we can round-robin the PCI + * device interrupts to the processors + */ + if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { + static int cpu_index = 0; + + while (!cpu_online(cpu_index)) + if (++cpu_index >= NR_CPUS) + cpu_index = 0; -#ifdef DEBUG_IRQ_ROUTING - printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n", - pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin, - iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); + dest = cpu_physical_id(cpu_index) & 0xffff; + } else { + /* + * Direct the interrupt vector to the current cpu, + * platform redirection will distribute them. + */ + dest = (ia64_get_lid() >> 16) & 0xffff; + } +#else + /* direct the interrupt vector to the running cpu id */ + dest = (ia64_get_lid() >> 16) & 0xffff; #endif - /* - * NOTE: The IOSAPIC RTE will be programmed in iosapic_pci_fixup(). It - * needs to be done there to ensure PCI hotplug works right. - */ + + printk("PCI->APIC IRQ transform: (%s INT%c) -> CPU 0x%04x vector %d\n", + dev->slot_name, 'A' + pci_pin, dest, vector); + set_rte(vector, dest); + } } } + void iosapic_pci_fixup (int phase) { struct pci_dev *dev; - unsigned char pin; - int vector; - struct hw_interrupt_type *irq_type; - irq_desc_t *idesc; if (phase == 0) { - iosapic_init_pci_irq(); + if (acpi_get_prt(&pci_irq.route, &pci_irq.num_routes)) { + printk("%s: acpi_get_prt failed\n", __FILE__); + } return; } @@ -709,76 +848,9 @@ return; pci_for_each_dev(dev) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin) { - pin--; /* interrupt pins are numbered starting from 1 */ - vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); - if (vector < 0 && dev->bus->parent) { - /* go back to the bridge */ - struct pci_dev *bridge = dev->bus->self; - - if (bridge) { - /* allow for multiple bridges on an adapter */ - do { - /* do the bridge swizzle... */ - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - vector = pci_pin_to_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), - pin); - } while (vector < 0 && (bridge = bridge->bus->self)); - } - if (vector >= 0) - printk(KERN_WARNING - "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - pin, vector); - else - printk(KERN_WARNING - "PCI: Couldn't map irq for (B%d,I%d,P%d)\n", - dev->bus->number, PCI_SLOT(dev->devfn), pin); - } - if (vector >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", - dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); - dev->irq = vector; - - irq_type = &irq_type_iosapic_level; - idesc = irq_desc(vector); - if (idesc->handler != irq_type) { - if (idesc->handler != &no_irq_type) - printk("iosapic_pci_fixup: changing vector 0x%02x " - "from %s to %s\n", vector, - idesc->handler->typename, - irq_type->typename); - idesc->handler = irq_type; - } -#ifdef CONFIG_SMP - /* - * For platforms that do not support interrupt redirect - * via the XTP interface, we can round-robin the PCI - * device interrupts to the processors - */ - if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { - static int cpu_index = 0; + /* fixup dev->irq and program IOSAPIC */ + iosapic_fixup_pci_interrupt(dev); - while (!cpu_online(cpu_index)) - if (++cpu_index >= NR_CPUS) - cpu_index = 0; - - set_rte(vector, cpu_physical_id(cpu_index) & 0xffff); - } else { - /* - * Direct the interrupt vector to the current cpu, - * platform redirection will distribute them. - */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); - } -#else - /* direct the interrupt vector to the running cpu id */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); -#endif - } - } /* * Nothing to fixup * Fix out-of-range IRQ numbers diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/kernel/irq.c Sat Aug 31 15:05:59 2002 @@ -802,8 +802,7 @@ #define HEX_DIGITS 8 -static unsigned int parse_hex_value (const char *buffer, - unsigned long count, unsigned long *ret) +static int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) { unsigned char hexnum [HEX_DIGITS]; unsigned long value; @@ -846,11 +845,11 @@ static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; -void set_irq_affinity_info(int irq, int hwid, int redir) +void set_irq_affinity_info (unsigned int irq, int hwid, int redir) { unsigned long mask = 1UL<= 0 && irq < NR_IRQS) { + if (irq < NR_IRQS) { irq_affinity[irq] = mask; irq_redir[irq] = (char) (redir & 0xff); } @@ -861,14 +860,15 @@ { if (count < HEX_DIGITS+3) return -EINVAL; - return sprintf (page, "%s%08lx\n", irq_redir[(long)data] ? "r " : "", - irq_affinity[(long)data]); + return sprintf (page, "%s%08lx\n", irq_redir[(unsigned long)data] ? "r " : "", + irq_affinity[(unsigned long)data]); } static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { - int irq = (long) data, full_count = count, err; + unsigned int irq = (unsigned long) data; + int full_count = count, err; unsigned long new_value; const char *buf = buffer; int redir; @@ -884,6 +884,8 @@ redir = 0; err = parse_hex_value(buf, count, &new_value); + if (err) + return err; /* * Do not allow disabling IRQs completely - it's a too easy @@ -893,7 +895,7 @@ if (!(new_value & cpu_online_map)) return -EINVAL; - irq_desc(irq)->handler->set_affinity(irq | (redir?(1<<31):0), new_value); + irq_desc(irq)->handler->set_affinity(irq | (redir? IA64_IRQ_REDIRECTED : 0), new_value); return full_count; } @@ -912,7 +914,8 @@ static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { - unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long *mask = (unsigned long *) data; + int full_count = count, err; unsigned long new_value; err = parse_hex_value(buffer, count, &new_value); @@ -946,7 +949,7 @@ if (entry) { entry->nlink = 1; - entry->data = (void *)(long)irq; + entry->data = (void *)(unsigned long)irq; entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; } diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c --- a/arch/ia64/kernel/irq_ia64.c Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/kernel/irq_ia64.c Sat Aug 31 15:05:59 2002 @@ -54,20 +54,15 @@ 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 }; -/* - * GSI to IA-64 vector translation table. - */ -__u8 gsi_to_vector_map[255]; - int -ia64_alloc_irq (void) +ia64_alloc_vector (void) { - static int next_irq = IA64_FIRST_DEVICE_VECTOR; + static int next_vector = IA64_FIRST_DEVICE_VECTOR; - if (next_irq > IA64_LAST_DEVICE_VECTOR) + if (next_vector > IA64_LAST_DEVICE_VECTOR) /* XXX could look for sharable vectors instead of panic'ing... */ - panic("ia64_alloc_irq: out of interrupt vectors!"); - return next_irq++; + panic("ia64_alloc_vector: out of interrupt vectors!"); + return next_vector++; } extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); diff -Nru a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c --- a/arch/ia64/kernel/palinfo.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/kernel/palinfo.c Sat Aug 31 15:05:54 2002 @@ -21,10 +21,10 @@ #include #include #include +#include #include #include -#include #include #include #ifdef CONFIG_SMP diff -Nru a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c --- a/arch/ia64/kernel/pci.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/pci.c Sat Aug 31 15:06:00 2002 @@ -46,9 +46,6 @@ struct pci_ops *pci_root_ops; -int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); -int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); - /* * Low-level SAL-based PCI configuration access functions. Note that SAL @@ -60,7 +57,7 @@ ((u64)(bus << 16) | (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg)) static int -pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +__pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { int result = 0; u64 data = 0; @@ -76,7 +73,7 @@ } static int -pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +__pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) return -EINVAL; @@ -86,77 +83,22 @@ static int -pci_sal_read_config_byte (struct pci_dev *dev, int where, u8 *value) -{ - int result = 0; - u32 data = 0; - - if (!value) - return -EINVAL; - - result = pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - - *value = (u8) data; - - return result; -} - -static int -pci_sal_read_config_word (struct pci_dev *dev, int where, u16 *value) -{ - int result = 0; - u32 data = 0; - - if (!value) - return -EINVAL; - - result = pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - - *value = (u16) data; - - return result; -} - -static int -pci_sal_read_config_dword (struct pci_dev *dev, int where, u32 *value) -{ - if (!value) - return -EINVAL; - - return pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int -pci_sal_write_config_byte (struct pci_dev *dev, int where, u8 value) -{ - return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); -} - -static int -pci_sal_write_config_word (struct pci_dev *dev, int where, u16 value) +pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); + return __pci_sal_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } static int -pci_sal_write_config_dword (struct pci_dev *dev, int where, u32 value) +pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_sal_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } struct pci_ops pci_sal_ops = { - pci_sal_read_config_byte, - pci_sal_read_config_word, - pci_sal_read_config_dword, - pci_sal_write_config_byte, - pci_sal_write_config_word, - pci_sal_write_config_dword + .read = pci_sal_read, + .write = pci_sal_write, }; @@ -193,8 +135,6 @@ printk("PCI: Using SAL to access configuration space\n"); pci_root_ops = &pci_sal_ops; - pci_config_read = pci_sal_read; - pci_config_write = pci_sal_write; return; } diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/kernel/process.c Sat Aug 31 15:06:00 2002 @@ -19,9 +19,9 @@ #include #include #include +#include #include -#include #include #include #include diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/kernel/setup.c Sat Aug 31 15:05:54 2002 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include #include @@ -58,9 +58,8 @@ unsigned long __per_cpu_offset[NR_CPUS]; #endif -DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info); - -unsigned long ia64_phys_stacked_size_p8; +DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info); +DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8); unsigned long ia64_cycles_per_usec; struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; @@ -564,11 +563,11 @@ my_cpu_data = (void *) get_free_page(GFP_KERNEL); memcpy(my_cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); __per_cpu_offset[cpu] = (char *) my_cpu_data - __per_cpu_start; - my_cpu_info = my_cpu_data + ((char *) &cpu_info - __per_cpu_start); + my_cpu_info = my_cpu_data + ((char *) &__get_cpu_var(cpu_info) - __per_cpu_start); #else my_cpu_data = __phys_per_cpu_start; #endif - my_cpu_info = my_cpu_data + ((char *) &cpu_info - __per_cpu_start); + my_cpu_info = my_cpu_data + ((char *) &__get_cpu_var(cpu_info) - __per_cpu_start); /* * We can't pass "local_cpu_data" to identify_cpu() because we haven't called @@ -652,6 +651,6 @@ num_phys_stacked = 96; } /* size of physical stacked register partition plus 8 bytes: */ - ia64_phys_stacked_size_p8 = num_phys_stacked*8 + 8; + __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8; platform_cpu_init(); } diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c --- a/arch/ia64/kernel/smp.c Sat Aug 31 15:06:06 2002 +++ b/arch/ia64/kernel/smp.c Sat Aug 31 15:06:06 2002 @@ -32,12 +32,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -72,7 +72,7 @@ #define IPI_CPU_STOP 1 /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ -static DECLARE_PER_CPU(__u64, ipi_operation) ____cacheline_aligned; +static DEFINE_PER_CPU(__u64, ipi_operation) ____cacheline_aligned; static void stop_this_cpu (void) diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/kernel/smpboot.c Sat Aug 31 15:05:55 2002 @@ -27,13 +27,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/kernel/time.c Sat Aug 31 15:05:55 2002 @@ -15,9 +15,9 @@ #include #include #include +#include #include -#include #include #include #include diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c --- a/arch/ia64/kernel/traps.c Sat Aug 31 15:06:06 2002 +++ b/arch/ia64/kernel/traps.c Sat Aug 31 15:06:06 2002 @@ -135,8 +135,6 @@ siginfo_t siginfo; int sig, code; - die_if_kernel("bad break", regs, break_num); - /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num; @@ -144,7 +142,8 @@ siginfo.si_isr = 0; switch (break_num) { - case 0: /* unknown error */ + case 0: /* unknown error (used by GCC for __builtin_abort()) */ + die_if_kernel("bad break", regs, break_num); sig = SIGILL; code = ILL_ILLOPC; break; diff -Nru a/arch/ia64/lib/memcpy.S b/arch/ia64/lib/memcpy.S --- a/arch/ia64/lib/memcpy.S Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/lib/memcpy.S Sat Aug 31 15:05:54 2002 @@ -13,8 +13,6 @@ * Stephane Eranian * David Mosberger-Tang */ -#include - #include GLOBAL_ENTRY(bcopy) diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/mm/init.c Sat Aug 31 15:05:59 2002 @@ -14,11 +14,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff -Nru a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c --- a/arch/ia64/mm/tlb.c Sat Aug 31 15:06:04 2002 +++ b/arch/ia64/mm/tlb.c Sat Aug 31 15:06:04 2002 @@ -41,7 +41,7 @@ .max_ctx = ~0U }; -u8 ia64_need_tlb_flush __per_cpu_data; +DEFINE_PER_CPU(u8, ia64_need_tlb_flush); /* * Acquire the ia64_ctx.lock before calling this function! diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp --- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Sat Aug 31 15:05:59 2002 @@ -526,6 +526,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp --- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Sat Aug 31 15:05:55 2002 @@ -526,6 +526,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-dig-mp b/arch/ia64/sn/configs/sn1/defconfig-dig-mp --- a/arch/ia64/sn/configs/sn1/defconfig-dig-mp Sat Aug 31 15:06:06 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-dig-mp Sat Aug 31 15:06:06 2002 @@ -288,6 +288,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-dig-sp b/arch/ia64/sn/configs/sn1/defconfig-dig-sp --- a/arch/ia64/sn/configs/sn1/defconfig-dig-sp Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-dig-sp Sat Aug 31 15:05:54 2002 @@ -288,6 +288,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-generic-mp b/arch/ia64/sn/configs/sn1/defconfig-generic-mp --- a/arch/ia64/sn/configs/sn1/defconfig-generic-mp Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-generic-mp Sat Aug 31 15:05:55 2002 @@ -283,6 +283,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-generic-sp b/arch/ia64/sn/configs/sn1/defconfig-generic-sp --- a/arch/ia64/sn/configs/sn1/defconfig-generic-sp Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-generic-sp Sat Aug 31 15:05:59 2002 @@ -283,6 +283,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-hp-sp b/arch/ia64/sn/configs/sn1/defconfig-hp-sp --- a/arch/ia64/sn/configs/sn1/defconfig-hp-sp Sat Aug 31 15:06:00 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-hp-sp Sat Aug 31 15:06:00 2002 @@ -253,6 +253,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-prom-medusa b/arch/ia64/sn/configs/sn1/defconfig-prom-medusa --- a/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Sat Aug 31 15:05:59 2002 @@ -363,6 +363,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp --- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Sat Aug 31 15:06:06 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Sat Aug 31 15:06:06 2002 @@ -497,6 +497,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules --- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Sat Aug 31 15:06:03 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Sat Aug 31 15:06:03 2002 @@ -499,6 +499,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 --- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Sat Aug 31 15:05:59 2002 @@ -497,6 +497,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-sp b/arch/ia64/sn/configs/sn1/defconfig-sn1-sp --- a/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Sat Aug 31 15:05:54 2002 @@ -497,6 +497,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-dig-numa b/arch/ia64/sn/configs/sn2/defconfig-dig-numa --- a/arch/ia64/sn/configs/sn2/defconfig-dig-numa Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-dig-numa Sat Aug 31 15:05:55 2002 @@ -289,6 +289,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Sat Aug 31 15:06:06 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Sat Aug 31 15:06:06 2002 @@ -288,6 +288,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Sat Aug 31 15:05:59 2002 @@ -288,6 +288,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Sat Aug 31 15:05:55 2002 @@ -496,6 +496,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Sat Aug 31 15:06:03 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Sat Aug 31 15:06:03 2002 @@ -498,6 +498,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa b/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Sat Aug 31 15:05:59 2002 @@ -371,6 +371,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-sp b/arch/ia64/sn/configs/sn2/defconfig-sn2-sp --- a/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Sat Aug 31 15:05:54 2002 @@ -496,6 +496,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ia64/sn/fakeprom/fpmem.c b/arch/ia64/sn/fakeprom/fpmem.c --- a/arch/ia64/sn/fakeprom/fpmem.c Sat Aug 31 15:05:59 2002 +++ b/arch/ia64/sn/fakeprom/fpmem.c Sat Aug 31 15:05:59 2002 @@ -18,7 +18,7 @@ */ #include -#include +#include #include "fpmem.h" /* diff -Nru a/arch/ia64/sn/fakeprom/fw-emu.c b/arch/ia64/sn/fakeprom/fw-emu.c --- a/arch/ia64/sn/fakeprom/fw-emu.c Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/fakeprom/fw-emu.c Sat Aug 31 15:05:55 2002 @@ -36,7 +36,7 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include -#include +#include #include #include #include diff -Nru a/arch/ia64/sn/io/efi-rtc.c b/arch/ia64/sn/io/efi-rtc.c --- a/arch/ia64/sn/io/efi-rtc.c Sat Aug 31 15:05:54 2002 +++ b/arch/ia64/sn/io/efi-rtc.c Sat Aug 31 15:05:54 2002 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /* diff -Nru a/arch/ia64/sn/io/pci.c b/arch/ia64/sn/io/pci.c --- a/arch/ia64/sn/io/pci.c Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/io/pci.c Sat Aug 31 15:05:55 2002 @@ -44,22 +44,21 @@ extern devfs_handle_t devfn_to_vertex(unsigned char bus, unsigned char devfn); /* - * snia64_read_config_byte - Read a byte from the config area of the device. + * snia64_read - Read from the config area of the device. */ -static int snia64_read_config_byte (struct pci_dev *dev, - int where, unsigned char *val) +static int snia64_read (struct pci_bus *bus, unsigned char devfn, + int where, int size, unsigned char *val) { unsigned long res = 0; - unsigned size = 1; devfs_handle_t device_vertex; - if ( (dev == (struct pci_dev *)0) || (val == (unsigned char *)0) ) { + if ( (bus == NULL) || (val == (unsigned char *)0) ) { return PCIBIOS_DEVICE_NOT_FOUND; } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); + device_vertex = devfn_to_vertex(bus->number, devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + __FUNCTION__, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); return(-1); } res = pciio_config_get(device_vertex, (unsigned) where, size); @@ -68,160 +67,40 @@ } /* - * snia64_read_config_word - Read 2 bytes from the config area of the device. + * snia64_write - Writes to the config area of the device. */ -static int snia64_read_config_word (struct pci_dev *dev, - int where, unsigned short *val) +static int snia64_write (struct pci_bus *bus, unsigned char devfn, + int where, int size, unsigned char val) { - unsigned long res = 0; - unsigned size = 2; /* 2 bytes */ - devfs_handle_t device_vertex; - - if ( (dev == (struct pci_dev *)0) || (val == (unsigned short *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned short) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_read_config_dword - Read 4 bytes from the config area of the device. - */ -static int snia64_read_config_dword (struct pci_dev *dev, - int where, unsigned int *val) -{ - unsigned long res = 0; - unsigned size = 4; /* 4 bytes */ devfs_handle_t device_vertex; - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( (dev == (struct pci_dev *)0) || (val == (unsigned int *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned int) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_byte - Writes 1 byte to the config area of the device. - */ -static int snia64_write_config_byte (struct pci_dev *dev, - int where, unsigned char val) -{ - devfs_handle_t device_vertex; - - if ( dev == (struct pci_dev *)0 ) { + if ( bus == NULL) { return PCIBIOS_DEVICE_NOT_FOUND; } /* * if it's an IOC3 then we bail out, we special * case them with pci_fixup_ioc3 */ - if (dev->vendor == PCI_VENDOR_ID_SGI && + /* Starting 2.5.32 struct pci_dev is not passed down */ + /*if (dev->vendor == PCI_VENDOR_ID_SGI && dev->device == PCI_DEVICE_ID_SGI_IOC3 ) return PCIBIOS_SUCCESSFUL; + */ - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 1, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_word - Writes 2 bytes to the config area of the device. - */ -static int snia64_write_config_word (struct pci_dev *dev, - int where, unsigned short val) -{ - devfs_handle_t device_vertex = NULL; - - if (where & 1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 2, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_dword - Writes 4 bytes to the config area of the device. - */ -static int snia64_write_config_dword (struct pci_dev *dev, - int where, unsigned int val) -{ - devfs_handle_t device_vertex; - - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); + device_vertex = devfn_to_vertex(bus->number, devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + __FUNCTION__, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); return(-1); } - pciio_config_set( device_vertex, (unsigned)where, 4, (uint64_t) val); + pciio_config_set( device_vertex, (unsigned)where, size, (uint64_t) val); return PCIBIOS_SUCCESSFUL; } static struct pci_ops snia64_pci_ops = { - snia64_read_config_byte, - snia64_read_config_word, - snia64_read_config_dword, - snia64_write_config_byte, - snia64_write_config_word, - snia64_write_config_dword + .read = snia64_read, + .write = snia64_write, }; /* diff -Nru a/arch/ia64/sn/io/sn1/pcibr.c b/arch/ia64/sn/io/sn1/pcibr.c --- a/arch/ia64/sn/io/sn1/pcibr.c Sat Aug 31 15:06:03 2002 +++ b/arch/ia64/sn/io/sn1/pcibr.c Sat Aug 31 15:06:03 2002 @@ -7485,7 +7485,7 @@ #ifdef LITTLE_ENDIAN /* - * on sn-ia we need to twiddle the the addresses going out + * on sn-ia we need to twiddle the addresses going out * the pci bus because we use the unswizzled synergy space * (the alternative is to use the swizzled synergy space * and byte swap the data) diff -Nru a/arch/ia64/sn/kernel/llsc4.c b/arch/ia64/sn/kernel/llsc4.c --- a/arch/ia64/sn/kernel/llsc4.c Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/sn/kernel/llsc4.c Sat Aug 31 15:05:55 2002 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S --- a/arch/ia64/vmlinux.lds.S Sat Aug 31 15:05:55 2002 +++ b/arch/ia64/vmlinux.lds.S Sat Aug 31 15:05:55 2002 @@ -7,7 +7,7 @@ OUTPUT_FORMAT("elf64-ia64-little") OUTPUT_ARCH(ia64) ENTRY(phys_start) -jiffies = jiffies_64; +jiffies = jiffies_64; SECTIONS { /* Sections to be discarded */ diff -Nru a/arch/m68k/defconfig b/arch/m68k/defconfig --- a/arch/m68k/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/m68k/defconfig Sat Aug 31 15:05:54 2002 @@ -228,6 +228,8 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/config.in b/arch/mips/config.in --- a/arch/mips/config.in Sat Aug 31 15:06:03 2002 +++ b/arch/mips/config.in Sat Aug 31 15:06:03 2002 @@ -389,6 +389,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in source drivers/media/Config.in @@ -474,7 +476,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c --- a/arch/mips/ddb5074/pci.c Sat Aug 31 15:06:00 2002 +++ b/arch/mips/ddb5074/pci.c Sat Aug 31 15:06:00 2002 @@ -43,137 +43,118 @@ } -static int nile4_pci_read_config_dword(struct pci_dev *dev, - int where, u32 * val) +static int nile4_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 * val) { - int slot_num, func_num; - u32 base; + int status, slot_num, func_num; + u32 result, base; - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { - /* - * This is Nile 4 and it will crash if we access it like other - * devices - */ - *val = nile4_in32(NILE4_PCI_BASE + where); - return PCIBIOS_SUCCESSFUL; + switch (size) { + case 4: + /* + * For starters let's do configuration cycle 0 only + * (one bus only) + */ + if (bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it + * like other devices + */ + *val = nile4_in32(NILE4_PCI_BASE + where); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *val = *((volatile u32 *) (base + (func_num << 8) + + (where & 0xfc))); + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; + + case 2: + status = nile4_pci_read(bus, devfn, where, 4, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = (u16)(result & 0xffff); + break; + case 1: + status = nile4_pci_read(bus, devfn, where, 4, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = (u8)(result & 0xff); + break; } - base = nile4_pre_pci_access0(slot_num); - *val = - *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))); - nile4_post_pci_access0(); return PCIBIOS_SUCCESSFUL; } -static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, - u32 val) -{ - int slot_num, func_num; - u32 base; - - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { - /* - * This is Nile 4 and it will crash if we access it like other - * devices - */ - nile4_out32(NILE4_PCI_BASE + where, val); - return PCIBIOS_SUCCESSFUL; - } - base = nile4_pre_pci_access0(slot_num); - *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))) = - val; - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_word(struct pci_dev *dev, int where, - u16 * val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return PCIBIOS_SUCCESSFUL; -} -static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, - u8 * val) +static int nile4_pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) { - int status; - u32 result; + int status, slot_num, func_num, shift = 0; + u32 result, base; - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_word(struct pci_dev *dev, int where, - u16 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); -} - -static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, - u8 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); + switch (size) { + case 4: + /* + * For starters let's do configuration cycle 0 only + * (one bus only) + */ + if (bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access + * it like other devices + */ + nile4_out32(NILE4_PCI_BASE + where, val); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *((volatile u32 *) (base + (func_num << 8) + + (where & 0xfc))) = val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; + + case 2: + status = nile4_pci_read(bus, devfn, where, 4, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= (u16)(val << shift); + break; + case 1: + status = nile4_pci_read(bus, devfn, where, 4, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= (u8)(val << shift); + break; + } + return nile4_pci_write(bus, devfn, where, 4, result); } struct pci_ops nile4_pci_ops = { - nile4_pci_read_config_byte, - nile4_pci_read_config_word, - nile4_pci_read_config_dword, - nile4_pci_write_config_byte, - nile4_pci_write_config_word, - nile4_pci_write_config_dword + .read = nile4_pci_read, + .write = nile4_pci_write, }; struct { diff -Nru a/arch/mips/ddb5476/pci.c b/arch/mips/ddb5476/pci.c --- a/arch/mips/ddb5476/pci.c Sat Aug 31 15:05:59 2002 +++ b/arch/mips/ddb5476/pci.c Sat Aug 31 15:05:59 2002 @@ -51,145 +51,106 @@ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); } - -static int nile4_pci_read_config_dword(struct pci_dev *dev, - int where, u32 * val) +static int nile4_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 * val) { - int slot_num, func_num; - u32 base; - u32 addr; - - /* - * Do we need to generate type 1 configure transaction? - */ - if (dev->bus->number) { - /* FIXME - not working yet */ - return PCIBIOS_FUNC_NOT_SUPPORTED; - - /* - * the largest type 1 configuration addr is 16M, < 256M - * config space - */ - slot_num = 0; - addr = - (dev->bus->number << 16) | (dev->devfn < - 8) | where | 1; - } else { - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - addr = (func_num << 8) + where; - } + int status, slot_num, func_num; + u32 result, base, addr; - base = nile4_pre_pci_access0(slot_num); - *val = *(volatile u32 *) (base + addr); - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, - u32 val) -{ - int slot_num, func_num; - u32 base; - u32 addr; - - /* - * Do we need to generate type 1 configure transaction? - */ - if (dev->bus->number) { - /* FIXME - not working yet */ - return PCIBIOS_FUNC_NOT_SUPPORTED; - - /* the largest type 1 configuration addr is 16M, < 256M config space */ - slot_num = 0; - addr = - (dev->bus->number << 16) | (dev->devfn < - 8) | where | 1; - } else { - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - addr = (func_num << 8) + where; + if(size == 4) { + /* Do we need to generate type 1 configure transaction? */ + if (bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* + * the largest type 1 configuration addr is 16M, + * < 256M config space + */ + slot_num = 0; + addr = (bus->number << 16) | (devfn < 8) | where | 1; + } else { + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + addr = (func_num << 8) + where; + } + base = nile4_pre_pci_access0(slot_num); + *val = *(volatile u32 *) (base + addr); + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; } - base = nile4_pre_pci_access0(slot_num); - *(volatile u32 *) (base + addr) = val; - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_word(struct pci_dev *dev, int where, - u16 * val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, - u8 * val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); + status = nile4_pci_read(bus, devfn, where & ~3, 4, &result); if (status != PCIBIOS_SUCCESSFUL) return status; - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; + switch (size) { + case 1: + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = (u8)(result & 0xff); + break; + case 2: + if (where & 2) + result >>= 16; + *val = (u16)(result & 0xffff); + break; + } return PCIBIOS_SUCCESSFUL; } -static int nile4_pci_write_config_word(struct pci_dev *dev, int where, - u16 val) +static int nile4_pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) { - int status, shift = 0; - u32 result; + int status, slot_num, func_num, shift = 0; + u32 result, base, addr; - status = nile4_pci_read_config_dword(dev, where & ~3, &result); + status = nile4_pci_read(bus, devfn, where & ~3, 4, &result); if (status != PCIBIOS_SUCCESSFUL) return status; - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where & ~3, result); -} - -static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, - u8 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where & ~3, result); + switch (size) { + case 1: + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + break; + case 2: + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + break; + case 4: + /* Do we need to generate type 1 configure transaction? */ + if (bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* the largest type 1 configuration addr is 16M, + * < 256M config space */ + slot_num = 0; + addr = (bus->number << 16) | (devfn < 8) | + where | 1; + } else { + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *(volatile u32 *) (base + addr) = val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; + } + return nile4_pci_write(bus, devfn, where & ~3, 4, result); } struct pci_ops nile4_pci_ops = { - nile4_pci_read_config_byte, - nile4_pci_read_config_word, - nile4_pci_read_config_dword, - nile4_pci_write_config_byte, - nile4_pci_write_config_word, - nile4_pci_write_config_dword + .read = nile4_pci_read, + .write = nile4_pci_write, }; struct { @@ -274,13 +235,13 @@ pci_pmu = dev; /* for LEDs D2 and D3 */ /* Program the lines for LEDs D2 and D3 to output */ - nile4_pci_read_config_byte(dev, 0x7d, &t8); + nile4_pci_read(dev->bus, dev->devfn, 0x7d, 1, &t8); t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7d, t8); + nile4_pci_write(dev->bus, dev->devfn, 0x7d, 1, t8); /* Turn LEDs D2 and D3 off */ - nile4_pci_read_config_byte(dev, 0x7e, &t8); + nile4_pci_read(dev->bus, dev->devfn, 0x7e, 1, &t8); t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7e, t8); + nile4_pci_write(dev->bus, dev->devfn, 0x7e, 1, t8); } else if (dev->vendor == PCI_VENDOR_ID_AL && dev->device == 0x5229) { int i; diff -Nru a/arch/mips/ddb5xxx/ddb5477/pci_ops.c b/arch/mips/ddb5xxx/ddb5477/pci_ops.c --- a/arch/mips/ddb5xxx/ddb5477/pci_ops.c Sat Aug 31 15:05:54 2002 +++ b/arch/mips/ddb5xxx/ddb5477/pci_ops.c Sat Aug 31 15:05:54 2002 @@ -134,173 +134,138 @@ ddb_out32(swap->pmr, swap->pmr_backup); } -static int read_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, +static int read_config(struct pci_config_swap *swap, + struct pci_bus *bus, + unsigned int devfn, u32 where, + int size, u32 *val) { - u32 bus, slot_num, func_num; - u32 base; + u32 busnum, slot_num, func_num, base, result; + int status - MIPS_ASSERT((where & 3) == 0); - MIPS_ASSERT(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - MIPS_ASSERT(bus != 0); - } else { - bus = 0; + switch (size) { + case 4: + MIPS_ASSERT((where & 3) == 0); + MIPS_ASSERT(where < (1 << 8)); + + /* check if the bus is top-level */ + if (bus->parent != NULL) { + busnum = bus->number; + MIPS_ASSERT(busnum != 0); + } else { + busnum = 0; + } + + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + base = ddb_access_config_base(swap, busnum, slot_num); + *val = *(volatile u32*) (base + (func_num << 8) + where); + ddb_close_config_base(swap); + return PCIBIOS_SUCCESSFUL; + + case 2: + MIPS_ASSERT((where & 1) == 0); + + status = read_config(swap, bus, devfn, where & ~3, 4, + &result); + if (where & 2) result >>= 16; + *val = (u16)(result & 0xffff); + return status; + + case 1: + status = read_config(swap, bus, devfn, where & ~3, 4, + &result); + if (where & 1) result >>= 8; + if (where & 2) result >>= 16; + *val = (u8)(result & 0xff); + return status; } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *val = *(volatile u32*) (base + (func_num << 8) + where); - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; -} - -static int read_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, - u32 where, - u16 *val) -{ - int status; - u32 result; - - MIPS_ASSERT((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 2) result >>= 16; - *val = result & 0xffff; - return status; } -static int read_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, - u32 where, - u8 *val) -{ - int status; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 1) result >>= 8; - if (where & 2) result >>= 16; - *val = result & 0xff; - return status; -} - -static int write_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, +static int write_config(struct pci_config_swap *swap, + struct pci_bus *bus, + unsigned int devfn, u32 where, + int size, u32 val) { - u32 bus, slot_num, func_num; - u32 base; + u32 busnum, slot_num, func_num, base, results; + int status, shift = 0; - MIPS_ASSERT((where & 3) == 0); - MIPS_ASSERT(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - MIPS_ASSERT(bus != 0); - } else { - bus = 0; + switch (size) { + case 4: + MIPS_ASSERT((where & 3) == 0); + MIPS_ASSERT(where < (1 << 8)); + + /* check if the bus is top-level */ + if (bus->parent != NULL) { + busnum = bus->number; + MIPS_ASSERT(busnum != 0); + } else { + busnum = 0; + } + + slot_num = PCI_SLOT(devfn); + func_num = PCI_FUNC(devfn); + base = ddb_access_config_base(swap, busnum, slot_num); + *(volatile u32*) (base + (func_num << 8) + where) = val; + ddb_close_config_base(swap); + return PCIBIOS_SUCCESSFUL; + + case 2: + MIPS_ASSERT((where & 1) == 0); + + status = read_config(swap, bus, devfn, where & ~3, 4, + &result); + if (status != PCIBIOS_SUCCESSFUL) return status; + + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= (u16)(val << shift); + return write_config(swap, bus, devfn, where & ~3, size, + result); + + case 1: + status = read_config(swap, bus, devfn, where & ~3, 4, + &result); + if (status != PCIBIOS_SUCCESSFUL) return status; + + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= (u8)(val << shift); + return write_config(swap, bus, devfn, where & ~3, size, + result); } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *(volatile u32*) (base + (func_num << 8) + where) = val; - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; } -static int write_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, - u32 where, - u16 val) -{ - int status, shift=0; - u32 result; - - MIPS_ASSERT((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) return status; - - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -static int write_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, - u32 where, - u8 val) -{ - int status, shift=0; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) return status; - - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ -static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ +#define MAKE_PCI_OPS(prefix, rw, pciswap) \ +static int prefix##_##rw##_config(struct pci_bus *bus, unsigned int devfn, \ + int where, int size, u32 val) \ { \ - return rw##_config_##unitname(pciswap, \ - dev, \ - where, \ - val); \ + return rw##_config(pciswap, bus, devfn, \ + where, size, val); \ } -MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) -MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) -MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) - -MAKE_PCI_OPS(iopci, read, byte, u8 *, &io_pci_swap) -MAKE_PCI_OPS(iopci, read, word, u16 *, &io_pci_swap) -MAKE_PCI_OPS(iopci, read, dword, u32 *, &io_pci_swap) - -MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) -MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) -MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) - -MAKE_PCI_OPS(iopci, write, byte, u8, &io_pci_swap) -MAKE_PCI_OPS(iopci, write, word, u16, &io_pci_swap) -MAKE_PCI_OPS(iopci, write, dword, u32, &io_pci_swap) +MAKE_PCI_OPS(extpci, read, &ext_pci_swap) +MAKE_PCI_OPS(extpci, write, &ext_pci_swap) + +MAKE_PCI_OPS(iopci, read, &io_pci_swap) +MAKE_PCI_OPS(iopci, write, &io_pci_swap) struct pci_ops ddb5477_ext_pci_ops ={ - extpci_read_config_byte, - extpci_read_config_word, - extpci_read_config_dword, - extpci_write_config_byte, - extpci_write_config_word, - extpci_write_config_dword + .read = extpci_read_config, + .write = extpci_write_config, }; struct pci_ops ddb5477_io_pci_ops ={ - iopci_read_config_byte, - iopci_read_config_word, - iopci_read_config_dword, - iopci_write_config_byte, - iopci_write_config_word, - iopci_write_config_dword + .read = iopci_read_config, + .write = iopci_write_config, }; #if defined(CONFIG_LL_DEBUG) diff -Nru a/arch/mips/defconfig b/arch/mips/defconfig --- a/arch/mips/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/mips/defconfig Sat Aug 31 15:05:54 2002 @@ -443,6 +443,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-atlas b/arch/mips/defconfig-atlas --- a/arch/mips/defconfig-atlas Sat Aug 31 15:05:59 2002 +++ b/arch/mips/defconfig-atlas Sat Aug 31 15:05:59 2002 @@ -433,6 +433,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476 --- a/arch/mips/defconfig-ddb5476 Sat Aug 31 15:05:59 2002 +++ b/arch/mips/defconfig-ddb5476 Sat Aug 31 15:05:59 2002 @@ -467,6 +467,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-ddb5477 b/arch/mips/defconfig-ddb5477 --- a/arch/mips/defconfig-ddb5477 Sat Aug 31 15:05:55 2002 +++ b/arch/mips/defconfig-ddb5477 Sat Aug 31 15:05:55 2002 @@ -394,6 +394,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation --- a/arch/mips/defconfig-decstation Sat Aug 31 15:06:06 2002 +++ b/arch/mips/defconfig-decstation Sat Aug 31 15:06:06 2002 @@ -430,6 +430,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22 --- a/arch/mips/defconfig-ip22 Sat Aug 31 15:06:06 2002 +++ b/arch/mips/defconfig-ip22 Sat Aug 31 15:06:06 2002 @@ -443,6 +443,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-it8172 b/arch/mips/defconfig-it8172 --- a/arch/mips/defconfig-it8172 Sat Aug 31 15:05:59 2002 +++ b/arch/mips/defconfig-it8172 Sat Aug 31 15:05:59 2002 @@ -546,6 +546,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-malta b/arch/mips/defconfig-malta --- a/arch/mips/defconfig-malta Sat Aug 31 15:05:55 2002 +++ b/arch/mips/defconfig-malta Sat Aug 31 15:05:55 2002 @@ -459,6 +459,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-nino b/arch/mips/defconfig-nino --- a/arch/mips/defconfig-nino Sat Aug 31 15:06:04 2002 +++ b/arch/mips/defconfig-nino Sat Aug 31 15:06:04 2002 @@ -270,6 +270,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-ocelot b/arch/mips/defconfig-ocelot --- a/arch/mips/defconfig-ocelot Sat Aug 31 15:06:00 2002 +++ b/arch/mips/defconfig-ocelot Sat Aug 31 15:06:00 2002 @@ -395,6 +395,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-pb1000 b/arch/mips/defconfig-pb1000 --- a/arch/mips/defconfig-pb1000 Sat Aug 31 15:05:59 2002 +++ b/arch/mips/defconfig-pb1000 Sat Aug 31 15:05:59 2002 @@ -382,6 +382,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200 --- a/arch/mips/defconfig-rm200 Sat Aug 31 15:06:06 2002 +++ b/arch/mips/defconfig-rm200 Sat Aug 31 15:06:06 2002 @@ -313,6 +313,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c --- a/arch/mips/gt64120/common/pci.c Sat Aug 31 15:06:00 2002 +++ b/arch/mips/gt64120/common/pci.c Sat Aug 31 15:06:00 2002 @@ -108,18 +108,10 @@ /* Functions to implement "pci ops" */ -static int galileo_pcibios_read_config_word(struct pci_dev *dev, - int offset, u16 * val); -static int galileo_pcibios_read_config_byte(struct pci_dev *dev, - int offset, u8 * val); -static int galileo_pcibios_read_config_dword(struct pci_dev *dev, - int offset, u32 * val); -static int galileo_pcibios_write_config_byte(struct pci_dev *dev, - int offset, u8 val); -static int galileo_pcibios_write_config_word(struct pci_dev *dev, - int offset, u16 val); -static int galileo_pcibios_write_config_dword(struct pci_dev *dev, - int offset, u32 val); +static int galileo_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 * val); +static int galileo_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 val); static void galileo_pcibios_set_master(struct pci_dev *dev); /* @@ -609,15 +601,16 @@ /* - * galileo_pcibios_(read/write)_config_(dword/word/byte) - + * galileo_pcibios_(read/write) - * * reads/write a dword/word/byte register from the configuration space * of a device. * * Inputs : * bus - bus number - * dev - device number + * devfn - device function index * offset - register offset in the configuration space + * size - size of value (1=byte,2=word,4-dword) * val - value to be written / read * * Outputs : @@ -626,165 +619,106 @@ * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned */ -static int galileo_pcibios_read_config_dword(struct pci_dev *device, - int offset, u32 * val) +static int galileo_pcibios_read (struct pci_bus *bus, unsigned int devfn, int offset, int size, u32 * val) { - int dev, bus; - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); + int dev, busnum; - if (pci_range_ck(bus, dev)) { - *val = 0xffffffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - if (offset & 0x3) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (bus == 0) - *val = pci0ReadConfigReg(offset, device); + busnum = bus->number; + dev = PCI_SLOT(devfn); - /* This is so that the upper PCI layer will get the correct return value if - we're not attached to anything. */ - if ((offset == 0) && (*val == 0xffffffff)) { + if (pci_range_ck(busnum, dev)) { + if(size == 1) + *val = (u8)0xff; + else if (size == 2) + *val = (u16)0xffff; + else if (size == 4) + *val = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } - - return PCIBIOS_SUCCESSFUL; -} - -static int galileo_pcibios_read_config_word(struct pci_dev *device, - int offset, u16 * val) -{ - int dev, bus; - - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); - - if (pci_range_ck(bus, dev)) { - *val = 0xffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - if (offset & 0x1) + if ((size == 2) && (offset & 0x1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (offset & 0x3)) return PCIBIOS_BAD_REGISTER_NUMBER; - if (bus == 0) - *val = - (unsigned short) (pci0ReadConfigReg(offset, device) >> + if (busnum == 0) { + if(size == 1) { + *val = (u8)(pci0ReadConfigReg(offset, bus->dev) >> + ((offset & ~0x3) * 8)); + }else if (size == 2) { + *val = (u16)(pci0ReadConfigReg(offset, bus->dev) >> ((offset & ~0x3) * 8)); - - return PCIBIOS_SUCCESSFUL; -} - -static int galileo_pcibios_read_config_byte(struct pci_dev *device, - int offset, u8 * val) -{ - int dev, bus; - - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); - - if (pci_range_ck(bus, dev)) { - *val = 0xff; - return PCIBIOS_DEVICE_NOT_FOUND; + }else if (size == 4) { + *val = pci0ReadConfigReg(offset, bus->dev); + } } - if (bus == 0) - *val = - (unsigned char) (pci0ReadConfigReg(offset, device) >> - ((offset & ~0x3) * 8)); - /* * This is so that the upper PCI layer will get the correct return * value if we're not attached to anything. */ - if ((offset == 0xe) && (*val == 0xff)) { - u32 MasterAbort; - GT_READ(GT_INTRCAUSE_OFS, &MasterAbort); - if (MasterAbort & 0x40000) { - GT_WRITE(GT_INTRCAUSE_OFS, - (MasterAbort & 0xfffbffff)); - return PCIBIOS_DEVICE_NOT_FOUND; - } + switch (size) { + case 1: + if ((offset == 0xe) && (*val == (u8)0xff)) { + u32 MasterAbort; + GT_READ(GT_INTRCAUSE_OFS, &MasterAbort); + if (MasterAbort & 0x40000) { + GT_WRITE(GT_INTRCAUSE_OFS, + (MasterAbort & 0xfffbffff)); + return PCIBIOS_DEVICE_NOT_FOUND; + } + } + break; + case 4: + if ((offset == 0) && (*val == 0xffffffff)) { + return PCIBIOS_DEVICE_NOT_FOUND; + } + break } - - return PCIBIOS_SUCCESSFUL; -} - -static int galileo_pcibios_write_config_dword(struct pci_dev *device, - int offset, u32 val) -{ - int dev, bus; - - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); - - if (pci_range_ck(bus, dev)) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset & 0x3) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (bus == 0) - pci0WriteConfigReg(offset, device, val); -// if (bus == 1) pci1WriteConfigReg (offset,device,val); - return PCIBIOS_SUCCESSFUL; } - -static int galileo_pcibios_write_config_word(struct pci_dev *device, - int offset, u16 val) +static int galileo_pcibios_write(struct pci_bus *bus, unsigned int devfn, int offset, int size, u32 val) { - int dev, bus; + int dev, busnum; unsigned long tmp; - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); + busnum = bus->number; + dev = PCI_SLOT(devfn); - if (pci_range_ck(bus, dev)) + if (pci_range_ck(busnum, dev)) return PCIBIOS_DEVICE_NOT_FOUND; - if (offset & 0x1) + if (size == 4) { + if (offset & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if(busnum == 0) + pci0WriteConfigReg(offset, bus->dev, val); + //if (busnum == 1) pci1WriteConfigReg (offset,bus->dev,val); + return PCIBIOS_SUCCESSFUL; + } + if ((size == 2) && (offset & 0x1)) return PCIBIOS_BAD_REGISTER_NUMBER; - if (bus == 0) - tmp = pci0ReadConfigReg(offset, device); -// if (bus == 1) tmp = pci1ReadConfigReg (offset,device); - - if ((offset % 4) == 0) - tmp = (tmp & 0xffff0000) | (val & 0xffff); - if ((offset % 4) == 2) - tmp = (tmp & 0x0000ffff) | ((val & 0xffff) << 16); - - if (bus == 0) - pci0WriteConfigReg(offset, device, tmp); -// if (bus == 1) pci1WriteConfigReg (offset,device,tmp); - return PCIBIOS_SUCCESSFUL; -} - -static int galileo_pcibios_write_config_byte(struct pci_dev *device, - int offset, u8 val) -{ - int dev, bus; - unsigned long tmp; - - bus = device->bus->number; - dev = PCI_SLOT(device->devfn); - - if (pci_range_ck(bus, dev)) - return PCIBIOS_DEVICE_NOT_FOUND; - if (bus == 0) - tmp = pci0ReadConfigReg(offset, device); -// if (bus == 1) tmp = pci1ReadConfigReg (offset,device); - - if ((offset % 4) == 0) - tmp = (tmp & 0xffffff00) | (val & 0xff); - if ((offset % 4) == 1) - tmp = (tmp & 0xffff00ff) | ((val & 0xff) << 8); - if ((offset % 4) == 2) - tmp = (tmp & 0xff00ffff) | ((val & 0xff) << 16); - if ((offset % 4) == 3) - tmp = (tmp & 0x00ffffff) | ((val & 0xff) << 24); - - if (bus == 0) - pci0WriteConfigReg(offset, device, tmp); -// if (bus == 1) pci1WriteConfigReg (offset,device,tmp); - + if (busnum == 0){ + tmp = pci0ReadConfigReg(offset, bus->dev); + //if (busnum == 1) tmp = pci1ReadConfigReg (offset,bus->dev); + if (size == 1) { + if ((offset % 4) == 0) + tmp = (tmp & 0xffffff00) | (val & (u8)0xff); + if ((offset % 4) == 1) + tmp = (tmp & 0xffff00ff) | ((val & (u8)0xff) << 8); + if ((offset % 4) == 2) + tmp = (tmp & 0xff00ffff) | ((val & (u8)0xff) << 16); + if ((offset % 4) == 3) + tmp = (tmp & 0x00ffffff) | ((val & (u8)0xff) << 24); + } else if (size == 2) { + if ((offset % 4) == 0) + tmp = (tmp & 0xffff0000) | (val & (u16)0xffff); + if ((offset % 4) == 2) + tmp = (tmp & 0x0000ffff) | ((val & (u16)0xffff) << 16); + } + if (busnum == 0) + pci0WriteConfigReg(offset, bus->dev, tmp); + //if (busnum == 1) pci1WriteConfigReg (offset,bus->dev,tmp); + } return PCIBIOS_SUCCESSFUL; } @@ -792,9 +726,9 @@ { u16 cmd; - galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd); + galileo_pcibios_read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd); cmd |= PCI_COMMAND_MASTER; - galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd); + galileo_pcibios_write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd); } /* Externally-expected functions. Do not change function names */ @@ -806,7 +740,7 @@ int idx; struct resource *r; - galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd); + galileo_pcibios_read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd); old_cmd = cmd; for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -822,7 +756,7 @@ cmd |= PCI_COMMAND_MEMORY; } if (cmd != old_cmd) { - galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd); + galileo_pcibios_write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd); } /* @@ -830,19 +764,17 @@ * line size = 32 bytes / sizeof dword (4) = 8. * Latency timer must be > 8. 32 is random but appears to work. */ - galileo_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1); + galileo_pcibios_read(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 1, &tmp1); if (tmp1 != 8) { printk(KERN_WARNING "PCI setting cache line size to 8 from " "%d\n", tmp1); - galileo_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - 8); + galileo_pcibios_write(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 1, 8); } - galileo_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1); + galileo_pcibios_read(dev->bus, dev->devfn, PCI_LATENCY_TIMER, 1, &tmp1); if (tmp1 < 32) { printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n", tmp1); - galileo_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER, - 32); + galileo_pcibios_write(dev->bus, dev->devfn, PCI_LATENCY_TIMER, 1, 32); } return 0; @@ -909,12 +841,8 @@ } struct pci_ops galileo_pci_ops = { - galileo_pcibios_read_config_byte, - galileo_pcibios_read_config_word, - galileo_pcibios_read_config_dword, - galileo_pcibios_write_config_byte, - galileo_pcibios_write_config_word, - galileo_pcibios_write_config_dword + .read = galileo_pcibios_read, + .write = galileo_pcibios_write, }; struct pci_fixup pcibios_fixups[] = { diff -Nru a/arch/mips/ite-boards/generic/it8172_pci.c b/arch/mips/ite-boards/generic/it8172_pci.c --- a/arch/mips/ite-boards/generic/it8172_pci.c Sat Aug 31 15:06:06 2002 +++ b/arch/mips/ite-boards/generic/it8172_pci.c Sat Aug 31 15:06:06 2002 @@ -45,18 +45,17 @@ #undef DEBUG_CONFIG_CYCLES static int -it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, - unsigned char where, u32 *data) +it8172_pcibios_config_access(unsigned char access_type, struct pci_bus *bus, unsigned int devfn, unsigned char where, u32 *data) { /* * config cycles are on 4 byte boundary only */ - unsigned char bus = dev->bus->number; - unsigned char dev_fn = dev->devfn; + unsigned char bus = bus->number; + unsigned char dev_fn = (char)devfn; #ifdef DEBUG_CONFIG_CYCLES - printk("it config: type %d dev %x bus %d dev_fn %x data %x\n", - access_type, dev, bus, dev_fn, *data); + printk("it config: type %d bus %d dev_fn %x data %x\n", + access_type, bus, dev_fn, *data); #endif @@ -86,121 +85,63 @@ * read/write a 32bit word and mask/modify the data we actually want. */ static int -it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +it8172_pcibios_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { u32 data = 0; - if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xff; -#ifdef DEBUG - printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n", - dev->bus->number, dev->devfn, where, *val); -#endif - - return PCIBIOS_SUCCESSFUL; -} - - -static int -it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) -{ - u32 data = 0; - - if (where & 1) + if ((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xffff; -#ifdef DEBUG - printk("cfg read word: bus %d dev_fn %x where %x: val %x\n", - dev->bus->number, dev->devfn, where, *val); -#endif - - return PCIBIOS_SUCCESSFUL; -} - -static int -it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) -{ - u32 data = 0; - - if (where & 3) + else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + if (it8172_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) return -1; + if (size == 1) + *val = (u8)(data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (u16)(data >> ((where & 3) << 3)) & 0xffff; + else if (size == 4) + *val = data; - *val = data; #ifdef DEBUG - printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n", - dev->bus->number, dev->devfn, where, *val); + printk("cfg read: bus %d devfn %x where %x size %x: val %x\n", + bus->number, devfn, where, size, *val); #endif return PCIBIOS_SUCCESSFUL; } - static int -it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +it8172_pcibios_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { u32 data = 0; - - if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; -} - -static int -it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) -{ - u32 data = 0; - - if (where & 1) + if ((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; + else if (size == 4) { + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val)) + return -1; + return PCIBIOS_SUCCESSFUL; + } - if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xffff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - - return PCIBIOS_SUCCESSFUL; -} - -static int -it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) -{ - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; + if (it8172_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return -1; - if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) - return -1; + if(size == 1) { + data = (u8)(data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } else if (size == 2) { + data = (u16)(data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } return PCIBIOS_SUCCESSFUL; } struct pci_ops it8172_pci_ops = { - it8172_pcibios_read_config_byte, - it8172_pcibios_read_config_word, - it8172_pcibios_read_config_dword, - it8172_pcibios_write_config_byte, - it8172_pcibios_write_config_word, - it8172_pcibios_write_config_dword + .read = it8172_pcibios_read, + .write = it8172_pcibios_write, }; void __init pcibios_init(void) diff -Nru a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c --- a/arch/mips/kernel/irixelf.c Sat Aug 31 15:06:00 2002 +++ b/arch/mips/kernel/irixelf.c Sat Aug 31 15:06:00 2002 @@ -54,7 +54,6 @@ #ifndef elf_addr_t #define elf_addr_t unsigned long -#define elf_caddr_t char * #endif #ifdef DEBUG_ELF @@ -155,8 +154,8 @@ unsigned int interp_load_addr, struct pt_regs *regs, struct elf_phdr *ephdr) { - elf_caddr_t *argv; - elf_caddr_t *envp; + elf_addr_t *argv; + elf_addr_t *envp; elf_addr_t *sp, *csp; #ifdef DEBUG_ELF @@ -202,20 +201,20 @@ #undef NEW_AUX_ENT sp -= envc+1; - envp = (elf_caddr_t *) sp; + envp = sp; sp -= argc+1; - argv = (elf_caddr_t *) sp; + argv = sp; __put_user((elf_addr_t)argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { - __put_user((elf_caddr_t)(unsigned long)p,argv++); + __put_user((unsigned long)p,argv++); p += strlen_user(p); } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { - __put_user((elf_caddr_t)(unsigned long)p,envp++); + __put_user((unsigned long)p,envp++); p += strlen_user(p); } __put_user(NULL, envp); diff -Nru a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c --- a/arch/mips/kernel/setup.c Sat Aug 31 15:05:55 2002 +++ b/arch/mips/kernel/setup.c Sat Aug 31 15:05:55 2002 @@ -285,7 +285,7 @@ mips_cpu.isa_level = MIPS_CPU_ISA_IV; mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_FPU | MIPS_CPU_32FPR; - mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ + mips_cpu.tlbsize = 384; /* has weird TLB: 3-way x 128 */ break; case PRID_IMP_R10000: mips_cpu.cputype = CPU_R10000; diff -Nru a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c --- a/arch/mips/mips-boards/generic/pci.c Sat Aug 31 15:05:59 2002 +++ b/arch/mips/mips-boards/generic/pci.c Sat Aug 31 15:05:59 2002 @@ -37,11 +37,9 @@ #define PCI_ACCESS_WRITE 1 static int -mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, - unsigned char where, u32 *data) +mips_pcibios_config_access(unsigned char access_type, struct pci_bus *bus_dev, unsigned int dev_fn, unsigned char where, u32 *data) { - unsigned char bus = dev->bus->number; - unsigned char dev_fn = dev->devfn; + unsigned char bus = bus_dev->number; u32 intr; if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0))) @@ -101,109 +99,56 @@ * read/write a 32bit word and mask/modify the data we actually want. */ static int -mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +mips_pcibios_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { u32 data = 0; - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xff; - - return PCIBIOS_SUCCESSFUL; -} - - -static int -mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) -{ - u32 data = 0; - - if (where & 1) + if((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) -{ - u32 data = 0; - - if (where & 3) + else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + if (mips_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) return -1; - - *val = data; + if(size == 1) + *val = (u8)(data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (u16)(data >> ((where & 3) << 3)) & 0xffff; + else if (size == 4) + *val = data; return PCIBIOS_SUCCESSFUL; } static int -mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +mips_pcibios_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { u32 data = 0; - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) -{ - u32 data = 0; - - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xffff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) -{ - if (where & 3) + if((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) - return -1; - + else if (size == 4) { + if(where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if(mips_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &val)) + return -1; + return PCIBIOS_SUCCESSFUL; + } + if (mips_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return -1; + if(size == 1) { + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } else if (size == 2) { + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } return PCIBIOS_SUCCESSFUL; } struct pci_ops mips_pci_ops = { - mips_pcibios_read_config_byte, - mips_pcibios_read_config_word, - mips_pcibios_read_config_dword, - mips_pcibios_write_config_byte, - mips_pcibios_write_config_word, - mips_pcibios_write_config_dword + .read = mips_pcibios_read, + .write = mips_pcibios_write, }; void __init pcibios_init(void) diff -Nru a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c --- a/arch/mips/sni/pci.c Sat Aug 31 15:06:00 2002 +++ b/arch/mips/sni/pci.c Sat Aug 31 15:06:00 2002 @@ -17,13 +17,13 @@ #ifdef CONFIG_PCI -#define mkaddr(dev, where) \ +#define mkaddr(bus, devfn, where) \ do { \ - if ((dev)->bus->number == 0) \ + if (bus->number == 0) \ return -1; \ *(volatile u32 *)PCIMT_CONFIG_ADDRESS = \ - ((dev->bus->number & 0xff) << 0x10) | \ - ((dev->devfn & 0xff) << 0x08) | \ + ((bus->number & 0xff) << 0x10) | \ + ((devfn & 0xff) << 0x08) | \ (where & 0xfc); \ } while(0) @@ -69,87 +69,67 @@ * We can't address 8 and 16 bit words directly. Instead we have to * read/write a 32bit word and mask/modify the data we actually want. */ -static int pcimt_read_config_byte (struct pci_dev *dev, - int where, unsigned char *val) +static int pcimt_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { u32 res; - mkaddr(dev, where); - res = *(volatile u32 *)PCIMT_CONFIG_DATA; - res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff; - *val = res; - - return PCIBIOS_SUCCESSFUL; -} - -static int pcimt_read_config_word (struct pci_dev *dev, - int where, unsigned short *val) -{ - u32 res; - - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(dev, where); - res = *(volatile u32 *)PCIMT_CONFIG_DATA; - res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff; - *val = res; - - return PCIBIOS_SUCCESSFUL; -} - -static int pcimt_read_config_dword (struct pci_dev *dev, - int where, unsigned int *val) -{ - u32 res; - - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(dev, where); - res = *(volatile u32 *)PCIMT_CONFIG_DATA; - res = le32_to_cpu(res); - *val = res; - - return PCIBIOS_SUCCESSFUL; -} - -static int pcimt_write_config_byte (struct pci_dev *dev, - int where, unsigned char val) -{ - mkaddr(dev, where); - *(volatile u8 *)(PCIMT_CONFIG_DATA + (where & 3)) = val; - - return PCIBIOS_SUCCESSFUL; -} - -static int pcimt_write_config_word (struct pci_dev *dev, - int where, unsigned short val) -{ - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(dev, where); - *(volatile u16 *)(PCIMT_CONFIG_DATA + (where & 3)) = le16_to_cpu(val); + switch (size) { + case 1: + mkaddr(bus, devfn, where); + res = *(volatile u32 *)PCIMT_CONFIG_DATA; + res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff; + *val = (u8)res; + break; + case 2: + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + mkaddr(bus, devfn, where); + res = *(volatile u32 *)PCIMT_CONFIG_DATA; + res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff; + *val = (u16)res; + break; + case 4: + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + mkaddr(bus, devfn, where); + res = *(volatile u32 *)PCIMT_CONFIG_DATA; + res = le32_to_cpu(res); + *val = res; + break; + } return PCIBIOS_SUCCESSFUL; } -static int pcimt_write_config_dword (struct pci_dev *dev, - int where, unsigned int val) +static int pcimt_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(dev, where); - *(volatile u32 *)PCIMT_CONFIG_DATA = le32_to_cpu(val); + switch (size) { + case 1: + mkaddr(bus, devfn, where); + *(volatile u8 *)(PCIMT_CONFIG_DATA + (where & 3)) = + (u8)le32_to_cpu(val); + break; + case 2: + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + mkaddr(bus, devfn, where); + *(volatile u16 *)(PCIMT_CONFIG_DATA + (where & 3)) = + (u16)le32_to_cpu(val); + break; + case 4: + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + mkaddr(bus, devfn, where); + *(volatile u32 *)PCIMT_CONFIG_DATA = le32_to_cpu(val); + break; + } return PCIBIOS_SUCCESSFUL; } struct pci_ops sni_pci_ops = { - pcimt_read_config_byte, - pcimt_read_config_word, - pcimt_read_config_dword, - pcimt_write_config_byte, - pcimt_write_config_word, - pcimt_write_config_dword + .read = pcimt_read, + .write = pcimt_write, }; void __init diff -Nru a/arch/mips64/config.in b/arch/mips64/config.in --- a/arch/mips64/config.in Sat Aug 31 15:05:54 2002 +++ b/arch/mips64/config.in Sat Aug 31 15:05:54 2002 @@ -189,6 +189,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -230,7 +232,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/mips64/defconfig b/arch/mips64/defconfig --- a/arch/mips64/defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/mips64/defconfig Sat Aug 31 15:05:55 2002 @@ -400,6 +400,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 --- a/arch/mips64/defconfig-ip22 Sat Aug 31 15:05:54 2002 +++ b/arch/mips64/defconfig-ip22 Sat Aug 31 15:05:54 2002 @@ -405,6 +405,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27 --- a/arch/mips64/defconfig-ip27 Sat Aug 31 15:06:00 2002 +++ b/arch/mips64/defconfig-ip27 Sat Aug 31 15:06:00 2002 @@ -400,6 +400,7 @@ # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips64/defconfig-ip32 b/arch/mips64/defconfig-ip32 --- a/arch/mips64/defconfig-ip32 Sat Aug 31 15:06:06 2002 +++ b/arch/mips64/defconfig-ip32 Sat Aug 31 15:06:06 2002 @@ -430,6 +430,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/mips64/kernel/binfmt_elf32.c b/arch/mips64/kernel/binfmt_elf32.c --- a/arch/mips64/kernel/binfmt_elf32.c Sat Aug 31 15:05:59 2002 +++ b/arch/mips64/kernel/binfmt_elf32.c Sat Aug 31 15:05:59 2002 @@ -80,7 +80,6 @@ }; #define elf_addr_t u32 -#define elf_caddr_t u32 #define init_elf_binfmt init_elf32_binfmt #undef CONFIG_BINFMT_ELF #ifdef CONFIG_BINFMT_ELF32 diff -Nru a/arch/parisc/defconfig b/arch/parisc/defconfig --- a/arch/parisc/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/parisc/defconfig Sat Aug 31 15:05:54 2002 @@ -294,6 +294,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/FADS_defconfig b/arch/ppc/configs/FADS_defconfig --- a/arch/ppc/configs/FADS_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/FADS_defconfig Sat Aug 31 15:06:06 2002 @@ -376,6 +376,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/IVMS8_defconfig b/arch/ppc/configs/IVMS8_defconfig --- a/arch/ppc/configs/IVMS8_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/IVMS8_defconfig Sat Aug 31 15:05:54 2002 @@ -404,6 +404,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/SM850_defconfig b/arch/ppc/configs/SM850_defconfig --- a/arch/ppc/configs/SM850_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/SM850_defconfig Sat Aug 31 15:05:59 2002 @@ -372,6 +372,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/SPD823TS_defconfig b/arch/ppc/configs/SPD823TS_defconfig --- a/arch/ppc/configs/SPD823TS_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/SPD823TS_defconfig Sat Aug 31 15:06:06 2002 @@ -371,6 +371,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/TQM823L_defconfig b/arch/ppc/configs/TQM823L_defconfig --- a/arch/ppc/configs/TQM823L_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/TQM823L_defconfig Sat Aug 31 15:05:55 2002 @@ -372,6 +372,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/TQM8260_defconfig b/arch/ppc/configs/TQM8260_defconfig --- a/arch/ppc/configs/TQM8260_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/TQM8260_defconfig Sat Aug 31 15:05:55 2002 @@ -345,6 +345,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/TQM850L_defconfig b/arch/ppc/configs/TQM850L_defconfig --- a/arch/ppc/configs/TQM850L_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/TQM850L_defconfig Sat Aug 31 15:06:00 2002 @@ -372,6 +372,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/TQM860L_defconfig b/arch/ppc/configs/TQM860L_defconfig --- a/arch/ppc/configs/TQM860L_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/TQM860L_defconfig Sat Aug 31 15:05:59 2002 @@ -417,6 +417,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/adir_defconfig b/arch/ppc/configs/adir_defconfig --- a/arch/ppc/configs/adir_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/adir_defconfig Sat Aug 31 15:06:06 2002 @@ -514,6 +514,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig --- a/arch/ppc/configs/apus_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/apus_defconfig Sat Aug 31 15:06:06 2002 @@ -659,6 +659,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/ash_defconfig b/arch/ppc/configs/ash_defconfig --- a/arch/ppc/configs/ash_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/ash_defconfig Sat Aug 31 15:05:54 2002 @@ -432,6 +432,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/bseip_defconfig b/arch/ppc/configs/bseip_defconfig --- a/arch/ppc/configs/bseip_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/bseip_defconfig Sat Aug 31 15:05:55 2002 @@ -371,6 +371,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/ceder_defconfig b/arch/ppc/configs/ceder_defconfig --- a/arch/ppc/configs/ceder_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/ceder_defconfig Sat Aug 31 15:06:06 2002 @@ -434,6 +434,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig --- a/arch/ppc/configs/common_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/common_defconfig Sat Aug 31 15:05:55 2002 @@ -725,6 +725,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/cpci405_defconfig b/arch/ppc/configs/cpci405_defconfig --- a/arch/ppc/configs/cpci405_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/cpci405_defconfig Sat Aug 31 15:05:59 2002 @@ -458,6 +458,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/ep405_defconfig b/arch/ppc/configs/ep405_defconfig --- a/arch/ppc/configs/ep405_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/ep405_defconfig Sat Aug 31 15:06:06 2002 @@ -428,6 +428,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig --- a/arch/ppc/configs/est8260_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/est8260_defconfig Sat Aug 31 15:06:00 2002 @@ -355,6 +355,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/ev64260_defconfig b/arch/ppc/configs/ev64260_defconfig --- a/arch/ppc/configs/ev64260_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/ev64260_defconfig Sat Aug 31 15:05:59 2002 @@ -473,6 +473,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig --- a/arch/ppc/configs/gemini_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/gemini_defconfig Sat Aug 31 15:05:59 2002 @@ -453,6 +453,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/iSeries_defconfig b/arch/ppc/configs/iSeries_defconfig --- a/arch/ppc/configs/iSeries_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/iSeries_defconfig Sat Aug 31 15:05:54 2002 @@ -364,6 +364,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/ibmchrp_defconfig b/arch/ppc/configs/ibmchrp_defconfig --- a/arch/ppc/configs/ibmchrp_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/ibmchrp_defconfig Sat Aug 31 15:06:00 2002 @@ -593,6 +593,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/k2_defconfig b/arch/ppc/configs/k2_defconfig --- a/arch/ppc/configs/k2_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/k2_defconfig Sat Aug 31 15:05:54 2002 @@ -494,6 +494,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/lopec_defconfig b/arch/ppc/configs/lopec_defconfig --- a/arch/ppc/configs/lopec_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/lopec_defconfig Sat Aug 31 15:05:54 2002 @@ -681,6 +681,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/mbx_defconfig b/arch/ppc/configs/mbx_defconfig --- a/arch/ppc/configs/mbx_defconfig Sat Aug 31 15:05:53 2002 +++ b/arch/ppc/configs/mbx_defconfig Sat Aug 31 15:05:53 2002 @@ -364,6 +364,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/mcpn765_defconfig b/arch/ppc/configs/mcpn765_defconfig --- a/arch/ppc/configs/mcpn765_defconfig Sat Aug 31 15:06:01 2002 +++ b/arch/ppc/configs/mcpn765_defconfig Sat Aug 31 15:06:01 2002 @@ -404,6 +404,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig --- a/arch/ppc/configs/menf1_defconfig Sat Aug 31 15:05:53 2002 +++ b/arch/ppc/configs/menf1_defconfig Sat Aug 31 15:05:53 2002 @@ -503,6 +503,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig --- a/arch/ppc/configs/mvme5100_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/mvme5100_defconfig Sat Aug 31 15:05:54 2002 @@ -552,6 +552,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/oak_defconfig b/arch/ppc/configs/oak_defconfig --- a/arch/ppc/configs/oak_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/oak_defconfig Sat Aug 31 15:05:54 2002 @@ -407,6 +407,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/pcore_defconfig b/arch/ppc/configs/pcore_defconfig --- a/arch/ppc/configs/pcore_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/pcore_defconfig Sat Aug 31 15:06:00 2002 @@ -504,6 +504,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig --- a/arch/ppc/configs/pmac_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/pmac_defconfig Sat Aug 31 15:06:06 2002 @@ -805,6 +805,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/configs/power3_defconfig b/arch/ppc/configs/power3_defconfig --- a/arch/ppc/configs/power3_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/power3_defconfig Sat Aug 31 15:05:55 2002 @@ -577,6 +577,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/pplus_defconfig b/arch/ppc/configs/pplus_defconfig --- a/arch/ppc/configs/pplus_defconfig Sat Aug 31 15:06:01 2002 +++ b/arch/ppc/configs/pplus_defconfig Sat Aug 31 15:06:01 2002 @@ -596,6 +596,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/prpmc750_defconfig b/arch/ppc/configs/prpmc750_defconfig --- a/arch/ppc/configs/prpmc750_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/prpmc750_defconfig Sat Aug 31 15:05:55 2002 @@ -440,6 +440,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/prpmc800_defconfig b/arch/ppc/configs/prpmc800_defconfig --- a/arch/ppc/configs/prpmc800_defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/ppc/configs/prpmc800_defconfig Sat Aug 31 15:05:59 2002 @@ -454,6 +454,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/redwood5_defconfig b/arch/ppc/configs/redwood5_defconfig --- a/arch/ppc/configs/redwood5_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/redwood5_defconfig Sat Aug 31 15:05:55 2002 @@ -433,6 +433,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/redwood_defconfig b/arch/ppc/configs/redwood_defconfig --- a/arch/ppc/configs/redwood_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/redwood_defconfig Sat Aug 31 15:06:00 2002 @@ -372,6 +372,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/rpxcllf_defconfig b/arch/ppc/configs/rpxcllf_defconfig --- a/arch/ppc/configs/rpxcllf_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/rpxcllf_defconfig Sat Aug 31 15:05:55 2002 @@ -371,6 +371,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/rpxlite_defconfig b/arch/ppc/configs/rpxlite_defconfig --- a/arch/ppc/configs/rpxlite_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/rpxlite_defconfig Sat Aug 31 15:05:55 2002 @@ -371,6 +371,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/sandpoint_defconfig b/arch/ppc/configs/sandpoint_defconfig --- a/arch/ppc/configs/sandpoint_defconfig Sat Aug 31 15:06:00 2002 +++ b/arch/ppc/configs/sandpoint_defconfig Sat Aug 31 15:06:00 2002 @@ -687,6 +687,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/spruce_defconfig b/arch/ppc/configs/spruce_defconfig --- a/arch/ppc/configs/spruce_defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/ppc/configs/spruce_defconfig Sat Aug 31 15:05:54 2002 @@ -402,6 +402,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/walnut_defconfig b/arch/ppc/configs/walnut_defconfig --- a/arch/ppc/configs/walnut_defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/ppc/configs/walnut_defconfig Sat Aug 31 15:06:06 2002 @@ -428,6 +428,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc/configs/zx4500_defconfig b/arch/ppc/configs/zx4500_defconfig --- a/arch/ppc/configs/zx4500_defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/configs/zx4500_defconfig Sat Aug 31 15:05:55 2002 @@ -409,6 +409,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/defconfig b/arch/ppc/defconfig --- a/arch/ppc/defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc/defconfig Sat Aug 31 15:05:55 2002 @@ -725,6 +725,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c --- a/arch/ppc/mm/tlb.c Sat Aug 31 15:06:03 2002 +++ b/arch/ppc/mm/tlb.c Sat Aug 31 15:06:03 2002 @@ -4,7 +4,7 @@ /* * This file contains the routines for TLB flushing. * On machines where the MMU uses a hash table to store virtual to - * physical translations, these routines flush entries from the the + * physical translations, these routines flush entries from the * hash table also. * -- paulus * diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig --- a/arch/ppc64/defconfig Sat Aug 31 15:05:55 2002 +++ b/arch/ppc64/defconfig Sat Aug 31 15:05:55 2002 @@ -584,6 +584,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/ppc64/kernel/iSeries_IoMmTable.c b/arch/ppc64/kernel/iSeries_IoMmTable.c --- a/arch/ppc64/kernel/iSeries_IoMmTable.c Sat Aug 31 15:06:06 2002 +++ b/arch/ppc64/kernel/iSeries_IoMmTable.c Sat Aug 31 15:06:06 2002 @@ -130,7 +130,7 @@ /* The HvCallPci_getBarParms is used to get the size of the BAR */ /* space. It calls iSeries_IoMmTable_AllocateEntry to allocate */ /* each entry. */ -/* - Loops through The Bar resourses(0 - 5) including the the ROM */ +/* - Loops through The Bar resources(0 - 5) including the ROM */ /* is resource(6). */ /*******************************************************************/ void iSeries_allocateDeviceBars(struct pci_dev* PciDev) diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig --- a/arch/s390/defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/s390/defconfig Sat Aug 31 15:06:06 2002 @@ -295,6 +295,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/s390x/defconfig b/arch/s390x/defconfig --- a/arch/s390x/defconfig Sat Aug 31 15:05:53 2002 +++ b/arch/s390x/defconfig Sat Aug 31 15:05:53 2002 @@ -295,6 +295,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVFS_FS=y diff -Nru a/arch/s390x/kernel/binfmt_elf32.c b/arch/s390x/kernel/binfmt_elf32.c --- a/arch/s390x/kernel/binfmt_elf32.c Sat Aug 31 15:06:00 2002 +++ b/arch/s390x/kernel/binfmt_elf32.c Sat Aug 31 15:06:00 2002 @@ -166,7 +166,6 @@ #define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) #define elf_addr_t u32 -#define elf_caddr_t u32 /* #define init_elf_binfmt init_elf32_binfmt */ diff -Nru a/arch/sh/defconfig b/arch/sh/defconfig --- a/arch/sh/defconfig Sat Aug 31 15:05:54 2002 +++ b/arch/sh/defconfig Sat Aug 31 15:05:54 2002 @@ -156,6 +156,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/sh/kernel/irq_intc2.c b/arch/sh/kernel/irq_intc2.c --- a/arch/sh/kernel/irq_intc2.c Sat Aug 31 15:06:04 2002 +++ b/arch/sh/kernel/irq_intc2.c Sat Aug 31 15:06:04 2002 @@ -107,7 +107,7 @@ } disable_irq_nosync(irq); - /* Fill the the data we need */ + /* Fill the data we need */ intc2_data[offset].addr=addr; intc2_data[offset].mask=1<bus->number==0 && dev->devfn==0) +#define BBA_SELECTED(bus,devfn) (bus->number==0 && devfn==0) -static int gapspci_read_config_byte(struct pci_dev *dev, int where, - u8 * val) +static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { - if (BBA_SELECTED(dev)) - *val = inb(GAPSPCI_BBA_CONFIG+where); - else - *val = 0xff; - + switch (size) { + case 1: + if (BBA_SELECTED(bus, devfn)) + *val = (u8)inb(GAPSPCI_BBA_CONFIG+where); + else + *val = (u8)0xff; + break; + case 2: + if (BBA_SELECTED(bus, devfn)) + *val = (u16)inw(GAPSPCI_BBA_CONFIG+where); + else + *val = (u16)0xffff; + break; + case 4: + if (BBA_SELECTED(bus, devfn)) + *val = inl(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xffffffff; + break; + } return PCIBIOS_SUCCESSFUL; } -static int gapspci_read_config_word(struct pci_dev *dev, int where, - u16 * val) -{ - if (BBA_SELECTED(dev)) - *val = inw(GAPSPCI_BBA_CONFIG+where); - else - *val = 0xffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int gapspci_read_config_dword(struct pci_dev *dev, int where, - u32 * val) -{ - if (BBA_SELECTED(dev)) - *val = inl(GAPSPCI_BBA_CONFIG+where); - else - *val = 0xffffffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int gapspci_write_config_byte(struct pci_dev *dev, int where, - u8 val) -{ - if (BBA_SELECTED(dev)) - outb(val, GAPSPCI_BBA_CONFIG+where); - - return PCIBIOS_SUCCESSFUL; -} - - -static int gapspci_write_config_word(struct pci_dev *dev, int where, - u16 val) -{ - if (BBA_SELECTED(dev)) - outw(val, GAPSPCI_BBA_CONFIG+where); - - return PCIBIOS_SUCCESSFUL; -} - -static int gapspci_write_config_dword(struct pci_dev *dev, int where, - u32 val) +static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - if (BBA_SELECTED(dev)) - outl(val, GAPSPCI_BBA_CONFIG+where); - - return PCIBIOS_SUCCESSFUL; + if (BBA_SELECTED(bus, devfn)) { + switch (size) { + case 1: + if (BBA_SELECTED(bus, devfn)) + outb((u8)val, GAPSPCI_BBA_CONFIG+where); + break; + case 2: + if (BBA_SELECTED(bus, devfn)) + outw((u16)val, GAPSPCI_BBA_CONFIG+where); + break; + case 4: + if (BBA_SELECTED(bus, devfn)) + outl(val, GAPSPCI_BBA_CONFIG+where); + break; + } + } + return PCIBIOS_SUCCESSFUL; } static struct pci_ops pci_config_ops = { - gapspci_read_config_byte, - gapspci_read_config_word, - gapspci_read_config_dword, - gapspci_write_config_byte, - gapspci_write_config_word, - gapspci_write_config_dword + .read = gapspci_read, + .write = gapspci_write, }; @@ -143,7 +124,7 @@ for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { dev = pci_dev_b(ln); - if (!BBA_SELECTED(dev)) continue; + if (!BBA_SELECTED(bus, dev->devfn)) continue; printk("PCI: MMIO fixup to %s\n", dev->name); dev->resource[1].start=0x01001700; diff -Nru a/arch/sh/kernel/pci-sh7751.c b/arch/sh/kernel/pci-sh7751.c --- a/arch/sh/kernel/pci-sh7751.c Sat Aug 31 15:05:54 2002 +++ b/arch/sh/kernel/pci-sh7751.c Sat Aug 31 15:05:54 2002 @@ -41,14 +41,14 @@ #ifdef CONFIG_PCI_DIRECT -#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) +#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) #define PCI_REG(reg) (SH7751_PCIREG_BASE+reg) /* * Functions for accessing PCI configuration space with type 1 accesses */ -static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) +static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { u32 word; unsigned long flags; @@ -57,144 +57,88 @@ * so we must do byte alignment by hand */ save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); + outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); word = inl(PCI_REG(SH7751_PCIPDR)); restore_flags(flags); - switch (where & 0x3) { - case 3: - *value = (u8)(word >> 24); - break; - case 2: - *value = (u8)(word >> 16); - break; - case 1: - *value = (u8)(word >> 8); - break; - default: - *value = (u8)word; - break; - } - PCIDBG(4,"pci_conf1_read_config_byte@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),*value); - return PCIBIOS_SUCCESSFUL; -} -static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - u32 word; - unsigned long flags; - - /* PCIPDR may only be accessed as 32 bit words, - * so we must do word alignment by hand - */ - save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); - word = inl(PCI_REG(SH7751_PCIPDR)); - restore_flags(flags); - switch (where & 0x3) { - case 3: - // This should never happen... - printk(KERN_ERR "PCI BIOS: read_config_word: Illegal u16 alignment"); - return PCIBIOS_BAD_REGISTER_NUMBER; - case 2: - *value = (u16)(word >> 16); - break; + switch (size) { case 1: - *value = (u16)(word >> 8); - break; - default: - *value = (u16)word; + switch (where & 0x3) { + case 3: + *value = (u8)(word >> 24); + break; + case 2: + *value = (u8)(word >> 16); + break; + case 1: + *value = (u8)(word >> 8); + break; + default: + *value = (u8)word; + break; + } + case 2: + switch (where & 0x3) { + case 3: /*This should never happen.*/ + printk(KERN_ERR "PCI BIOS: read_config: Illegal u16 alignment"); + return PCIBIOS_BAD_REGISTER_NUMBER; + case 2: + *value = (u16)(word >> 16); + break; + case 1: + *value = (u16)(word >> 8); + break; + default: + *value = (u16)word; + break; + } + case 4: + *value = word; break; - } - PCIDBG(4,"pci_conf1_read_config_word@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),*value); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long flags; - - save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); - *value = inl(PCI_REG(SH7751_PCIPDR)); - restore_flags(flags); - PCIDBG(4,"pci_conf1_read_config_dword@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),*value); + } + PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) +/* + * Since SH7751 only does 32bit access we'll have to do a read,mask,write operation. + * We'll allow an odd byte offset, though it should be illegal. + */ +static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - u32 word; - u32 shift = (where & 3) * 8; - u32 mask = ((1 << 8) - 1) << shift; // create the byte mask + u32 word,mask; unsigned long flags; - - /* Since SH7751 only does 32bit access we'll have to do a - * read,mask,write operation - */ - save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); - word = inl(PCI_REG(SH7751_PCIPDR)) ; - word &= ~mask; - word |= value << shift; - - outl(word, PCI_REG(SH7751_PCIPDR)); - restore_flags(flags); - PCIDBG(4,"pci_conf1_write_config_byte@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),word); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - u32 word; u32 shift = (where & 3) * 8; - u32 mask = ((1 << 16) - 1) << shift; // create the word mask - unsigned long flags; - /* Since SH7751 only does 32bit access we'll have to do a - * read,mask,write operation. We'll allow an odd byte offset, - * though it should be illegal. - */ - if (shift == 24) - return PCIBIOS_BAD_REGISTER_NUMBER; - save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); + if(size == 1) { + mask = ((1 << 8) - 1) << shift; // create the byte mask + } else if(size == 2){ + if(shift == 24) + return PCIBIOS_BAD_REGISTER_NUMBER; + mask = ((1 << 16) - 1) << shift; // create the word mask + } + save_and_cli(flags); + outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); + if(size == 4){ + outl(value, PCI_REG(SH7751_PCIPDR)); + restore_flags(flags); + PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value); + return PCIBIOS_SUCCESSFUL; + } word = inl(PCI_REG(SH7751_PCIPDR)) ; word &= ~mask; word |= value << shift; - - outl(value, PCI_REG(SH7751_PCIPDR)); - restore_flags(flags); - PCIDBG(4,"pci_conf1_write_config_word@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),word); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - unsigned long flags; - - save_and_cli(flags); - outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR)); - outl(value, PCI_REG(SH7751_PCIPDR)); + outl(word, PCI_REG(SH7751_PCIPDR)); restore_flags(flags); - PCIDBG(4,"pci_conf1_write_config_dword@0x%08x=0x%x\n", - CONFIG_CMD(dev,where),value); + PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word); return PCIBIOS_SUCCESSFUL; } #undef CONFIG_CMD static struct pci_ops pci_direct_conf1 = { - pci_conf1_read_config_byte, - pci_conf1_read_config_word, - pci_conf1_read_config_dword, - pci_conf1_write_config_byte, - pci_conf1_write_config_word, - pci_conf1_write_config_dword + .read = pci_conf1_read, + .write = pci_conf1_write, }; struct pci_ops * __init pci_check_direct(void) diff -Nru a/arch/sh/kernel/pci_st40.c b/arch/sh/kernel/pci_st40.c --- a/arch/sh/kernel/pci_st40.c Sat Aug 31 15:06:06 2002 +++ b/arch/sh/kernel/pci_st40.c Sat Aug 31 15:06:06 2002 @@ -268,7 +268,7 @@ #define SET_CONFIG_BITS(bus,devfn,where)\ (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0)) -#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where) +#define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where) static int CheckForMasterAbort(void) @@ -284,79 +284,53 @@ } /* Write to config register */ -static int st40pci_read_config_byte(struct pci_dev *dev, int where, - u8 * val) +static int st40pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { - ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - - *val = ST40PCI_READ_BYTE(PDR + (where & 3)); - - if (CheckForMasterAbort()) - *val = 0xff; - - - return PCIBIOS_SUCCESSFUL; -} - -static int st40pci_read_config_word(struct pci_dev *dev, int where, - u16 * val) -{ - ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - - *val = ST40PCI_READ_SHORT(PDR + (where & 2)); - - if (CheckForMasterAbort()) - *val = 0xffff; - - return PCIBIOS_SUCCESSFUL; -} - - -static int st40pci_read_config_dword(struct pci_dev *dev, int where, - u32 * val) -{ - - ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - - *val = ST40PCI_READ(PDR); - - if (CheckForMasterAbort()) - *val = 0xffffffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int st40pci_write_config_byte(struct pci_dev *dev, int where, - u8 val) -{ - ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - - ST40PCI_WRITE_BYTE(PDR + (where & 3), val); - - CheckForMasterAbort(); - - return PCIBIOS_SUCCESSFUL; -} - - -static int st40pci_write_config_word(struct pci_dev *dev, int where, - u16 val) -{ - ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - - ST40PCI_WRITE_SHORT(PDR + (where & 2), val); + ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where)); + switch (size) { + case 1: + *val = (u8)ST40PCI_READ_BYTE(PDR + (where & 3)); + break; + case 2: + *val = (u16)ST40PCI_READ_SHORT(PDR + (where & 2)); + break; + case 4: + *val = ST40PCI_READ(PDR); + break; + } - CheckForMasterAbort(); + if (CheckForMasterAbort()){ + switch (size) { + case 1: + *val = (u8)0xff; + break; + case 2: + *val = (u16)0xffff; + break; + case 4: + *val = 0xffffffff; + break; + } + } return PCIBIOS_SUCCESSFUL; } -static int st40pci_write_config_dword(struct pci_dev *dev, int where, - u32 val) +static int st40pci_write(struct pci_bus *bus, unsigned int devfn; int where, int size, u32 val) { ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); - ST40PCI_WRITE(PDR, val); + switch (size) { + case 1: + ST40PCI_WRITE_BYTE(PDR + (where & 3), (u8)val); + break; + case 2: + ST40PCI_WRITE_SHORT(PDR + (where & 2), (u16)val); + break; + case 4: + ST40PCI_WRITE(PDR, val); + break; + } CheckForMasterAbort(); @@ -364,12 +338,8 @@ } static struct pci_ops pci_config_ops = { - st40pci_read_config_byte, - st40pci_read_config_word, - st40pci_read_config_dword, - st40pci_write_config_byte, - st40pci_write_config_word, - st40pci_write_config_dword + .read = st40pci_read, + .write = st40pci_write, }; diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in --- a/arch/sparc/config.in Sat Aug 31 15:05:54 2002 +++ b/arch/sparc/config.in Sat Aug 31 15:05:54 2002 @@ -15,6 +15,7 @@ define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y +define_bool CONFIG_HW_CONSOLE y bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig --- a/arch/sparc/defconfig Sat Aug 31 15:06:06 2002 +++ b/arch/sparc/defconfig Sat Aug 31 15:06:06 2002 @@ -302,6 +302,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in --- a/arch/sparc64/config.in Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/config.in Sat Aug 31 15:05:59 2002 @@ -13,6 +13,7 @@ define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y +define_bool CONFIG_HW_CONSOLE y bool 'Symmetric multi-processing support' CONFIG_SMP bool 'Preemptible Kernel' CONFIG_PREEMPT diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/defconfig Sat Aug 31 15:05:59 2002 @@ -28,6 +28,7 @@ CONFIG_BBC_I2C=m CONFIG_VT=y CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y CONFIG_SMP=y # CONFIG_PREEMPT is not set CONFIG_SPARC64=y @@ -194,67 +195,82 @@ # ATA/ATAPI/MFM/RLL device support # CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# CONFIG_BLK_DEV_IDE=y -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_IDEDISK_STROKE is not set -CONFIG_ATAPI=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_IDE_TASK_IOCTL is not set # -# ATA host controller support +# IDE chipset support/bugfixes # -# CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set - -# -# PCI host controller support -# -# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_BLK_DEV_IDE_TCQ is not set -# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC6280_BURST is not set +# CONFIG_AEC62XX_TUNING is not set CONFIG_BLK_DEV_ALI15X3=y # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_CMD680 is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_PIIX is not set CONFIG_BLK_DEV_NS87415=y # CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_ADMA100 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set # CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_BLK_DEV_SL82C105 is not set # CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support @@ -475,7 +491,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set -# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_8139_OLD_RX_RESET is not set CONFIG_SIS900=m CONFIG_EPIC100=m CONFIG_SUNDANCE=m @@ -490,6 +506,7 @@ # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set +# CONFIG_E1000_NAPI is not set CONFIG_MYRI_SBUS=m # CONFIG_NS83820 is not set CONFIG_HAMACHI=m @@ -574,7 +591,6 @@ # # Userland interfaces # -CONFIG_INPUT_KEYBDEV=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 @@ -583,7 +599,6 @@ # CONFIG_INPUT_TSDEV is not set CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set -# CONFIG_INPUT_UINPUT is not set # # Input I/O drivers @@ -597,7 +612,10 @@ # CONFIG_GAMEPORT_FM801 is not set # CONFIG_GAMEPORT_CS461x is not set CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_I8042=y +CONFIG_I8042_REG_BASE=60 +CONFIG_I8042_KBD_IRQ=1 +CONFIG_I8042_AUX_IRQ=12 # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PARKBD is not set @@ -606,12 +624,12 @@ # Input Device Drivers # CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_ATKBD=y CONFIG_KEYBOARD_SUNKBD=y # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set CONFIG_INPUT_MOUSE=y -# CONFIG_MOUSE_PS2 is not set +CONFIG_MOUSE_PS2=y CONFIG_MOUSE_SERIAL=y # CONFIG_MOUSE_INPORT is not set # CONFIG_MOUSE_LOGIBM is not set @@ -641,6 +659,10 @@ # CONFIG_INPUT_JOYDUMP is not set # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_TOUCHSCREEN_GUNZE is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_PCSPKR is not set +CONFIG_INPUT_SPARCSPKR=y +# CONFIG_INPUT_UINPUT is not set # # File systems @@ -681,6 +703,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -924,6 +947,8 @@ CONFIG_USB_AUERSWALD=m CONFIG_USB_RIO500=m # CONFIG_USB_BRLVGER is not set +CONFIG_USB_LCD=m +CONFIG_USB_SPEEDTOUCH=m # # Bluetooth support diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c --- a/arch/sparc64/kernel/binfmt_elf32.c Sat Aug 31 15:06:06 2002 +++ b/arch/sparc64/kernel/binfmt_elf32.c Sat Aug 31 15:06:06 2002 @@ -147,7 +147,6 @@ } #define elf_addr_t u32 -#define elf_caddr_t u32 #undef start_thread #define start_thread start_thread32 #define init_elf_binfmt init_elf32_binfmt diff -Nru a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c --- a/arch/sparc64/kernel/cpu.c Sat Aug 31 15:06:06 2002 +++ b/arch/sparc64/kernel/cpu.c Sat Aug 31 15:06:06 2002 @@ -57,25 +57,24 @@ void __init cpu_probe(void) { - int manuf, impl; - unsigned i, cpuid; - long ver, fpu_vers; - long fprs; + unsigned long ver, fpu_vers, manuf, impl, fprs; + int i, cpuid; cpuid = hard_smp_processor_id(); - fprs = fprs_read (); - fprs_write (FPRS_FEF); + fprs = fprs_read(); + fprs_write(FPRS_FEF); __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=&r" (ver) : "r" (&fpu_vers)); - fprs_write (fprs); + fprs_write(fprs); manuf = ((ver >> 48) & 0xffff); impl = ((ver >> 32) & 0xffff); fpu_vers = ((fpu_vers >> 17) & 0x7); +retry: for (i = 0; i < NSPARCCHIPS; i++) { if (linux_sparc_chips[i].manuf == manuf) { if (linux_sparc_chips[i].impl == impl) { @@ -87,8 +86,17 @@ } if (i == NSPARCCHIPS) { - printk("DEBUG: manuf = 0x%x impl = 0x%x\n", - manuf, impl); + /* Maybe it is a cheetah+ derivative, report it as cheetah+ + * in that case until we learn the real names. + */ + if (manuf == 0x3e && + impl > 0x15) { + impl = 0x15; + goto retry; + } else { + printk("DEBUG: manuf[%lx] impl[%lx]\n", + manuf, impl); + } sparc_cpu_type[cpuid] = "Unknown CPU"; } @@ -104,9 +112,8 @@ } if (i == NSPARCFPU) { - printk("DEBUG: manuf = 0x%x impl = 0x%x fsr.vers = 0x%x\n", - manuf, impl, - (unsigned int) fpu_vers); + printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n", + manuf, impl, fpu_vers); sparc_fpu_type[cpuid] = "Unknown FPU"; } } diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S --- a/arch/sparc64/kernel/entry.S Sat Aug 31 15:05:53 2002 +++ b/arch/sparc64/kernel/entry.S Sat Aug 31 15:05:53 2002 @@ -1820,23 +1820,13 @@ ldx [%g3 + %lo(timer_tick_offset)], %g3 or %g2, %lo(xtime), %g2 or %g1, %lo(timer_tick_compare), %g1 -1: rdpr %ver, %o2 - sethi %hi(CHEETAH_ID), %o1 - srlx %o2, 32, %o2 - or %o1, %lo(CHEETAH_ID), %o1 - membar #Sync +1: membar #Sync ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4 - cmp %o2, %o1 - be,a,pn %xcc, 3f - rd %asr24, %o1 - sethi %hi(CHEETAH_PLUS_ID), %o1 - or %o1, %lo(CHEETAH_PLUS_ID), %o1 - cmp %o2, %o1 - bne,pt %xcc, 2f - nop + BRANCH_IF_ANY_CHEETAH(o2,o1,2f) ba,pt %xcc, 3f + rd %tick, %o1 +2: ba,pt %xcc, 3f rd %asr24, %o1 -2: rd %tick, %o1 3: ldx [%g1], %g7 membar #Sync ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o2 diff -Nru a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S --- a/arch/sparc64/kernel/etrap.S Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/kernel/etrap.S Sat Aug 31 15:05:59 2002 @@ -115,11 +115,12 @@ * 0x00 TL1's TSTATE * 0x08 TL1's TPC * 0x10 TL1's TNPC + * 0x18 TL1's TT * ... - * 0x58 TL4's TNPC + * 0x58 TL4's TT * 0x60 TL */ - sub %sp, (24 * 8) + 8, %g2 + sub %sp, ((4 * 8) * 4) + 8, %g2 rdpr %tl, %g1 wrpr %g0, 1, %tl @@ -129,33 +130,41 @@ stx %g3, [%g2 + STACK_BIAS + 0x08] rdpr %tnpc, %g3 stx %g3, [%g2 + STACK_BIAS + 0x10] + rdpr %tt, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x18] wrpr %g0, 2, %tl rdpr %tstate, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x18] - rdpr %tpc, %g3 stx %g3, [%g2 + STACK_BIAS + 0x20] - rdpr %tnpc, %g3 + rdpr %tpc, %g3 stx %g3, [%g2 + STACK_BIAS + 0x28] + rdpr %tnpc, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x30] + rdpr %tt, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x38] wrpr %g0, 3, %tl rdpr %tstate, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x30] + stx %g3, [%g2 + STACK_BIAS + 0x40] rdpr %tpc, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x38] + stx %g3, [%g2 + STACK_BIAS + 0x48] rdpr %tnpc, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x40] + stx %g3, [%g2 + STACK_BIAS + 0x50] + rdpr %tt, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x58] wrpr %g0, 4, %tl rdpr %tstate, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x48] + stx %g3, [%g2 + STACK_BIAS + 0x60] rdpr %tpc, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x50] + stx %g3, [%g2 + STACK_BIAS + 0x68] rdpr %tnpc, %g3 - stx %g3, [%g2 + STACK_BIAS + 0x58] + stx %g3, [%g2 + STACK_BIAS + 0x70] + rdpr %tt, %g3 + stx %g3, [%g2 + STACK_BIAS + 0x78] wrpr %g1, %tl - stx %g1, [%g2 + STACK_BIAS + 0x60] + stx %g1, [%g2 + STACK_BIAS + 0x80] rdpr %tstate, %g1 ! Single Group+4bubbles sub %g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S --- a/arch/sparc64/kernel/head.S Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/kernel/head.S Sat Aug 31 15:05:59 2002 @@ -78,16 +78,9 @@ * PROM entry point is on %o4 */ sparc64_boot: - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,pn %icc, cheetah_boot - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,pt %icc, spitfire_boot + BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_boot) + BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_boot) + ba,pt %xcc, spitfire_boot nop cheetah_plus_boot: @@ -212,15 +205,11 @@ add %l0, (1 << 3), %l0 /* On Cheetah+, have to check second DTLB. */ - rdpr %ver, %g1 - srlx %g1, 32, %g1 - sethi %hi(CHEETAH_PLUS_ID), %l0 - or %l0, %lo(CHEETAH_PLUS_ID), %l0 - cmp %g1, %l0 - bne,pt %icc, 9f + BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,l0,2f) + ba,pt %xcc, 9f nop - set 3 << 16, %l0 +2: set 3 << 16, %l0 1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1 membar #Sync andn %g1, %l2, %g1 @@ -469,16 +458,9 @@ stxa %g3, [%g2] ASI_DMMU membar #Sync - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,pn %icc, cheetah_tlb_fixup - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,pt %icc, spitfire_tlb_fixup + BRANCH_IF_ANY_CHEETAH(g1,g5,cheetah_tlb_fixup) + + ba,pt %xcc, spitfire_tlb_fixup nop cheetah_tlb_fixup: @@ -499,15 +481,10 @@ flush %g3 membar #Sync - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - rdpr %ver, %g2 - srlx %g2, 32, %g2 - cmp %g2, %g5 - bne,a,pt %icc, 1f - mov 1, %g2 /* Set TLB type to cheetah. */ - mov 2, %g2 /* Set TLB type to cheetah+. */ + BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g5,g2,1f) + + mov 1, %g2 /* Set TLB type to cheetah. */ 1: sethi %hi(tlb_type), %g5 stw %g2, [%g5 + %lo(tlb_type)] @@ -631,16 +608,8 @@ sllx %g2, 32, %g2 or %g2, KERN_LOWBITS, %g2 - rdpr %ver, %g3 - sethi %hi(CHEETAH_ID), %g7 - srlx %g3, 32, %g3 - or %g7, %lo(CHEETAH_ID), %g7 - cmp %g3, %g7 - be,pn %icc, cheetah_vpte_base - sethi %hi(CHEETAH_PLUS_ID), %g7 - or %g7, %lo(CHEETAH_PLUS_ID), %g7 - cmp %g3, %g7 - bne,pt %icc, spitfire_vpte_base + BRANCH_IF_ANY_CHEETAH(g3,g7,cheetah_vpte_base) + ba,pt %xcc, spitfire_vpte_base nop cheetah_vpte_base: @@ -648,6 +617,7 @@ or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 ba,pt %xcc, 2f sllx %g3, 32, %g3 + spitfire_vpte_base: sethi %uhi(VPTE_BASE_SPITFIRE), %g3 or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 @@ -675,16 +645,9 @@ nop not_starfire: - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,pn %icc, is_cheetah - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,pt %icc, not_cheetah + BRANCH_IF_ANY_CHEETAH(g1,g5,is_cheetah) + + ba,pt %xcc, not_cheetah nop is_cheetah: @@ -710,23 +673,16 @@ /* Kill PROM timer */ wr %g0, 0, %tick_cmpr - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,pn %icc, 1f - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,pt %icc, 2f + BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + + ba,pt %xcc, 2f nop /* Disable STICK_INT interrupts. */ 1: - sethi %hi(0x80000000), %g1 - sllx %g1, 32, %g1 - wr %g1, %asr25 + sethi %hi(0x80000000), %g1 + sllx %g1, 32, %g1 + wr %g1, %asr25 /* Ok, we're done setting up all the state our trap mechanims needs, * now get back into normal globals and let the PROM know what is up. diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c --- a/arch/sparc64/kernel/irq.c Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/kernel/irq.c Sat Aug 31 15:05:59 2002 @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/kernel/setup.c Sat Aug 31 15:05:59 2002 @@ -705,19 +705,5 @@ prom_cmdline(); } -#ifdef CONFIG_MAGIC_SYSRQ -/* Because we use the generic input layer keyboard drivers for - * everything, this PC sysrq translation table is all we need. - */ -unsigned char kbd_sysrq_xlate[128] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ - "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\r\000/"; /* 0x60 - 0x6f */ -#endif - int serial_console; int stop_a_enabled = 1; diff -Nru a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S --- a/arch/sparc64/kernel/trampoline.S Sat Aug 31 15:05:59 2002 +++ b/arch/sparc64/kernel/trampoline.S Sat Aug 31 15:05:59 2002 @@ -33,16 +33,10 @@ sparc64_cpu_startup: flushw - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,pn %icc, cheetah_startup - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,pt %icc, spitfire_startup + BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_startup) + BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_startup) + + ba,pt %xcc, spitfire_startup nop cheetah_plus_startup: @@ -51,15 +45,15 @@ nop cheetah_startup: - mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 - wr %g1, %asr18 + mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 + wr %g1, %asr18 - sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - sllx %g5, 32, %g5 - or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 - stxa %g5, [%g0] ASI_DCU_CONTROL_REG - membar #Sync + sethi %uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5 + or %g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5 + sllx %g5, 32, %g5 + or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 + stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync cheetah_generic_startup: mov TSB_EXTENSION_P, %g3 @@ -127,19 +121,10 @@ ldx [%g2 + %lo(kern_locked_tte_data)], %g2 stx %g2, [%sp + 2047 + 128 + 0x30] - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,a,pn %icc, 1f - mov 15, %g2 - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,a,pt %icc, 1f - mov 63, %g2 mov 15, %g2 + BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + + mov 63, %g2 1: stx %g2, [%sp + 2047 + 128 + 0x38] sethi %hi(p1275buf), %g2 @@ -167,19 +152,10 @@ ldx [%g2 + %lo(kern_locked_tte_data)], %g2 stx %g2, [%sp + 2047 + 128 + 0x30] - rdpr %ver, %g1 - sethi %hi(CHEETAH_ID), %g5 - srlx %g1, 32, %g1 - or %g5, %lo(CHEETAH_ID), %g5 - cmp %g1, %g5 - be,a,pn %icc, 1f - mov 15, %g2 - sethi %hi(CHEETAH_PLUS_ID), %g5 - or %g5, %lo(CHEETAH_PLUS_ID), %g5 - cmp %g1, %g5 - bne,a,pt %icc, 1f - mov 63, %g2 mov 15, %g2 + BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + + mov 63, %g2 1: stx %g2, [%sp + 2047 + 128 + 0x38] @@ -244,16 +220,9 @@ sllx %g2, 32, %g2 or %g2, KERN_LOWBITS, %g2 - rdpr %ver, %g3 - sethi %hi(CHEETAH_ID), %g7 - srlx %g3, 32, %g3 - or %g7, %lo(CHEETAH_ID), %g7 - cmp %g3, %g7 - be,pn %icc, 9f - sethi %hi(CHEETAH_PLUS_ID), %g7 - or %g7, %lo(CHEETAH_PLUS_ID), %g7 - cmp %g3, %g7 - bne,pt %icc, 1f + BRANCH_IF_ANY_CHEETAH(g3,g7,9f) + + ba,pt %xcc, 1f nop 9: diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c Sat Aug 31 15:06:06 2002 +++ b/arch/sparc64/kernel/traps.c Sat Aug 31 15:06:06 2002 @@ -47,6 +47,7 @@ unsigned long tstate; unsigned long tpc; unsigned long tnpc; + unsigned long tt; } trapstack[4]; unsigned long tl; }; @@ -58,9 +59,12 @@ printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n", p->tl); for (i = 0; i < 4; i++) { - printk("TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] TNPC[%016lx]\n", + printk(KERN_CRIT + "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] " + "TNPC[%016lx] TT[%lx]\n", i + 1, - p->trapstack[i].tstate, p->trapstack[i].tpc, p->trapstack[i].tnpc); + p->trapstack[i].tstate, p->trapstack[i].tpc, + p->trapstack[i].tnpc, p->trapstack[i].tt); } } @@ -182,43 +186,36 @@ #endif /* When access exceptions happen, we must do this. */ -static void clean_and_reenable_l1_caches(void) +static void spitfire_clean_and_reenable_l1_caches(void) { unsigned long va; - if (tlb_type == spitfire) { - /* Clean 'em. */ - for (va = 0; va < (PAGE_SIZE << 1); va += 32) { - spitfire_put_icache_tag(va, 0x0); - spitfire_put_dcache_tag(va, 0x0); - } + if (tlb_type != spitfire) + BUG(); - /* Re-enable in LSU. */ - __asm__ __volatile__("flush %%g6\n\t" - "membar #Sync\n\t" - "stxa %0, [%%g0] %1\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC | - LSU_CONTROL_IM | LSU_CONTROL_DM), - "i" (ASI_LSU_CONTROL) - : "memory"); - } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { - /* Flush D-cache */ - for (va = 0; va < (1 << 16); va += (1 << 5)) { - __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (va), "i" (ASI_DCACHE_TAG)); - } - } + /* Clean 'em. */ + for (va = 0; va < (PAGE_SIZE << 1); va += 32) { + spitfire_put_icache_tag(va, 0x0); + spitfire_put_dcache_tag(va, 0x0); + } + + /* Re-enable in LSU. */ + __asm__ __volatile__("flush %%g6\n\t" + "membar #Sync\n\t" + "stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC | + LSU_CONTROL_IM | LSU_CONTROL_DM), + "i" (ASI_LSU_CONTROL) + : "memory"); } void do_iae(struct pt_regs *regs) { siginfo_t info; - clean_and_reenable_l1_caches(); + spitfire_clean_and_reenable_l1_caches(); info.si_signo = SIGBUS; info.si_errno = 0; @@ -232,7 +229,7 @@ { #ifdef CONFIG_PCI if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { - clean_and_reenable_l1_caches(); + spitfire_clean_and_reenable_l1_caches(); pci_poke_faulted = 1; diff -Nru a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S --- a/arch/sparc64/lib/blockops.S Sat Aug 31 15:05:54 2002 +++ b/arch/sparc64/lib/blockops.S Sat Aug 31 15:05:54 2002 @@ -106,13 +106,8 @@ bne,pn %xcc, copy_page_using_blkcommit nop - rdpr %ver, %g3 - sllx %g3, 16, %g3 - srlx %g3, 32 + 16, %g3 - cmp %g3, 0x14 ! CHEETAH_ID - be,pn %icc, cheetah_copy_user_page - cmp %g3, 0x15 ! CHEETAH_PLUS_ID - bne,pt %icc, spitfire_copy_user_page + BRANCH_IF_ANY_CHEETAH(g3,o2,cheetah_copy_user_page) + ba,pt %xcc, spitfire_copy_user_page nop cheetah_copy_user_page: diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig --- a/arch/x86_64/defconfig Sat Aug 31 15:06:03 2002 +++ b/arch/x86_64/defconfig Sat Aug 31 15:06:03 2002 @@ -513,6 +513,7 @@ # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c --- a/arch/x86_64/ia32/ia32_binfmt.c Sat Aug 31 15:05:54 2002 +++ b/arch/x86_64/ia32/ia32_binfmt.c Sat Aug 31 15:05:54 2002 @@ -186,7 +186,6 @@ #undef MODULE_AUTHOR #define elf_addr_t __u32 -#define elf_caddr_t __u32 static void elf32_init(struct pt_regs *); diff -Nru a/arch/x86_64/pci/direct.c b/arch/x86_64/pci/direct.c --- a/arch/x86_64/pci/direct.c Sat Aug 31 15:06:06 2002 +++ b/arch/x86_64/pci/direct.c Sat Aug 31 15:06:06 2002 @@ -13,7 +13,7 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -69,75 +69,23 @@ return 0; } - #undef PCI_CONF1_ADDRESS -static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) +static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - - *value = (u8)data; - - return result; + return __pci_conf1_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } -static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) +static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - int result; - u32 data; - - if (!value) - return -EINVAL; - - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - - *value = (u16)data; - - return result; -} - -static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - if (!value) - return -EINVAL; - - return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); -} - -static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); -} - -static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_conf1_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } static struct pci_ops pci_direct_conf1 = { - pci_conf1_read_config_byte, - pci_conf1_read_config_word, - pci_conf1_read_config_dword, - pci_conf1_write_config_byte, - pci_conf1_write_config_word, - pci_conf1_write_config_dword + .read = pci_conf1_read, + .write = pci_conf1_write, }; @@ -147,7 +95,7 @@ #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -181,7 +129,7 @@ return 0; } -static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -217,57 +165,21 @@ #undef PCI_CONF2_ADDRESS -static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - int result; - u32 data; - result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, &data); - *value = (u8)data; - return result; -} - -static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - int result; - u32 data; - result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, &data); - *value = (u16)data; - return result; -} - -static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); -} - -static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value) +static int pci_conf2_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 1, value); + return __pci_conf2_read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } -static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value) +static int pci_conf2_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 2, value); -} - -static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), where, 4, value); + return __pci_conf2_write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); } static struct pci_ops pci_direct_conf2 = { - pci_conf2_read_config_byte, - pci_conf2_read_config_word, - pci_conf2_read_config_dword, - pci_conf2_write_config_byte, - pci_conf2_write_config_word, - pci_conf2_write_config_dword + .read = pci_conf2_read, + .write = pci_conf2_write, }; @@ -283,7 +195,7 @@ */ static int __devinit pci_sanity_check(struct pci_ops *o) { - u16 x; + u32 x = 0; struct pci_bus bus; /* Fake bus and device */ struct pci_dev dev; @@ -292,16 +204,16 @@ bus.number = 0; dev.bus = &bus; for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++) - if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) && + if ((!o->read(&bus, dev.devfn, PCI_CLASS_DEVICE, 2, &x) && (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || - (!o->read_word(&dev, PCI_VENDOR_ID, &x) && + (!o->read(&bus, dev.devfn, PCI_VENDOR_ID, 2, &x) && (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) return 1; DBG("PCI: Sanity check failed\n"); return 0; } -static struct pci_ops * __devinit pci_check_direct(void) +static int __init pci_direct_init(void) { unsigned int tmp; unsigned long flags; @@ -321,8 +233,10 @@ local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) - return NULL; - return &pci_direct_conf1; + pci_root_ops = NULL; + else + pci_root_ops = &pci_direct_conf1; + return 0; } outl (tmp, 0xCF8); } @@ -339,28 +253,15 @@ local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) - return NULL; - return &pci_direct_conf2; + pci_root_ops = NULL; + else + pci_root_ops = &pci_direct_conf2; + return 0; } } local_irq_restore(flags); - return NULL; -} - -static int __init pci_direct_init(void) -{ - if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) - && (pci_root_ops = pci_check_direct())) { - if (pci_root_ops == &pci_direct_conf1) { - pci_config_read = pci_conf1_read; - pci_config_write = pci_conf1_write; - } - else { - pci_config_read = pci_conf2_read; - pci_config_write = pci_conf2_write; - } - } + pci_root_ops = NULL; return 0; } diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in --- a/drivers/acpi/Config.in Sat Aug 31 15:06:06 2002 +++ b/drivers/acpi/Config.in Sat Aug 31 15:06:06 2002 @@ -31,6 +31,9 @@ tristate ' Fan' CONFIG_ACPI_FAN tristate ' Processor' CONFIG_ACPI_PROCESSOR dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR + if [ "$CONFIG_NUMA" = "y" ]; then + bool ' NUMA support' CONFIG_ACPI_NUMA $CONFIG_NUMA + fi tristate ' Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA bool ' Debug Statements' CONFIG_ACPI_DEBUG fi @@ -58,6 +61,7 @@ define_bool CONFIG_ACPI_FAN n define_bool CONFIG_ACPI_PROCESSOR n define_bool CONFIG_ACPI_THERMAL n + define_bool CONFIG_ACPI_NUMA y endmenu fi @@ -77,7 +81,10 @@ tristate ' Button' CONFIG_ACPI_BUTTON tristate ' Fan' CONFIG_ACPI_FAN tristate ' Processor' CONFIG_ACPI_PROCESSOR - dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR + dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR + if [ "$CONFIG_NUMA" = "y" ]; then + bool ' NUMA support' CONFIG_ACPI_NUMA $CONFIG_NUMA + fi bool ' Debug Statements' CONFIG_ACPI_DEBUG endmenu fi diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile --- a/drivers/acpi/Makefile Sat Aug 31 15:06:06 2002 +++ b/drivers/acpi/Makefile Sat Aug 31 15:06:06 2002 @@ -43,6 +43,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_SYSTEM) += system.o +obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c --- a/drivers/acpi/bus.c Sat Aug 31 15:06:01 2002 +++ b/drivers/acpi/bus.c Sat Aug 31 15:06:01 2002 @@ -32,6 +32,7 @@ #include #include #include +#include #include "acpi_bus.h" #include "acpi_drivers.h" #include "include/acinterp.h" /* for acpi_ex_eisa_id_to_string() */ @@ -46,8 +47,11 @@ #define PREFIX "ACPI: " +extern void eisa_set_level_irq(unsigned int irq); + +extern int acpi_disabled; + FADT_DESCRIPTOR acpi_fadt; -static u8 acpi_disabled; struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; @@ -1962,6 +1966,12 @@ printk(KERN_ERR PREFIX "Unable to get the FADT\n"); goto error1; } + + /* Ensure the SCI is set to level-triggered, active-low */ + if (acpi_ioapic) + mp_override_legacy_irq(acpi_fadt.sci_int, 3, 3, acpi_fadt.sci_int); + else + eisa_set_level_irq(acpi_fadt.sci_int); status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE(status)) { diff -Nru a/drivers/acpi/debugger/dbdisasm.c b/drivers/acpi/debugger/dbdisasm.c --- a/drivers/acpi/debugger/dbdisasm.c Sat Aug 31 15:06:00 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,707 +0,0 @@ -/******************************************************************************* - * - * Module Name: dbdisasm - parser op tree display routines - * $Revision: 67 $ - * - ******************************************************************************/ - -/* - * Copyright (C) 2000 - 2002, R. Byron Moore - * - * 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 "acpi.h" -#include "acparser.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "acdebug.h" - - -#ifdef ENABLE_DEBUGGER - -#define _COMPONENT ACPI_DEBUGGER - ACPI_MODULE_NAME ("dbdisasm") - - -#define BLOCK_PAREN 1 -#define BLOCK_BRACE 2 -#define DB_NO_OP_INFO " [%2.2d] " -#define DB_FULL_OP_INFO "%5.5X #%4.4hX [%2.2d] " - - -NATIVE_CHAR *acpi_gbl_db_disasm_indent = "...."; - - -/******************************************************************************* - * - * FUNCTION: Acpi_db_block_type - * - * PARAMETERS: Op - Object to be examined - * - * RETURN: Status - * - * DESCRIPTION: Type of block for this op (parens or braces) - * - ******************************************************************************/ - -u32 -acpi_db_block_type ( - acpi_parse_object *op) -{ - - switch (op->common.aml_opcode) { - case AML_METHOD_OP: - return (BLOCK_BRACE); - - default: - break; - } - - return (BLOCK_PAREN); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ps_display_object_pathname - * - * PARAMETERS: Op - Object whose pathname is to be obtained - * - * RETURN: Status - * - * DESCRIPTION: Diplay the pathname associated with a named object. Two - * versions. One searches the parse tree (for parser-only - * applications suchas Acpi_dump), and the other searches the - * ACPI namespace (the parse tree is probably deleted) - * - ******************************************************************************/ - -#ifdef PARSER_ONLY - -acpi_status -acpi_ps_display_object_pathname ( - acpi_walk_state *walk_state, - acpi_parse_object *op) -{ - acpi_parse_object *target_op; - char *name; - - - if (op->common.flags & ACPI_PARSEOP_GENERIC) { - name = op->common.value.name; - if (name[0] == '\\') { - acpi_os_printf (" (Fully Qualified Pathname)"); - return (AE_OK); - } - } - else { - name = (char *) &op->named.name; - } - - /* Search parent tree up to the root if necessary */ - - target_op = acpi_ps_find (op, name, 0, 0); - if (!target_op) { - /* - * Didn't find the name in the parse tree. This may be - * a problem, or it may simply be one of the predefined names - * (such as _OS_). Rather than worry about looking up all - * the predefined names, just display the name as given - */ - acpi_os_printf (" **** Path not found in parse tree"); - } - else { - /* The target was found, print the name and complete path */ - - acpi_os_printf (" (Path "); - acpi_db_display_path (target_op); - acpi_os_printf (")"); - } - - return (AE_OK); -} - -#else - -acpi_status -acpi_ps_display_object_pathname ( - acpi_walk_state *walk_state, - acpi_parse_object *op) -{ - acpi_status status; - acpi_namespace_node *node; - acpi_buffer buffer; - u32 debug_level; - - - /* Save current debug level so we don't get extraneous debug output */ - - debug_level = acpi_dbg_level; - acpi_dbg_level = 0; - - /* Just get the Node out of the Op object */ - - node = op->common.node; - if (!node) { - /* Node not defined in this scope, look it up */ - - status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, ACPI_TYPE_ANY, - ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); - - if (ACPI_FAILURE (status)) { - /* - * We can't get the pathname since the object - * is not in the namespace. This can happen during single - * stepping where a dynamic named object is *about* to be created. - */ - acpi_os_printf (" [Path not found]"); - goto exit; - } - - /* Save it for next time. */ - - op->common.node = node; - } - - /* Convert Named_desc/handle to a full pathname */ - - buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname (node, &buffer); - if (ACPI_FAILURE (status)) { - acpi_os_printf ("****Could not get pathname****)"); - goto exit; - } - - acpi_os_printf (" (Path %s)", buffer.pointer); - ACPI_MEM_FREE (buffer.pointer); - - -exit: - /* Restore the debug level */ - - acpi_dbg_level = debug_level; - return (status); -} - -#endif - - -/******************************************************************************* - * - * FUNCTION: Acpi_db_display_op - * - * PARAMETERS: Origin - Starting object - * Num_opcodes - Max number of opcodes to be displayed - * - * RETURN: None - * - * DESCRIPTION: Display parser object and its children - * - ******************************************************************************/ - -void -acpi_db_display_op ( - acpi_walk_state *walk_state, - acpi_parse_object *origin, - u32 num_opcodes) -{ - acpi_parse_object *op = origin; - acpi_parse_object *arg; - acpi_parse_object *depth; - u32 depth_count = 0; - u32 last_depth = 0; - u32 i; - u32 j; - - - if (!op) { - acpi_db_display_opcode (walk_state, op); - return; - } - - - while (op) { - /* Indentation */ - - depth_count = 0; - if (!acpi_gbl_db_opt_verbose) { - depth_count++; - } - - /* Determine the nesting depth of this argument */ - - for (depth = op->common.parent; depth; depth = depth->common.parent) { - arg = acpi_ps_get_arg (depth, 0); - while (arg && arg != origin) { - arg = arg->common.next; - } - - if (arg) { - break; - } - - depth_count++; - } - - /* Open a new block if we are nested further than last time */ - - if (depth_count > last_depth) { - VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth)); - for (i = 0; i < last_depth; i++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - - if (acpi_db_block_type (op) == BLOCK_PAREN) { - acpi_os_printf ("(\n"); - } - else { - acpi_os_printf ("{\n"); - } - } - - /* Close a block if we are nested less than last time */ - - else if (depth_count < last_depth) { - for (j = last_depth; j >= (depth_count + 1); j--) { - VERBOSE_PRINT ((DB_NO_OP_INFO, (j - 1))); - for (i = 1; i < j; i++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - - if (acpi_db_block_type (op) == BLOCK_PAREN) { - acpi_os_printf (")\n"); - } - else { - acpi_os_printf ("}\n"); - } - } - } - - /* In verbose mode, print the AML offset, opcode and depth count */ - - VERBOSE_PRINT ((DB_FULL_OP_INFO, (u32) op->common.aml_offset, - op->common.aml_opcode, depth_count)); - - - /* Indent the output according to the depth count */ - - for (i = 0; i < depth_count; i++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - - /* Now print the opcode */ - - acpi_db_display_opcode (walk_state, op); - - /* Resolve a name reference */ - - if ((op->common.aml_opcode == AML_INT_NAMEPATH_OP && op->common.value.name) && - (op->common.parent) && - (acpi_gbl_db_opt_verbose)) { - (void) acpi_ps_display_object_pathname (walk_state, op); - } - - acpi_os_printf ("\n"); - - /* Get the next node in the tree */ - - op = acpi_ps_get_depth_next (origin, op); - last_depth = depth_count; - - num_opcodes--; - if (!num_opcodes) { - op = NULL; - } - } - - /* Close the last block(s) */ - - depth_count = last_depth -1; - for (i = 0; i < last_depth; i++) { - VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth - i)); - for (j = 0; j < depth_count; j++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - acpi_os_printf ("}\n"); - depth_count--; - } -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_db_display_namestring - * - * PARAMETERS: Name - ACPI Name string to store - * - * RETURN: None - * - * DESCRIPTION: Display namestring. Handles prefix characters - * - ******************************************************************************/ - -void -acpi_db_display_namestring ( - NATIVE_CHAR *name) -{ - u32 seg_count; - - - if (!name) { - acpi_os_printf (""); - return; - } - - /* Handle all Scope Prefix operators */ - - while (acpi_ps_is_prefix_char (ACPI_GET8 (name))) { - /* Append prefix character */ - - acpi_os_printf ("%1c", ACPI_GET8 (name)); - name++; - } - - switch (ACPI_GET8 (name)) { - case 0: - seg_count = 0; - break; - - case AML_DUAL_NAME_PREFIX: - seg_count = 2; - name++; - break; - - case AML_MULTI_NAME_PREFIX_OP: - seg_count = (u32) ACPI_GET8 (name + 1); - name += 2; - break; - - default: - seg_count = 1; - break; - } - - while (seg_count) { - /* Append Name segment */ - - acpi_os_printf ("%4.4s", name); - - seg_count--; - if (seg_count) { - /* Not last name, append dot separator */ - - acpi_os_printf ("."); - } - name += ACPI_NAME_SIZE; - } -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_db_display_path - * - * PARAMETERS: Op - Named Op whose path is to be constructed - * - * RETURN: None - * - * DESCRIPTION: Walk backwards from current scope and display the name - * of each previous level of scope up to the root scope - * (like "pwd" does with file systems) - * - ******************************************************************************/ - -void -acpi_db_display_path ( - acpi_parse_object *op) -{ - acpi_parse_object *prev; - acpi_parse_object *search; - u32 name; - u8 do_dot = FALSE; - acpi_parse_object *name_path; - const acpi_opcode_info *op_info; - - - /* We are only interested in named objects */ - - op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); - if (!(op_info->flags & AML_NSNODE)) { - return; - } - - if (op_info->flags & AML_CREATE) { - /* Field creation - check for a fully qualified namepath */ - - if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { - name_path = acpi_ps_get_arg (op, 3); - } - else { - name_path = acpi_ps_get_arg (op, 2); - } - - if ((name_path) && - (name_path->common.value.string) && - (name_path->common.value.string[0] == '\\')) { - acpi_db_display_namestring (name_path->common.value.string); - return; - } - } - - prev = NULL; /* Start with Root Node */ - - while (prev != op) { - /* Search upwards in the tree to find scope with "prev" as its parent */ - - search = op; - for (; ;) { - if (search->common.parent == prev) { - break; - } - - /* Go up one level */ - - search = search->common.parent; - } - - if (prev) { - op_info = acpi_ps_get_opcode_info (search->common.aml_opcode); - if (!(op_info->flags & AML_FIELD)) { - /* below root scope, append scope name */ - - if (do_dot) { - /* append dot */ - - acpi_os_printf ("."); - } - - if (op_info->flags & AML_CREATE) { - if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { - name_path = acpi_ps_get_arg (op, 3); - } - else { - name_path = acpi_ps_get_arg (op, 2); - } - - if ((name_path) && - (name_path->common.value.string)) { - acpi_os_printf ("%4.4s", name_path->common.value.string); - } - } - else { - name = acpi_ps_get_name (search); - acpi_os_printf ("%4.4s", &name); - } - - do_dot = TRUE; - } - } - - prev = search; - } -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_db_display_opcode - * - * PARAMETERS: Op - Op that is to be printed - * - * RETURN: Status - * - * DESCRIPTION: Store printed op in a Buffer and return its length - * (or -1 if out of space) - * - * NOTE: Terse mode prints out ASL-like code. Verbose mode adds more info. - * - ******************************************************************************/ - -void -acpi_db_display_opcode ( - acpi_walk_state *walk_state, - acpi_parse_object *op) -{ - u8 *byte_data; - u32 byte_count; - u32 i; - const acpi_opcode_info *op_info = NULL; - u32 name; - - - if (!op) { - acpi_os_printf (""); - return; - } - - /* op and arguments */ - - switch (op->common.aml_opcode) { - case AML_BYTE_OP: - - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u8) 0x%2.2hX", op->common.value.integer8); - } - else { - acpi_os_printf ("0x%2.2hX", op->common.value.integer8); - } - break; - - - case AML_WORD_OP: - - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u16) 0x%4.4hX", op->common.value.integer16); - } - else { - acpi_os_printf ("0x%4.4hX", op->common.value.integer16); - } - break; - - - case AML_DWORD_OP: - - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u32) 0x%8.8X", op->common.value.integer32); - } - else { - acpi_os_printf ("0x%8.8X", op->common.value.integer32); - } - break; - - - case AML_QWORD_OP: - - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u64) 0x%8.8X%8.8X", op->common.value.integer64.hi, - op->common.value.integer64.lo); - } - else { - acpi_os_printf ("0x%8.8X%8.8X", op->common.value.integer64.hi, - op->common.value.integer64.lo); - } - break; - - - case AML_STRING_OP: - - if (op->common.value.string) { - acpi_os_printf ("\"%s\"", op->common.value.string); - } - else { - acpi_os_printf ("<\"NULL STRING PTR\">"); - } - break; - - - case AML_INT_STATICSTRING_OP: - - if (op->common.value.string) { - acpi_os_printf ("\"%s\"", op->common.value.string); - } - else { - acpi_os_printf ("\"\""); - } - break; - - - case AML_INT_NAMEPATH_OP: - - acpi_db_display_namestring (op->common.value.name); - break; - - - case AML_INT_NAMEDFIELD_OP: - - acpi_os_printf ("Named_field (Length 0x%8.8X) ", op->common.value.integer32); - break; - - - case AML_INT_RESERVEDFIELD_OP: - - acpi_os_printf ("Reserved_field (Length 0x%8.8X) ", op->common.value.integer32); - break; - - - case AML_INT_ACCESSFIELD_OP: - - acpi_os_printf ("Access_field (Length 0x%8.8X) ", op->common.value.integer32); - break; - - - case AML_INT_BYTELIST_OP: - - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("Byte_list (Length 0x%8.8X) ", op->common.value.integer32); - } - else { - acpi_os_printf ("0x%2.2X", op->common.value.integer32); - - byte_count = op->common.value.integer32; - byte_data = op->named.data; - - for (i = 0; i < byte_count; i++) { - acpi_os_printf (", 0x%2.2X", byte_data[i]); - } - } - break; - - - default: - - /* Just get the opcode name and print it */ - - op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); - acpi_os_printf ("%s", op_info->name); - - -#ifndef PARSER_ONLY - if ((op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) && - (walk_state) && - (walk_state->results) && - (walk_state->results->results.num_results)) { - acpi_db_decode_internal_object ( - walk_state->results->results.obj_desc [walk_state->results->results.num_results-1]); - } -#endif - break; - } - - if (!op_info) { - /* If there is another element in the list, add a comma */ - - if (op->common.next) { - acpi_os_printf (","); - } - } - - /* - * If this is a named opcode, print the associated name value - */ - op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); - if (op && (op_info->flags & AML_NAMED)) { - name = acpi_ps_get_name (op); - acpi_os_printf (" %4.4s", &name); - - if ((acpi_gbl_db_opt_verbose) && (op->common.aml_opcode != AML_INT_NAMEDFIELD_OP)) { - (void) acpi_ps_display_object_pathname (walk_state, op); - } - } -} - -#endif /* ENABLE_DEBUGGER */ - diff -Nru a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c --- a/drivers/acpi/dispatcher/dsopcode.c Sat Aug 31 15:05:55 2002 +++ b/drivers/acpi/dispatcher/dsopcode.c Sat Aug 31 15:05:55 2002 @@ -2,7 +2,7 @@ * * Module Name: dsopcode - Dispatcher Op Region support and handling of * "control" opcodes - * $Revision: 81 $ + * $Revision: 82 $ * *****************************************************************************/ @@ -93,7 +93,7 @@ return_ACPI_STATUS (status); } - walk_state->parse_flags = 0; + walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; /* Pass1: Parse the entire declaration */ diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c --- a/drivers/acpi/dispatcher/dswload.c Sat Aug 31 15:05:54 2002 +++ b/drivers/acpi/dispatcher/dswload.c Sat Aug 31 15:05:54 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks - * $Revision: 70 $ + * $Revision: 71 $ * *****************************************************************************/ @@ -109,22 +109,27 @@ acpi_status status; acpi_object_type object_type; NATIVE_CHAR *path; + u32 flags; ACPI_FUNCTION_NAME ("Ds_load1_begin_op"); + op = walk_state->op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); - - if (op && (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP)) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); - } - /* We are only interested in opcodes that have an associated name */ if (op) { if (!(walk_state->op_info->flags & AML_NAMED)) { +#if 0 + if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || + (walk_state->op_info->class == AML_CLASS_CONTROL)) { + acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name); + *out_op = op; + return (AE_CTRL_SKIP); + } +#endif *out_op = op; return (AE_OK); } @@ -144,7 +149,31 @@ object_type = walk_state->op_info->object_type; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "State=%p Op=%p Type=%X\n", walk_state, op, object_type)); + "State=%p Op=%p [%s] ", walk_state, op, acpi_ut_get_type_name (object_type))); + + /* + * Setup the search flags. + * + * Since we are entering a name into the namespace, we do not want to + * enable the search-to-root upsearch. + * + * There are only two conditions where it is acceptable that the name + * already exists: + * 1) the Scope() operator can reopen a scoping object that was + * previously defined (Scope, Method, Device, etc.) + * 2) Whenever we are parsing a deferred opcode (Op_region, Buffer, + * Buffer_field, or Package), the name of the object is already + * in the namespace. + */ + flags = ACPI_NS_NO_UPSEARCH; + if ((walk_state->opcode != AML_SCOPE_OP) && + (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { + flags |= ACPI_NS_ERROR_IF_FOUND; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Cannot already exist\n")); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Both Find or Create allowed\n")); + } /* * Enter the named type into the internal namespace. We enter the name @@ -152,12 +181,38 @@ * arguments to the opcode must be created as we go back up the parse tree later. */ status = acpi_ns_lookup (walk_state->scope_info, path, object_type, - ACPI_IMODE_LOAD_PASS1, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); - + ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node)); if (ACPI_FAILURE (status)) { return (status); } + /* + * For the scope op, we must check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + if (walk_state->opcode == AML_SCOPE_OP) { + switch (node->type) { + case ACPI_TYPE_ANY: /* Scope nodes are untyped (ANY) */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_METHOD: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + default: + + /* All other types are an error */ + + ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", + acpi_ut_get_type_name (node->type), path)); + + return (AE_AML_OPERAND_TYPE); + } + } + if (!op) { /* Create a new op */ @@ -214,9 +269,9 @@ ACPI_FUNCTION_NAME ("Ds_load1_end_op"); + op = walk_state->op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); - /* We are only interested in opcodes that have an associated name */ diff -Nru a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c --- a/drivers/acpi/events/evevent.c Sat Aug 31 15:06:06 2002 +++ b/drivers/acpi/events/evevent.c Sat Aug 31 15:06:06 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evevent - Fixed and General Purpose Even handling and dispatch - * $Revision: 90 $ + * $Revision: 91 $ * *****************************************************************************/ @@ -137,6 +137,7 @@ return_ACPI_STATUS (status); } + acpi_gbl_events_initialized = TRUE; return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c --- a/drivers/acpi/events/evmisc.c Sat Aug 31 15:06:00 2002 +++ b/drivers/acpi/events/evmisc.c Sat Aug 31 15:06:00 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evmisc - Miscellaneous event manager support functions - * $Revision: 56 $ + * $Revision: 57 $ * *****************************************************************************/ @@ -547,7 +547,7 @@ * * RETURN: none * - * DESCRIPTION: free memory allocated for table storage. + * DESCRIPTION: Disable events and free memory allocated for table storage. * ******************************************************************************/ @@ -560,39 +560,42 @@ ACPI_FUNCTION_TRACE ("Ev_terminate"); - /* - * Disable all event-related functionality. - * In all cases, on error, print a message but obviously we don't abort. - */ - /* - * Disable all fixed events - */ - for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { - status = acpi_disable_event(i, ACPI_EVENT_FIXED, 0); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to disable fixed event %d.\n", i)); - } - } + if (acpi_gbl_events_initialized) { + /* + * Disable all event-related functionality. + * In all cases, on error, print a message but obviously we don't abort. + */ - /* - * Disable all GPEs - */ - for (i = 0; i < acpi_gbl_gpe_number_max; i++) { - if (acpi_ev_get_gpe_number_index(i) != ACPI_GPE_INVALID) { - status = acpi_hw_disable_gpe(i); + /* + * Disable all fixed events + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { + status = acpi_disable_event(i, ACPI_EVENT_FIXED, 0); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to disable GPE %d.\n", i)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", i)); } } - } - /* - * Remove SCI handler - */ - status = acpi_ev_remove_sci_handler(); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to remove SCI handler.\n")); + /* + * Disable all GPEs + */ + for (i = 0; i < acpi_gbl_gpe_number_max; i++) { + if (acpi_ev_get_gpe_number_index(i) != ACPI_GPE_INVALID) { + status = acpi_hw_disable_gpe(i); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable GPE %d\n", i)); + } + } + } + + /* + * Remove SCI handler + */ + status = acpi_ev_remove_sci_handler(); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n")); + } } /* @@ -601,7 +604,7 @@ if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { status = acpi_disable (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Acpi_disable failed.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Acpi_disable failed\n")); } } diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h --- a/drivers/acpi/include/acconfig.h Sat Aug 31 15:05:55 2002 +++ b/drivers/acpi/include/acconfig.h Sat Aug 31 15:05:55 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 109 $ + * $Revision: 110 $ * *****************************************************************************/ @@ -54,7 +54,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20020815 +#define ACPI_CA_VERSION 0x20020829 /* Version of ACPI supported */ diff -Nru a/drivers/acpi/include/acglobal.h b/drivers/acpi/include/acglobal.h --- a/drivers/acpi/include/acglobal.h Sat Aug 31 15:05:53 2002 +++ b/drivers/acpi/include/acglobal.h Sat Aug 31 15:05:53 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acglobal.h - Declarations for global variables - * $Revision: 130 $ + * $Revision: 131 $ * *****************************************************************************/ @@ -136,6 +136,7 @@ ACPI_EXTERN u8 acpi_gbl_step_to_next_call; ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_global_lock_present; +ACPI_EXTERN u8 acpi_gbl_events_initialized; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; diff -Nru a/drivers/acpi/include/aclocal.h b/drivers/acpi/include/aclocal.h --- a/drivers/acpi/include/aclocal.h Sat Aug 31 15:06:03 2002 +++ b/drivers/acpi/include/aclocal.h Sat Aug 31 15:06:03 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: aclocal.h - Internal data types used across the ACPI subsystem - * $Revision: 175 $ + * $Revision: 176 $ * *****************************************************************************/ @@ -667,8 +667,8 @@ u32 aml_subtree_length; u32 final_aml_length; u32 final_aml_offset; + u32 compile_flags; u16 parse_opcode; - u16 compile_flags; u8 aml_opcode_length; u8 aml_pkg_len_bytes; u8 extra; diff -Nru a/drivers/acpi/include/acparser.h b/drivers/acpi/include/acparser.h --- a/drivers/acpi/include/acparser.h Sat Aug 31 15:06:03 2002 +++ b/drivers/acpi/include/acparser.h Sat Aug 31 15:06:03 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: acparser.h - AML Parser subcomponent prototypes and defines - * $Revision: 61 $ + * $Revision: 62 $ * *****************************************************************************/ @@ -44,6 +44,7 @@ #define ACPI_PARSE_EXECUTE 0x0030 #define ACPI_PARSE_MODE_MASK 0x0030 +#define ACPI_PARSE_DEFERRED_OP 0x0100 /* Parser external interfaces */ diff -Nru a/drivers/acpi/include/actbl2.h b/drivers/acpi/include/actbl2.h --- a/drivers/acpi/include/actbl2.h Sat Aug 31 15:06:01 2002 +++ b/drivers/acpi/include/actbl2.h Sat Aug 31 15:06:01 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: actbl2.h - ACPI Specification Revision 2.0 Tables - * $Revision: 27 $ + * $Revision: 28 $ * *****************************************************************************/ @@ -139,8 +139,8 @@ u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ u16 flush_size; /* Number of flush strides that need to be read */ u16 flush_stride; /* Processor's memory cache line width, in bytes */ - u8 duty_offset; /* Processor’s duty cycle index in processor's P_CNT reg*/ - u8 duty_width; /* Processor’s duty cycle value bit width in P_CNT register.*/ + u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ + u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ u8 century; /* Index to century in RTC CMOS RAM */ diff -Nru a/drivers/acpi/include/platform/aclinux.h b/drivers/acpi/include/platform/aclinux.h --- a/drivers/acpi/include/platform/aclinux.h Sat Aug 31 15:06:06 2002 +++ b/drivers/acpi/include/platform/aclinux.h Sat Aug 31 15:06:06 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: aclinux.h - OS specific defines, etc. - * $Revision: 26 $ + * $Revision: 27 $ * *****************************************************************************/ @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(__ia64__) || defined(__x86_64__) #define ACPI_MACHINE_WIDTH 64 diff -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/numa.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,187 @@ +/* + * acpi_numa.c - ACPI NUMA support + * + * Copyright (C) 2002 Takayoshi Kochi + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + +#define PREFIX "ACPI: " + +extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler); + +void __init +acpi_table_print_srat_entry ( + acpi_table_entry_header *header) +{ + if (!header) + return; + + switch (header->type) { + + case ACPI_SRAT_PROCESSOR_AFFINITY: + { + struct acpi_table_processor_affinity *p = + (struct acpi_table_processor_affinity*) header; + printk(KERN_INFO PREFIX "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", + p->apic_id, p->lsapic_eid, p->proximity_domain, + p->flags.enabled?"enabled":"disabled"); + } + break; + + case ACPI_SRAT_MEMORY_AFFINITY: + { + struct acpi_table_memory_affinity *p = + (struct acpi_table_memory_affinity*) header; + printk(KERN_INFO PREFIX "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", + p->base_addr_hi, p->base_addr_lo, p->length_hi, p->length_lo, + p->memory_type, p->proximity_domain, + p->flags.enabled ? "enabled" : "disabled", + p->flags.hot_pluggable ? " hot-pluggable" : ""); + } + break; + + default: + printk(KERN_WARNING PREFIX "Found unsupported SRAT entry (type = 0x%x)\n", + header->type); + break; + } +} + + +static int __init +acpi_parse_slit (unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_slit *slit; + u32 localities; + + if (!phys_addr || !size) + return -EINVAL; + + slit = (struct acpi_table_slit *) __va(phys_addr); + + /* downcast just for %llu vs %lu for i386/ia64 */ + localities = (u32) slit->localities; + + printk(KERN_INFO PREFIX "SLIT localities %ux%u\n", localities, localities); + + acpi_numa_slit_init(slit); + + return 0; +} + + +static int __init +acpi_parse_processor_affinity (acpi_table_entry_header *header) +{ + struct acpi_table_processor_affinity *processor_affinity = NULL; + + processor_affinity = (struct acpi_table_processor_affinity*) header; + if (!processor_affinity) + return -EINVAL; + + acpi_table_print_srat_entry(header); + + /* let architecture-dependent part to do it */ + acpi_numa_processor_affinity_init(processor_affinity); + + return 0; +} + + +static int __init +acpi_parse_memory_affinity (acpi_table_entry_header *header) +{ + struct acpi_table_memory_affinity *memory_affinity = NULL; + + memory_affinity = (struct acpi_table_memory_affinity*) header; + if (!memory_affinity) + return -EINVAL; + + acpi_table_print_srat_entry(header); + + /* let architecture-dependent part to do it */ + acpi_numa_memory_affinity_init(memory_affinity); + + return 0; +} + + +static int __init +acpi_parse_srat (unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_srat *srat = NULL; + + if (!phys_addr || !size) + return -EINVAL; + + srat = (struct acpi_table_srat *) __va(phys_addr); + + printk(KERN_INFO PREFIX "SRAT revision %d\n", srat->table_revision); + + return 0; +} + + +int __init +acpi_table_parse_srat ( + enum acpi_srat_entry_id id, + acpi_madt_entry_handler handler) +{ + return acpi_table_parse_madt_family(ACPI_SRAT, sizeof(struct acpi_table_srat), + id, handler); +} + + +int __init +acpi_numa_init() +{ + int result; + + /* SRAT: Static Resource Affinity Table */ + result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat); + + if (result > 0) { + result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, + acpi_parse_processor_affinity); + result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, + acpi_parse_memory_affinity); + } else { + /* FIXME */ + printk("Warning: acpi_table_parse(ACPI_SRAT) returned %d!\n",result); + } + + /* SLIT: System Locality Information Table */ + result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit); + if (result < 1) { + /* FIXME */ + printk("Warning: acpi_table_parse(ACPI_SLIT) returned %d!\n",result); + } + + acpi_numa_arch_fixup(); + return 0; +} diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c Sat Aug 31 15:06:06 2002 +++ b/drivers/acpi/osl.c Sat Aug 31 15:06:06 2002 @@ -71,6 +71,7 @@ static OSD_HANDLER acpi_irq_handler = NULL; static void *acpi_irq_context = NULL; +extern struct pci_ops *pci_root_ops; acpi_status acpi_os_initialize(void) @@ -80,7 +81,7 @@ * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */ #ifdef CONFIG_ACPI_PCI - if (!pci_config_read || !pci_config_write) { + if (!pci_root_ops) { printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; } @@ -438,27 +439,31 @@ u32 width) { int result = 0; + int size = 0; + struct pci_bus bus; + if (!value) return AE_BAD_PARAMETER; - switch (width) - { + switch (width) { case 8: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 1, value); + size = 1; break; case 16: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 2, value); + size = 2; break; case 32: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 4, value); + size = 4; break; default: BUG(); } + bus.number = pci_id->bus; + result = pci_root_ops->read(&bus, PCI_DEVFN(pci_id->device, + pci_id->function), + reg, size, value); + return (result ? AE_ERROR : AE_OK); } @@ -470,25 +475,27 @@ u32 width) { int result = 0; + int size = 0; + struct pci_bus bus; - switch (width) - { + switch (width) { case 8: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 1, value); + size = 1; break; case 16: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 2, value); + size = 2; break; case 32: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 4, value); + size = 4; break; default: BUG(); } + bus.number = pci_id->bus; + result = pci_root_ops->write(&bus, PCI_DEVFN(pci_id->device, + pci_id->function), + reg, size, value); return (result ? AE_ERROR : AE_OK); } diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c --- a/drivers/acpi/system.c Sat Aug 31 15:06:00 2002 +++ b/drivers/acpi/system.c Sat Aug 31 15:06:00 2002 @@ -257,7 +257,6 @@ unsigned long flags = 0; local_irq_save(flags); - local_irq_disable(); switch (state) { diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Sat Aug 31 15:05:59 2002 +++ b/drivers/acpi/tables.c Sat Aug 31 15:05:59 2002 @@ -224,11 +224,13 @@ int __init -acpi_table_parse_madt ( +acpi_table_parse_madt_family ( enum acpi_table_id id, + unsigned long madt_size, + int entry_id, acpi_madt_entry_handler handler) { - struct acpi_table_madt *madt = NULL; + void *madt = NULL; acpi_table_entry_header *entry = NULL; unsigned long count = 0; unsigned long madt_end = 0; @@ -240,19 +242,21 @@ /* Locate the MADT (if exists). There should only be one. */ for (i = 0; i < sdt.count; i++) { - if (sdt.entry[i].id != ACPI_APIC) + if (sdt.entry[i].id != id) continue; - madt = (struct acpi_table_madt *) + madt = (void *) __acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size); if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map MADT\n"); + printk(KERN_WARNING PREFIX "Unable to map %s\n", + acpi_table_signatures[id]); return -ENODEV; } break; } if (!madt) { - printk(KERN_WARNING PREFIX "MADT not present\n"); + printk(KERN_WARNING PREFIX "%s not present\n", + acpi_table_signatures[id]); return -ENODEV; } @@ -261,10 +265,10 @@ /* Parse all entries looking for a match. */ entry = (acpi_table_entry_header *) - ((unsigned long) madt + sizeof(struct acpi_table_madt)); + ((unsigned long) madt + madt_size); while (((unsigned long) entry) < madt_end) { - if (entry->type == id) { + if (entry->type == entry_id) { count++; handler(entry); } @@ -273,6 +277,16 @@ } return count; +} + + +int __init +acpi_table_parse_madt ( + enum acpi_madt_entry_id id, + acpi_madt_entry_handler handler) +{ + return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt), + id, handler); } diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Sat Aug 31 15:05:54 2002 +++ b/drivers/acpi/utilities/utglobal.c Sat Aug 31 15:05:54 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utglobal - Global variables for the ACPI subsystem - * $Revision: 168 $ + * $Revision: 170 $ * *****************************************************************************/ @@ -166,10 +166,10 @@ /* - * Names built-in to the interpreter + * Predefined ACPI Names (Built-in to the Interpreter) * * Initial values are currently supported only for types String and Number. - * To avoid type punning, both are specified as strings in this table. + * Both are specified as strings in this table. * * NOTES: * 1) _SB_ is defined to be a device to allow _SB_/_INI to be run @@ -177,11 +177,11 @@ */ const acpi_predefined_names acpi_gbl_pre_defined_names[] = -{ {"_GPE", INTERNAL_TYPE_DEF_ANY, NULL}, - {"_PR_", INTERNAL_TYPE_DEF_ANY, NULL}, +{ {"_GPE", INTERNAL_TYPE_SCOPE, NULL}, + {"_PR_", INTERNAL_TYPE_SCOPE, NULL}, {"_SB_", ACPI_TYPE_DEVICE, NULL}, - {"_SI_", INTERNAL_TYPE_DEF_ANY, NULL}, - {"_TZ_", INTERNAL_TYPE_DEF_ANY, NULL}, + {"_SI_", INTERNAL_TYPE_SCOPE, NULL}, + {"_TZ_", INTERNAL_TYPE_SCOPE, NULL}, {"_REV", ACPI_TYPE_INTEGER, "2"}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, @@ -195,9 +195,7 @@ /* * Properties of the ACPI Object Types, both internal and external. - * - * Elements of Acpi_ns_properties are bit significant - * and the table is indexed by values of acpi_object_type + * The table is indexed by values of acpi_object_type */ const u8 acpi_gbl_ns_properties[] = @@ -530,7 +528,6 @@ /* * Strings and procedures used for debug only - * */ @@ -763,6 +760,7 @@ acpi_gbl_gpe_register_info = NULL; acpi_gbl_gpe_number_info = NULL; + acpi_gbl_events_initialized = FALSE; /* Namespace */ diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Sat Aug 31 15:05:54 2002 +++ b/drivers/block/floppy.c Sat Aug 31 15:05:54 2002 @@ -239,6 +239,7 @@ static int irqdma_allocated; +#define CURRENT current_req #define LOCAL_END_REQUEST #define MAJOR_NR FLOPPY_MAJOR #define DEVICE_NAME "floppy" @@ -249,6 +250,8 @@ #include /* for the compatibility eject ioctl */ #include +static struct request *current_req; + #ifndef fd_get_dma_residue #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA) #endif @@ -2296,8 +2299,13 @@ return; add_blkdev_randomness(major(dev)); floppy_off(DEVICE_NR(dev)); - blkdev_dequeue_request(req); end_that_request_last(req); + + /* Get the next request */ + req = elv_next_request(QUEUE); + if (req) + blkdev_dequeue_request(req); + CURRENT = req; } @@ -2306,15 +2314,15 @@ static void request_done(int uptodate) { struct request_queue *q = QUEUE; - struct request *req = elv_next_request(q); + struct request *req = CURRENT; unsigned long flags; int block; probing = 0; reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); - if (blk_queue_empty(q)) { - DPRINT("request list destroyed in floppy request done\n"); + if (!req) { + printk("floppy.c: no request in request_done\n"); return; } @@ -2328,7 +2336,7 @@ /* unlock chained buffers */ spin_lock_irqsave(q->queue_lock, flags); - while (current_count_sectors && !blk_queue_empty(q) && + while (current_count_sectors && CURRENT && current_count_sectors >= req->current_nr_sectors){ current_count_sectors -= req->current_nr_sectors; req->nr_sectors -= req->current_nr_sectors; @@ -2337,7 +2345,7 @@ } spin_unlock_irqrestore(q->queue_lock, flags); - if (current_count_sectors && !blk_queue_empty(q)) { + if (current_count_sectors && CURRENT) { /* "unlock" last subsector */ req->buffer += current_count_sectors <<9; req->current_nr_sectors -= current_count_sectors; @@ -2346,7 +2354,7 @@ return; } - if (current_count_sectors && blk_queue_empty(q)) + if (current_count_sectors && !CURRENT) DPRINT("request list destroyed in floppy request done\n"); } else { @@ -2924,10 +2932,15 @@ floppy_off(current_drive); for (;;) { - if (blk_queue_empty(QUEUE)) { - do_floppy = NULL; - unlock_fdc(); - return; + if (!CURRENT) { + struct request *req = elv_next_request(QUEUE); + if (!req) { + do_floppy = NULL; + unlock_fdc(); + return; + } + blkdev_dequeue_request(req); + CURRENT = req; } if (major(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c --- a/drivers/bluetooth/hci_ldisc.c Sat Aug 31 15:06:06 2002 +++ b/drivers/bluetooth/hci_ldisc.c Sat Aug 31 15:06:06 2002 @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help --- a/drivers/char/Config.help Sat Aug 31 15:05:59 2002 +++ b/drivers/char/Config.help Sat Aug 31 15:05:59 2002 @@ -985,9 +985,10 @@ CONFIG_NVRAM If you say Y here and create a character special file /dev/nvram with major number 10 and minor number 144 using mknod ("man mknod"), - you get read and write access to the 50 bytes of non-volatile memory - in the real time clock (RTC), which is contained in every PC and - most Ataris. + you get read and write access to the extra bytes of non-volatile + memory in the real time clock (RTC), which is contained in every PC + and most Ataris. The actual number of bytes varies, depending on the + nvram in the system, but is usually 114 (128-14 for the RTC). This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" on Ataris. /dev/nvram may be used to view settings there, or to diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Sat Aug 31 15:06:06 2002 +++ b/drivers/char/Makefile Sat Aug 31 15:06:06 2002 @@ -15,7 +15,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o \ sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \ - ip2main.o + ip2main.o nvram.o obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o obj-$(CONFIG_HW_CONSOLE) += console.o defkeymap.o diff -Nru a/drivers/char/console.c b/drivers/char/console.c --- a/drivers/char/console.c Sat Aug 31 15:06:06 2002 +++ b/drivers/char/console.c Sat Aug 31 15:06:06 2002 @@ -150,6 +150,7 @@ static void hide_cursor(int currcons); static void unblank_screen_t(unsigned long dummy); static void console_callback(void *ignored); +static void __init con_init_devfs (void); static int printable; /* Is console ready for printing? */ @@ -2526,6 +2527,7 @@ kbd_init(); console_map_init(); + con_init_devfs(); vcs_init(); return 0; } @@ -2624,7 +2626,7 @@ * is called before kmalloc() works. This function is called later to * do the registration. */ -void __init con_init_devfs (void) +static void __init con_init_devfs (void) { int i; diff -Nru a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h --- a/drivers/char/drm/drmP.h Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/drmP.h Sat Aug 31 15:06:06 2002 @@ -165,7 +165,7 @@ #define pte_unmap(pte) #endif -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < 0x020413 /* KERNEL_VERSION(2,4,19) */ static inline struct page * vmalloc_to_page(void * vmalloc_addr) { unsigned long addr = (unsigned long) vmalloc_addr; @@ -201,9 +201,9 @@ /* Macros to make printk easier */ #define DRM_ERROR(fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg) + printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) #define DRM_MEM_ERROR(area, fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \ + printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ DRM(mem_stats)[area].name , ##arg) #define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) @@ -212,8 +212,8 @@ do { \ if ( DRM(flags) & DRM_FLAG_DEBUG ) \ printk(KERN_DEBUG \ - "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \ - ##arg); \ + "[" DRM_NAME ":%s] " fmt , \ + __FUNCTION__ , ##arg); \ } while (0) #else #define DRM_DEBUG(fmt, arg...) do { } while (0) diff -Nru a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h --- a/drivers/char/drm/drm_agpsupport.h Sat Aug 31 15:05:53 2002 +++ b/drivers/char/drm/drm_agpsupport.h Sat Aug 31 15:05:53 2002 @@ -268,11 +268,11 @@ case INTEL_I810: head->chipset = "Intel i810"; break; case INTEL_I815: head->chipset = "Intel i815"; break; -#if LINUX_VERSION_CODE >= 0x020415 +#if LINUX_VERSION_CODE >= 0x02040f /* KERNEL_VERSION(2,4,15) */ case INTEL_I820: head->chipset = "Intel i820"; break; #endif case INTEL_I840: head->chipset = "Intel i840"; break; -#if LINUX_VERSION_CODE >= 0x020415 +#if LINUX_VERSION_CODE >= 0x02040f /* KERNEL_VERSION(2,4,15) */ case INTEL_I845: head->chipset = "Intel i845"; break; #endif case INTEL_I850: head->chipset = "Intel i850"; break; diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h --- a/drivers/char/drm/drm_drv.h Sat Aug 31 15:05:55 2002 +++ b/drivers/char/drm/drm_drv.h Sat Aug 31 15:05:55 2002 @@ -115,15 +115,15 @@ #ifndef DRIVER_FOPS #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ - owner: THIS_MODULE, \ - open: DRM(open), \ - flush: DRM(flush), \ - release: DRM(release), \ - ioctl: DRM(ioctl), \ - mmap: DRM(mmap), \ - read: DRM(read), \ - fasync: DRM(fasync), \ - poll: DRM(poll), \ + .owner = THIS_MODULE, \ + .open = DRM(open), \ + .flush = DRM(flush), \ + .release = DRM(release), \ + .ioctl = DRM(ioctl), \ + .mmap = DRM(mmap), \ + .read = DRM(read), \ + .fasync = DRM(fasync), \ + .poll = DRM(poll), \ } #endif diff -Nru a/drivers/char/drm/drm_stub.h b/drivers/char/drm/drm_stub.h --- a/drivers/char/drm/drm_stub.h Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/drm_stub.h Sat Aug 31 15:06:06 2002 @@ -66,8 +66,8 @@ } static struct file_operations DRM(stub_fops) = { - owner: THIS_MODULE, - open: DRM(stub_open) + .owner = THIS_MODULE, + .open = DRM(stub_open) }; static int DRM(stub_getminor)(const char *name, struct file_operations *fops, diff -Nru a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h --- a/drivers/char/drm/drm_vm.h Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/drm_vm.h Sat Aug 31 15:06:06 2002 @@ -33,27 +33,27 @@ #include "drmP.h" struct vm_operations_struct DRM(vm_ops) = { - nopage: DRM(vm_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; struct vm_operations_struct DRM(vm_shm_ops) = { - nopage: DRM(vm_shm_nopage), - open: DRM(vm_open), - close: DRM(vm_shm_close), + .nopage = DRM(vm_shm_nopage), + .open = DRM(vm_open), + .close = DRM(vm_shm_close), }; struct vm_operations_struct DRM(vm_dma_ops) = { - nopage: DRM(vm_dma_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_dma_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; struct vm_operations_struct DRM(vm_sg_ops) = { - nopage: DRM(vm_sg_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_sg_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; struct page *DRM(vm_nopage)(struct vm_area_struct *vma, @@ -343,7 +343,7 @@ vma->vm_ops = &DRM(vm_dma_ops); -#if LINUX_VERSION_CODE <= 0x020414 +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ #else vma->vm_flags |= VM_RESERVED; /* Don't swap */ @@ -473,7 +473,7 @@ vma->vm_private_data = (void *)map; /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ -#if LINUX_VERSION_CODE <= 0x020414 +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ vma->vm_flags |= VM_LOCKED; #else vma->vm_flags |= VM_RESERVED; @@ -482,7 +482,7 @@ case _DRM_SCATTER_GATHER: vma->vm_ops = &DRM(vm_sg_ops); vma->vm_private_data = (void *)map; -#if LINUX_VERSION_CODE <= 0x020414 +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ vma->vm_flags |= VM_LOCKED; #else vma->vm_flags |= VM_RESERVED; @@ -491,7 +491,7 @@ default: return -EINVAL; /* This should never happen. */ } -#if LINUX_VERSION_CODE <= 0x020414 +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ #else vma->vm_flags |= VM_RESERVED; /* Don't swap */ diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c --- a/drivers/char/drm/i810_dma.c Sat Aug 31 15:05:59 2002 +++ b/drivers/char/drm/i810_dma.c Sat Aug 31 15:05:59 2002 @@ -131,14 +131,14 @@ } static struct file_operations i810_buffer_fops = { - open: DRM(open), - flush: DRM(flush), - release: DRM(release), - ioctl: DRM(ioctl), - mmap: i810_mmap_buffers, - read: DRM(read), - fasync: DRM(fasync), - poll: DRM(poll), + .open = DRM(open), + .flush = DRM(flush), + .release = DRM(release), + .ioctl = DRM(ioctl), + .mmap = i810_mmap_buffers, + .read = DRM(read), + .fasync = DRM(fasync), + .poll = DRM(poll), }; int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) @@ -272,20 +272,24 @@ if(address == 0UL) return 0; -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < 0x020409 atomic_inc(&virt_to_page(address)->count); set_bit(PG_locked, &virt_to_page(address)->flags); #else get_page(virt_to_page(address)); +#if LINUX_VERSION_CODE < 0x020500 + LockPage(virt_to_page(address)); +#else SetPageLocked(virt_to_page(address)); #endif +#endif return address; } static void i810_free_page(drm_device_t *dev, unsigned long page) { if (page) { -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < 0x020409 atomic_dec(&virt_to_page(page)->count); clear_bit(PG_locked, &virt_to_page(page)->flags); wake_up(&virt_to_page(page)->wait); @@ -339,8 +343,6 @@ end = jiffies + (HZ*3); while (ring->space < n) { - int i; - ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; ring->space = ring->head - (ring->tail+8); if (ring->space < 0) ring->space += ring->Size; diff -Nru a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c --- a/drivers/char/drm/i830_dma.c Sat Aug 31 15:05:54 2002 +++ b/drivers/char/drm/i830_dma.c Sat Aug 31 15:05:54 2002 @@ -153,14 +153,14 @@ } static struct file_operations i830_buffer_fops = { - open: DRM(open), - flush: DRM(flush), - release: DRM(release), - ioctl: DRM(ioctl), - mmap: i830_mmap_buffers, - read: DRM(read), - fasync: DRM(fasync), - poll: DRM(poll), + .open = DRM(open), + .flush = DRM(flush), + .release = DRM(release), + .ioctl = DRM(ioctl), + .mmap = i830_mmap_buffers, + .read = DRM(read), + .fasync = DRM(fasync), + .poll = DRM(poll), }; int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) @@ -303,20 +303,24 @@ if(address == 0UL) return 0; -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < 0x020409 atomic_inc(&virt_to_page(address)->count); set_bit(PG_locked, &virt_to_page(address)->flags); #else get_page(virt_to_page(address)); +#if LINUX_VERSION_CODE < 0x020500 + LockPage(virt_to_page(address)); +#else SetPageLocked(virt_to_page(address)); #endif +#endif return address; } static void i830_free_page(drm_device_t *dev, unsigned long page) { if (page) { -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < 0x020409 atomic_dec(&virt_to_page(page)->count); clear_bit(PG_locked, &virt_to_page(page)->flags); wake_up(&virt_to_page(page)->wait); diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c --- a/drivers/char/drm/mga_dma.c Sat Aug 31 15:05:59 2002 +++ b/drivers/char/drm/mga_dma.c Sat Aug 31 15:05:59 2002 @@ -696,7 +696,7 @@ #if MGA_DMA_DEBUG int ret = mga_do_wait_for_idle( dev_priv ); if ( ret < 0 ) - DRM_INFO( "%s: -EBUSY\n", __func__ ); + DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ ); return ret; #else return mga_do_wait_for_idle( dev_priv ); diff -Nru a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h --- a/drivers/char/drm/mga_drv.h Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/mga_drv.h Sat Aug 31 15:06:06 2002 @@ -38,7 +38,7 @@ u32 tail; int space; - int wrapped; + volatile long wrapped; volatile u32 *status; @@ -188,7 +188,7 @@ if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ dev->lock.pid != DRM_CURRENTPID ) { \ DRM_ERROR( "%s called without lock held\n", \ - __func__ ); \ + __FUNCTION__ ); \ return DRM_ERR(EINVAL); \ } \ } while (0) @@ -201,7 +201,7 @@ } else if ( dev_priv->prim.space < \ dev_priv->prim.high_mark ) { \ if ( MGA_DMA_DEBUG ) \ - DRM_INFO( "%s: wrap...\n", __func__ ); \ + DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ return DRM_ERR(EBUSY); \ } \ } \ @@ -212,7 +212,7 @@ if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \ if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \ if ( MGA_DMA_DEBUG ) \ - DRM_INFO( "%s: wrap...\n", __func__ ); \ + DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ return DRM_ERR(EBUSY); \ } \ mga_do_dma_wrap_end( dev_priv ); \ @@ -234,7 +234,7 @@ do { \ if ( MGA_VERBOSE ) { \ DRM_INFO( "BEGIN_DMA( %d ) in %s\n", \ - (n), __func__ ); \ + (n), __FUNCTION__ ); \ DRM_INFO( " space=0x%x req=0x%x\n", \ dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \ } \ @@ -245,7 +245,7 @@ #define BEGIN_DMA_WRAP() \ do { \ if ( MGA_VERBOSE ) { \ - DRM_INFO( "BEGIN_DMA() in %s\n", __func__ ); \ + DRM_INFO( "BEGIN_DMA() in %s\n", __FUNCTION__ ); \ DRM_INFO( " space=0x%x\n", dev_priv->prim.space ); \ } \ prim = dev_priv->prim.start; \ @@ -264,7 +264,7 @@ #define FLUSH_DMA() \ do { \ if ( 0 ) { \ - DRM_INFO( "%s:\n", __func__ ); \ + DRM_INFO( "%s:\n", __FUNCTION__ ); \ DRM_INFO( " tail=0x%06x head=0x%06lx\n", \ dev_priv->prim.tail, \ MGA_READ( MGA_PRIMADDRESS ) - \ diff -Nru a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c --- a/drivers/char/drm/mga_state.c Sat Aug 31 15:05:59 2002 +++ b/drivers/char/drm/mga_state.c Sat Aug 31 15:05:59 2002 @@ -37,7 +37,6 @@ #include "drm.h" #include "mga_drm.h" #include "mga_drv.h" -#include "drm.h" /* ================================================================ @@ -662,7 +661,7 @@ FLUSH_DMA(); - DRM_DEBUG( "%s... done.\n", __func__ ); + DRM_DEBUG( "%s... done.\n", __FUNCTION__ ); } static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf ) @@ -1023,7 +1022,7 @@ #if 0 if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { if ( MGA_DMA_DEBUG ) - DRM_INFO( "%s: -EBUSY\n", __func__ ); + DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ ); return DRM_ERR(EBUSY); } #endif diff -Nru a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c --- a/drivers/char/drm/r128_cce.c Sat Aug 31 15:05:54 2002 +++ b/drivers/char/drm/r128_cce.c Sat Aug 31 15:05:54 2002 @@ -666,7 +666,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) { - DRM_DEBUG( "%s while CCE running\n", __func__ ); + DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ ); return 0; } @@ -728,7 +728,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_DEBUG( "%s called before init done\n", __func__ ); + DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } diff -Nru a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h --- a/drivers/char/drm/r128_drv.h Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/r128_drv.h Sat Aug 31 15:06:06 2002 @@ -401,7 +401,7 @@ do { \ if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ dev->lock.pid != DRM_CURRENTPID ) { \ - DRM_ERROR( "%s called without lock held\n", __func__ ); \ + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); \ return DRM_ERR(EINVAL); \ } \ } while (0) @@ -459,7 +459,7 @@ #define BEGIN_RING( n ) do { \ if ( R128_VERBOSE ) { \ DRM_INFO( "BEGIN_RING( %d ) in %s\n", \ - (n), __func__ ); \ + (n), __FUNCTION__ ); \ } \ if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ r128_wait_ring( dev_priv, (n) * sizeof(u32) ); \ diff -Nru a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c --- a/drivers/char/drm/r128_state.c Sat Aug 31 15:05:54 2002 +++ b/drivers/char/drm/r128_state.c Sat Aug 31 15:05:54 2002 @@ -43,7 +43,7 @@ { u32 aux_sc_cntl = 0x00000000; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 17 ); @@ -86,7 +86,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 2 ); @@ -101,7 +101,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 13 ); @@ -127,7 +127,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 3 ); @@ -143,7 +143,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 5 ); @@ -162,7 +162,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 2 ); @@ -179,7 +179,7 @@ drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0]; int i; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 7 + R128_MAX_TEXTURE_LEVELS ); @@ -205,7 +205,7 @@ drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1]; int i; RING_LOCALS; - DRM_DEBUG( " %s\n", __func__ ); + DRM_DEBUG( " %s\n", __FUNCTION__ ); BEGIN_RING( 5 + R128_MAX_TEXTURE_LEVELS ); @@ -228,7 +228,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; - DRM_DEBUG( "%s: dirty=0x%08x\n", __func__, dirty ); + DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty ); if ( dirty & R128_UPLOAD_CORE ) { r128_emit_core( dev_priv ); @@ -369,7 +369,7 @@ unsigned int flags = clear->flags; int i; RING_LOCALS; - DRM_DEBUG( "%s\n", __func__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { unsigned int tmp = flags; @@ -472,7 +472,7 @@ drm_clip_rect_t *pbox = sarea_priv->boxes; int i; RING_LOCALS; - DRM_DEBUG( "%s\n", __func__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); #if R128_PERFORMANCE_BOXES /* Do some trivial performance monitoring... @@ -1148,7 +1148,7 @@ int count, *x, *y; int i; RING_LOCALS; - DRM_DEBUG( "%s\n", __func__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); count = depth->n; if ( count > dev_priv->depth_pitch ) { @@ -1215,7 +1215,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; int i; RING_LOCALS; - DRM_DEBUG( "%s\n", __func__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); BEGIN_RING( 33 ); @@ -1264,7 +1264,7 @@ DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; - DRM_DEBUG( "%s\n", __func__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); LOCK_TEST_WITH_RETURN( dev ); @@ -1296,7 +1296,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1356,7 +1356,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1505,7 +1505,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } diff -Nru a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h --- a/drivers/char/drm/radeon.h Sat Aug 31 15:05:59 2002 +++ b/drivers/char/drm/radeon.h Sat Aug 31 15:05:59 2002 @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020611" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 4 +#define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -64,9 +64,10 @@ * - Add support for new radeon packets (keith) * - Add getparam ioctl (keith) * - Add flip-buffers ioctl, deprecate fullscreen foo (keith). - * 1.4 - Add r200 packets to cmdbuf ioctl + * 1.4 - Add scratch registers to get_param ioctl. + * 1.5 - Add r200 packets to cmdbuf ioctl * - Add r200 function to init ioctl - * - Add 'scalar2' hack to cmdbuf ioctl (must die) + * - Add 'scalar2' instruction to cmdbuf */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c --- a/drivers/char/drm/radeon_cp.c Sat Aug 31 15:05:55 2002 +++ b/drivers/char/drm/radeon_cp.c Sat Aug 31 15:05:55 2002 @@ -925,6 +925,24 @@ RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 ); + /* Writeback doesn't seem to work everywhere, test it first */ + DRM_WRITE32( &dev_priv->scratch[1], 0 ); + RADEON_WRITE( RADEON_SCRATCH_REG1, 0xdeadbeef ); + + for ( tmp = 0 ; tmp < dev_priv->usec_timeout ; tmp++ ) { + if ( DRM_READ32( &dev_priv->scratch[1] ) == 0xdeadbeef ) + break; + DRM_UDELAY( 1 ); + } + + if ( tmp < dev_priv->usec_timeout ) { + dev_priv->writeback_works = 1; + DRM_DEBUG( "writeback test succeeded, tmp=%d\n", tmp ); + } else { + dev_priv->writeback_works = 0; + DRM_DEBUG( "writeback test failed\n" ); + } + dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; RADEON_WRITE( RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); @@ -1000,7 +1018,7 @@ } dev_priv->is_r200 = (init->func == RADEON_INIT_R200_CP); - dev_priv->do_boxes = 1; + dev_priv->do_boxes = 0; dev_priv->cp_mode = init->cp_mode; /* We don't support anything other than bus-mastering ring mode, @@ -1307,12 +1325,12 @@ LOCK_TEST_WITH_RETURN( dev ); if ( dev_priv->cp_running ) { - DRM_DEBUG( "%s while CP running\n", __func__ ); + DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); return 0; } if ( dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS ) { DRM_DEBUG( "%s called with bogus CP mode (%d)\n", - __func__, dev_priv->cp_mode ); + __FUNCTION__, dev_priv->cp_mode ); return 0; } @@ -1374,7 +1392,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_DEBUG( "%s called before init done\n", __func__ ); + DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1456,8 +1474,8 @@ start = dev_priv->last_buf; for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { - u32 done_age = DRM_READ32(&dev_priv->scratch[1]); - + u32 done_age = GET_SCRATCH( 1 ); + DRM_DEBUG("done_age = %d\n",done_age); for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h --- a/drivers/char/drm/radeon_drv.h Sat Aug 31 15:06:00 2002 +++ b/drivers/char/drm/radeon_drv.h Sat Aug 31 15:06:00 2002 @@ -76,6 +76,7 @@ drm_radeon_freelist_t *tail; int last_buf; volatile u32 *scratch; + int writeback_works; int usec_timeout; @@ -233,6 +234,10 @@ #define RADEON_SCRATCH_UMSK 0x0770 #define RADEON_SCRATCH_ADDR 0x0774 +#define GET_SCRATCH( x ) (dev_priv->writeback_works \ + ? DRM_READ32( &dev_priv->scratch[(x)] ) \ + : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) + #define RADEON_HOST_PATH_CNTL 0x0130 # define RADEON_HDP_SOFT_RESET (1 << 26) # define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) @@ -680,7 +685,7 @@ do { \ if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ dev->lock.pid != DRM_CURRENTPID ) { \ - DRM_ERROR( "%s called without lock held\n", __func__ ); \ + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); \ return DRM_ERR(EINVAL); \ } \ } while (0) @@ -742,7 +747,7 @@ #define BEGIN_RING( n ) do { \ if ( RADEON_VERBOSE ) { \ DRM_INFO( "BEGIN_RING( %d ) in %s\n", \ - n, __func__ ); \ + n, __FUNCTION__ ); \ } \ if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ COMMIT_RING(); \ diff -Nru a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c --- a/drivers/char/drm/radeon_state.c Sat Aug 31 15:06:06 2002 +++ b/drivers/char/drm/radeon_state.c Sat Aug 31 15:06:06 2002 @@ -50,8 +50,7 @@ OUT_RING( CP_PACKET0( RADEON_RE_TOP_LEFT, 0 ) ); OUT_RING( (box->y1 << 16) | box->x1 ); OUT_RING( CP_PACKET0( RADEON_RE_WIDTH_HEIGHT, 0 ) ); -/* OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );*/ - OUT_RING( (box->y2 << 16) | box->x2 ); + OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) ); ADVANCE_RING(); } @@ -412,7 +411,6 @@ RING_LOCALS; DRM_DEBUG( "flags = 0x%x\n", flags ); - dev_priv->stats.clears++; if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { @@ -810,9 +808,6 @@ BEGIN_RING( 4 ); RADEON_WAIT_UNTIL_3D_IDLE(); -/* - RADEON_WAIT_UNTIL_PAGE_FLIPPED(); -*/ OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET, 0 ) ); if ( dev_priv->current_page == 0 ) { @@ -1383,7 +1378,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1470,7 +1465,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1620,7 +1615,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1697,7 +1692,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -1941,6 +1936,19 @@ if ( i < cmdbuf->nbox ) { if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) )) return DRM_ERR(EFAULT); + /* FIXME The second and subsequent times round this loop, send a + * WAIT_UNTIL_3D_IDLE before calling emit_clip_rect(). This + * fixes a lockup on fast machines when sending several + * cliprects with a cmdbuf, as when waving a 2D window over + * a 3D window. Something in the commands from user space + * seems to hang the card when they're sent several times + * in a row. That would be the correct place to fix it but + * this works around it until I can figure that out - Tim Smith */ + if ( i ) { + BEGIN_RING( 2 ); + RADEON_WAIT_UNTIL_3D_IDLE(); + ADVANCE_RING(); + } radeon_emit_clip_rect( dev_priv, &box ); } @@ -1949,7 +1957,6 @@ ADVANCE_RING(); } while ( ++i < cmdbuf->nbox ); - if (cmdbuf->nbox == 1) cmdbuf->nbox = 0; @@ -1975,7 +1982,7 @@ LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -2097,7 +2104,7 @@ int value; if ( !dev_priv ) { - DRM_ERROR( "%s called with no initialization\n", __func__ ); + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } @@ -2112,14 +2119,14 @@ break; case RADEON_PARAM_LAST_FRAME: dev_priv->stats.last_frame_reads++; - value = DRM_READ32(&dev_priv->scratch[0]); + value = GET_SCRATCH( 0 ); break; case RADEON_PARAM_LAST_DISPATCH: - value = DRM_READ32(&dev_priv->scratch[1]); + value = GET_SCRATCH( 1 ); break; case RADEON_PARAM_LAST_CLEAR: dev_priv->stats.last_clear_reads++; - value = DRM_READ32(&dev_priv->scratch[2]); + value = GET_SCRATCH( 2 ); break; default: return DRM_ERR(EINVAL); diff -Nru a/drivers/char/efirtc.c b/drivers/char/efirtc.c --- a/drivers/char/efirtc.c Sat Aug 31 15:06:04 2002 +++ b/drivers/char/efirtc.c Sat Aug 31 15:06:04 2002 @@ -35,8 +35,8 @@ #include #include #include +#include -#include #include #include diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c --- a/drivers/char/keyboard.c Sat Aug 31 15:05:59 2002 +++ b/drivers/char/keyboard.c Sat Aug 31 15:05:59 2002 @@ -906,7 +906,7 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -929,6 +929,11 @@ extern int mac_hid_mouse_emulate_buttons(int, int, int); #endif /* CONFIG_MAC_EMUMOUSEBTN */ +#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) +static int sparc_l1_a_state = 0; +extern void sun_do_break(void); +#endif + static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { @@ -1001,6 +1006,10 @@ if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) sysrq_alt = down; +#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) + if (keycode == KEY_STOP) + sparc_l1_a_state = down; +#endif rep = (down == 2); @@ -1018,6 +1027,12 @@ return; } #endif +#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) + if (keycode == KEY_A && sparc_l1_a_state) { + sparc_l1_a_state = 0; + sun_do_break(); + } +#endif if (kbd->kbdmode == VC_MEDIUMRAW) { /* @@ -1180,8 +1195,10 @@ for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i] = kbd0; + input_register_handler(&kbd_handler); + tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet); - input_register_handler(&kbd_handler); + return 0; } diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c --- a/drivers/char/mxser.c Sat Aug 31 15:06:03 2002 +++ b/drivers/char/mxser.c Sat Aug 31 15:06:04 2002 @@ -650,7 +650,7 @@ n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1; index = 0; for (b = 0; b < n; b++) { - while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) + while ((pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev))) { if (pci_enable_device(pdev)) continue; diff -Nru a/drivers/char/nvram.c b/drivers/char/nvram.c --- a/drivers/char/nvram.c Sat Aug 31 15:05:59 2002 +++ b/drivers/char/nvram.c Sat Aug 31 15:05:59 2002 @@ -3,6 +3,7 @@ * * Copyright (C) 1997 Roman Hodek * idea by and with help from Richard Jelinek + * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) * * This driver allows you to access the contents of the non-volatile memory in * the mc146818rtc.h real-time clock. This chip is built into all PCs and into @@ -10,9 +11,10 @@ * "NVRAM" (NV stands for non-volatile). * * The data are supplied as a (seekable) character device, /dev/nvram. The - * size of this file is 50, the number of freely available bytes in the memory - * (i.e., not used by the RTC itself). - * + * size of this file is dependant on the controller. The usual size is 114, + * the number of freely available bytes in the memory (i.e., not used by the + * RTC itself). + * * Checksums over the NVRAM contents are managed by this driver. In case of a * bad checksum, reads and writes return -EIO. The checksum can be initialized * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or @@ -28,25 +30,35 @@ * * 1.1 Cesar Barros: SMP locking fixes * added changelog + * 1.2 Erik Gilling: Cobalt Networks support + * Tim Hockin: general cleanup, Cobalt support */ -#define NVRAM_VERSION "1.1" +#define NVRAM_VERSION "1.2" #include #include #include #include +#include #define PC 1 #define ATARI 2 +#define COBALT 3 /* select machine configuration */ #if defined(CONFIG_ATARI) -#define MACH ATARI +# define MACH ATARI #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */ #define MACH PC +# if defined(CONFIG_COBALT) +# include +# define MACH COBALT +# else +# define MACH PC +# endif #else -#error Cannot build nvram driver for this machine configuration. +# error Cannot build nvram driver for this machine configuration. #endif #if MACH == PC @@ -58,10 +70,23 @@ #define PC_CKS_RANGE_START 2 #define PC_CKS_RANGE_END 31 #define PC_CKS_LOC 32 +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) + +#define mach_check_checksum pc_check_checksum +#define mach_set_checksum pc_set_checksum +#define mach_proc_infos pc_proc_infos + +#endif + +#if MACH == COBALT + +#define CHECK_DRIVER_INIT() 1 + +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) -#define mach_check_checksum pc_check_checksum -#define mach_set_checksum pc_set_checksum -#define mach_proc_infos pc_proc_infos +#define mach_check_checksum cobalt_check_checksum +#define mach_set_checksum cobalt_set_checksum +#define mach_proc_infos cobalt_proc_infos #endif @@ -79,9 +104,9 @@ #define ATARI_CKS_RANGE_END 47 #define ATARI_CKS_LOC 48 -#define mach_check_checksum atari_check_checksum -#define mach_set_checksum atari_set_checksum -#define mach_proc_infos atari_proc_infos +#define mach_check_checksum atari_check_checksum +#define mach_set_checksum atari_set_checksum +#define mach_proc_infos atari_proc_infos #endif @@ -98,7 +123,6 @@ #include #include #include -#include #include #include #include @@ -107,17 +131,11 @@ #include #include +static spinlock_t nvram_state_lock = SPIN_LOCK_UNLOCKED; static int nvram_open_cnt; /* #times opened */ static int nvram_open_mode; /* special open modes */ -static spinlock_t nvram_open_lock = SPIN_LOCK_UNLOCKED; /* guards - * nvram_open_cnt and - * nvram_open_mode */ -#define NVRAM_WRITE 1 /* opened for writing (exclusive) */ -#define NVRAM_EXCL 2 /* opened with O_EXCL */ - -#define RTC_FIRST_BYTE 14 /* RTC register number of first - * NVRAM byte */ -#define NVRAM_BYTES 128-RTC_FIRST_BYTE /* number of NVRAM bytes */ +#define NVRAM_WRITE 1 /* opened for writing (exclusive) */ +#define NVRAM_EXCL 2 /* opened with O_EXCL */ static int mach_check_checksum(void); static void mach_set_checksum(void); @@ -128,95 +146,85 @@ #endif /* - * These are the internal NVRAM access functions, which do NOT disable - * interrupts and do not check the checksum. Both tasks are left to higher - * level function, so they need to be done only once per syscall. - */ - -static __inline__ unsigned char -nvram_read_int(int i) -{ - return CMOS_READ(RTC_FIRST_BYTE + i); -} - -static __inline__ void -nvram_write_int(unsigned char c, int i) -{ - CMOS_WRITE(c, RTC_FIRST_BYTE + i); -} - -static __inline__ int -nvram_check_checksum_int(void) -{ - return mach_check_checksum(); -} - -static __inline__ void -nvram_set_checksum_int(void) -{ - mach_set_checksum(); -} - -#if MACH == ATARI - -/* - * These non-internal functions are provided to be called by other parts of + * These functions are provided to be called internally or by other parts of * the kernel. It's up to the caller to ensure correct checksum before reading * or after writing (needs to be done only once). * - * They're only built if CONFIG_ATARI is defined, because Atari drivers use - * them. For other configurations (PC), the rest of the kernel can't rely on - * them being present (this driver may not be configured at all, or as a - * module), so they access config information themselves. + * It is worth noting that these functions all access bytes of general + * purpose memory in the NVRAM - that is to say, they all add the + * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not + * know about the RTC cruft. */ unsigned char +__nvram_read_byte(int i) +{ + return CMOS_READ(NVRAM_FIRST_BYTE + i); +} + +unsigned char nvram_read_byte(int i) { unsigned long flags; unsigned char c; spin_lock_irqsave(&rtc_lock, flags); - c = nvram_read_int(i); + c = __nvram_read_byte(i); spin_unlock_irqrestore(&rtc_lock, flags); return c; } /* This races nicely with trying to read with checksum checking (nvram_read) */ void +__nvram_write_byte(unsigned char c, int i) +{ + CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); +} + +void nvram_write_byte(unsigned char c, int i) { unsigned long flags; spin_lock_irqsave(&rtc_lock, flags); - nvram_write_int(c, i); + __nvram_write_byte(c, i); spin_unlock_irqrestore(&rtc_lock, flags); } int +__nvram_check_checksum(void) +{ + return mach_check_checksum(); +} + +int nvram_check_checksum(void) { unsigned long flags; int rv; spin_lock_irqsave(&rtc_lock, flags); - rv = nvram_check_checksum_int(); + rv = __nvram_check_checksum(); spin_unlock_irqrestore(&rtc_lock, flags); return rv; } void +__nvram_set_checksum(void) +{ + mach_set_checksum(); +} + +void nvram_set_checksum(void) { unsigned long flags; spin_lock_irqsave(&rtc_lock, flags); - nvram_set_checksum_int(); + __nvram_set_checksum(); spin_unlock_irqrestore(&rtc_lock, flags); } -#endif /* MACH == ATARI */ - /* * The are the file operation function for user access to /dev/nvram */ @@ -243,17 +251,17 @@ static ssize_t nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - char contents[NVRAM_BYTES]; + unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; - char *tmp; + unsigned char *tmp; spin_lock_irq(&rtc_lock); - if (!nvram_check_checksum_int()) + if (!__nvram_check_checksum()) goto checksum_err; for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) - *tmp = nvram_read_int(i); + *tmp = __nvram_read_byte(i); spin_unlock_irq(&rtc_lock); @@ -272,23 +280,24 @@ static ssize_t nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - char contents[NVRAM_BYTES]; + unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; - char *tmp; + unsigned char *tmp; + int len; - if (copy_from_user(contents, buf, (NVRAM_BYTES - i) < count ? - (NVRAM_BYTES - i) : count)) + len = (NVRAM_BYTES - i) < count ? (NVRAM_BYTES - i) : count; + if (copy_from_user(contents, buf, len)) return -EFAULT; spin_lock_irq(&rtc_lock); - if (!nvram_check_checksum_int()) + if (!__nvram_check_checksum()) goto checksum_err; for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) - nvram_write_int(*tmp, i); + __nvram_write_byte(*tmp, i); - nvram_set_checksum_int(); + __nvram_set_checksum(); spin_unlock_irq(&rtc_lock); @@ -309,27 +318,28 @@ switch (cmd) { - case NVRAM_INIT: /* initialize NVRAM contents and checksum */ + case NVRAM_INIT: + /* initialize NVRAM contents and checksum */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; spin_lock_irq(&rtc_lock); for (i = 0; i < NVRAM_BYTES; ++i) - nvram_write_int(0, i); - nvram_set_checksum_int(); + __nvram_write_byte(0, i); + __nvram_set_checksum(); spin_unlock_irq(&rtc_lock); return 0; - case NVRAM_SETCKS: /* just set checksum, contents unchanged - * (maybe useful after checksum garbaged - * somehow...) */ + case NVRAM_SETCKS: + /* just set checksum, contents unchanged (maybe useful after + * checksum garbaged somehow...) */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; spin_lock_irq(&rtc_lock); - nvram_set_checksum_int(); + __nvram_set_checksum(); spin_unlock_irq(&rtc_lock); return 0; @@ -341,11 +351,12 @@ static int nvram_open(struct inode *inode, struct file *file) { - spin_lock(&nvram_open_lock); + spin_lock(&nvram_state_lock); + if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || (nvram_open_mode & NVRAM_EXCL) || ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE))) { - spin_unlock(&nvram_open_lock); + spin_unlock(&nvram_state_lock); return -EBUSY; } @@ -354,20 +365,27 @@ if (file->f_mode & 2) nvram_open_mode |= NVRAM_WRITE; nvram_open_cnt++; - spin_unlock(&nvram_open_lock); + + spin_unlock(&nvram_state_lock); + return 0; } static int nvram_release(struct inode *inode, struct file *file) { - spin_lock(&nvram_open_lock); + spin_lock(&nvram_state_lock); + nvram_open_cnt--; - if (file->f_flags & O_EXCL) + + /* if only one instance is open, clear the EXCL bit */ + if (nvram_open_mode & NVRAM_EXCL) nvram_open_mode &= ~NVRAM_EXCL; if (file->f_mode & 2) nvram_open_mode &= ~NVRAM_WRITE; - spin_unlock(&nvram_open_lock); + + spin_unlock(&nvram_state_lock); + return 0; } @@ -390,7 +408,7 @@ spin_lock_irq(&rtc_lock); for (i = 0; i < NVRAM_BYTES; ++i) - contents[i] = nvram_read_int(i); + contents[i] = __nvram_read_byte(i); spin_unlock_irq(&rtc_lock); *eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size); @@ -404,7 +422,7 @@ /* This macro frees the machine specific function from bounds checking and * this like that... */ -#define PRINT_PROC(fmt,args...) \ +#define PRINT_PROC(fmt,args...) \ do { \ *len += sprintf(buffer+*len, fmt, ##args); \ if (*begin + *len > offset + size) \ @@ -484,11 +502,13 @@ { int i; unsigned short sum = 0; + unsigned short expect; for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) - sum += nvram_read_int(i); - return ((sum & 0xffff) == - ((nvram_read_int(PC_CKS_LOC)<<8) | nvram_read_int(PC_CKS_LOC+1))); + sum += __nvram_read_byte(i); + expect = __nvram_read_byte(PC_CKS_LOC)<<8 | + __nvram_read_byte(PC_CKS_LOC+1); + return ((sum & 0xffff) == expect); } static void @@ -498,9 +518,9 @@ unsigned short sum = 0; for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) - sum += nvram_read_int(i); - nvram_write_int(sum >> 8, PC_CKS_LOC); - nvram_write_int(sum & 0xff, PC_CKS_LOC + 1); + sum += __nvram_read_byte(i); + __nvram_write_byte(sum >> 8, PC_CKS_LOC); + __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); } #ifdef CONFIG_PROC_FS @@ -525,7 +545,7 @@ int type; spin_lock_irq(&rtc_lock); - checksum = nvram_check_checksum_int(); + checksum = __nvram_check_checksum(); spin_unlock_irq(&rtc_lock); PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); @@ -583,6 +603,177 @@ #endif /* MACH == PC */ +#if MACH == COBALT + +/* the cobalt CMOS has a wider range of it's checksum */ +static int cobalt_check_checksum(void) +{ + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { + if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) + continue; + + sum += __nvram_read_byte(i); + } + expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 | + __nvram_read_byte(COBT_CMOS_CHECKSUM+1); + return ((sum & 0xffff) == expect); +} + +static void cobalt_set_checksum(void) +{ + int i; + unsigned short sum = 0; + + for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { + if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) + continue; + + sum += __nvram_read_byte(i); + } + + __nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM); + __nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1); +} + +#ifdef CONFIG_PROC_FS + +static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + int i; + unsigned int checksum; + unsigned int flags; + char sernum[14]; + char *key = "cNoEbTaWlOtR!"; + unsigned char bto_csum; + + spin_lock_irq(&rtc_lock); + checksum = __nvram_check_checksum(); + spin_unlock_irq(&rtc_lock); + + PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + + flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8 + | nvram[COBT_CMOS_FLAG_BYTE_1]; + + PRINT_PROC("Console: %s\n", + flags & COBT_CMOS_CONSOLE_FLAG ? "on": "off"); + + PRINT_PROC("Firmware Debug Messages: %s\n", + flags & COBT_CMOS_DEBUG_FLAG ? "on": "off"); + + PRINT_PROC("Auto Prompt: %s\n", + flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off"); + + PRINT_PROC("Shutdown Status: %s\n", + flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty"); + + PRINT_PROC("Hardware Probe: %s\n", + flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full"); + + PRINT_PROC("System Fault: %sdetected\n", + flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not "); + + PRINT_PROC("Panic on OOPS: %s\n", + flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no"); + + PRINT_PROC("Delayed Cache Initialization: %s\n", + flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no"); + + PRINT_PROC("Show Logo at Boot: %s\n", + flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes"); + + PRINT_PROC("Boot Method: "); + switch (nvram[COBT_CMOS_BOOT_METHOD]) { + case COBT_CMOS_BOOT_METHOD_DISK: + PRINT_PROC("disk\n"); + break; + + case COBT_CMOS_BOOT_METHOD_ROM: + PRINT_PROC("rom\n"); + break; + + case COBT_CMOS_BOOT_METHOD_NET: + PRINT_PROC("net\n"); + break; + + default: + PRINT_PROC("unknown\n"); + break; + } + + PRINT_PROC("Primary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV0_MAJ], + nvram[COBT_CMOS_BOOT_DEV0_MIN] ); + PRINT_PROC("Secondary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV1_MAJ], + nvram[COBT_CMOS_BOOT_DEV1_MIN] ); + PRINT_PROC("Tertiary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV2_MAJ], + nvram[COBT_CMOS_BOOT_DEV2_MIN] ); + + PRINT_PROC("Uptime: %d\n", + nvram[COBT_CMOS_UPTIME_0] << 24 | + nvram[COBT_CMOS_UPTIME_1] << 16 | + nvram[COBT_CMOS_UPTIME_2] << 8 | + nvram[COBT_CMOS_UPTIME_3]); + + PRINT_PROC("Boot Count: %d\n", + nvram[COBT_CMOS_BOOTCOUNT_0] << 24 | + nvram[COBT_CMOS_BOOTCOUNT_1] << 16 | + nvram[COBT_CMOS_BOOTCOUNT_2] << 8 | + nvram[COBT_CMOS_BOOTCOUNT_3]); + + /* 13 bytes of serial num */ + for (i=0 ; i<13 ; i++) { + sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i]; + } + sernum[13] = '\0'; + + checksum = 0; + for (i=0 ; i<13 ; i++) { + checksum += sernum[i] ^ key[i]; + } + checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff; + + PRINT_PROC("Serial Number: %s", sernum); + if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) { + PRINT_PROC(" (invalid checksum)"); + } + PRINT_PROC("\n"); + + PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ], + nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]); + + PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0], + nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2], + nvram[COBT_CMOS_BTO_IP_3]); + bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1] + + nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3]; + if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) { + PRINT_PROC(" (invalid checksum)"); + } + PRINT_PROC("\n"); + + if (flags & COBT_CMOS_VERSION_FLAG + && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) { + PRINT_PROC("BTO Code: 0x%x\n", + nvram[COBT_CMOS_BTO_CODE_0] << 24 | + nvram[COBT_CMOS_BTO_CODE_1] << 16 | + nvram[COBT_CMOS_BTO_CODE_2] << 8 | + nvram[COBT_CMOS_BTO_CODE_3]); + } + + return 1; +} +#endif /* CONFIG_PROC_FS */ + +#endif /* MACH == COBALT */ + #if MACH == ATARI static int @@ -592,9 +783,9 @@ unsigned char sum = 0; for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) - sum += nvram_read_int(i); - return (nvram_read_int(ATARI_CKS_LOC) == (~sum & 0xff) && - nvram_read_int(ATARI_CKS_LOC + 1) == (sum & 0xff)); + sum += __nvram_read_byte(i); + return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff) && + __nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); } static void @@ -604,9 +795,9 @@ unsigned char sum = 0; for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) - sum += nvram_read_int(i); - nvram_write_int(~sum, ATARI_CKS_LOC); - nvram_write_int(sum, ATARI_CKS_LOC + 1); + sum += __nvram_read_byte(i); + __nvram_write_byte(~sum, ATARI_CKS_LOC); + __nvram_write_byte(sum, ATARI_CKS_LOC + 1); } #ifdef CONFIG_PROC_FS @@ -722,3 +913,12 @@ #endif /* MACH == ATARI */ MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(__nvram_read_byte); +EXPORT_SYMBOL(nvram_read_byte); +EXPORT_SYMBOL(__nvram_write_byte); +EXPORT_SYMBOL(nvram_write_byte); +EXPORT_SYMBOL(__nvram_check_checksum); +EXPORT_SYMBOL(nvram_check_checksum); +EXPORT_SYMBOL(__nvram_set_checksum); +EXPORT_SYMBOL(nvram_set_checksum); diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c --- a/drivers/char/sysrq.c Sat Aug 31 15:06:06 2002 +++ b/drivers/char/sysrq.c Sat Aug 31 15:06:06 2002 @@ -76,7 +76,7 @@ }; #endif - +#ifdef CONFIG_VT /* unraw sysrq handler */ static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, struct tty_struct *tty) @@ -91,7 +91,7 @@ help_msg: "unRaw", action_msg: "Keyboard mode set to XLATE", }; - +#endif /* CONFIG_VT */ /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, @@ -371,7 +371,11 @@ as 'Off' at init time */ /* p */ &sysrq_showregs_op, /* q */ NULL, +#ifdef CONFIG_VT /* r */ &sysrq_unraw_op, +#else +/* r */ NULL, +#endif /* s */ &sysrq_sync_op, /* t */ &sysrq_showstate_op, /* u */ &sysrq_mountro_op, diff -Nru a/drivers/hotplug/pci_hotplug_util.c b/drivers/hotplug/pci_hotplug_util.c --- a/drivers/hotplug/pci_hotplug_util.c Sat Aug 31 15:06:03 2002 +++ b/drivers/hotplug/pci_hotplug_util.c Sat Aug 31 15:06:03 2002 @@ -51,245 +51,6 @@ static int debug; -static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev) -{ - struct pci_dev *my_dev; - struct pci_bus *my_bus; - - /* Some validity checks. */ - if ((function > 7) || - (slot > 31) || - (pci_dev == NULL) || - (ops == NULL)) - return -ENODEV; - - my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL); - if (!my_dev) - return -ENOMEM; - my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL); - if (!my_bus) { - kfree (my_dev); - return -ENOMEM; - } - memset(my_dev, 0, sizeof(struct pci_dev)); - memset(my_bus, 0, sizeof(struct pci_bus)); - - my_bus->number = bus; - my_bus->ops = ops; - my_dev->devfn = PCI_DEVFN(slot, function); - my_dev->bus = my_bus; - *pci_dev = my_dev; - return 0; -} - -/** - * pci_read_config_byte_nodev - read a byte from a pci device - * @ops: pointer to a &struct pci_ops that will be used to read from the pci device - * @bus: the bus of the pci device to read from - * @slot: the pci slot number of the pci device to read from - * @function: the function of the pci device to read from - * @where: the location on the pci address space to read from - * @value: pointer to where to place the data read - * - * Like pci_read_config_byte() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_read_config_byte (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_read_config_byte(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - -/** - * pci_read_config_word_nodev - read a word from a pci device - * @ops: pointer to a &struct pci_ops that will be used to read from the pci device - * @bus: the bus of the pci device to read from - * @slot: the pci slot number of the pci device to read from - * @function: the function of the pci device to read from - * @where: the location on the pci address space to read from - * @value: pointer to where to place the data read - * - * Like pci_read_config_word() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_read_config_word (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_read_config_word(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - -/** - * pci_read_config_dword_nodev - read a dword from a pci device - * @ops: pointer to a &struct pci_ops that will be used to read from the pci - * device - * @bus: the bus of the pci device to read from - * @slot: the pci slot number of the pci device to read from - * @function: the function of the pci device to read from - * @where: the location on the pci address space to read from - * @value: pointer to where to place the data read - * - * Like pci_read_config_dword() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_read_config_dword (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_read_config_dword(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - -/** - * pci_write_config_byte_nodev - write a byte to a pci device - * @ops: pointer to a &struct pci_ops that will be used to write to the pci - * device - * @bus: the bus of the pci device to write to - * @slot: the pci slot number of the pci device to write to - * @function: the function of the pci device to write to - * @where: the location on the pci address space to write to - * @value: the value to write to the pci device - * - * Like pci_write_config_byte() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_write_config_byte (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_write_config_byte(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - -/** - * pci_write_config_word_nodev - write a word to a pci device - * @ops: pointer to a &struct pci_ops that will be used to write to the pci - * device - * @bus: the bus of the pci device to write to - * @slot: the pci slot number of the pci device to write to - * @function: the function of the pci device to write to - * @where: the location on the pci address space to write to - * @value: the value to write to the pci device - * - * Like pci_write_config_word() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_write_config_word (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_write_config_word(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - -/** - * pci_write_config_dword_nodev - write a dword to a pci device - * @ops: pointer to a &struct pci_ops that will be used to write to the pci - * device - * @bus: the bus of the pci device to write to - * @slot: the pci slot number of the pci device to write to - * @function: the function of the pci device to write to - * @where: the location on the pci address space to write to - * @value: the value to write to the pci device - * - * Like pci_write_config_dword() but works for pci devices that do not have a - * pci_dev structure set up yet. - * Returns 0 on success. - */ -int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value) -{ - struct pci_dev *dev = NULL; - int result; - - dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); - dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); - if (dev) { - dbg("using native pci_dev\n"); - return pci_write_config_dword (dev, where, value); - } - - result = build_dev (ops, bus, slot, function, &dev); - if (result) - return result; - result = pci_write_config_dword(dev, where, value); - kfree (dev->bus); - kfree (dev); - return result; -} - /* * This is code that scans the pci buses. * Every bus and every function is presented to a custom @@ -394,10 +155,4 @@ EXPORT_SYMBOL(pci_visit_dev); -EXPORT_SYMBOL(pci_read_config_byte_nodev); -EXPORT_SYMBOL(pci_read_config_word_nodev); -EXPORT_SYMBOL(pci_read_config_dword_nodev); -EXPORT_SYMBOL(pci_write_config_byte_nodev); -EXPORT_SYMBOL(pci_write_config_word_nodev); -EXPORT_SYMBOL(pci_write_config_dword_nodev); diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Sat Aug 31 15:06:00 2002 +++ b/drivers/ide/ide-cd.c Sat Aug 31 15:06:00 2002 @@ -3005,14 +3005,8 @@ static void ide_cdrom_revalidate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - int unit = drive - hwif->drives; - struct gendisk *g = hwif->gd[unit]; struct request_sense sense; - cdrom_read_toc(drive, &sense); - g->minor_shift = 0; - grok_partitions(mk_kdev(g->major, drive->select.b.unit), current_capacity(drive)); } static @@ -3031,6 +3025,9 @@ { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *devinfo = &info->devinfo; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; if (ide_unregister_subdriver (drive)) return 1; @@ -3044,13 +3041,14 @@ printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; + del_gendisk(g); return 0; } -int ide_cdrom_init(void); -int ide_cdrom_reinit (ide_drive_t *drive); +static int ide_cdrom_reinit (ide_drive_t *drive); static ide_driver_t ide_cdrom_driver = { + owner: THIS_MODULE, name: "ide-cdrom", version: IDECD_VERSION, media: ide_cdrom, @@ -3079,17 +3077,10 @@ capacity: ide_cdrom_capacity, special: NULL, proc: NULL, - init: ide_cdrom_init, reinit: ide_cdrom_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, -}; - -static ide_module_t ide_cdrom_module = { - IDE_DRIVER_MODULE, - ide_cdrom_init, - &ide_cdrom_driver, - NULL + drives: LIST_HEAD_INIT(ide_cdrom_driver.drives), }; /* options */ @@ -3098,95 +3089,81 @@ MODULE_PARM(ignore, "s"); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); -int ide_cdrom_reinit (ide_drive_t *drive) +static int ide_cdrom_reinit (ide_drive_t *drive) { struct cdrom_info *info; - int failed = 0; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; + struct request_sense sense; - MOD_INC_USE_COUNT; + if (!strstr("ide-cdrom", drive->driver_req)) + goto failed; + if (!drive->present) + goto failed; + if (drive->media != ide_cdrom) + goto failed; + /* skip drives that we were told to ignore */ + if (ignore != NULL) { + if (strstr(ignore, drive->name)) { + printk("ide-cd: ignoring drive %s\n", drive->name); + goto failed; + } + } + if (drive->scsi) { + printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); + goto failed; + } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); - return 1; + goto failed; } if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) { printk ("%s: Failed to register the driver with ide.c\n", drive->name); kfree (info); - return 1; + goto failed; } memset (info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; DRIVER(drive)->busy++; if (ide_cdrom_setup (drive)) { + struct cdrom_device_info *devinfo = &info->devinfo; DRIVER(drive)->busy--; - if (ide_cdrom_cleanup (drive)) - printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); - return 1; + ide_unregister_subdriver (drive); + if (info->buffer != NULL) + kfree(info->buffer); + if (info->toc != NULL) + kfree(info->toc); + if (info->changer_info != NULL) + kfree(info->changer_info); + if (devinfo->handle == drive && unregister_cdrom (devinfo)) + printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); + kfree(info); + drive->driver_data = NULL; + goto failed; } DRIVER(drive)->busy--; - failed--; - ide_register_module(&ide_cdrom_module); - MOD_DEC_USE_COUNT; + cdrom_read_toc(drive, &sense); + g->minor_shift = 0; + add_gendisk(g); + register_disk(g, mk_kdev(g->major,g->first_minor), + 1<minor_shift, ide_fops, + g->part[0].nr_sects); return 0; +failed: + return 1; } static void __exit ide_cdrom_exit(void) { - ide_drive_t *drive; - int failed = 0; - - while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL) - if (ide_cdrom_cleanup (drive)) { - printk ("%s: cleanup_module() called while still busy\n", drive->name); - failed++; - } - ide_unregister_module (&ide_cdrom_module); + ide_unregister_driver(&ide_cdrom_driver); } -int ide_cdrom_init(void) +static int ide_cdrom_init(void) { - ide_drive_t *drive; - struct cdrom_info *info; - int failed = 0; - - MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { - /* skip drives that we were told to ignore */ - if (ignore != NULL) { - if (strstr(ignore, drive->name)) { - printk("ide-cd: ignoring drive %s\n", drive->name); - continue; - } - } - if (drive->scsi) { - printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); - if (info == NULL) { - printk ("%s: Can't allocate a cdrom structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) { - printk ("%s: Failed to register the driver with ide.c\n", drive->name); - kfree (info); - continue; - } - memset (info, 0, sizeof (struct cdrom_info)); - drive->driver_data = info; - DRIVER(drive)->busy++; - if (ide_cdrom_setup (drive)) { - DRIVER(drive)->busy--; - if (ide_cdrom_cleanup (drive)) - printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); - continue; - } - DRIVER(drive)->busy--; - failed--; - } - ide_register_module(&ide_cdrom_module); - MOD_DEC_USE_COUNT; + ide_register_driver(&ide_cdrom_driver); return 0; } diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Sat Aug 31 15:05:59 2002 +++ b/drivers/ide/ide-disk.c Sat Aug 31 15:05:59 2002 @@ -1629,20 +1629,26 @@ static int idedisk_cleanup (ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) if (do_idedisk_flushcache(drive)) printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", drive->name); - return ide_unregister_subdriver(drive); + if (ide_unregister_subdriver(drive)) + return 1; + del_gendisk(g); + return 0; } -int idedisk_init (void); -int idedisk_reinit(ide_drive_t *drive); +static int idedisk_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ static ide_driver_t idedisk_driver = { + owner: THIS_MODULE, name: "ide-disk", version: IDEDISK_VERSION, media: ide_disk, @@ -1667,92 +1673,64 @@ capacity: idedisk_capacity, special: idedisk_special, proc: idedisk_proc, - init: idedisk_init, reinit: idedisk_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, -}; - -static ide_module_t idedisk_module = { - IDE_DRIVER_MODULE, - idedisk_init, - &idedisk_driver, - NULL + drives: LIST_HEAD_INIT(idedisk_driver.drives), }; MODULE_DESCRIPTION("ATA DISK Driver"); -int idedisk_reinit (ide_drive_t *drive) +static int idedisk_reinit(ide_drive_t *drive) { - int failed = 0; - - MOD_INC_USE_COUNT; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; + + /* strstr("foo", "") is non-NULL */ + if (!strstr("ide-disk", drive->driver_req)) + goto failed; + if (!drive->present) + goto failed; + if (drive->media != ide_disk) + goto failed; if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); - return 1; + goto failed; } DRIVER(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - (void) idedisk_cleanup(drive); + if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) + if (do_idedisk_flushcache(drive)) + printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", + drive->name); + ide_unregister_subdriver(drive); DRIVER(drive)->busy--; - return 1; + goto failed; } DRIVER(drive)->busy--; - failed--; - - ide_register_module(&idedisk_module); - MOD_DEC_USE_COUNT; + g->minor_shift = PARTN_BITS; + add_gendisk(g); + register_disk(g, mk_kdev(g->major,g->first_minor), + 1<minor_shift, ide_fops, + current_capacity(drive)); return 0; +failed: + return 1; } static void __exit idedisk_exit (void) { - ide_drive_t *drive; - int failed = 0; - - while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) { - if (idedisk_cleanup (drive)) { - printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); - failed++; - } - /* We must remove proc entries defined in this module. - Otherwise we oops while accessing these entries */ -#ifdef CONFIG_PROC_FS - if (drive->proc) - ide_remove_proc_entries(drive->proc, idedisk_proc); -#endif - } - ide_unregister_module(&idedisk_module); + ide_unregister_driver(&idedisk_driver); } -int idedisk_init (void) +static int idedisk_init (void) { - ide_drive_t *drive; - int failed = 0; - - MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { - if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { - printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); - continue; - } - DRIVER(drive)->busy++; - idedisk_setup(drive); - if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { - printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - (void) idedisk_cleanup(drive); - DRIVER(drive)->busy--; - continue; - } - DRIVER(drive)->busy--; - failed--; - } - ide_register_module(&idedisk_module); - MOD_DEC_USE_COUNT; + ide_register_driver(&idedisk_driver); return 0; } diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Sat Aug 31 15:06:00 2002 +++ b/drivers/ide/ide-floppy.c Sat Aug 31 15:06:00 2002 @@ -2122,11 +2122,15 @@ static int idefloppy_cleanup (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; if (ide_unregister_subdriver (drive)) return 1; drive->driver_data = NULL; kfree (floppy); + del_gendisk(g); return 0; } @@ -2143,13 +2147,13 @@ #endif /* CONFIG_PROC_FS */ -int idefloppy_init (void); -int idefloppy_reinit(ide_drive_t *drive); +static int idefloppy_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ static ide_driver_t idefloppy_driver = { + owner: THIS_MODULE, name: "ide-floppy", version: IDEFLOPPY_VERSION, media: ide_floppy, @@ -2178,111 +2182,68 @@ capacity: idefloppy_capacity, special: NULL, proc: idefloppy_proc, - init: idefloppy_init, reinit: idefloppy_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, + drives: LIST_HEAD_INIT(idefloppy_driver.drives), }; -static ide_module_t idefloppy_module = { - IDE_DRIVER_MODULE, - idefloppy_init, - &idefloppy_driver, - NULL -}; - -int idefloppy_reinit (ide_drive_t *drive) +static int idefloppy_reinit (ide_drive_t *drive) { idefloppy_floppy_t *floppy; - int failed = 0; - - MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { - if (!idefloppy_identify_device (drive, drive->id)) { - printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); - continue; - } - if (drive->scsi) { - printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { - printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) { - printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (floppy); - continue; - } - DRIVER(drive)->busy++; - idefloppy_setup (drive, floppy); - DRIVER(drive)->busy--; - failed--; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive - hwif->drives; + struct gendisk *g = hwif->gd[unit]; + if (!strstr("ide-floppy", drive->driver_req)) + goto failed; + if (!drive->present) + goto failed; + if (drive->media != ide_floppy) + goto failed; + if (!idefloppy_identify_device (drive, drive->id)) { + printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); + goto failed; + } + if (drive->scsi) { + printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); + goto failed; } - ide_register_module(&idefloppy_module); - MOD_DEC_USE_COUNT; + if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { + printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); + goto failed; + } + if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); + kfree (floppy); + goto failed; + } + DRIVER(drive)->busy++; + idefloppy_setup (drive, floppy); + DRIVER(drive)->busy--; + g->minor_shift = PARTN_BITS; + add_gendisk(g); + register_disk(g, mk_kdev(g->major,g->first_minor), + 1<minor_shift, ide_fops, + g->part[0].nr_sects); return 0; +failed: + return 1; } MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); static void __exit idefloppy_exit (void) { - ide_drive_t *drive; - int failed = 0; - - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) { - if (idefloppy_cleanup (drive)) { - printk ("%s: cleanup_module() called while still busy\n", drive->name); - failed++; - } - /* We must remove proc entries defined in this module. - Otherwise we oops while accessing these entries */ -#ifdef CONFIG_PROC_FS - if (drive->proc) - ide_remove_proc_entries(drive->proc, idefloppy_proc); -#endif - } - ide_unregister_module(&idefloppy_module); + ide_unregister_driver(&idefloppy_driver); } /* * idefloppy_init will register the driver for each floppy. */ -int idefloppy_init (void) +static int idefloppy_init (void) { - ide_drive_t *drive; - idefloppy_floppy_t *floppy; - int failed = 0; - printk("ide-floppy driver " IDEFLOPPY_VERSION "\n"); - MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { - if (!idefloppy_identify_device (drive, drive->id)) { - printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); - continue; - } - if (drive->scsi) { - printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { - printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) { - printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (floppy); - continue; - } - DRIVER(drive)->busy++; - idefloppy_setup (drive, floppy); - DRIVER(drive)->busy--; - failed--; - } - ide_register_module(&idefloppy_module); - MOD_DEC_USE_COUNT; + ide_register_driver(&idefloppy_driver); return 0; } diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Sat Aug 31 15:06:00 2002 +++ b/drivers/ide/ide-probe.c Sat Aug 31 15:06:00 2002 @@ -555,6 +555,7 @@ */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; + drive->dn = ((hwif->channel ? 2 : 0) + unit); (void) probe_for_drive (drive); if (drive->present && !hwif->present) { hwif->present = 1; @@ -585,6 +586,17 @@ if (hwif->tuneproc != NULL && drive->autotune == 1) /* auto-tune PIO mode */ hwif->tuneproc(drive, 255); + + if ((drive->autotune != 2) && hwif->dmaproc != NULL) { + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting + * things, if not checked and cleared. + * PARANOIA!!! + */ + hwif->dmaproc(ide_dma_off_quietly, drive); + hwif->dmaproc(ide_dma_check, drive); + } } } } @@ -852,14 +864,12 @@ gd[unit].nr_real = 1; gd[unit].fops = ide_fops; hwif->gd[unit] = gd + unit; - add_gendisk(gd + unit); } for (unit = 0; unit < units; ++unit) { #if 1 char name[64]; ide_add_generic_settings(hwif->drives + unit); - hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); sprintf (name, "host%d/bus%d/target%d/lun%d", (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, @@ -871,7 +881,6 @@ char name[64]; ide_add_generic_settings(hwif->drives + unit); - hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); sprintf (name, "host%d/bus%d/target%d/lun%d", (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, hwif->channel, unit, hwif->drives[unit].lun); @@ -997,6 +1006,15 @@ for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) hwif_init(&ide_hwifs[index]); + for (index = 0; index < MAX_HWIFS; ++index) + if (probe[index]) { + ide_hwif_t *hwif = &ide_hwifs[index]; + int unit; + if (!hwif->present) + continue; + for (unit = 0; unit < MAX_DRIVES; ++unit) + ata_attach(&hwif->drives[unit]); + } if (!ide_probe) ide_probe = &ideprobe_module; MOD_DEC_USE_COUNT; diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c --- a/drivers/ide/ide-proc.c Sat Aug 31 15:05:53 2002 +++ b/drivers/ide/ide-proc.c Sat Aug 31 15:05:53 2002 @@ -67,6 +67,7 @@ #include #include #include +#include #include @@ -374,24 +375,6 @@ return digit; } -static int proc_ide_read_drivers - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - char *out = page; - int len; - ide_module_t *p = ide_modules; - ide_driver_t *driver; - - while (p) { - driver = (ide_driver_t *) p->info; - if (driver) - out += sprintf(out, "%s version %s\n", driver->name, driver->version); - p = p->next; - } - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_ide_read_imodel (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -832,15 +815,29 @@ } } +extern struct seq_operations ide_drivers_op; +static int ide_drivers_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ide_drivers_op); +} +static struct file_operations ide_drivers_operations = { + open: ide_drivers_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; + void proc_ide_create(void) { + struct proc_dir_entry *entry; proc_ide_root = proc_mkdir("ide", 0); if (!proc_ide_root) return; create_proc_ide_interfaces(); - create_proc_read_entry("drivers", 0, proc_ide_root, - proc_ide_read_drivers, NULL); + entry = create_proc_entry("drivers", 0, proc_ide_root); + if (entry) + entry->proc_fops = &ide_drivers_operations; #ifdef CONFIG_BLK_DEV_AEC62XX if ((aec62xx_display_info) && (aec62xx_proc)) diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Sat Aug 31 15:05:59 2002 +++ b/drivers/ide/ide-tape.c Sat Aug 31 15:05:59 2002 @@ -1424,7 +1424,6 @@ * Additional state variables are defined in our ide_drive_t structure. */ static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; -static int idetape_chrdev_present = 0; #if IDETAPE_DEBUG_LOG_VERBOSE @@ -6272,11 +6271,6 @@ devfs_unregister(tape->de_r); devfs_unregister(tape->de_n); kfree (tape); - for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) - if (idetape_chrdevs[minor].drive != NULL) - return 0; - unregister_chrdev(IDETAPE_MAJOR, "ht"); - idetape_chrdev_present = 0; return 0; } @@ -6305,13 +6299,13 @@ #endif -int idetape_init (void); -int idetape_reinit(ide_drive_t *drive); +static int idetape_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ static ide_driver_t idetape_driver = { + owner: THIS_MODULE, name: "ide-tape", version: IDETAPE_VERSION, media: ide_tape, @@ -6340,17 +6334,10 @@ capacity: NULL, special: NULL, proc: idetape_proc, - init: idetape_init, reinit: idetape_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, -}; - -static ide_module_t idetape_module = { - IDE_DRIVER_MODULE, - idetape_init, - &idetape_driver, - NULL + drives: LIST_HEAD_INIT(idetape_driver.drives), }; /* @@ -6365,91 +6352,57 @@ release: idetape_chrdev_release, }; -int idetape_reinit (ide_drive_t *drive) +static int idetape_reinit (ide_drive_t *drive) { -#if 0 idetape_tape_t *tape; - int minor, failed = 0, supported = 0; -/* DRIVER(drive)->busy++; */ - MOD_INC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); -#endif - if (!idetape_chrdev_present) - for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) - idetape_chrdevs[minor].drive = NULL; + int minor; - if ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { - ide_register_module(&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - return 0; - } - if (!idetape_chrdev_present && - register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { - printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - return -EBUSY; - } - do { - if (!idetape_identify_device(drive, drive->id)) { - printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); - continue; - } - if (drive->scsi) { - if (strstr(drive->id->model, "OnStream DI-30")) { - printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); - } else { - printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - } - tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); - if (tape == NULL) { - printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) { - printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); - kfree(tape); - continue; + if (!strstr("ide-tape", drive->driver_req)) + goto failed; + if (!drive->present) + goto failed; + if (drive->media != ide_tape) + goto failed; + if (!idetape_identify_device (drive, drive->id)) { + printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); + goto failed; + } + if (drive->scsi) { + if (strstr(drive->id->model, "OnStream DI-")) { + printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); + } else { + printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); + goto failed; } - for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++); - idetape_setup(drive, tape, minor); - idetape_chrdevs[minor].drive = drive; - tape->de_r = - devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - tape->de_n = - devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor + 128, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - devfs_register_tape(tape->de_r); - supported++; - failed--; - } while ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) != NULL); - if (!idetape_chrdev_present && !supported) { - devfs_unregister_chrdev(IDETAPE_MAJOR, "ht"); - } else - idetape_chrdev_present = 1; - ide_register_module(&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - + } + tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); + if (tape == NULL) { + printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); + goto failed; + } + if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) { + printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); + kfree(tape); + goto failed; + } + for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++) + ; + idetape_setup(drive, tape, minor); + idetape_chrdevs[minor].drive = drive; + tape->de_r = + devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor, + S_IFCHR | S_IRUGO | S_IWUGO, + &idetape_fops, NULL); + tape->de_n = + devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor + 128, + S_IFCHR | S_IRUGO | S_IWUGO, + &idetape_fops, NULL); + devfs_register_tape(tape->de_r); return 0; -#else +failed: return 1; -#endif } MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); @@ -6457,100 +6410,20 @@ static void __exit idetape_exit (void) { - ide_drive_t *drive; - int minor; - - for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) { - drive = idetape_chrdevs[minor].drive; - if (drive != NULL && idetape_cleanup (drive)) - printk(KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name); - } - ide_unregister_module(&idetape_module); + ide_unregister_driver(&idetape_driver); + unregister_chrdev(IDETAPE_MAJOR, "ht"); } /* * idetape_init will register the driver for each tape. */ -int idetape_init (void) +static int idetape_init (void) { - ide_drive_t *drive; - idetape_tape_t *tape; - int minor, failed = 0, supported = 0; -/* DRIVER(drive)->busy++; */ - MOD_INC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); -#endif - if (!idetape_chrdev_present) - for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) - idetape_chrdevs[minor].drive = NULL; - - if ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { - ide_register_module(&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - return 0; - } - if (!idetape_chrdev_present && - register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { + if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif return -EBUSY; } - do { - if (!idetape_identify_device (drive, drive->id)) { - printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); - continue; - } - if (drive->scsi) { - if (strstr(drive->id->model, "OnStream DI-")) { - printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); - } else { - printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - } - tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); - if (tape == NULL) { - printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) { - printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); - kfree(tape); - continue; - } - for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++); - idetape_setup(drive, tape, minor); - idetape_chrdevs[minor].drive = drive; - tape->de_r = - devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - tape->de_n = - devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor + 128, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - devfs_register_tape(tape->de_r); - supported++; - failed--; - } while ((drive = ide_scan_devices(ide_tape, idetape_driver.name, NULL, failed++)) != NULL); - if (!idetape_chrdev_present && !supported) { - unregister_chrdev(IDETAPE_MAJOR, "ht"); - } else - idetape_chrdev_present = 1; - ide_register_module(&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif + ide_register_driver(&idetape_driver); return 0; } diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Sat Aug 31 15:05:55 2002 +++ b/drivers/ide/ide.c Sat Aug 31 15:05:55 2002 @@ -151,6 +151,7 @@ #include #include #include +#include #include #include @@ -177,7 +178,6 @@ #ifdef CONFIG_BLK_DEV_IDESCSI_24 #define CONFIG_BLK_DEV_IDESCSI -extern int idescsi_init(void); #endif #ifdef CONFIG_BLK_DEV_IDEPCI @@ -197,7 +197,6 @@ /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ -ide_module_t *ide_modules; ide_module_t *ide_probe; /* @@ -277,6 +276,7 @@ drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; drive->max_failures = IDE_DEFAULT_MAX_FAILURES; init_waitqueue_head(&drive->wqueue); + INIT_LIST_HEAD(&drive->list); } } @@ -443,30 +443,6 @@ } extern struct block_device_operations ide_fops[]; -/* - * ide_geninit() is called exactly *once* for each interface. - */ -void ide_geninit (ide_hwif_t *hwif) -{ - unsigned int unit; - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - struct gendisk *gd = hwif->gd[unit]; - - if (!drive->present) - continue; - if (drive->media!=ide_disk && drive->media!=ide_floppy - && drive->media != ide_cdrom) - continue; - register_disk(gd,mk_kdev(hwif->major,unit<forced_geom && drive->noprobe) ? 1 : -#endif /* CONFIG_BLK_DEV_ISAPNP */ - 1<drives; struct gendisk *g = hwif->gd[unit]; - int minor = (drive->select.b.unit << g->minor_shift); - - grok_partitions(mk_kdev(g->major, minor), current_capacity(drive)); + g->part[0].nr_sects = current_capacity(drive); } /* @@ -1788,53 +1762,14 @@ * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -int ide_revalidate_disk (kdev_t i_rdev) +static int ide_revalidate_disk (kdev_t i_rdev) { ide_drive_t *drive; - ide_hwgroup_t *hwgroup; - unsigned long flags; - int res; - if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; - hwgroup = HWGROUP(drive); - spin_lock_irqsave(&ide_lock, flags); - if (drive->busy || (drive->usage > 1)) { - spin_unlock_irqrestore(&ide_lock, flags); - return -EBUSY; - }; - drive->busy = 1; - MOD_INC_USE_COUNT; - spin_unlock_irqrestore(&ide_lock, flags); - - res = wipe_partitions(i_rdev); - - if (!res && DRIVER(drive)->revalidate) + if (DRIVER(drive)->revalidate) DRIVER(drive)->revalidate(drive); - - drive->busy = 0; - wake_up(&drive->wqueue); - MOD_DEC_USE_COUNT; - return res; -} - -static void revalidate_drives (void) -{ - ide_hwif_t *hwif; - ide_drive_t *drive; - int index, unit; - - for (index = 0; index < MAX_HWIFS; ++index) { - hwif = &ide_hwifs[index]; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - drive = &ide_hwifs[index].drives[unit]; - if (drive->revalidate) { - drive->revalidate = 0; - if (!initializing) - (void) ide_revalidate_disk(mk_kdev(hwif->major, unit<init(); } - revalidate_drives(); -} - -static void ide_driver_module (void) -{ - int index; - ide_module_t *module = ide_modules; - - for (index = 0; index < MAX_HWIFS; ++index) - if (ide_hwifs[index].present) - goto search; - ide_probe_module(); -search: - while (module) { - (void) module->init(); - module = module->next; - } - revalidate_drives(); } static int ide_open (struct inode * inode, struct file * filp) @@ -1872,8 +1789,6 @@ if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENXIO; - if (drive->driver == NULL) - ide_driver_module(); #ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) @@ -1916,6 +1831,50 @@ return 0; } +static LIST_HEAD(ata_unused); +static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(drivers); + +/* Iterator */ +static void *m_start(struct seq_file *m, loff_t *pos) +{ + struct list_head *p; + loff_t l = *pos; + spin_lock(&drivers_lock); + list_for_each(p, &drivers) + if (!l--) + return list_entry(p, ide_driver_t, drivers); + return NULL; +} +static void *m_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct list_head *p = ((ide_driver_t *)v)->drivers.next; + (*pos)++; + return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers); +} +static void m_stop(struct seq_file *m, void *v) +{ + spin_unlock(&drivers_lock); +} +static int show_driver(struct seq_file *m, void *v) +{ + ide_driver_t *driver = v; + seq_printf(m, "%s version %s\n", driver->name, driver->version); + return 0; +} +struct seq_operations ide_drivers_op = { + start: m_start, + next: m_next, + stop: m_stop, + show: show_driver +}; + +/* + * Locking is badly broken here - since way back. That sucker is + * root-only, but that's not an excuse... The real question is what + * exclusion rules do we want here. + */ int ide_replace_subdriver (ide_drive_t *drive, const char *driver) { if (!drive->present || drive->busy || drive->usage) @@ -1923,9 +1882,15 @@ if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); - ide_driver_module(); - drive->driver_req[0] = 0; - ide_driver_module(); + if (ata_attach(drive)) { + spin_lock(&drives_lock); + list_del_init(&drive->list); + spin_unlock(&drives_lock); + drive->driver_req[0] = 0; + ata_attach(drive); + } else { + drive->driver_req[0] = 0; + } if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0; abort: @@ -2096,8 +2061,6 @@ gd = hwif->gd[0]; if (gd) { int i; - for (i = 0; i < MAX_DRIVES; i++) - del_gendisk(gd + i); kfree(gd->part); if (gd->de_arr) kfree (gd->de_arr); @@ -2221,7 +2184,6 @@ #ifdef CONFIG_PROC_FS create_proc_ide_interfaces(); #endif - ide_driver_module(); } if (hwifp) @@ -2509,59 +2471,29 @@ return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); } -int ide_reinit_drive (ide_drive_t *drive) +int ata_attach(ide_drive_t *drive) { - switch (drive->media) { -#ifdef CONFIG_BLK_DEV_IDECD - case ide_cdrom: - { - extern int ide_cdrom_reinit(ide_drive_t *drive); - if (ide_cdrom_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDEDISK - case ide_disk: - { - extern int idedisk_reinit(ide_drive_t *drive); - if (idedisk_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY - case ide_floppy: - { - extern int idefloppy_reinit(ide_drive_t *drive); - if (idefloppy_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDETAPE - case ide_tape: - { - extern int idetape_reinit(ide_drive_t *drive); - if (idetape_reinit(drive)) - return 1; - break; + struct list_head *p; + spin_lock(&drivers_lock); + list_for_each(p, &drivers) { + ide_driver_t *driver = list_entry(p, ide_driver_t, drivers); + if (!try_inc_mod_count(driver->owner)) + continue; + spin_unlock(&drivers_lock); + if (driver->reinit(drive) == 0) { + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); + return 0; } -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDESCSI -/* - * { - * extern int idescsi_reinit(ide_drive_t *drive); - * if (idescsi_reinit(drive)) - * return 1; - * break; - * } - */ -#endif /* CONFIG_BLK_DEV_IDESCSI */ - default: - return 1; - } - return 0; + spin_lock(&drivers_lock); + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); + } + spin_unlock(&drivers_lock); + spin_lock(&drives_lock); + list_add(&drive->list, &ata_unused); + spin_unlock(&drives_lock); + return 1; } static int ide_ioctl (struct inode *inode, struct file *file, @@ -2615,10 +2547,6 @@ return 0; } - case BLKRRPART: /* Re-read partition tables */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - return ide_revalidate_disk(inode->i_rdev); - case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (minor(inode->i_rdev) & PARTN_MASK) @@ -2720,7 +2648,8 @@ * } * HWIF(drive)->multiproc(drive); */ - return ide_revalidate_disk(inode->i_rdev); + return file->f_op->ioctl(inode, file, + BLKRRPART, 0); } return 0; } @@ -3382,29 +3311,6 @@ #ifdef CONFIG_PROC_FS proc_ide_create(); #endif - - /* - * Attempt to match drivers for the available drives - */ -#ifdef CONFIG_BLK_DEV_IDEDISK - (void) idedisk_init(); -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDECD - (void) ide_cdrom_init(); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - (void) idetape_init(); -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY - (void) idefloppy_init(); -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDESCSI - #ifdef CONFIG_SCSI - (void) idescsi_init(); - #else - #warning ide scsi-emulation selected but no SCSI-subsystem in kernel - #endif -#endif /* CONFIG_BLK_DEV_IDESCSI */ } static int default_cleanup (ide_drive_t *drive) @@ -3492,11 +3398,6 @@ return ide_stopped; } -static int default_init (void) -{ - return 0; -} - static int default_reinit (ide_drive_t *drive) { printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name); @@ -3524,30 +3425,9 @@ if (d->pre_reset == NULL) d->pre_reset = default_pre_reset; if (d->capacity == NULL) d->capacity = default_capacity; if (d->special == NULL) d->special = default_special; - if (d->init == NULL) d->init = default_init; if (d->reinit == NULL) d->reinit = default_reinit; } -ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n) -{ - unsigned int unit, index, i; - - for (index = 0, i = 0; index < MAX_HWIFS; ++index) { - ide_hwif_t *hwif = &ide_hwifs[index]; - if (!hwif->present) - continue; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - char *req = drive->driver_req; - if (*req && !strstr(name, req)) - continue; - if (drive->present && drive->media == media && drive->driver == driver && ++i > n) - return drive; - } - } - return NULL; -} - int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version) { unsigned long flags; @@ -3561,21 +3441,15 @@ drive->driver = driver; setup_driver_defaults(drive); spin_unlock_irqrestore(&ide_lock, flags); + spin_lock(&drives_lock); + list_add(&drive->list, &driver->drives); + spin_unlock(&drives_lock); if (drive->autotune != 2) { - if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { - /* - * Force DMAing for the beginning of the check. - * Some chipsets appear to do interesting things, - * if not checked and cleared. - * PARANOIA!!! - */ + if (!driver->supports_dma && HWIF(drive)->dmaproc != NULL) (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); - (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); - } drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); drive->nice1 = 1; } - drive->revalidate = 1; drive->suspend_reset = 0; #ifdef CONFIG_PROC_FS ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); @@ -3604,31 +3478,55 @@ auto_remove_settings(drive); drive->driver = NULL; spin_unlock_irqrestore(&ide_lock, flags); + spin_lock(&drives_lock); + list_del_init(&drive->list); + spin_unlock(&drives_lock); return 0; } -int ide_register_module (ide_module_t *module) +int ide_register_driver(ide_driver_t *driver) { - ide_module_t *p = ide_modules; + struct list_head list; - while (p) { - if (p == module) - return 1; - p = p->next; - } - module->next = ide_modules; - ide_modules = module; - revalidate_drives(); + spin_lock(&drivers_lock); + list_add(&driver->drivers, &drivers); + spin_unlock(&drivers_lock); + + spin_lock(&drives_lock); + INIT_LIST_HEAD(&list); + list_splice_init(&ata_unused, &list); + spin_unlock(&drives_lock); + + while (!list_empty(&list)) { + ide_drive_t *drive = list_entry(list.next, ide_drive_t, list); + list_del_init(&drive->list); + ata_attach(drive); + } return 0; } -void ide_unregister_module (ide_module_t *module) +void ide_unregister_driver(ide_driver_t *driver) { - ide_module_t **p; + ide_drive_t *drive; - for (p = &ide_modules; (*p) && (*p) != module; p = &((*p)->next)); - if (*p) - *p = (*p)->next; + spin_lock(&drivers_lock); + list_del(&driver->drivers); + spin_unlock(&drivers_lock); + + while(!list_empty(&driver->drives)) { + drive = list_entry(driver->drives.next, ide_drive_t, list); + if (driver->cleanup(drive)) { + printk("%s: cleanup_module() called while still busy\n", drive->name); + BUG(); + } + /* We must remove proc entries defined in this module. + Otherwise we oops while accessing these entries */ +#ifdef CONFIG_PROC_FS + if (drive->proc) + ide_remove_proc_entries(drive->proc, driver->proc); +#endif + ata_attach(drive); + } } struct block_device_operations ide_fops[] = {{ @@ -3641,8 +3539,8 @@ }}; EXPORT_SYMBOL(ide_hwifs); -EXPORT_SYMBOL(ide_register_module); -EXPORT_SYMBOL(ide_unregister_module); +EXPORT_SYMBOL(ide_register_driver); +EXPORT_SYMBOL(ide_unregister_driver); EXPORT_SYMBOL(ide_spin_wait_hwgroup); /* @@ -3663,7 +3561,6 @@ /* * Driver module */ -EXPORT_SYMBOL(ide_scan_devices); EXPORT_SYMBOL(ide_register_subdriver); EXPORT_SYMBOL(ide_unregister_subdriver); EXPORT_SYMBOL(ide_replace_subdriver); @@ -3678,7 +3575,6 @@ EXPORT_SYMBOL(ide_end_drive_cmd); EXPORT_SYMBOL(ide_end_request); EXPORT_SYMBOL(ide_revalidate_drive); -EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); EXPORT_SYMBOL(ide_wait_cmd_task); @@ -3705,7 +3601,7 @@ EXPORT_SYMBOL(system_bus_clock); -EXPORT_SYMBOL(ide_reinit_drive); +EXPORT_SYMBOL(ata_attach); static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x) { @@ -3759,8 +3655,6 @@ int __init ide_init (void) { static char banner_printed; - int i; - if (!banner_printed) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); @@ -3773,12 +3667,6 @@ initializing = 1; ide_init_builtin_drivers(); initializing = 0; - - for (i = 0; i < MAX_HWIFS; ++i) { - ide_hwif_t *hwif = &ide_hwifs[i]; - if (hwif->present) - ide_geninit(hwif); - } register_reboot_notifier(&ide_notifier); return 0; diff -Nru a/drivers/input/Config.in b/drivers/input/Config.in --- a/drivers/input/Config.in Sat Aug 31 15:06:00 2002 +++ b/drivers/input/Config.in Sat Aug 31 15:06:00 2002 @@ -9,7 +9,7 @@ comment 'Userland interfaces' dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT -dep_mbool ' Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT +dep_mbool ' Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT_MOUSEDEV if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 diff -Nru a/drivers/input/input.c b/drivers/input/input.c --- a/drivers/input/input.c Sat Aug 31 15:06:00 2002 +++ b/drivers/input/input.c Sat Aug 31 15:06:00 2002 @@ -1,29 +1,13 @@ /* - * $Id: input.c,v 1.48 2001/12/26 21:08:33 jsimmons Exp $ + * The input core * - * Copyright (c) 1999-2001 Vojtech Pavlik - * - * The input core + * Copyright (c) 1999-2002 Vojtech Pavlik */ /* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. */ #include @@ -39,7 +23,7 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); @@ -54,6 +38,7 @@ EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); +EXPORT_SYMBOL(input_devclass); #define INPUT_MAJOR 13 #define INPUT_DEVICES 256 @@ -337,7 +322,7 @@ int i = 0, j, value; if (!hotplug_path[0]) { - printk(KERN_ERR "input.c: calling hotplug a hotplug agent defined\n"); + printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n"); return; } if (in_interrupt()) { @@ -395,16 +380,20 @@ envp[i++] = 0; +#ifdef INPUT_DEBUG printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); +#endif value = call_usermodehelper(argv [0], argv, envp); kfree(buf); kfree(envp); +#ifdef INPUT_DEBUG if (value != 0) - printk(KERN_WARNING "input.c: hotplug returned %d\n", value); + printk(KERN_DEBUG "input.c: hotplug returned %d\n", value); +#endif } #endif @@ -415,31 +404,17 @@ struct input_handle *handle; struct input_device_id *id; -/* - * Add the EV_SYN capability. - */ - set_bit(EV_SYN, dev->evbit); -/* - * Initialize repeat timer to default values. - */ - init_timer(&dev->timer); dev->timer.data = (long) dev; dev->timer.function = input_repeat_key; dev->rep[REP_DELAY] = HZ/4; dev->rep[REP_PERIOD] = HZ/33; -/* - * Add the device. - */ INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node,&input_dev_list); -/* - * Notify handlers. - */ list_for_each(node,&input_handler_list) { struct input_handler *handler = to_handler(node); if ((id = input_match_device(handler->id_table, dev))) @@ -447,18 +422,10 @@ input_link_handle(handle); } -/* - * Notify the hotplug agent. - */ - #ifdef CONFIG_HOTPLUG input_call_hotplug("add", dev); #endif -/* - * Notify /proc. - */ - #ifdef CONFIG_PROC_FS input_devices_state++; wake_up(&input_devices_poll_wait); @@ -471,22 +438,11 @@ if (!dev) return; -/* - * Turn off power management for the device. - */ if (dev->pm_dev) pm_unregister(dev->pm_dev); -/* - * Kill any pending repeat timers. - */ - del_timer_sync(&dev->timer); -/* - * Notify handlers. - */ - list_for_each_safe(node,next,&dev->h_list) { struct input_handle * handle = to_handle(node); list_del_init(&handle->d_node); @@ -494,23 +450,12 @@ handle->handler->disconnect(handle); } -/* - * Notify the hotplug agent. - */ - #ifdef CONFIG_HOTPLUG input_call_hotplug("remove", dev); #endif -/* - * Remove the device. - */ list_del_init(&dev->node); -/* - * Notify /proc. - */ - #ifdef CONFIG_PROC_FS input_devices_state++; wake_up(&input_devices_poll_wait); @@ -526,22 +471,12 @@ if (!handler) return; INIT_LIST_HEAD(&handler->h_list); -/* - * Add minors if needed. - */ if (handler->fops != NULL) input_table[handler->minor >> 5] = handler; -/* - * Add the handler. - */ list_add_tail(&handler->node,&input_handler_list); -/* - * Notify it about all existing devices. - */ - list_for_each(node,&input_dev_list) { struct input_dev *dev = to_dev(node); if ((id = input_match_device(handler->id_table, dev))) @@ -549,10 +484,6 @@ input_link_handle(handle); } -/* - * Notify /proc. - */ - #ifdef CONFIG_PROC_FS input_devices_state++; wake_up(&input_devices_poll_wait); @@ -563,10 +494,6 @@ { struct list_head * node, * next; - -/* - * Tell the handler to disconnect from all devices it keeps open. - */ list_for_each_safe(node,next,&handler->h_list) { struct input_handle * handle = to_handle_h(node); list_del_init(&handle->h_node); @@ -574,21 +501,11 @@ handler->disconnect(handle); } -/* - * Remove it. - */ list_del_init(&handler->node); -/* - * Remove minors. - */ if (handler->fops != NULL) input_table[handler->minor >> 5] = NULL; -/* - * Notify /proc. - */ - #ifdef CONFIG_PROC_FS input_devices_state++; wake_up(&input_devices_poll_wait); @@ -643,10 +560,6 @@ { devfs_unregister(handle); } - -/* - * ProcFS interface for the input drivers. - */ #ifdef CONFIG_PROC_FS diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c --- a/drivers/input/keyboard/atkbd.c Sat Aug 31 15:06:06 2002 +++ b/drivers/input/keyboard/atkbd.c Sat Aug 31 15:06:06 2002 @@ -1,27 +1,13 @@ /* - * $Id: atkbd.c,v 1.33 2002/02/12 09:34:34 vojtech Exp $ + * AT and PS/2 keyboard driver * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2002 Vojtech Pavlik */ /* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. */ #include @@ -33,7 +19,7 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); MODULE_PARM(atkbd_set, "1i"); MODULE_LICENSE("GPL"); @@ -94,9 +80,11 @@ #define ATKBD_CMD_SETLEDS 0x10ed #define ATKBD_CMD_GSCANSET 0x11f0 #define ATKBD_CMD_SSCANSET 0x10f0 -#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_GETID 0x01f2 +#define ATKBD_CMD_GETID2 0x0100 #define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_RESET_BAT 0x01ff #define ATKBD_CMD_SETALL_MB 0x00f8 #define ATKBD_CMD_RESEND 0x00fe #define ATKBD_CMD_EX_ENABLE 0x10ea @@ -147,7 +135,7 @@ #endif /* Interface error. Request that the keyboard resend. */ - if ((flags & (SERIO_FRAME | SERIO_PARITY)) && atkbd->write) { + if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && atkbd->write) { printk("atkbd.c: frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); return; @@ -360,70 +348,60 @@ unsigned char param[2]; /* - * Full reset with selftest can on some keyboards be annoyingly slow, - * so we just do a reset-and-disable on the keyboard, which - * is considerably faster, but doesn't have to reset everything. + * Some systems, where the bit-twiddling when testing the io-lines of the + * controller may confuse the keyboard need a full reset of the keyboard. On + * these systems the BIOS also usually doesn't do it for us. */ - if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS)) +#ifdef CONFIG_KEYBOARD_ATKBD_RESET + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) printk(KERN_WARNING "atkbd.c: keyboard reset failed\n"); +#endif /* - * Next, we check if it's a keyboard. It should send 0xab83 - * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard, - * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f - * on Fujitsu Lifebook). - * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse), - * and we'll time out here, and report an error. + * Next we check we can set LEDs on the keyboard. This should work on every + * keyboard out there. It also turns the LEDs off, which we want anyway. */ - param[0] = param[1] = 0; - - if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) + param[0] = 0; + if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) return -1; - atkbd->id = (param[0] << 8) | param[1]; - - if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 && - atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03) - printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n", - atkbd->id, atkbd->serio->phys); - - return 0; -} - /* - * atkbd_initialize() sets the keyboard into a sane state. + * Then we check the keyboard ID. We should get 0xab83 under normal conditions. + * Some keyboards report different values, but the first byte is always 0xab or + * 0xac. Some old AT keyboards don't report anything. */ -static void atkbd_initialize(struct atkbd *atkbd) -{ - unsigned char param; + if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) { + atkbd->id = 0xabba; + return 0; + } + if (param[0] != 0xab && param[0] != 0xac) + return -1; + atkbd->id = param[0] << 8; + if (atkbd_command(atkbd, param, ATKBD_CMD_GETID2)) + return -1; + atkbd->id |= param[0]; /* * Disable autorepeat. We don't need it, as we do it in software anyway, - * because that way can get faster repeat, and have less system load - * (less accesses to the slow ISA hardware). If this fails, we don't care, - * and will just ignore the repeated keys. + * because that way can get faster repeat, and have less system load (less + * accesses to the slow ISA hardware). If this fails, we don't care, and will + * just ignore the repeated keys. */ atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB); /* - * We also shut off all the leds. The console code will turn them back on, - * if needed. - */ - - param = 0; - atkbd_command(atkbd, ¶m, ATKBD_CMD_SETLEDS); - -/* - * Last, we enable the keyboard so that we get keypresses from it. + * Last, we enable the keyboard to make sure that we get keypresses from it. */ if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", atkbd->serio->phys); + + return 0; } /* @@ -524,9 +502,6 @@ input_register_device(&atkbd->dev); printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); - - if (atkbd->write) - atkbd_initialize(atkbd); } diff -Nru a/drivers/input/misc/Config.help b/drivers/input/misc/Config.help --- a/drivers/input/misc/Config.help Sat Aug 31 15:06:06 2002 +++ b/drivers/input/misc/Config.help Sat Aug 31 15:06:06 2002 @@ -17,6 +17,17 @@ The module will be called pcspkr.o. If you want to compile it as a module, say M here and read . +CONFIG_INPUT_SPARCSPKR + Say Y here if you want the standard Speaker on Sparc PCI systems + to be used for bells and whistles. + + If unsure, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pcspkr.o. If you want to compile it as a + module, say M here and read . + CONFIG_INPUT_UINPUT Say Y here if you want to support user level drivers for input diff -Nru a/drivers/input/misc/Config.in b/drivers/input/misc/Config.in --- a/drivers/input/misc/Config.in Sat Aug 31 15:06:04 2002 +++ b/drivers/input/misc/Config.in Sat Aug 31 15:06:04 2002 @@ -5,4 +5,7 @@ bool 'Misc' CONFIG_INPUT_MISC dep_tristate ' PC Speaker support' CONFIG_INPUT_PCSPKR $CONFIG_INPUT $CONFIG_INPUT_MISC +if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then + dep_tristate ' SPARC Speaker support' CONFIG_INPUT_SPARCSPKR $CONFIG_INPUT $CONFIG_INPUT_MISC +fi dep_tristate ' User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_INPUT_MISC diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile --- a/drivers/input/misc/Makefile Sat Aug 31 15:06:01 2002 +++ b/drivers/input/misc/Makefile Sat Aug 31 15:06:01 2002 @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o diff -Nru a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/misc/sparcspkr.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,189 @@ +/* + * Driver for PC-speaker like devices found on various Sparc systems. + * + * Copyright (c) 2002 Vojtech Pavlik + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + */ +#include +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_SPARC64 +#include +#endif + +MODULE_AUTHOR("David S. Miller "); +MODULE_DESCRIPTION("PC Speaker beeper driver"); +MODULE_LICENSE("GPL"); + +static unsigned long beep_iobase; + +static char *sparcspkr_isa_name = "Sparc ISA Speaker"; +static char *sparcspkr_ebus_name = "Sparc EBUS Speaker"; +static char *sparcspkr_phys = "sparc/input0"; +static struct input_dev sparcspkr_dev; + +spinlock_t beep_lock = SPIN_LOCK_UNLOCKED; + +static void __init init_sparcspkr_struct(void) +{ + sparcspkr_dev.evbit[0] = BIT(EV_SND); + sparcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + + sparcspkr_dev.phys = sparcspkr_phys; + sparcspkr_dev.id.bustype = BUS_ISA; + sparcspkr_dev.id.vendor = 0x001f; + sparcspkr_dev.id.product = 0x0001; + sparcspkr_dev.id.version = 0x0100; +} + +static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + unsigned int count = 0; + unsigned long flags; + + if (type != EV_SND) + return -1; + + switch (code) { + case SND_BELL: if (value) value = 1000; + case SND_TONE: break; + default: return -1; + } + + if (value > 20 && value < 32767) + count = 1193182 / value; + + spin_lock_irqsave(&beep_lock, flags); + + /* EBUS speaker only has on/off state, the frequency does not + * appear to be programmable. + */ + if (count) { + if (beep_iobase & 0x2UL) + outb(1, beep_iobase); + else + outl(1, beep_iobase); + } else { + if (beep_iobase & 0x2UL) + outb(0, beep_iobase); + else + outl(0, beep_iobase); + } + + spin_unlock_irqrestore(&beep_lock, flags); + + return 0; +} + +static int __init init_ebus_beep(struct linux_ebus_device *edev) +{ + beep_iobase = edev->resource[0].start; + + init_sparcspkr_struct(); + + sparcspkr_dev.name = sparcspkr_ebus_name; + sparcspkr_dev.event = ebus_spkr_event; + + input_register_device(&sparcspkr_dev); + + printk(KERN_INFO "input: %s\n", sparcspkr_ebus_name); + return 0; +} + +#ifdef CONFIG_SPARC64 +static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + unsigned int count = 0; + unsigned long flags; + + if (type != EV_SND) + return -1; + + switch (code) { + case SND_BELL: if (value) value = 1000; + case SND_TONE: break; + default: return -1; + } + + if (value > 20 && value < 32767) + count = 1193182 / value; + + spin_lock_irqsave(&beep_lock, flags); + + if (count) { + /* enable counter 2 */ + outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); + /* set command for counter 2, 2 byte write */ + outb(0xB6, beep_iobase + 0x43); + /* select desired HZ */ + outb(count & 0xff, beep_iobase + 0x42); + outb((count >> 8) & 0xff, beep_iobase + 0x42); + } else { + /* disable counter 2 */ + outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); + } + + spin_unlock_irqrestore(&beep_lock, flags); + + return 0; +} + +static int __init init_isa_beep(struct isa_device *isa_dev) +{ + beep_iobase = isa_dev->resource.start; + + init_sparcspkr_struct(); + + sparcspkr_dev.name = sparcspkr_isa_name; + sparcspkr_dev.event = isa_spkr_event; + sparcspkr_dev.id.bustype = BUS_ISA; + + input_register_device(&sparcspkr_dev); + + printk(KERN_INFO "input: %s\n", sparcspkr_isa_name); + return 0; +} +#endif + +static int __init sparcspkr_init(void) +{ + struct linux_ebus *ebus; + struct linux_ebus_device *edev = NULL; +#ifdef CONFIG_SPARC64 + struct isa_bridge *isa_br; + struct isa_device *isa_dev; +#endif + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "beep")) + return init_ebus_beep(edev); + } + } +#ifdef CONFIG_SPARC64 + for_each_isa(isa_br) { + for_each_isadev(isa_dev, isa_br) { + /* A hack, the beep device's base lives in + * the DMA isa node. + */ + if (!strcmp(isa_dev->prom_name, "dma")) + return init_isa_beep(isa_dev); + } + } +#endif + + return -ENODEV; +} + +static void __exit sparcspkr_exit(void) +{ + input_unregister_device(&sparcspkr_dev); +} + +module_init(sparcspkr_init); +module_exit(sparcspkr_exit); diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c --- a/drivers/input/mouse/psmouse.c Sat Aug 31 15:05:55 2002 +++ b/drivers/input/mouse/psmouse.c Sat Aug 31 15:05:55 2002 @@ -1,27 +1,13 @@ /* - * $Id: psmouse.c,v 1.18 2002/03/13 10:03:43 vojtech Exp $ + * PS/2 mouse driver * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2002 Vojtech Pavlik */ /* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. */ #include @@ -33,7 +19,7 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_LICENSE("GPL"); @@ -43,6 +29,7 @@ #define PSMOUSE_CMD_SETSTREAM 0x00ea #define PSMOUSE_CMD_POLL 0x03eb #define PSMOUSE_CMD_GETID 0x01f2 +#define PSMOUSE_CMD_GETID2 0x0100 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 #define PSMOUSE_CMD_RESET_DIS 0x00f6 @@ -313,7 +300,7 @@ param[0] = 0; psmouse->vendor = "Generic"; psmouse->name = "Mouse"; - psmouse->model = 2; + psmouse->model = 0; /* * Try Genius NetMouse magic init. @@ -327,13 +314,13 @@ psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) { - psmouse->vendor = "Genius"; - psmouse->name = "Mouse"; set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(REL_WHEEL, psmouse->dev.relbit); + psmouse->vendor = "Genius"; + psmouse->name = "Wheel Mouse"; return PSMOUSE_GENPS; } @@ -356,7 +343,6 @@ static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, 76, 80, 81, 83, 88, 96, 97, -1 }; psmouse->vendor = "Logitech"; - psmouse->name = "Mouse"; psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); if (param[1] < 3) @@ -367,46 +353,53 @@ psmouse->type = PSMOUSE_PS2; for (i = 0; logitech_ps2pp[i] != -1; i++) - if (logitech_ps2pp[i] == psmouse->model) psmouse->type = PSMOUSE_PS2PP; + if (logitech_ps2pp[i] == psmouse->model) + psmouse->type = PSMOUSE_PS2PP; - if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2; + if (psmouse->type == PSMOUSE_PS2PP) { - for (i = 0; logitech_4btn[i] != -1; i++) - if (logitech_4btn[i] == psmouse->model) set_bit(BTN_SIDE, psmouse->dev.keybit); - - for (i = 0; logitech_wheel[i] != -1; i++) - if (logitech_wheel[i] == psmouse->model) set_bit(REL_WHEEL, psmouse->dev.relbit); + for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == psmouse->model) + set_bit(BTN_SIDE, psmouse->dev.keybit); + + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == psmouse->model) { + set_bit(REL_WHEEL, psmouse->dev.relbit); + psmouse->name = "Wheel Mouse"; + } /* * Do Logitech PS2++ / PS2T++ magic init. */ - if (psmouse->model == 97) { /* TouchPad 3 */ + if (psmouse->model == 97) { /* TouchPad 3 */ - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(REL_HWHEEL, psmouse->dev.relbit); + set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, psmouse->dev.relbit); - param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ - psmouse_command(psmouse, param, 0x30d1); - - param[0] = 0; - if (!psmouse_command(psmouse, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) - return PSMOUSE_PS2TPP; - - } else { - psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ - psmouse_ps2pp_cmd(psmouse, param, 0xDB); - - if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && - (param[2] & 3) == ((param[1] >> 2) & 3)) - return PSMOUSE_PS2PP; + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(psmouse, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(psmouse, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) + return PSMOUSE_PS2TPP; + + } else { + param[0] = param[1] = param[2] = 0; + + psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ + psmouse_ps2pp_cmd(psmouse, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) + return PSMOUSE_PS2PP; + } } - } /* @@ -426,7 +419,7 @@ set_bit(REL_WHEEL, psmouse->dev.relbit); /* - * Try IntelliMouse Explorer magic init. + * Try IntelliMouse/Explorer magic init. */ param[0] = 200; @@ -439,29 +432,22 @@ if (param[0] == 4) { - psmouse->vendor = "Microsoft"; - psmouse->name = "IntelliMouse Explorer"; - set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit); + psmouse->name = "Explorer Mouse"; return PSMOUSE_IMEX; } - psmouse->vendor = "Microsoft"; - psmouse->name = "IntelliMouse"; - + psmouse->name = "Wheel Mouse"; return PSMOUSE_IMPS; } /* - * Okay, all failed, we have a standard mouse here. The number of the buttons is - * still a question, though. + * Okay, all failed, we have a standard mouse here. The number of the buttons + * is still a question, though. We assume 3. */ - psmouse->vendor = "Generic"; - psmouse->name = "Mouse"; - return PSMOUSE_PS2; } @@ -474,14 +460,7 @@ unsigned char param[2]; /* - * First we reset and disable the mouse. - */ - - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) - return -1; - -/* - * Next, we check if it's a mouse. It should send 0x00 or 0x03 + * First, we check if it's a mouse. It should send 0x00 or 0x03 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. */ @@ -490,10 +469,22 @@ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID)) return -1; + if (param[0] == 0xab || param[0] == 0xac) { + psmouse_command(psmouse, param, PSMOUSE_CMD_GETID2); + return -1; + } + if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) return -1; /* + * Then we reset and disable the mouse so that it doesn't generate events. + */ + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) + return -1; + +/* * And here we try to determine if it has any extensions over the * basic PS/2 3-button mouse. */ @@ -602,9 +593,9 @@ psmouse->dev.name = psmouse->devname; psmouse->dev.phys = psmouse->phys; psmouse->dev.id.bustype = BUS_I8042; - psmouse->dev.id.vendor = psmouse->type; - psmouse->dev.id.product = psmouse->model; - psmouse->dev.id.version = 0x0100; + psmouse->dev.id.vendor = 0x0002; + psmouse->dev.id.product = psmouse->type; + psmouse->dev.id.version = psmouse->model; input_register_device(&psmouse->dev); diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c --- a/drivers/input/mousedev.c Sat Aug 31 15:05:59 2002 +++ b/drivers/input/mousedev.c Sat Aug 31 15:05:59 2002 @@ -330,7 +330,6 @@ list->ps2[0] = 0xfa; list->bufsiz = 1; - list->ready = 1; switch (c) { @@ -351,6 +350,15 @@ list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; list->bufsiz = 4; break; + + case 0xff: /* Reset */ + list->impsseq = 0; + list->imexseq = 0; + list->mode = 0; + list->ps2[0] = 0xaa; + list->ps2[1] = 0x00; + list->bufsiz = 2; + break; } list->buffer = list->bufsiz; @@ -395,16 +403,16 @@ if (retval) return retval; - if (!list->buffer) + if (!list->buffer && list->ready) mousedev_packet(list, 0); if (count > list->buffer) count = list->buffer; - if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count)) - return -EFAULT; - list->buffer -= count; + + if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count)) + return -EFAULT; return count; } diff -Nru a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in --- a/drivers/input/serio/Config.in Sat Aug 31 15:06:03 2002 +++ b/drivers/input/serio/Config.in Sat Aug 31 15:06:03 2002 @@ -5,11 +5,6 @@ tristate 'Serial i/o support' CONFIG_SERIO dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO -if [ "$CONFIG_SERIO_I8042" != "n" ]; then - hex ' Register Base Address' CONFIG_I8042_REG_BASE 60 - int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1 - int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12 -fi dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO if [ "$CONFIG_Q40" = "y" ]; then diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h --- a/drivers/input/serio/i8042-io.h Sat Aug 31 15:05:54 2002 +++ b/drivers/input/serio/i8042-io.h Sat Aug 31 15:05:54 2002 @@ -18,17 +18,21 @@ * IRQs. */ -#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ -#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ +#ifdef __alpha__ +#define I8042_KBD_IRQ 1 +#define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */ +#else +#define I8042_KBD_IRQ 1 +#define I8042_AUX_IRQ 12 +#endif /* * Register numbers. */ -#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4 -#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4 -#define I8042_DATA_REG CONFIG_I8042_REG_BASE - +#define I8042_COMMAND_REG 0x64 +#define I8042_STATUS_REG 0x64 +#define I8042_DATA_REG 0x60 static inline int i8042_read_data(void) { diff -Nru a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/i8042-sparcio.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,102 @@ +#ifndef _I8042_SPARCIO_H +#define _I8042_SPARCIO_H + +#include +#include + +static int i8042_kbd_irq = -1; +static int i8042_aux_irq = -1; +#define I8042_KBD_IRQ i8042_kbd_irq +#define I8042_AUX_IRQ i8042_aux_irq + +#define I8042_KBD_PHYS_DESC "sparcps2/serio0" +#define I8042_AUX_PHYS_DESC "sparcps2/serio1" + +static unsigned long kbd_iobase; + +#define I8042_COMMAND_REG (kbd_iobase + 0x64UL) +#define I8042_DATA_REG (kbd_iobase + 0x60UL) + +static inline int i8042_read_data(void) +{ + return readb(kbd_iobase + 0x60UL); +} + +static inline int i8042_read_status(void) +{ + return readb(kbd_iobase + 0x64UL); +} + +static inline void i8042_write_data(int val) +{ + writeb(val, kbd_iobase + 0x60UL); +} + +static inline void i8042_write_command(int val) +{ + writeb(val, kbd_iobase + 0x64UL); +} + +#define OBP_PS2KBD_NAME1 "kb_ps2" +#define OBP_PS2KBD_NAME2 "keyboard" +#define OBP_PS2MS_NAME1 "kdmouse" +#define OBP_PS2MS_NAME2 "mouse" + +static int i8042_platform_init(void) +{ + char prop[128]; + int len; + + len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); + if (len < 0) { + printk("i8042: Cannot get name property of root OBP node.\n"); + return 0; + } + if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { + /* Hardcoded values for MrCoffee. */ + i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; + kbd_iobase = (unsigned long) ioremap(0x71300060, 8); + if (!kbd_iobase) + return 0; + } else { + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + struct linux_ebus_child *child; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "8042")) + goto edev_found; + } + } + return 0; + + edev_found: + for_each_edevchild(edev, child) { + if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || + !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { + i8042_kbd_irq = child->irqs[0]; + kbd_iobase = (unsigned long) + ioremap(child->resource[0].start, 8); + } + if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || + !strcmp(child->prom_name, OBP_PS2MS_NAME2)) + i8042_aux_irq = child->irqs[0]; + } + if (i8042_kbd_irq == -1 || + i8042_aux_irq == -1) { + printk("i8042: Error, 8042 device lacks both kbd and " + "mouse nodes.\n"); + return 0; + } + } + + return 1; +} + +static inline void i8042_platform_exit(void) +{ + iounmap((void *)kbd_iobase); +} + +#endif /* _I8042_SPARCIO_H */ diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c Sat Aug 31 15:05:54 2002 +++ b/drivers/input/serio/i8042.c Sat Aug 31 15:05:54 2002 @@ -23,7 +23,7 @@ #include "i8042.h" -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_LICENSE("GPL"); @@ -299,7 +299,7 @@ */ static struct i8042_values i8042_kbd_values = { - .irq = I8042_KBD_IRQ, + .irq = 0, .irqen = I8042_CTR_KBDINT, .disable = I8042_CTR_KBDDIS, .name = "KBD", @@ -318,7 +318,7 @@ }; static struct i8042_values i8042_aux_values = { - .irq = I8042_AUX_IRQ, + .irq = 0, .irqen = I8042_CTR_AUXINT, .disable = I8042_CTR_AUXDIS, .name = "AUX", @@ -347,6 +347,11 @@ unsigned long flags; unsigned char str, data; unsigned int dfl; + struct { + int data; + int str; + } buffer[I8042_BUFFER_SIZE]; + int i, j = 0; #ifdef CONFIG_VT kbd_pt_regs = regs; @@ -354,20 +359,31 @@ spin_lock_irqsave(&i8042_lock, flags); - while ((str = i8042_read_status()) & I8042_STR_OBF) { + while (j < I8042_BUFFER_SIZE && + (buffer[j].str = i8042_read_status()) & I8042_STR_OBF) + buffer[j++].data = i8042_read_data(); + + spin_unlock_irqrestore(&i8042_lock, flags); + + for (i = 0; i < j; i++) { + + str = buffer[i].str; + data = buffer[i].data; - data = i8042_read_data(); dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); #ifdef I8042_DEBUG_IO - printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt, %s, %d) [%d]\n", - data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, (int) (jiffies - i8042_start)); + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt, %s, %d%s%s) [%d]\n", + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : "", + (int) (jiffies - i8042_start)); #endif - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(&i8042_aux_port, data, dfl); - } else { + if (i8042_aux_values.exists && (buffer[i].str & I8042_STR_AUXDATA)) { + serio_interrupt(&i8042_aux_port, buffer[i].data, dfl); + } else if (i8042_kbd_values.exists) { if (!i8042_direct) { if (data > 0x7f) { @@ -385,10 +401,8 @@ } serio_interrupt(&i8042_kbd_port, data, dfl); } - } } - spin_unlock_irqrestore(&i8042_lock, flags); } /* @@ -562,9 +576,12 @@ /* * External connection test - filters out AT-soldered PS/2 i8042's + * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error + * We ignore general error, since some chips report it even under normal + * operation. */ - if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) + if (i8042_command(¶m, I8042_CMD_AUX_TEST) || (param && param != 0xff)) return -1; /* @@ -573,23 +590,11 @@ if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) return -1; - if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) return -1; - if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) { - -/* - * We've got an old AMI i8042 with 'Bad Cache' commands. - */ - - i8042_command(¶m, I8042_CMD_AUX_ENABLE); - return -1; - } - if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) return -1; - if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) return -1; @@ -624,8 +629,11 @@ serio_register_port(port); - printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n", - values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq); + printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", + values->name, + (unsigned long) I8042_DATA_REG, + (unsigned long) I8042_COMMAND_REG, + values->irq); return 0; } @@ -702,6 +710,9 @@ if (!i8042_platform_init()) return -EBUSY; + + i8042_kbd_values.irq = I8042_KBD_IRQ; + i8042_aux_values.irq = I8042_AUX_IRQ; if (i8042_controller_init()) return -ENODEV; diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h --- a/drivers/input/serio/i8042.h Sat Aug 31 15:06:06 2002 +++ b/drivers/input/serio/i8042.h Sat Aug 31 15:06:06 2002 @@ -15,6 +15,8 @@ #if defined(CONFIG_PPC) #include "i8042-ppcio.h" +#elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) +#include "i8042-sparcio.h" #else #include "i8042-io.h" #endif diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c --- a/drivers/macintosh/via-pmu.c Sat Aug 31 15:05:59 2002 +++ b/drivers/macintosh/via-pmu.c Sat Aug 31 15:05:59 2002 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #ifdef CONFIG_PMAC_BACKLIGHT diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Sat Aug 31 15:05:55 2002 +++ b/drivers/md/raid5.c Sat Aug 31 15:05:55 2002 @@ -937,7 +937,7 @@ for (i=disks; i--; ) if (sh->dev[i].written) { dev = &sh->dev[i]; - if (!test_bit(R5_Insync, &dev->flags) && + if (!test_bit(R5_Insync, &sh->dev[sh->pd_idx].flags) && (!test_bit(R5_LOCKED, &dev->flags) && test_bit(R5_UPTODATE, &dev->flags)) ) { /* maybe we can return some write requests */ struct bio *wbi, *wbi2; diff -Nru a/drivers/media/video/Config.in b/drivers/media/video/Config.in --- a/drivers/media/video/Config.in Sat Aug 31 15:06:00 2002 +++ b/drivers/media/video/Config.in Sat Aug 31 15:06:00 2002 @@ -4,7 +4,7 @@ mainmenu_option next_comment comment 'Video For Linux' -bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS +dep_bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS $CONFIG_PROC_FS comment 'Video Adapters' if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then diff -Nru a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c --- a/drivers/media/video/bt819.c Sat Aug 31 15:05:54 2002 +++ b/drivers/media/video/bt819.c Sat Aug 31 15:05:54 2002 @@ -39,15 +39,32 @@ #include -#include +#include #include #define DEBUG(x) x /* Debug driver */ /* ----------------------------------------------------------------------- */ +static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c , normal_i2c_range, + probe , probe_range, + ignore , ignore_range, + force +}; + +static struct i2c_client client_template; + struct bt819 { - struct i2c_bus *bus; + struct i2c_client *client; int addr; unsigned char reg[32]; @@ -59,6 +76,7 @@ int contrast; int hue; int sat; + struct semaphore lock; }; struct timing { @@ -82,71 +100,17 @@ /* ----------------------------------------------------------------------- */ -static int bt819_write(struct bt819 *dev, unsigned char subaddr, - unsigned char data) +static int bt819_probe(struct i2c_adapter *adap) { - int ack; - - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); - dev->reg[subaddr] = data; - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return ack; + return i2c_probe(adap, &addr_data, bt819_attach); } static int bt819_setbit(struct bt819 *dev, int subaddr, int bit, int data) { - return bt819_write(dev, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); -} - -static int bt819_write_block(struct bt819 *dev, unsigned const char *data, - unsigned int len) -{ - int ack; - unsigned subaddr; - - ack = 0; - while (len > 1) { - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), - I2C_DELAY); - len -= 2; - while (len > 1 && *data == ++subaddr) { - data++; - ack = - i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); - len -= 2; - } - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - } - return ack; -} - -static int bt819_read(struct bt819 *dev, unsigned char subaddr) -{ - int data; - - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); - data = i2c_readbyte(dev->bus, 1); - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return data; + return i2c_smbus_write_byte_data(dev->client, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); } -static int bt819_init(struct i2c_device *device) +static int bt819_init(struct i2c_client *client) { struct bt819 *decoder; @@ -178,7 +142,7 @@ struct timing *timing; - decoder = device->data; + decoder = client->data; timing = &timing_data[decoder->norm]; init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) | @@ -192,31 +156,38 @@ init[8 * 2 - 1] = timing->hscale >> 8; init[9 * 2 - 1] = timing->hscale & 0xff; - bt819_write(decoder, 0x1f, 0x00); + i2c_smbus_write_byte_data(client, 0x1f, 0x00); mdelay(1); - return bt819_write_block(decoder, init, sizeof(init)); + return i2c_master_send(client, init, sizeof(init)); } /* ----------------------------------------------------------------------- */ -static int bt819_attach(struct i2c_device *device) +static int bt819_attach(struct i2c_adapter *adap, int addr , unsigned long flags, int kind) { int i; struct bt819 *decoder; + struct i2c_client *client; - MOD_INC_USE_COUNT; - - device->data = decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL); + client = kmalloc(sizeof(*client), GFP_KERNEL); + if(client == NULL) + return -ENOMEM; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(*client)); + + decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL); if (decoder == NULL) { MOD_DEC_USE_COUNT; return -ENOMEM; } memset(decoder, 0, sizeof(struct bt819)); - strcpy(device->name, "bt819"); - decoder->bus = device->bus; - decoder->addr = device->addr; + strcpy(client->name, "bt819"); + client->data = decoder; + decoder->client = client; + decoder->addr = addr; decoder->norm = VIDEO_MODE_NTSC; decoder->input = 0; decoder->enable = 1; @@ -226,34 +197,39 @@ decoder->sat = 32768; decoder->initialized = 0; - i = bt819_init(device); + i = bt819_init(client); if (i < 0) { printk(KERN_ERR "%s: bt819_attach: init status %d\n", - decoder->bus->name, i); + decoder->client->name, i); } else { printk(KERN_INFO "%s: bt819_attach: chip version %x\n", - decoder->bus->name, bt819_read(decoder, + decoder->client->name, i2c_smbus_read_byte_data(client, 0x17) & 0x0f); } + init_MUTEX(&decoder->lock); + i2c_attach_client(client); + MOD_INC_USE_COUNT; return 0; } -static int bt819_detach(struct i2c_device *device) +static int bt819_detach(struct i2c_client *client) { - kfree(device->data); + i2c_detach_client(client); + kfree(client->data); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int bt819_command(struct i2c_device *device, unsigned int cmd, void *arg) +static int bt819_command(struct i2c_client *client, unsigned int cmd, void *arg) { int temp; - struct bt819 *decoder = device->data; + struct bt819 *decoder = client->data; //return 0; if (!decoder->initialized) { // First call to bt819_init could be - bt819_init(device); // without #FRST = 0 + bt819_init(client); // without #FRST = 0 decoder->initialized = 1; } @@ -277,7 +253,7 @@ int status; int res; - status = bt819_read(decoder, 0x00); + status = i2c_smbus_read_byte_data(client, 0x00); res = 0; if ((status & 0x80)) { res |= DECODER_STATUS_GOOD; @@ -302,7 +278,7 @@ *iarg = res; DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n", - decoder->bus->name, *iarg)); + decoder->client->name, *iarg)); } break; @@ -312,37 +288,38 @@ struct timing *timing; DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n", - decoder->bus->name, *iarg)); + decoder->client->name, *iarg)); if (*iarg == VIDEO_MODE_NTSC) { bt819_setbit(decoder, 0x01, 0, 1); bt819_setbit(decoder, 0x01, 1, 0); - bt819_write(decoder, 0x18, 0x68); - bt819_write(decoder, 0x19, 0x5d); + i2c_smbus_write_byte_data(client, 0x18, 0x68); + i2c_smbus_write_byte_data(client, 0x19, 0x5d); //bt819_setbit(decoder, 0x1a, 5, 1); timing = &timing_data[VIDEO_MODE_NTSC]; } else { bt819_setbit(decoder, 0x01, 0, 1); bt819_setbit(decoder, 0x01, 1, 1); - bt819_write(decoder, 0x18, 0x7f); - bt819_write(decoder, 0x19, 0x72); + i2c_smbus_write_byte_data(client, 0x18, 0x7f); + i2c_smbus_write_byte_data(client, 0x19, 0x72); //bt819_setbit(decoder, 0x1a, 5, 0); timing = &timing_data[VIDEO_MODE_PAL]; } - bt819_write(decoder, 0x03, + i2c_smbus_write_byte_data(client, 0x03, (((timing->vdelay >> 8) & 0x03) << 6) | (((timing-> vactive >> 8) & 0x03) << 4) | (((timing-> hdelay >> 8) & 0x03) << 2) | ((timing->hactive >> 8) & 0x03)); - bt819_write(decoder, 0x04, timing->vdelay & 0xff); - bt819_write(decoder, 0x05, timing->vactive & 0xff); - bt819_write(decoder, 0x06, timing->hdelay & 0xff); - bt819_write(decoder, 0x07, timing->hactive & 0xff); - bt819_write(decoder, 0x08, timing->hscale >> 8); - bt819_write(decoder, 0x09, timing->hscale & 0xff); + + i2c_smbus_write_byte_data(client, 0x04, timing->vdelay & 0xff); + i2c_smbus_write_byte_data(client, 0x05, timing->vactive & 0xff); + i2c_smbus_write_byte_data(client, 0x06, timing->hdelay & 0xff); + i2c_smbus_write_byte_data(client, 0x07, timing->hactive & 0xff); + i2c_smbus_write_byte_data(client, 0x08, timing->hscale >> 8); + i2c_smbus_write_byte_data(client, 0x09, timing->hscale & 0xff); decoder->norm = *iarg; } break; @@ -352,7 +329,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n", - decoder->bus->name, *iarg)); + decoder->client->name, *iarg)); if (*iarg < 0 || *iarg > 7) { return -EINVAL; @@ -377,7 +354,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n", - decoder->bus->name, *iarg)); + decoder->client->name, *iarg)); /* not much choice of outputs */ if (*iarg != 0) { @@ -393,7 +370,7 @@ DEBUG(printk (KERN_INFO "%s-bt819: enable output %x\n", - decoder->bus->name, *iarg)); + decoder->client->name, *iarg)); if (decoder->enable != enable) { decoder->enable = enable; @@ -414,21 +391,21 @@ DEBUG(printk (KERN_INFO "%s-bt819: set picture brightness %d contrast %d colour %d\n", - decoder->bus->name, pic->brightness, + decoder->client->name, pic->brightness, pic->contrast, pic->colour)); if (decoder->bright != pic->brightness) { /* We want -128 to 127 we get 0-65535 */ decoder->bright = pic->brightness; - bt819_write(decoder, 0x0a, + i2c_smbus_write_byte_data(client, 0x0a, (decoder->bright >> 8) - 128); } if (decoder->contrast != pic->contrast) { /* We want 0 to 511 we get 0-65535 */ decoder->contrast = pic->contrast; - bt819_write(decoder, 0x0c, + i2c_smbus_write_byte_data(client, 0x0c, (decoder-> contrast >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 2, @@ -439,14 +416,14 @@ if (decoder->sat != pic->colour) { /* We want 0 to 511 we get 0-65535 */ decoder->sat = pic->colour; - bt819_write(decoder, 0x0d, + i2c_smbus_write_byte_data(client, 0x0d, (decoder->sat >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 1, ((decoder-> sat >> 15) & 0x01)); temp = (decoder->sat * 201) / 237; - bt819_write(decoder, 0x0e, + i2c_smbus_write_byte_data(client, 0x0e, (temp >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); @@ -455,7 +432,7 @@ if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; - bt819_write(decoder, 0x0f, + i2c_smbus_write_byte_data(client, 0x0f, 128 - (decoder->hue >> 8)); } } @@ -472,22 +449,30 @@ static struct i2c_driver i2c_driver_bt819 = { "bt819", /* name */ - I2C_DRIVERID_VIDEODECODER, /* ID */ - I2C_BT819, I2C_BT819 + 1, - - bt819_attach, + I2C_DRIVERID_BT819, /* ID */ + I2C_DF_NOTIFY, + bt819_probe, bt819_detach, bt819_command }; +static struct i2c_client client_template = { + "bt819_client", + -1, + 0, + 0, + NULL, + &i2c_driver_bt819 +}; + static int bt819_setup(void) { - return i2c_register_driver(&i2c_driver_bt819); + return i2c_add_driver(&i2c_driver_bt819); } static void bt819_exit(void) { - i2c_unregister_driver(&i2c_driver_bt819); + i2c_del_driver(&i2c_driver_bt819); } module_init(bt819_setup); diff -Nru a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c --- a/drivers/media/video/bt856.c Sat Aug 31 15:05:54 2002 +++ b/drivers/media/video/bt856.c Sat Aug 31 15:05:54 2002 @@ -47,15 +47,32 @@ #include #include -#include +#include #include #define DEBUG(x) x /* Debug driver */ /* ----------------------------------------------------------------------- */ +static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c , normal_i2c_range, + probe , probe_range, + ignore , ignore_range, + force +}; + +static struct i2c_client client_template; + struct bt856 { - struct i2c_bus *bus; + struct i2c_client *client; int addr; unsigned char reg[128]; @@ -73,40 +90,35 @@ /* ----------------------------------------------------------------------- */ -static int bt856_write(struct bt856 *dev, unsigned char subaddr, - unsigned char data) +static int bt856_probe(struct i2c_adapter *adap) { - int ack; - - LOCK_I2C_BUS(dev->bus); - - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); - dev->reg[subaddr] = data; - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return ack; + return i2c_probe(adap, &addr_data , bt856_attach); } static int bt856_setbit(struct bt856 *dev, int subaddr, int bit, int data) { - return bt856_write(dev, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); + return i2c_smbus_write_byte_data(dev->client, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); } /* ----------------------------------------------------------------------- */ -static int bt856_attach(struct i2c_device *device) +static int bt856_attach(struct i2c_adapter *adap, int addr , unsigned long flags, int kind) { struct bt856 *encoder; - + struct i2c_client *client; + + client = kmalloc(sizeof(*client), GFP_KERNEL); + if(client == NULL) + return -ENOMEM; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(*client)); + /* This chip is not on the buz card but at the same address saa7185 */ //if (memcmp(device->bus->name, "buz", 3) == 0 || memcmp(device->bus->name, "zr36057", 6) == 0) // return 1; - MOD_INC_USE_COUNT; - device->data = encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL); + encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL); if (encoder == NULL) { MOD_DEC_USE_COUNT; @@ -115,17 +127,21 @@ memset(encoder, 0, sizeof(struct bt856)); - strcpy(device->name, "bt856"); - encoder->bus = device->bus; - encoder->addr = device->addr; + strcpy(client->name, "bt856"); + encoder->client = client; + client->data = encoder; + encoder->addr = client->addr; encoder->norm = VIDEO_MODE_NTSC; encoder->enable = 1; DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->bus->name)); - bt856_write(encoder, 0xdc, 0x18); - bt856_write(encoder, 0xda, 0); - bt856_write(encoder, 0xde, 0); + i2c_smbus_write_byte_data(client, 0xdc, 0x18); + encoder->reg[0xdc] = 0x18; + i2c_smbus_write_byte_data(client, 0xda, 0); + encoder->reg[0xda] = 0; + i2c_smbus_write_byte_data(client, 0xde, 0); + encoder->reg[0xde] = 0; bt856_setbit(encoder, 0xdc, 3, 1); //bt856_setbit(encoder, 0xdc, 6, 0); @@ -145,21 +161,26 @@ bt856_setbit(encoder, 0xdc, 1, 1); bt856_setbit(encoder, 0xde, 4, 0); bt856_setbit(encoder, 0xde, 3, 1); + init_MUTEX(&encoder->lock); + i2c_attach_client(client); + MOD_INC_USE_COUNT; return 0; } -static int bt856_detach(struct i2c_device *device) +static int bt856_detach(struct i2c_client *client) { - kfree(device->data); + i2c_detach_client(client); + kfree(client->data); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int bt856_command(struct i2c_device *device, unsigned int cmd, +static int bt856_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct bt856 *encoder = device->data; + struct bt856 *encoder = client->data; switch (cmd) { @@ -169,7 +190,7 @@ DEBUG(printk (KERN_INFO "%s-bt856: get capabilities\n", - encoder->bus->name)); + encoder->client->name)); cap->flags = VIDEO_ENCODER_PAL @@ -184,7 +205,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n", - encoder->bus->name, *iarg)); + encoder->client->name, *iarg)); switch (*iarg) { @@ -211,7 +232,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n", - encoder->bus->name, *iarg)); + encoder->client->name, *iarg)); /* We only have video bus. *iarg = 0: input is from bt819 @@ -247,7 +268,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n", - encoder->bus->name, *iarg)); + encoder->client->name, *iarg)); /* not much choice of outputs */ if (*iarg != 0) { @@ -264,7 +285,7 @@ DEBUG(printk (KERN_INFO "%s-bt856: enable output %d\n", - encoder->bus->name, encoder->enable)); + encoder->client->name, encoder->enable)); } break; @@ -279,21 +300,30 @@ static struct i2c_driver i2c_driver_bt856 = { "bt856", /* name */ - I2C_DRIVERID_VIDEOENCODER, /* ID */ - I2C_BT856, I2C_BT856 + 1, - bt856_attach, + I2C_DRIVERID_BT856, /* ID */ + I2C_DF_NOTIFY, + bt856_probe, bt856_detach, bt856_command }; +static struct i2c_client client_template = { + "bt856_client", + -1, + 0, + 0, + NULL, + &i2c_driver_bt856 +}; + static int bt856_init(void) { - return i2c_register_driver(&i2c_driver_bt856); + return i2c_add_driver(&i2c_driver_bt856); } static void bt856_exit(void) { - i2c_unregister_driver(&i2c_driver_bt856); + i2c_del_driver(&i2c_driver_bt856); } module_init(bt856_init); diff -Nru a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c --- a/drivers/media/video/saa7110.c Sat Aug 31 15:05:53 2002 +++ b/drivers/media/video/saa7110.c Sat Aug 31 15:05:53 2002 @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "linux/video_decoder.h" @@ -37,13 +37,31 @@ #define I2C_SAA7110 0x9C /* or 0x9E */ +#define IF_NAME "saa7110" #define I2C_DELAY 10 /* 10 us or 100khz */ +static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +static struct i2c_client client_template; + struct saa7110 { - struct i2c_bus *bus; + struct i2c_client *client; int addr; unsigned char reg[36]; - + struct semaphore lock; int norm; int input; int enable; @@ -54,67 +72,10 @@ }; /* ----------------------------------------------------------------------- */ -/* I2C support functions */ -/* ----------------------------------------------------------------------- */ -static -int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) -{ - int ack; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); - i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); - i2c_stop(decoder->bus); - decoder->reg[subaddr] = data; - UNLOCK_I2C_BUS(decoder->bus); - return ack; -} - -static -int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) -{ - unsigned subaddr = *data; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); - while (len-- > 0) { - if (i2c_sendbyte(decoder->bus,*data,0)) { - i2c_stop(decoder->bus); - UNLOCK_I2C_BUS(decoder->bus); - return -EAGAIN; - } - decoder->reg[subaddr++] = *data++; - } - i2c_stop(decoder->bus); - UNLOCK_I2C_BUS(decoder->bus); - - return 0; -} - -static -int saa7110_read(struct saa7110* decoder) -{ - int data; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); - data = i2c_readbyte(decoder->bus, 1); - i2c_stop(decoder->bus); - UNLOCK_I2C_BUS(decoder->bus); - return data; -} - -/* ----------------------------------------------------------------------- */ /* SAA7110 functions */ /* ----------------------------------------------------------------------- */ static -int saa7110_selmux(struct i2c_device *device, int chan) +int saa7110_selmux(struct i2c_client *client, int chan) { static const unsigned char modes[9][8] = { /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, @@ -126,61 +87,59 @@ /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; - struct saa7110* decoder = device->data; const unsigned char* ptr = modes[chan]; - saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ - saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ - saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ - saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ - saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ - saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ - saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ - saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ + i2c_smbus_write_byte_data(client,0x06,ptr[0]); /* Luminance control */ + i2c_smbus_write_byte_data(client,0x20,ptr[1]); /* Analog Control #1 */ + i2c_smbus_write_byte_data(client,0x21,ptr[2]); /* Analog Control #2 */ + i2c_smbus_write_byte_data(client,0x22,ptr[3]); /* Mixer Control #1 */ + i2c_smbus_write_byte_data(client,0x2C,ptr[4]); /* Mixer Control #2 */ + i2c_smbus_write_byte_data(client,0x30,ptr[5]); /* ADCs gain control */ + i2c_smbus_write_byte_data(client,0x31,ptr[6]); /* Mixer Control #3 */ + i2c_smbus_write_byte_data(client,0x21,ptr[7]); /* Analog Control #2 */ return 0; } static -int determine_norm(struct i2c_device* dev) +int determine_norm(struct i2c_client* client) { - struct saa7110* decoder = dev->data; int status; /* mode changed, start automatic detection */ - status = saa7110_read(decoder); + status = i2c_smbus_read_byte(client); if ((status & 3) == 0) { - saa7110_write(decoder,0x06,0x80); + i2c_smbus_write_byte_data(client,0x06,0x80); if (status & 0x20) { - DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); - saa7110_write(decoder,0x2E,0x81); + DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name)); + i2c_smbus_write_byte_data(client,0x2E,0x81); return VIDEO_MODE_NTSC; } - DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); - saa7110_write(decoder,0x2E,0x9A); + DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name)); + i2c_smbus_write_byte_data(client,0x2E,0x9A); return VIDEO_MODE_PAL; } - saa7110_write(decoder,0x06,0x00); + i2c_smbus_write_byte_data(client,0x06,0x00); if (status & 0x20) { /* 60Hz */ - DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); - saa7110_write(decoder,0x0D,0x06); - saa7110_write(decoder,0x11,0x2C); - saa7110_write(decoder,0x2E,0x81); + DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name)); + i2c_smbus_write_byte_data(client,0x0D,0x06); + i2c_smbus_write_byte_data(client,0x11,0x2C); + i2c_smbus_write_byte_data(client,0x2E,0x81); return VIDEO_MODE_NTSC; } /* 50Hz -> PAL/SECAM */ - saa7110_write(decoder,0x0D,0x06); - saa7110_write(decoder,0x11,0x59); - saa7110_write(decoder,0x2E,0x9A); + i2c_smbus_write_byte_data(client,0x0D,0x06); + i2c_smbus_write_byte_data(client,0x11,0x59); + i2c_smbus_write_byte_data(client,0x2E,0x9A); mdelay(150); /* pause 150 ms */ - status = saa7110_read(decoder); + status = i2c_smbus_read_byte(client); if ((status & 0x03) == 0x01) { DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); - saa7110_write(decoder,0x0D,0x07); + i2c_smbus_write_byte_data(client,0x0D,0x07); return VIDEO_MODE_SECAM; } DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); @@ -188,7 +147,7 @@ } static -int saa7110_attach(struct i2c_device *device) +int saa7110_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) { static const unsigned char initseq[] = { 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, @@ -198,20 +157,28 @@ 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, 0x40, 0x75, 0x01, 0x8C, 0x03}; - struct saa7110* decoder; + struct saa7110 *decoder; + struct i2c_client *client; int rv; - - device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); - if (device->data == 0) + client=kmalloc(sizeof(*client), GFP_KERNEL); + if(client == NULL) return -ENOMEM; - - MOD_INC_USE_COUNT; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(*client)); + + decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); + if (decoder == NULL) { + kfree(client); + return -ENOMEM; + } /* clear our private data */ - memset(decoder, 0, sizeof(struct saa7110)); - strcpy(device->name, "saa7110"); - decoder->bus = device->bus; - decoder->addr = device->addr; + memset(decoder, 0, sizeof(*decoder)); + strcpy(client->name, IF_NAME); + decoder->client = client; + client->data = decoder; + decoder->addr = addr; decoder->norm = VIDEO_MODE_PAL; decoder->input = 0; decoder->enable = 1; @@ -220,40 +187,52 @@ decoder->hue = 32768; decoder->sat = 32768; - rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); + rv = i2c_master_send(client, initseq, sizeof(initseq)); if (rv < 0) - printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); + printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv); else { - saa7110_write(decoder,0x21,0x16); - saa7110_write(decoder,0x0D,0x04); - DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); - saa7110_write(decoder,0x0D,0x06); + i2c_smbus_write_byte_data(client,0x21,0x16); + i2c_smbus_write_byte_data(client,0x0D,0x04); + DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client))); + i2c_smbus_write_byte_data(client,0x0D,0x06); } + init_MUTEX(&decoder->lock); + i2c_attach_client(client); + MOD_INC_USE_COUNT; /* setup and implicit mode 0 select has been performed */ return 0; } +static +int saa7110_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, saa7110_attach); +} + static -int saa7110_detach(struct i2c_device *device) +int saa7110_detach(struct i2c_client *client) { - struct saa7110* decoder = device->data; + struct saa7110* decoder = client->data; - DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); + i2c_detach_client(client); + + DEBUG(printk(KERN_INFO "%s_detach\n",client->name)); /* stop further output */ - saa7110_write(decoder,0x0E,0x00); + i2c_smbus_write_byte_data(client,0x0E,0x00); - kfree(device->data); + kfree(decoder); + kfree(client); MOD_DEC_USE_COUNT; return 0; } static -int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) +int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct saa7110* decoder = device->data; + struct saa7110* decoder = client->data; int v; switch (cmd) { @@ -272,11 +251,11 @@ case DECODER_GET_STATUS: { - struct saa7110* decoder = device->data; + struct saa7110* decoder = client->data; int status; int res = 0; - status = i2c_read(device->bus,device->addr|1); + status = i2c_smbus_read_byte(client); if (status & 0x40) res |= DECODER_STATUS_GOOD; if (status & 0x03) @@ -301,26 +280,26 @@ v = *(int*)arg; if (decoder->norm != v) { decoder->norm = v; - saa7110_write(decoder, 0x06, 0x00); + i2c_smbus_write_byte_data(client, 0x06, 0x00); switch (v) { case VIDEO_MODE_NTSC: - saa7110_write(decoder, 0x0D, 0x06); - saa7110_write(decoder, 0x11, 0x2C); - saa7110_write(decoder, 0x30, 0x81); - saa7110_write(decoder, 0x2A, 0xDF); + i2c_smbus_write_byte_data(client, 0x0D, 0x06); + i2c_smbus_write_byte_data(client, 0x11, 0x2C); + i2c_smbus_write_byte_data(client, 0x30, 0x81); + i2c_smbus_write_byte_data(client, 0x2A, 0xDF); break; case VIDEO_MODE_PAL: - saa7110_write(decoder, 0x0D, 0x06); - saa7110_write(decoder, 0x11, 0x59); - saa7110_write(decoder, 0x2E, 0x9A); + i2c_smbus_write_byte_data(client, 0x0D, 0x06); + i2c_smbus_write_byte_data(client, 0x11, 0x59); + i2c_smbus_write_byte_data(client, 0x2E, 0x9A); break; case VIDEO_MODE_SECAM: - saa7110_write(decoder, 0x0D, 0x07); - saa7110_write(decoder, 0x11, 0x59); - saa7110_write(decoder, 0x2E, 0x9A); + i2c_smbus_write_byte_data(client, 0x0D, 0x07); + i2c_smbus_write_byte_data(client, 0x11, 0x59); + i2c_smbus_write_byte_data(client, 0x2E, 0x9A); break; case VIDEO_MODE_AUTO: - *(int*)arg = determine_norm(device); + *(int*)arg = determine_norm(client); break; default: return -EPERM; @@ -334,7 +313,7 @@ return -EINVAL; if (decoder->input != v) { decoder->input = v; - saa7110_selmux(device, v); + saa7110_selmux(client, v); } break; @@ -349,7 +328,7 @@ v = *(int*)arg; if (decoder->enable != v) { decoder->enable = v; - saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); + i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00); } break; @@ -360,22 +339,22 @@ if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; - saa7110_write(decoder, 0x19, decoder->bright >> 8); + i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 127 we get 0-65535 */ decoder->contrast = pic->contrast; - saa7110_write(decoder, 0x13, decoder->contrast >> 9); + i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9); } if (decoder->sat != pic->colour) { /* We want 0 to 127 we get 0-65535 */ decoder->sat = pic->colour; - saa7110_write(decoder, 0x12, decoder->sat >> 9); + i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; - saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); + i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128); } } break; @@ -383,7 +362,7 @@ case DECODER_DUMP: for (v=0; v<34; v+=16) { int j; - DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); + DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v)); for (j=0; j<16; j++) { DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); } @@ -402,24 +381,30 @@ static struct i2c_driver i2c_driver_saa7110 = { - "saa7110", /* name */ - - I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ - I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ - - saa7110_attach, + IF_NAME, /* name */ + I2C_DRIVERID_SAA7110, /* in i2c.h */ + I2C_DF_NOTIFY, /* Addr range */ + saa7110_probe, saa7110_detach, saa7110_command }; +static struct i2c_client client_template = { + "saa7110_client", + -1, + 0, + 0, + NULL, + &i2c_driver_saa7110 +}; static int saa7110_init(void) { - return i2c_register_driver(&i2c_driver_saa7110); + return i2c_add_driver(&i2c_driver_saa7110); } static void saa7110_exit(void) { - i2c_unregister_driver(&i2c_driver_saa7110); + i2c_del_driver(&i2c_driver_saa7110); } diff -Nru a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c --- a/drivers/media/video/videodev.c Sat Aug 31 15:05:54 2002 +++ b/drivers/media/video/videodev.c Sat Aug 31 15:05:54 2002 @@ -44,7 +44,7 @@ static DECLARE_MUTEX(videodev_lock); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS #include @@ -60,7 +60,7 @@ EXPORT_SYMBOL(video_proc_entry); LIST_HEAD(videodev_proc_list); -#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ +#endif /* CONFIG_VIDEO_PROC_FS */ struct video_device* video_devdata(struct file *file) { @@ -198,7 +198,7 @@ * /proc support */ -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS /* Hmm... i'd like to see video_capability information here, but * how can I access it (without changing the other drivers? -claudio @@ -289,7 +289,7 @@ } #ifdef MODULE -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS static void videodev_proc_destroy(void) { if (video_dev_proc_entry != NULL) @@ -439,7 +439,7 @@ NULL); init_MUTEX(&vfd->lock); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS sprintf (name, "%s%d", name_base, i - base); videodev_proc_create_dev (vfd, name); #endif @@ -460,7 +460,7 @@ if(video_device[vfd->minor]!=vfd) panic("videodev: bad unregister"); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS videodev_proc_destroy_dev (vfd); #endif @@ -489,7 +489,7 @@ return -EIO; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS videodev_proc_create (); #endif @@ -498,7 +498,7 @@ static void __exit videodev_exit(void) { -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS videodev_proc_destroy (); #endif unregister_chrdev(VIDEO_MAJOR, "video_capture"); diff -Nru a/drivers/message/i2o/README.ioctl b/drivers/message/i2o/README.ioctl --- a/drivers/message/i2o/README.ioctl Sat Aug 31 15:06:03 2002 +++ b/drivers/message/i2o/README.ioctl Sat Aug 31 15:06:03 2002 @@ -318,7 +318,7 @@ DESCRIPTION This function posts an ExecConfigValidate message to the controller - identified by iop. This message indicates that the the current + identified by iop. This message indicates that the current configuration is accepted. The iop changes the status of suspect drivers to valid and may delete old drivers from its store. diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c --- a/drivers/mtd/devices/blkmtd.c Sat Aug 31 15:05:54 2002 +++ b/drivers/mtd/devices/blkmtd.c Sat Aug 31 15:05:54 2002 @@ -51,7 +51,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c --- a/drivers/mtd/mtdblock.c Sat Aug 31 15:05:59 2002 +++ b/drivers/mtd/mtdblock.c Sat Aug 31 15:05:59 2002 @@ -406,7 +406,7 @@ if (minor(req->rq_dev) >= MAX_MTD_DEVICES) panic(__FUNCTION__": minor out of bound"); - if (req->flags & REQ_CMD) + if (! (req->flags & REQ_CMD)) goto end_req; if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c Sat Aug 31 15:06:00 2002 +++ b/drivers/net/8139cp.c Sat Aug 31 15:06:00 2002 @@ -24,17 +24,16 @@ PCI suspend/resume - Felipe Damasio TODO, in rough priority order: + * Test Tx checksumming thoroughly * dev->tx_timeout * LinkChg interrupt * Support forcing media type with a module parameter, like dl2k.c/sundance.c * Constants (module parms?) for Rx work limit - * support 64-bit PCI DMA * Complete reset on PciErr * Consider Rx interrupt mitigation using TimerIntr * Implement 8139C+ statistics dump; maybe not... h/w stats can be reset only by software reset - * Tx checksumming * Handle netif_rx return value * Investigate using skb->priority with h/w VLAN priority * Investigate using High Priority Tx Queue with skb->priority @@ -50,8 +49,8 @@ */ #define DRV_NAME "8139cp" -#define DRV_VERSION "0.1.0" -#define DRV_RELDATE "Jun 14, 2002" +#define DRV_VERSION "0.2.1" +#define DRV_RELDATE "Aug 9, 2002" #include @@ -67,9 +66,17 @@ #include #include #include +#include +#include +#include +#include #include #include +/* experimental TX checksumming feature enable/disable */ +#undef CP_TX_CHECKSUM + +/* VLAN tagging feature enable/disable */ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define CP_VLAN_TAG_USED 1 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ @@ -245,6 +252,7 @@ /* C+ mode command register */ RxVlanOn = (1 << 6), /* Rx VLAN de-tagging enable */ RxChkSum = (1 << 5), /* Rx checksum offload enable */ + PCIDAC = (1 << 4), /* PCI Dual Address Cycle (64-bit PCI) */ PCIMulRW = (1 << 3), /* Enable PCI read/write multiple */ CpRxOn = (1 << 1), /* Rx mode enable */ CpTxOn = (1 << 0), /* Tx mode enable */ @@ -295,8 +303,7 @@ struct cp_desc { u32 opts1; u32 opts2; - u32 addr_lo; - u32 addr_hi; + u64 addr; }; struct ring_info { @@ -357,6 +364,7 @@ struct sk_buff *frag_skb; unsigned dropping_frag : 1; + unsigned pci_using_dac : 1; unsigned int board_type; unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */ @@ -637,7 +645,7 @@ else desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); cp->rx_ring[rx_tail].opts2 = 0; - cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping); + cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping); rx_tail = NEXT_RX(rx_tail); } @@ -768,22 +776,33 @@ eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; - u32 mapping, len; + u32 len; + dma_addr_t mapping; len = skb->len; mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; CP_VLAN_TX_TAG(txd, vlan_tag); - txd->addr_lo = cpu_to_le32(mapping); + txd->addr = cpu_to_le64(mapping); wmb(); #ifdef CP_TX_CHECKSUM - txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag | - LastFrag | IPCS | UDPCS | TCPCS); -#else - txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag | - LastFrag); + if (skb->ip_summed == CHECKSUM_HW) { + const struct iphdr *ip = skb->nh.iph; + if (ip->protocol == IPPROTO_TCP) + txd->opts1 = cpu_to_le32(eor | len | DescOwn | + FirstFrag | LastFrag | + IPCS | TCPCS); + else if (ip->protocol == IPPROTO_UDP) + txd->opts1 = cpu_to_le32(eor | len | DescOwn | + FirstFrag | LastFrag | + IPCS | UDPCS); + else + BUG(); + } else #endif + txd->opts1 = cpu_to_le32(eor | len | DescOwn | + FirstFrag | LastFrag); wmb(); cp->tx_skb[entry].skb = skb; @@ -792,8 +811,12 @@ entry = NEXT_TX(entry); } else { struct cp_desc *txd; - u32 first_len, first_mapping; + u32 first_len; + dma_addr_t first_mapping; int frag, first_entry = entry; +#ifdef CP_TX_CHECKSUM + const struct iphdr *ip = skb->nh.iph; +#endif /* We must give this initial chunk to the device last. * Otherwise we could race with the device. @@ -808,8 +831,9 @@ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; - u32 len, mapping; + u32 len; u32 ctrl; + dma_addr_t mapping; len = this_frag->size; mapping = pci_map_single(cp->pdev, @@ -818,16 +842,24 @@ len, PCI_DMA_TODEVICE); eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; #ifdef CP_TX_CHECKSUM - ctrl = eor | len | DescOwn | IPCS | UDPCS | TCPCS; -#else - ctrl = eor | len | DescOwn; + if (skb->ip_summed == CHECKSUM_HW) { + ctrl = eor | len | DescOwn | IPCS; + if (ip->protocol == IPPROTO_TCP) + ctrl |= TCPCS; + else if (ip->protocol == IPPROTO_UDP) + ctrl |= UDPCS; + else + BUG(); + } else #endif + ctrl = eor | len | DescOwn; + if (frag == skb_shinfo(skb)->nr_frags - 1) ctrl |= LastFrag; txd = &cp->tx_ring[entry]; CP_VLAN_TX_TAG(txd, vlan_tag); - txd->addr_lo = cpu_to_le32(mapping); + txd->addr = cpu_to_le64(mapping); wmb(); txd->opts1 = cpu_to_le32(ctrl); @@ -841,14 +873,23 @@ txd = &cp->tx_ring[first_entry]; CP_VLAN_TX_TAG(txd, vlan_tag); - txd->addr_lo = cpu_to_le32(first_mapping); + txd->addr = cpu_to_le64(first_mapping); wmb(); #ifdef CP_TX_CHECKSUM - txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn | IPCS | UDPCS | TCPCS); -#else - txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn); + if (skb->ip_summed == CHECKSUM_HW) { + if (ip->protocol == IPPROTO_TCP) + txd->opts1 = cpu_to_le32(first_len | FirstFrag | + DescOwn | IPCS | TCPCS); + else if (ip->protocol == IPPROTO_UDP) + txd->opts1 = cpu_to_le32(first_len | FirstFrag | + DescOwn | IPCS | UDPCS); + else + BUG(); + } else #endif + txd->opts1 = cpu_to_le32(first_len | FirstFrag | + DescOwn); wmb(); } cp->tx_head = entry; @@ -977,10 +1018,11 @@ static inline void cp_start_hw (struct cp_private *cp) { + u16 pci_dac = cp->pci_using_dac ? PCIDAC : 0; if (cp->board_type == RTL8169) - cpw16(CpCmd, PCIMulRW | RxChkSum); + cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum); else - cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn); + cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum | CpRxOn | CpTxOn); cpw8(Cmd, RxOn | TxOn); } @@ -1053,8 +1095,7 @@ cp->rx_ring[i].opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); cp->rx_ring[i].opts2 = 0; - cp->rx_ring[i].addr_lo = cpu_to_le32(cp->rx_skb[i].mapping); - cp->rx_ring[i].addr_hi = 0; + cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping); } return 0; @@ -1173,6 +1214,7 @@ return 0; } +#ifdef BROKEN static int cp_change_mtu(struct net_device *dev, int new_mtu) { struct cp_private *cp = dev->priv; @@ -1206,6 +1248,7 @@ return rc; } +#endif /* BROKEN */ static char mii_2_8139_map[8] = { BasicModeCtrl, @@ -1716,7 +1759,7 @@ int rc; void *regs; long pciaddr; - unsigned addr_len, i; + unsigned int addr_len, i; u8 pci_rev, cache_size; u16 pci_command; unsigned int board_type = (unsigned int) ent->driver_data; @@ -1781,6 +1824,19 @@ goto err_out_res; } + /* Configure DMA attributes. */ + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + cp->pci_using_dac = 1; + } else { + rc = pci_set_dma_mask(pdev, (u64) 0xffffffff); + if (rc) { + printk(KERN_ERR PFX "No usable DMA configuration, " + "aborting.\n"); + goto err_out_res; + } + cp->pci_using_dac = 0; + } + regs = ioremap_nocache(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; @@ -1805,7 +1861,9 @@ dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; +#ifdef BROKEN dev->change_mtu = cp_change_mtu; +#endif #if 0 dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Sat Aug 31 15:05:53 2002 +++ b/drivers/net/8139too.c Sat Aug 31 15:05:53 2002 @@ -92,7 +92,7 @@ */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.25" +#define DRV_VERSION "0.9.26" #include @@ -462,7 +462,7 @@ /* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links. */ + Completely undocumented, but required to tune bad links on some boards. */ enum CSCRBits { CSCR_LinkOKBit = 0x0400, CSCR_LinkChangeBit = 0x0800, @@ -477,10 +477,14 @@ Cfg9346_Unlock = 0xC0, }; +#ifdef CONFIG_8139TOO_TUNE_TWISTER + +enum TwisterParamVals { + PARA78_default = 0x78fa8388, + PARA7c_default = 0xcb38de43, /* param[0][3] */ + PARA7c_xxx = 0xcb38de43, +}; -#define PARA78_default 0x78fa8388 -#define PARA7c_default 0xcb38de43 /* param[0][3] */ -#define PARA7c_xxx 0xcb38de43 static const unsigned long param[4][4] = { {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43}, {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83}, @@ -488,6 +492,8 @@ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83} }; +#endif /* CONFIG_8139TOO_TUNE_TWISTER */ + typedef enum { CH_8139 = 0, CH_8139_K, @@ -1302,7 +1308,7 @@ tp->mii.full_duplex = tp->mii.duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; - tp->twistie = 1; + tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0; tp->time_to_die = 0; rtl8139_init_ring (dev); @@ -1784,7 +1790,7 @@ struct rtl8139_private *tp, void *ioaddr) { u8 tmp8; -#ifndef CONFIG_8139_NEW_RX_RESET +#ifdef CONFIG_8139_OLD_RX_RESET int tmp_work; #endif @@ -1807,7 +1813,7 @@ tp->xstats.rx_lost_in_ring++; } -#ifdef CONFIG_8139_NEW_RX_RESET +#ifndef CONFIG_8139_OLD_RX_RESET tmp8 = RTL_R8 (ChipCmd); RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb); RTL_W8 (ChipCmd, tmp8); diff -Nru a/drivers/net/Config.help b/drivers/net/Config.help --- a/drivers/net/Config.help Sat Aug 31 15:05:54 2002 +++ b/drivers/net/Config.help Sat Aug 31 15:05:54 2002 @@ -673,16 +673,25 @@ say N. CONFIG_8139TOO_TUNE_TWISTER - This implements a function which might come in handy in case you are - using low quality on long cabling. It tries to match the transceiver - to the cable characteristics. This is experimental since hardly - documented by the manufacturer. If unsure, say N. + This implements a function which might come in handy in case you + are using low quality on long cabling. It is required for RealTek + RTL-8139 revision K boards, and totally unused otherwise. It tries + to match the transceiver to the cable characteristics. This is + experimental since hardly documented by the manufacturer. + If unsure, say Y. CONFIG_8139TOO_8129 This enables support for the older and uncommon RTL-8129 and RTL-8130 chips, which support MII via an external transceiver, instead of an internal one. Disabling this option will save some memory by making the code size smaller. If unsure, say Y. + +CONFIG_8139_OLD_RX_RESET + The 8139too driver was recently updated to contain a more rapid + reset sequence, in the face of severe receive errors. This "new" + RX-reset method should be adequate for all boards. But if you + experience problems, you can enable this option to restore the + old RX-reset behavior. If unsure, say N. CONFIG_SIS900 This is a driver for the Fast Ethernet PCI network cards based on diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in --- a/drivers/net/Config.in Sat Aug 31 15:05:54 2002 +++ b/drivers/net/Config.in Sat Aug 31 15:05:54 2002 @@ -174,9 +174,9 @@ dep_tristate ' RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI dep_mbool ' Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO - dep_mbool ' Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL + dep_mbool ' Support for uncommon RTL-8139 rev. K (automatic channel equalization)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO dep_mbool ' Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO - dep_mbool ' Experiment for better RX reset (EXPERIMENTAL)' CONFIG_8139_NEW_RX_RESET $CONFIG_8139TOO $CONFIG_EXPERIMENTAL + dep_mbool ' Use older RX-reset method' CONFIG_8139_OLD_RX_RESET $CONFIG_8139TOO dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI @@ -226,6 +226,7 @@ fi dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI +dep_mbool ' Use Rx Polling (NAPI) (EXPERIMENTAL)' CONFIG_E1000_NAPI $CONFIG_E1000 $CONFIG_EXPERIMENTAL dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c --- a/drivers/net/bonding.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/bonding.c Sat Aug 31 15:05:59 2002 @@ -680,7 +680,7 @@ } /* - * This function counts the the number of attached + * This function counts the number of attached * slaves for use by bond_xmit_xor. */ static void update_slave_cnt(bonding_t *bond) diff -Nru a/drivers/net/e100/LICENSE b/drivers/net/e100/LICENSE --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e100/LICENSE Sat Aug 31 15:06:07 2002 @@ -0,0 +1,339 @@ + +"This software program is licensed subject to the GNU General Public License +(GPL). Version 2, June 1991, available at +" + +GNU General Public License + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public License is intended +to guarantee your freedom to share and change free software--to make sure +the software is free for all its users. This General Public License applies +to most of the Free Software Foundation's software and to any other program +whose authors commit to using it. (Some other Free Software Foundation +software is covered by the GNU Library General Public License instead.) You +can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you distribute +copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its +recipients to know that what they have is not the original, so that any +problems introduced by others will not reflect on the original authors' +reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent must be +licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice + placed by the copyright holder saying it may be distributed under the + terms of this General Public License. The "Program", below, refers to any + such program or work, and a "work based on the Program" means either the + Program or any derivative work under copyright law: that is to say, a + work containing the Program or a portion of it, either verbatim or with + modifications and/or translated into another language. (Hereinafter, + translation is included without limitation in the term "modification".) + Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is covered + only if its contents constitute a work based on the Program (independent + of having been made by running the Program). Whether that is true depends + on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code + as you receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice and + disclaimer of warranty; keep intact all the notices that refer to this + License and to the absence of any warranty; and give any other recipients + of the Program a copy of this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, and you + may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, + thus forming a work based on the Program, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + * a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + * b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any part + thereof, to be licensed as a whole at no charge to all third parties + under the terms of this License. + + * c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive + use in the most ordinary way, to print or display an announcement + including an appropriate copyright notice and a notice that there is + no warranty (or else, saying that you provide a warranty) and that + users may redistribute the program under these conditions, and + telling the user how to view a copy of this License. (Exception: if + the Program itself is interactive but does not normally print such + an announcement, your work based on the Program is not required to + print an announcement.) + + These requirements apply to the modified work as a whole. If identifiable + sections of that work are not derived from the Program, and can be + reasonably considered independent and separate works in themselves, then + this License, and its terms, do not apply to those sections when you + distribute them as separate works. But when you distribute the same + sections as part of a whole which is a work based on the Program, the + distribution of the whole must be on the terms of this License, whose + permissions for other licensees extend to the entire whole, and thus to + each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under + Section 2) in object code or executable form under the terms of Sections + 1 and 2 above provided that you also do one of the following: + + * a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or, + + * b) Accompany it with a written offer, valid for at least three years, + to give any third party, for a charge no more than your cost of + physically performing source distribution, a complete machine- + readable copy of the corresponding source code, to be distributed + under the terms of Sections 1 and 2 above on a medium customarily + used for software interchange; or, + + * c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed + only for noncommercial distribution and only if you received the + program in object code or executable form with such an offer, in + accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source code + means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to control + compilation and installation of the executable. However, as a special + exception, the source code distributed need not include anything that is + normally distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on which + the executable runs, unless that component itself accompanies the + executable. + + If distribution of executable or object code is made by offering access + to copy from a designated place, then offering equivalent access to copy + the source code from the same place counts as distribution of the source + code, even though third parties are not compelled to copy the source + along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as + expressly provided under this License. Any attempt otherwise to copy, + modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, parties + who have received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in full + compliance. + +5. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Program or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Program (or any work based on the Program), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Program or works + based on it. + +6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further restrictions + on the recipients' exercise of the rights granted herein. You are not + responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot distribute + so as to satisfy simultaneously your obligations under this License and + any other pertinent obligations, then as a consequence you may not + distribute the Program at all. For example, if a patent license would + not permit royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only way you + could satisfy both it and this License would be to refrain entirely from + distribution of the Program. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is implemented + by public license practices. Many people have made generous contributions + to the wide range of software distributed through that system in + reliance on consistent application of that system; it is up to the + author/donor to decide if he or she is willing to distribute software + through any other system and a licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed to be + a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Program under this License may add an + explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of + the General Public License from time to time. Such new versions will be + similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Program does not specify a version + number of this License, you may choose any version ever published by the + Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs + whose distribution conditions are different, write to the author to ask + for permission. For software which is copyrighted by the Free Software + Foundation, write to the Free Software Foundation; we sometimes make + exceptions for this. Our decision will be guided by the two goals of + preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH + YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it free +software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey the +exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + +one line to give the program's name and an idea of what it does. +Copyright (C) yyyy name of author + +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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free +software, and you are welcome to redistribute it under certain conditions; +type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +'Gnomovision' (which makes passes at compilers) written by James Hacker. + +signature of Ty Coon, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h --- a/drivers/net/e100/e100.h Sat Aug 31 15:05:55 2002 +++ b/drivers/net/e100/e100.h Sat Aug 31 15:05:55 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #ifndef _E100_INC_ @@ -104,6 +59,7 @@ #include #include +#define E100_REGS_LEN 1 /* * Configure parameters for buffers per controller. * If the machine this is being used on is a faster machine (i.e. > 150MHz) diff -Nru a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c --- a/drivers/net/e100/e100_config.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e100/e100_config.c Sat Aug 31 15:05:59 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ /********************************************************************** diff -Nru a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h --- a/drivers/net/e100/e100_config.h Sat Aug 31 15:05:54 2002 +++ b/drivers/net/e100/e100_config.h Sat Aug 31 15:05:54 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #ifndef _E100_CONFIG_INC_ diff -Nru a/drivers/net/e100/e100_eeprom.c b/drivers/net/e100/e100_eeprom.c --- a/drivers/net/e100/e100_eeprom.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e100/e100_eeprom.c Sat Aug 31 15:05:59 2002 @@ -1,77 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -******************************************************************************* - -Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2. - + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ /********************************************************************** diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c --- a/drivers/net/e100/e100_main.c Sat Aug 31 15:06:00 2002 +++ b/drivers/net/e100/e100_main.c Sat Aug 31 15:06:00 2002 @@ -1,77 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -******************************************************************************* - -Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2. - + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ /********************************************************************** @@ -95,6 +46,21 @@ /* Change Log * + * 2.1.12 8/2/02 + * o Feature: ethtool register dump + * o Bug fix: Driver passes wrong name to /proc/interrupts + * o Bug fix: Ethernet bridging not working + * o Bug fix: Promiscuous mode is not working + * o Bug fix: Checked return value from copy_from_user (William Stinson, + * wstinson@infonie.fr) + * o Bug fix: ARP wake on LAN fails + * o Bug fix: mii-diag does not update driver level's speed, duplex and + * re-configure flow control + * o Bug fix: Ethtool shows wrong speed/duplex when not connected + * o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced + * speed/duplex + * o Bug fix: PHY loopback diagnostic fails + * * 2.1.6 7/5/02 * o Added device ID support for Dell LOM. * o Added device ID support for 82511QM mobile nics. @@ -145,6 +111,7 @@ #define E100_EEPROM_MAGIC 0x1234 static int e100_ethtool_glink(struct net_device *, struct ifreq *); +static int e100_ethtool_gregs(struct net_device *, struct ifreq *); static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); static int e100_ethtool_wol(struct net_device *, struct ifreq *); static unsigned char e100_setup_filter(struct e100_private *bdp); @@ -176,7 +143,7 @@ /* Global Data structures and variables */ char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation"; -char e100_driver_version[]="2.1.6-k1"; +char e100_driver_version[]="2.1.15-k1"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; char e100_short_driver_name[] = "e100"; static int e100nics = 0; @@ -397,7 +364,7 @@ MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); E100_PARAM(TxDescriptors, "Number of transmit descriptors"); E100_PARAM(RxDescriptors, "Number of receive descriptors"); @@ -779,16 +746,6 @@ bdp->non_tx_command_state = E100_NON_TX_IDLE; } - /* Set up wol options and enable PME if wol is enabled */ - if (bdp->wolopts) { - e100_do_wol(pcid, bdp); - /* Enable PME for power state D3 */ - pci_enable_wake(pcid, 3, 1); - /* Set power state to D1 in case driver is RELOADED */ - /* If system powers down, device is switched from D1 to D3 */ - pci_set_power_state(pcid, 1); - } - e100_clear_structs(dev); --e100nics; @@ -1028,7 +985,7 @@ e100_start_ru(bdp); if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, - e100_short_driver_name, dev)) != 0) { + dev->name, dev)) != 0) { del_timer_sync(&bdp->watchdog_timer); goto err_exit; } @@ -1059,7 +1016,9 @@ bdp->intr_mask = SCB_INT_MASK; e100_isolate_driver(bdp); - bdp->ip_lbytes = e100_get_ip_lbytes(dev); + netif_carrier_off(bdp->device); + bdp->cur_line_speed = 0; + bdp->cur_dplx_mode = 0; free_irq(dev->irq, dev); e100_clear_pools(bdp); @@ -1243,7 +1202,7 @@ if (bdp->driver_isolated) { goto exit; } - promisc_enbl = (dev->flags & IFF_PROMISC); + promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MAX_MULTICAST_ADDRS)); @@ -3343,6 +3302,9 @@ case ETHTOOL_GDRVINFO: rc = e100_ethtool_get_drvinfo(dev, ifr); break; + case ETHTOOL_GREGS: + rc = e100_ethtool_gregs(dev, ifr); + break; case ETHTOOL_NWAY_RST: rc = e100_ethtool_nway_rst(dev, ifr); break; @@ -3390,9 +3352,15 @@ ecmd.transceiver = XCVR_INTERNAL; ecmd.phy_address = bdp->phy_addr; - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; + if (netif_carrier_ok(bdp->device)) { + ecmd.speed = bdp->cur_line_speed; + ecmd.duplex = + (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; + } + else { + ecmd.speed = -1; + ecmd.duplex = -1; + } ecmd.advertising = ADVERTISED_TP; @@ -3514,7 +3482,8 @@ bdp = dev->priv; info.cmd = ETHTOOL_GLINK; - info.data = e100_get_link_state(bdp); + /* Consider both PHY link and netif_running */ + info.data = e100_update_link_state(bdp); if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) return -EFAULT; @@ -3532,7 +3501,7 @@ GFP_ATOMIC); if (!info) - return -EFAULT; + return -ENOMEM; memset((void *) info, 0, sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)); @@ -3551,6 +3520,36 @@ } static int +e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) +{ + struct e100_private *bdp; + u32 regs_buff[E100_REGS_LEN]; + struct ethtool_regs regs = {ETHTOOL_GREGS}; + void *addr = ifr->ifr_data; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + bdp = dev->priv; + + if(copy_from_user(®s, addr, sizeof(regs))) + return -EFAULT; + + regs.version = (1 << 24) | bdp->rev_id; + regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | + readb(&(bdp->scb->scb_cmd_low)) << 16 | + readw(&(bdp->scb->scb_status)); + + if(copy_to_user(addr, ®s, sizeof(regs))) + return -EFAULT; + + addr += offsetof(struct ethtool_regs, data); + if(copy_to_user(addr, regs_buff, regs.len)) + return -EFAULT; + + return 0; +} + +static int e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) { struct e100_private *bdp; @@ -3581,10 +3580,11 @@ strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1); strncpy(info.version, e100_driver_version, sizeof (info.version) - 1); - strncpy(info.fw_version, e100_get_brand_msg(bdp), + strncpy(info.fw_version, "N/A", sizeof (info.fw_version) - 1); strncpy(info.bus_info, bdp->pdev->slot_name, sizeof (info.bus_info) - 1); + info.regdump_len = E100_REGS_LEN * sizeof(u32); info.eedump_len = (bdp->eeprom_size << 1); info.testinfo_len = E100_MAX_TEST_RES; if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) @@ -3616,6 +3616,10 @@ (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data)); max_len = bdp->eeprom_size * 2; + + if (ecmd.offset > ecmd.offset + ecmd.len) + return -EINVAL; + if ((ecmd.offset + ecmd.len) > max_len) ecmd.len = (max_len - ecmd.offset); @@ -3892,7 +3896,6 @@ if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) res = -EFAULT; break; - case ETHTOOL_SWOL: /* If ALL requests are supported or request is DISABLE wol */ if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) @@ -3901,6 +3904,8 @@ } else { res = -EOPNOTSUPP; } + if (wolinfo.wolopts & WAKE_ARP) + bdp->ip_lbytes = e100_get_ip_lbytes(dev); break; default: break; @@ -3929,7 +3934,7 @@ info.len = E100_MAX_TEST_RES; strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); if (!strings) - return -EFAULT; + return -ENOMEM; memset(strings, 0, info.len * ETH_GSTRING_LEN); for (i = 0; i < info.len; i++) { @@ -3978,8 +3983,30 @@ if (netif_running(dev)) { return -EBUSY; } - e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, + /* If reg = 0 && change speed/duplex */ + if (data_ptr->reg_num == 0 && + (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ + || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ + || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) + || data_ptr->val_in == 0)) { + if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) + || data_ptr->val_in == (BMCR_RESET)) + bdp->params.e100_speed_duplex = E100_AUTONEG; + else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) + bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; + else if (data_ptr->val_in == (BMCR_SPEED100)) + bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; + else if (data_ptr->val_in == (BMCR_FULLDPLX)) + bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; + else + bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; + e100_set_speed_duplex(bdp); + } + else { + e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr, data_ptr->val_in); + } + break; default: @@ -4150,6 +4177,7 @@ e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) { struct pci_dev *pdev = NULL; + switch(event) { case SYS_DOWN: case SYS_HALT: @@ -4159,7 +4187,8 @@ /* If net_device struct is allocated? */ if (pci_get_drvdata(pdev)) e100_suspend(pdev, 3); - } + + } } } return NOTIFY_DONE; @@ -4176,7 +4205,6 @@ /* If wol is enabled */ if (bdp->wolopts) { - bdp->ip_lbytes = e100_get_ip_lbytes(netdev); e100_do_wol(pcid, bdp); pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ pci_set_power_state(pcid, 3); /* Set power state to D3. */ @@ -4185,7 +4213,6 @@ pci_disable_device(pcid); pci_set_power_state(pcid, state); } - return 0; } @@ -4213,7 +4240,6 @@ return 0; } - #endif /* CONFIG_PM */ static void diff -Nru a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c --- a/drivers/net/e100/e100_phy.c Sat Aug 31 15:05:53 2002 +++ b/drivers/net/e100/e100_phy.c Sat Aug 31 15:05:53 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #include "e100_phy.h" @@ -90,11 +45,12 @@ * Returns: * NOTHING */ -void +int e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) { int e100_retry; u32 temp_val; + unsigned int mdi_cntrl; spin_lock_bh(&bdp->mdi_access_lock); temp_val = (((u32) data) | (reg_addr << 16) | @@ -107,13 +63,18 @@ /* poll for the mdi write to complete */ e100_retry = E100_CMD_WAIT; - while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && - (e100_retry)) { + while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { udelay(20); e100_retry--; } spin_unlock_bh(&bdp->mdi_access_lock); + if (mdi_cntrl & MDI_PHY_READY) + return 0; + else { + printk(KERN_ERR "e100: MDI write timeout\n"); + return 1; + } } /* @@ -135,11 +96,12 @@ * Returns: * NOTHING */ -void +int e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) { int e100_retry; u32 temp_val; + unsigned int mdi_cntrl; spin_lock_bh(&bdp->mdi_access_lock); /* Issue the read command to the MDI control register. */ @@ -152,16 +114,22 @@ /* poll for the mdi read to complete */ e100_retry = E100_CMD_WAIT; - while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && - (e100_retry)) { + while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { udelay(20); e100_retry--; } - // return the lower word - *data = (u16) readl(&bdp->scb->scb_mdi_cntrl); spin_unlock_bh(&bdp->mdi_access_lock); + if (mdi_cntrl & MDI_PHY_READY) { + /* return the lower word */ + *data = (u16) mdi_cntrl; + return 0; + } + else { + printk(KERN_ERR "e100: MDI read timeout\n"); + return 1; + } } static unsigned char __devinit @@ -525,10 +493,8 @@ /* First we should check to see if we have link */ /* If we don't have a link no reason to print a speed and duplex */ if (!e100_update_link_state(bdp)) { - return; - } - - if (bdp->flags & DF_SPEED_FORCED) { + bdp->cur_line_speed = 0; + bdp->cur_dplx_mode = 0; return; } @@ -656,16 +622,19 @@ * Returns: void * */ -static void +void e100_force_speed_duplex(struct e100_private *bdp) { u16 control; unsigned long expires; + e100_phy_reset(bdp); + bdp->flags |= DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); control &= ~BMCR_ANENABLE; + control &= ~BMCR_LOOPBACK; /* Check e100.c values */ switch (bdp->params.e100_speed_duplex) { @@ -883,7 +852,7 @@ } void -e100_phy_reset(struct e100_private *bdp) +e100_phy_autoneg(struct e100_private *bdp) { u16 ctrl_reg; @@ -894,6 +863,23 @@ udelay(100); } +void +e100_phy_set_loopback(struct e100_private *bdp) +{ + u16 ctrl_reg; + ctrl_reg = BMCR_LOOPBACK; + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); + udelay(100); +} + +void +e100_phy_reset(struct e100_private *bdp) +{ + u16 ctrl_reg; + ctrl_reg = BMCR_RESET; + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); +} + unsigned char __devinit e100_phy_init(struct e100_private *bdp) { @@ -960,7 +946,8 @@ /* * Procedure: e100_update_link_state * - * Description: This routine updates the link status of the adapter + * Description: This routine updates the link status of the adapter, + * also considering netif_running * * Arguments: bdp - Pointer to the e100_private structure for the board * @@ -974,7 +961,8 @@ { unsigned char link; - link = e100_get_link_state(bdp); + /* Logical AND PHY link & netif_running */ + link = e100_get_link_state(bdp) && netif_running(bdp->device); if (link) { if (!netif_carrier_ok(bdp->device)) diff -Nru a/drivers/net/e100/e100_phy.h b/drivers/net/e100/e100_phy.h --- a/drivers/net/e100/e100_phy.h Sat Aug 31 15:05:54 2002 +++ b/drivers/net/e100/e100_phy.h Sat Aug 31 15:05:54 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #ifndef _E100_PHY_INC_ @@ -196,8 +151,10 @@ extern unsigned char e100_phy_check(struct e100_private *bdp); extern void e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart); +extern void e100_phy_autoneg(struct e100_private *bdp); extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_mdi_write(struct e100_private *, u32, u32, u16); -extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *); +extern void e100_phy_set_loopback(struct e100_private *bdp); +extern int e100_mdi_write(struct e100_private *, u32, u32, u16); +extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); #endif diff -Nru a/drivers/net/e100/e100_proc.c b/drivers/net/e100/e100_proc.c --- a/drivers/net/e100/e100_proc.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e100/e100_proc.c Sat Aug 31 15:05:59 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ /********************************************************************** @@ -106,7 +61,7 @@ extern char e100_driver_version[]; extern struct net_device_stats *e100_get_stats(struct net_device *dev); extern char *e100_get_brand_msg(struct e100_private *bdp); -extern void e100_mdi_write(struct e100_private *, u32, u32, u16); +extern int e100_mdi_write(struct e100_private *, u32, u32, u16); static void e100_proc_cleanup(void); static unsigned char e100_init_proc_dir(void); diff -Nru a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c --- a/drivers/net/e100/e100_test.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e100/e100_test.c Sat Aug 31 15:05:59 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #include "e100.h" @@ -76,6 +31,9 @@ extern u16 e100_eeprom_read(struct e100_private *, u16); extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8); extern void e100_phy_reset(struct e100_private *bdp); +extern void e100_phy_autoneg(struct e100_private *bdp); +extern void e100_phy_set_loopback(struct e100_private *bdp); +extern void e100_force_speed_duplex(struct e100_private *bdp); static u8 e100_diag_selftest(struct net_device *); static u8 e100_diag_eeprom(struct net_device *); @@ -284,6 +242,7 @@ *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); if (set_loopback) { + /* Configure loopback on MAC */ e100_config_loopback_mode(bdp,loopback_mode); } else { e100_config_loopback_mode(bdp,NO_LOOPBACK); @@ -292,16 +251,20 @@ e100_config(bdp); if (loopback_mode == PHY_LOOPBACK) { - unsigned long expires = jiffies + HZ * 5; - if (set_loopback) - e100_phy_reset(bdp); - - /* wait up to 5 secs for PHY loopback ON/OFF to take effect */ - while ((e100_get_link_state(bdp) != set_loopback) && - time_before(jiffies, expires)) { - yield(); + /* Set PHY loopback mode */ + e100_phy_set_loopback(bdp); + else { /* Back to normal speed and duplex */ + if (bdp->params.e100_speed_duplex == E100_AUTONEG) + /* Reset PHY and do autoneg */ + e100_phy_autoneg(bdp); + else + /* Reset PHY and force speed and duplex */ + e100_force_speed_duplex(bdp); } + /* Wait for PHY state change */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); } else { /* For MAC loopback wait 500 msec to take effect */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 2); @@ -321,6 +284,7 @@ rfd_t *rfd; tbd_t *tbd; + /* tcb, tbd and transmit buffer are allocated */ tcb = pci_alloc_consistent(bdp->pdev, (sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE), @@ -328,22 +292,26 @@ if (tcb == NULL) return false; - memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE); + memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); tcb->tcb_phys = dma_handle; tcb->tcb_hdr.cb_status = 0; tcb->tcb_hdr.cb_cmd = cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys); - tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff); + /* Next command is null */ + tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); tcb->tcb_cnt = 0; tcb->tcb_thrshld = bdp->tx_thld; tcb->tcb_tbd_num = 1; + /* Set up tcb tbd pointer */ tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); + /* Set up tbd transmit buffer */ tbd->tbd_buf_addr = cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024); + /* The value of first 512 bytes is FF */ + memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); + /* The value of second 512 bytes is BA */ memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); wmb(); rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); @@ -358,10 +326,9 @@ memset(rfd, 0x00, sizeof (rfd_t)); /* init all fields in rfd */ - rfd->rfd_header.cb_status = 0; rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_act_cnt = 0; rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); + /* dma_handle is physical address of rfd */ bdp->loopback.dma_handle = dma_handle; bdp->loopback.tcb = tcb; bdp->loopback.rfd = rfd; @@ -399,12 +366,15 @@ static u8 e100_diag_check_pkt(u8 *datap) { - if( (*datap)==0xFF) { - if(*(datap + 600) == 0xBA) { - return true; - } - } - return false; + int i; + for (i = 0; i<512; i++) { + if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { + printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); + return false; + } + } + printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); + return true; } /** @@ -434,10 +404,14 @@ } } - if (rfd_status & RFD_STATUS_COMPLETE) + if (rfd_status & RFD_STATUS_COMPLETE) { + printk(KERN_DEBUG "e100: Loopback packet received\n"); return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - else + } + else { + printk(KERN_ERR "e100: Loopback packet not received\n"); return false; + } } /** diff -Nru a/drivers/net/e100/e100_ucode.h b/drivers/net/e100/e100_ucode.h --- a/drivers/net/e100/e100_ucode.h Sat Aug 31 15:06:06 2002 +++ b/drivers/net/e100/e100_ucode.h Sat Aug 31 15:06:06 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #ifndef _E100_UCODE_H_ diff -Nru a/drivers/net/e100/e100_vendor.h b/drivers/net/e100/e100_vendor.h --- a/drivers/net/e100/e100_vendor.h Sat Aug 31 15:06:06 2002 +++ b/drivers/net/e100/e100_vendor.h Sat Aug 31 15:06:06 2002 @@ -1,73 +1,28 @@ /******************************************************************************* -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ #ifndef E100_VENDOR_ID_INFO diff -Nru a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE --- a/drivers/net/e1000/LICENSE Sat Aug 31 15:06:06 2002 +++ b/drivers/net/e1000/LICENSE Sat Aug 31 15:06:06 2002 @@ -1,68 +1,339 @@ -This software program is available to you under a choice of one of two -licenses. You may choose to be licensed under either the GNU General Public -License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -or the Intel BSD + Patent License, the text of which follows: - -Recipient has requested a license and Intel Corporation ("Intel") is willing -to grant a license for the software entitled Linux Base Driver for the -Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided -by Intel Corporation. The following definitions apply to this license: - -"Licensed Patents" means patent claims licensable by Intel Corporation which -are necessarily infringed by the use of sale of the Software alone or when -combined with the operating system referred to below. - -"Recipient" means the party to whom Intel delivers this Software. - -"Licensee" means Recipient and those third parties that receive a license to -any operating system available under the GNU General Public License 2.0 or -later. - -Copyright (c) 1999 - 2002 Intel Corporation. -All rights reserved. - -The license is provided to Recipient and Recipient's Licensees under the -following terms. - -Redistribution and use in source and binary forms of the Software, with or -without modification, are permitted provided that the following conditions -are met: - -Redistributions of source code of the Software may retain the above -copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form of the Software may reproduce the above -copyright notice, this list of conditions and the following disclaimer in -the documentation and/or materials provided with the distribution. - -Neither the name of Intel Corporation nor the names of its contributors -shall be used to endorse or promote products derived from this Software -without specific prior written permission. - -Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -royalty-free patent license under Licensed Patents to make, use, sell, offer -to sell, import and otherwise transfer the Software, if any, in source code -and object code form. This license shall include changes to the Software -that are error corrections or other minor changes to the Software that do -not add functionality or features when the Software is incorporated in any -version of an operating system that has been distributed under the GNU -General Public License 2.0 or later. This patent license shall apply to the -combination of the Software and any operating system licensed under the GNU -General Public License 2.0 or later if, at the time Intel provides the -Software to Recipient, such addition of the Software to the then publicly -available versions of such operating systems available under the GNU General -Public License 2.0 or later (whether in gold, beta or alpha form) causes -such combination to be covered by the Licensed Patents. The patent license -shall not apply to any other combinations which include the Software. NO -hardware per se is licensed hereunder. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"This software program is licensed subject to the GNU General Public License +(GPL). Version 2, June 1991, available at +" + +GNU General Public License + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public License is intended +to guarantee your freedom to share and change free software--to make sure +the software is free for all its users. This General Public License applies +to most of the Free Software Foundation's software and to any other program +whose authors commit to using it. (Some other Free Software Foundation +software is covered by the GNU Library General Public License instead.) You +can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you distribute +copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its +recipients to know that what they have is not the original, so that any +problems introduced by others will not reflect on the original authors' +reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent must be +licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice + placed by the copyright holder saying it may be distributed under the + terms of this General Public License. The "Program", below, refers to any + such program or work, and a "work based on the Program" means either the + Program or any derivative work under copyright law: that is to say, a + work containing the Program or a portion of it, either verbatim or with + modifications and/or translated into another language. (Hereinafter, + translation is included without limitation in the term "modification".) + Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is covered + only if its contents constitute a work based on the Program (independent + of having been made by running the Program). Whether that is true depends + on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code + as you receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice and + disclaimer of warranty; keep intact all the notices that refer to this + License and to the absence of any warranty; and give any other recipients + of the Program a copy of this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, and you + may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, + thus forming a work based on the Program, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + * a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + * b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any part + thereof, to be licensed as a whole at no charge to all third parties + under the terms of this License. + + * c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive + use in the most ordinary way, to print or display an announcement + including an appropriate copyright notice and a notice that there is + no warranty (or else, saying that you provide a warranty) and that + users may redistribute the program under these conditions, and + telling the user how to view a copy of this License. (Exception: if + the Program itself is interactive but does not normally print such + an announcement, your work based on the Program is not required to + print an announcement.) + + These requirements apply to the modified work as a whole. If identifiable + sections of that work are not derived from the Program, and can be + reasonably considered independent and separate works in themselves, then + this License, and its terms, do not apply to those sections when you + distribute them as separate works. But when you distribute the same + sections as part of a whole which is a work based on the Program, the + distribution of the whole must be on the terms of this License, whose + permissions for other licensees extend to the entire whole, and thus to + each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under + Section 2) in object code or executable form under the terms of Sections + 1 and 2 above provided that you also do one of the following: + + * a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or, + + * b) Accompany it with a written offer, valid for at least three years, + to give any third party, for a charge no more than your cost of + physically performing source distribution, a complete machine- + readable copy of the corresponding source code, to be distributed + under the terms of Sections 1 and 2 above on a medium customarily + used for software interchange; or, + + * c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed + only for noncommercial distribution and only if you received the + program in object code or executable form with such an offer, in + accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source code + means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to control + compilation and installation of the executable. However, as a special + exception, the source code distributed need not include anything that is + normally distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on which + the executable runs, unless that component itself accompanies the + executable. + + If distribution of executable or object code is made by offering access + to copy from a designated place, then offering equivalent access to copy + the source code from the same place counts as distribution of the source + code, even though third parties are not compelled to copy the source + along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as + expressly provided under this License. Any attempt otherwise to copy, + modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, parties + who have received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in full + compliance. + +5. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Program or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Program (or any work based on the Program), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Program or works + based on it. + +6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further restrictions + on the recipients' exercise of the rights granted herein. You are not + responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot distribute + so as to satisfy simultaneously your obligations under this License and + any other pertinent obligations, then as a consequence you may not + distribute the Program at all. For example, if a patent license would + not permit royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only way you + could satisfy both it and this License would be to refrain entirely from + distribution of the Program. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is implemented + by public license practices. Many people have made generous contributions + to the wide range of software distributed through that system in + reliance on consistent application of that system; it is up to the + author/donor to decide if he or she is willing to distribute software + through any other system and a licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed to be + a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Program under this License may add an + explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of + the General Public License from time to time. Such new versions will be + similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Program does not specify a version + number of this License, you may choose any version ever published by the + Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs + whose distribution conditions are different, write to the author to ask + for permission. For software which is copyrighted by the Free Software + Foundation, write to the Free Software Foundation; we sometimes make + exceptions for this. Our decision will be guided by the two goals of + preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH + YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it free +software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey the +exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + +one line to give the program's name and an idea of what it does. +Copyright (C) yyyy name of author + +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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free +software, and you are welcome to redistribute it under certain conditions; +type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +'Gnomovision' (which makes passes at compilers) written by James Hacker. + +signature of Ty Coon, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. diff -Nru a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile --- a/drivers/net/e1000/Makefile Sat Aug 31 15:05:54 2002 +++ b/drivers/net/e1000/Makefile Sat Aug 31 15:05:54 2002 @@ -1,73 +1,28 @@ ################################################################################ # -# This software program is available to you under a choice of one of two -# licenses. You may choose to be licensed under either the GNU General Public -# License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, -# or the Intel BSD + Patent License, the text of which follows: -# -# Recipient has requested a license and Intel Corporation ("Intel") is willing -# to grant a license for the software entitled Linux Base Driver for the -# Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided -# by Intel Corporation. The following definitions apply to this license: -# -# "Licensed Patents" means patent claims licensable by Intel Corporation which -# are necessarily infringed by the use of sale of the Software alone or when -# combined with the operating system referred to below. -# -# "Recipient" means the party to whom Intel delivers this Software. -# -# "Licensee" means Recipient and those third parties that receive a license to -# any operating system available under the GNU General Public License 2.0 or -# later. -# -# Copyright (c) 1999 - 2002 Intel Corporation. -# All rights reserved. -# -# The license is provided to Recipient and Recipient's Licensees under the -# following terms. -# -# Redistribution and use in source and binary forms of the Software, with or -# without modification, are permitted provided that the following conditions -# are met: -# -# Redistributions of source code of the Software may retain the above -# copyright notice, this list of conditions and the following disclaimer. -# -# Redistributions in binary form of the Software may reproduce the above -# copyright notice, this list of conditions and the following disclaimer in -# the documentation and/or materials provided with the distribution. -# -# Neither the name of Intel Corporation nor the names of its contributors -# shall be used to endorse or promote products derived from this Software -# without specific prior written permission. -# -# Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, -# royalty-free patent license under Licensed Patents to make, use, sell, offer -# to sell, import and otherwise transfer the Software, if any, in source code -# and object code form. This license shall include changes to the Software -# that are error corrections or other minor changes to the Software that do -# not add functionality or features when the Software is incorporated in any -# version of an operating system that has been distributed under the GNU -# General Public License 2.0 or later. This patent license shall apply to the -# combination of the Software and any operating system licensed under the GNU -# General Public License 2.0 or later if, at the time Intel provides the -# Software to Recipient, such addition of the Software to the then publicly -# available versions of such operating systems available under the GNU General -# Public License 2.0 or later (whether in gold, beta or alpha form) causes -# such combination to be covered by the Licensed Patents. The patent license -# shall not apply to any other combinations which include the Software. NO -# hardware per se is licensed hereunder. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This 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. +# +# The full GNU General Public License is included in this distribution in the +# file called LICENSE. +# +# Contact Information: +# Linux NICS +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 # ################################################################################ diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h Sat Aug 31 15:05:54 2002 +++ b/drivers/net/e1000/e1000.h Sat Aug 31 15:05:54 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: - - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. - - "Recipient" means the party to whom Intel delivers this Software. - - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. - - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. - - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -108,6 +63,8 @@ #include #include #include +#include +#include #include #include @@ -130,11 +87,7 @@ #define E1000_ERR(args...) printk(KERN_ERR "e1000: " args) -#ifdef CONFIG_PPC -#define E1000_MAX_INTR 1 -#else #define E1000_MAX_INTR 10 -#endif /* Supported Rx Buffer Sizes */ #define E1000_RXBUFFER_2048 2048 @@ -207,6 +160,7 @@ uint16_t link_duplex; spinlock_t stats_lock; atomic_t irq_sem; + struct tq_struct tx_timeout_task; struct timer_list blink_timer; unsigned long led_status; @@ -214,6 +168,8 @@ /* TX */ struct e1000_desc_ring tx_ring; uint32_t txd_cmd; + uint32_t tx_int_delay; + uint32_t tx_abs_int_delay; int max_data_per_txd; /* RX */ @@ -221,6 +177,7 @@ uint64_t hw_csum_err; uint64_t hw_csum_good; uint32_t rx_int_delay; + uint32_t rx_abs_int_delay; boolean_t rx_csum; /* OS defined structs */ diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Sat Aug 31 15:06:00 2002 +++ b/drivers/net/e1000/e1000_ethtool.c Sat Aug 31 15:06:00 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. - - "Recipient" means the party to whom Intel delivers this Software. - - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. - - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. - - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -82,6 +37,7 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); +extern void e1000_reset(struct e1000_adapter *adapter); static void e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) @@ -189,8 +145,11 @@ /* reset the link */ - e1000_down(adapter); - e1000_up(adapter); + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); return 0; } @@ -211,7 +170,7 @@ { strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); - strncpy(drvinfo->fw_version, "", 32); + strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32); #define E1000_REGS_LEN 32 drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t); @@ -244,19 +203,23 @@ return; } -static void +static int e1000_ethtool_geeprom(struct e1000_adapter *adapter, struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff) { struct e1000_hw *hw = &adapter->hw; int i, max_len, first_word, last_word; - if(eeprom->len == 0) return; + if(eeprom->len == 0) + return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); max_len = e1000_eeprom_size(hw); + if(eeprom->offset > eeprom->offset + eeprom->len) + return -EINVAL; + if((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); @@ -265,6 +228,7 @@ for(i = 0; i <= (last_word - first_word); i++) e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]); + return 0; } static int @@ -276,11 +240,12 @@ int i, max_len, first_word, last_word; void *ptr; + if(eeprom->len == 0) + return -EOPNOTSUPP; + if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; - if(eeprom->len == 0) return 0; - max_len = e1000_eeprom_size(hw); if((eeprom->offset + eeprom->len) > max_len) @@ -510,8 +475,10 @@ case ETHTOOL_NWAY_RST: { if(!capable(CAP_NET_ADMIN)) return -EPERM; - e1000_down(adapter); - e1000_up(adapter); + if(netif_running(netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } return 0; } case ETHTOOL_PHYS_ID: { @@ -546,11 +513,13 @@ struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; uint16_t eeprom_buff[256]; void *ptr; + int err; if(copy_from_user(&eeprom, addr, sizeof(eeprom))) return -EFAULT; - e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff); + if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))<0) + return err; if(copy_to_user(addr, &eeprom, sizeof(eeprom))) return -EFAULT; diff -Nru a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c --- a/drivers/net/e1000/e1000_hw.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e1000/e1000_hw.c Sat Aug 31 15:05:59 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. + 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. - "Recipient" means the party to whom Intel delivers this Software. + 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. - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. + You 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. - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. + The full GNU General Public License is included in this distribution in the + file called LICENSE. - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -93,9 +48,63 @@ static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw); static void e1000_setup_eeprom(struct e1000_hw *hw); static void e1000_standby_eeprom(struct e1000_hw *hw); +static void e1000_clock_eeprom(struct e1000_hw *hw); +static void e1000_cleanup_eeprom(struct e1000_hw *hw); static int32_t e1000_id_led_init(struct e1000_hw * hw); /****************************************************************************** + * Set the mac type member in the hw struct. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +e1000_set_mac_type(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_set_mac_type"); + + switch (hw->device_id) { + case E1000_DEV_ID_82542: + switch (hw->revision_id) { + case E1000_82542_2_0_REV_ID: + hw->mac_type = e1000_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + hw->mac_type = e1000_82542_rev2_1; + break; + default: + /* Invalid 82542 revision ID */ + return -E1000_ERR_MAC_TYPE; + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + hw->mac_type = e1000_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + hw->mac_type = e1000_82544; + break; + case E1000_DEV_ID_82540EM: + case E1000_DEV_ID_82540EM_LOM: + hw->mac_type = e1000_82540; + break; + case E1000_DEV_ID_82545EM_COPPER: + case E1000_DEV_ID_82545EM_FIBER: + hw->mac_type = e1000_82545; + break; + case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_FIBER: + hw->mac_type = e1000_82546; + break; + default: + /* Should never have loaded on this device */ + return -E1000_ERR_MAC_TYPE; + } + return E1000_SUCCESS; +} +/****************************************************************************** * Reset the transmit and receive units; mask and clear all interrupts. * * hw - Struct containing variables accessed by shared code @@ -152,7 +161,7 @@ /* Force a reload from the EEPROM if necessary */ if(hw->mac_type < e1000_82540) { /* Wait for reset to complete */ - usec_delay(10); + udelay(10); ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); ctrl_ext |= E1000_CTRL_EXT_EE_RST; E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); @@ -209,8 +218,8 @@ /* Initialize Identification LED */ ret_val = e1000_id_led_init(hw); if(ret_val < 0) { - DEBUGOUT("Error Initializing Identification LED\n"); - return ret_val; + DEBUGOUT("Error Initializing Identification LED\n"); + return ret_val; } /* Set the Media Type and exit with error if it is not valid. */ @@ -284,6 +293,8 @@ PCIX_COMMAND_MMRBC_SHIFT; stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> PCIX_STATUS_HI_MMRBC_SHIFT; + if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) + stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; if(cmd_mmrbc > stat_mmrbc) { pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; @@ -294,6 +305,13 @@ /* Call a subroutine to configure the link and setup flow control. */ ret_val = e1000_setup_link(hw); + /* Set the transmit descriptor write-back policy */ + if(hw->mac_type > e1000_82544) { + ctrl = E1000_READ_REG(hw, TXDCTL); + ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + E1000_WRITE_REG(hw, TXDCTL, ctrl); + } + /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -419,7 +437,6 @@ * Sets up link for a fiber based adapter * * hw - Struct containing variables accessed by shared code - * ctrl - Current value of the device control register * * Manipulates Physical Coding Sublayer functions in order to configure * link. Assumes the hardware has been previously reset and the transmitter @@ -550,7 +567,6 @@ * Detects which PHY is present and the speed and duplex * * hw - Struct containing variables accessed by shared code -* ctrl - current value of the device control register ******************************************************************************/ static int32_t e1000_setup_copper_link(struct e1000_hw *hw) @@ -761,7 +777,7 @@ DEBUGOUT("Valid link established!!!\n"); return 0; } - usec_delay(10); + udelay(10); } DEBUGOUT("Unable to establish link!!!\n"); @@ -1014,7 +1030,7 @@ DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } - usec_delay(1); + udelay(1); /* The wait_autoneg_complete flag may be a little misleading here. * Since we are forcing speed and duplex, Auto-Neg is not enabled. @@ -1718,7 +1734,7 @@ */ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC)); E1000_WRITE_FLUSH(hw); - usec_delay(2); + udelay(2); } /****************************************************************************** @@ -1736,7 +1752,7 @@ */ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC)); E1000_WRITE_FLUSH(hw); - usec_delay(2); + udelay(2); } /****************************************************************************** @@ -1780,7 +1796,7 @@ E1000_WRITE_REG(hw, CTRL, ctrl); E1000_WRITE_FLUSH(hw); - usec_delay(2); + udelay(2); e1000_raise_mdi_clk(hw, &ctrl); e1000_lower_mdi_clk(hw, &ctrl); @@ -1876,7 +1892,7 @@ /* Poll the ready bit to see if the MDI read completed */ for(i = 0; i < 64; i++) { - usec_delay(10); + udelay(10); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -1958,7 +1974,7 @@ /* Poll the ready bit to see if the MDI read completed */ for(i = 0; i < 64; i++) { - usec_delay(10); + udelay(10); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -2029,7 +2045,7 @@ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); E1000_WRITE_FLUSH(hw); } - usec_delay(150); + udelay(150); } /****************************************************************************** @@ -2055,7 +2071,7 @@ DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } - usec_delay(1); + udelay(1); return 0; } @@ -2078,7 +2094,7 @@ return -E1000_ERR_PHY; } hw->phy_id = (uint32_t) (phy_id_high << 16); - usec_delay(2); + udelay(2); if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -2231,7 +2247,7 @@ *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); } /****************************************************************************** @@ -2250,7 +2266,7 @@ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); } /****************************************************************************** @@ -2289,7 +2305,7 @@ E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); e1000_raise_ee_clk(hw, &eecd); e1000_lower_ee_clk(hw, &eecd); @@ -2383,25 +2399,25 @@ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); /* Clock high */ eecd |= E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); /* Select EEPROM */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); /* Clock low */ eecd &= ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); } /****************************************************************************** @@ -2420,13 +2436,13 @@ eecd |= E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); /* Falling edge of clock */ eecd &= ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + udelay(50); } /****************************************************************************** @@ -2475,7 +2491,7 @@ eecd = E1000_READ_REG(hw, EECD); while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { i++; - usec_delay(5); + udelay(5); eecd = E1000_READ_REG(hw, EECD); } if(!(eecd & E1000_EECD_GNT)) { @@ -2610,7 +2626,7 @@ eecd = E1000_READ_REG(hw, EECD); while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { i++; - usec_delay(5); + udelay(5); eecd = E1000_READ_REG(hw, EECD); } if(!(eecd & E1000_EECD_GNT)) { @@ -2661,7 +2677,7 @@ for(i = 0; i < 200; i++) { eecd = E1000_READ_REG(hw, EECD); if(eecd & E1000_EECD_DO) break; - usec_delay(50); + udelay(50); } if(i == 200) { DEBUGOUT("EEPROM Write did not complete\n"); @@ -3031,12 +3047,12 @@ const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF; uint16_t eeprom_data, i, temp; const uint16_t led_mask = 0x0F; - + DEBUGFUNC("e1000_id_led_init"); if(hw->mac_type < e1000_82540) { - /* Nothing to do */ - return 0; + /* Nothing to do */ + return 0; } ledctl = E1000_READ_REG(hw, LEDCTL); @@ -3053,39 +3069,39 @@ for(i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; switch(temp) { - case ID_LED_ON1_DEF2: - case ID_LED_ON1_ON2: - case ID_LED_ON1_OFF2: + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); hw->ledctl_mode1 |= ledctl_on << (i << 3); break; - case ID_LED_OFF1_DEF2: - case ID_LED_OFF1_ON2: - case ID_LED_OFF1_OFF2: + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); hw->ledctl_mode1 |= ledctl_off << (i << 3); break; - default: - /* Do nothing */ - break; - } - switch(temp) { - case ID_LED_DEF1_ON2: - case ID_LED_ON1_ON2: - case ID_LED_OFF1_ON2: + default: + /* Do nothing */ + break; + } + switch(temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); hw->ledctl_mode2 |= ledctl_on << (i << 3); break; - case ID_LED_DEF1_OFF2: - case ID_LED_ON1_OFF2: - case ID_LED_OFF1_OFF2: + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); hw->ledctl_mode2 |= ledctl_off << (i << 3); break; - default: - /* Do nothing */ - break; - } + default: + /* Do nothing */ + break; + } } return 0; } diff -Nru a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h --- a/drivers/net/e1000/e1000_hw.h Sat Aug 31 15:06:06 2002 +++ b/drivers/net/e1000/e1000_hw.h Sat Aug 31 15:06:06 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. + 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. - "Recipient" means the party to whom Intel delivers this Software. + 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. - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. + You 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. - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. + The full GNU General Public License is included in this distribution in the + file called LICENSE. - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -87,7 +42,8 @@ /* Enumerated types specific to the e1000 hardware */ /* Media Access Controlers */ typedef enum { - e1000_82542_rev2_0 = 0, + e1000_undefined = 0, + e1000_82542_rev2_0, e1000_82542_rev2_1, e1000_82543, e1000_82544, @@ -204,16 +160,18 @@ /* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_EEPROM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 +#define E1000_SUCCESS 0 +#define E1000_ERR_EEPROM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_TYPE 5 /* Function prototypes */ /* Initialization */ void e1000_reset_hw(struct e1000_hw *hw); int32_t e1000_init_hw(struct e1000_hw *hw); +int32_t e1000_set_mac_type(struct e1000_hw *hw); /* Link Configuration */ int32_t e1000_setup_link(struct e1000_hw *hw); @@ -1230,6 +1188,7 @@ #define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ #define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ +#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ /* Transmit Configuration Word */ #define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ @@ -1469,6 +1428,8 @@ #define PCIX_COMMAND_MMRBC_SHIFT 0x2 #define PCIX_STATUS_HI_MMRBC_MASK 0x0060 #define PCIX_STATUS_HI_MMRBC_SHIFT 0x5 +#define PCIX_STATUS_HI_MMRBC_4K 0x3 +#define PCIX_STATUS_HI_MMRBC_2K 0x2 /* The number of bits that we need to shift right to move the "pause" diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/e1000/e1000_main.c Sat Aug 31 15:05:59 2002 @@ -1,80 +1,53 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. + 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. - "Recipient" means the party to whom Intel delivers this Software. + 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. - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. + You 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. - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. + The full GNU General Public License is included in this distribution in the + file called LICENSE. - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ + #define __E1000_MAIN__ #include "e1000.h" /* Change Log * + * o Feature: merged in modified NAPI patch from Robert Olsson + * Uppsala Univeristy, Sweden. + * + * 4.3.15 8/9/02 + * o Converted from Dual BSD/GPL license to GPL license. + * o Clean up: use pci_[clear|set]_mwi rather than direct calls to + * pci_write_config_word. + * o Bug fix: added read-behind-write calls to post writes before delays. + * o Bug fix: removed mdelay busy-waits in interrupt context. + * o Clean up: direct clear of descriptor bits rather than using memset. + * o Bug fix: added wmb() for ia-64 between descritor writes and advancing + * descriptor tail. + * o Feature: added locking mechanism for asf functionality. + * o Feature: exposed two Tx and one Rx interrupt delay knobs for finer + * control over interurpt rate tuning. + * o Misc ethtool bug fixes. + * * 4.3.2 7/5/02 * o Bug fix: perform controller reset using I/O rather than mmio because * some chipsets try to perform a 64-bit write, but the controller ignores @@ -95,10 +68,10 @@ * * 4.2.17 5/30/02 */ - + char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "4.3.2-k1"; +char e1000_driver_version[] = "4.3.15-k1"; char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -186,7 +159,11 @@ static inline void e1000_irq_enable(struct e1000_adapter *adapter); static void e1000_intr(int irq, void *data, struct pt_regs *regs); static void e1000_clean_tx_irq(struct e1000_adapter *adapter); +#ifdef CONFIG_E1000_NAPI +static int e1000_poll(struct net_device *netdev, int *budget); +#else static void e1000_clean_rx_irq(struct e1000_adapter *adapter); +#endif static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); @@ -195,6 +172,7 @@ 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_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); @@ -233,7 +211,7 @@ MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); /** * e1000_init_module - Driver Registration Routine @@ -420,6 +398,10 @@ netdev->do_ioctl = &e1000_ioctl; netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = HZ; +#ifdef CONFIG_E1000_NAPI + netdev->poll = &e1000_poll; + netdev->weight = 64; +#endif netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; @@ -445,6 +427,11 @@ netdev->features = NETIF_F_SG; } +#ifdef NETIF_F_TSO + if(adapter->hw.mac_type >= e1000_82544) + netdev->features |= NETIF_F_TSO; +#endif + if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -483,6 +470,9 @@ adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; + INIT_TQUEUE(&adapter->tx_timeout_task, + (void (*)(void *))e1000_tx_timeout_task, netdev); + register_netdev(netdev); /* we're going to reset, so assume we have no link for now */ @@ -589,43 +579,8 @@ /* identify the MAC */ - switch (hw->device_id) { - case E1000_DEV_ID_82542: - switch (hw->revision_id) { - case E1000_82542_2_0_REV_ID: - hw->mac_type = e1000_82542_rev2_0; - break; - case E1000_82542_2_1_REV_ID: - hw->mac_type = e1000_82542_rev2_1; - break; - default: - hw->mac_type = e1000_82542_rev2_0; - E1000_ERR("Could not identify 82542 revision\n"); - } - break; - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - hw->mac_type = e1000_82543; - break; - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - hw->mac_type = e1000_82544; - break; - case E1000_DEV_ID_82540EM: - hw->mac_type = e1000_82540; - break; - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82545EM_FIBER: - hw->mac_type = e1000_82545; - break; - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_FIBER: - hw->mac_type = e1000_82546; - break; - default: - E1000_ERR("Should never have loaded on this device\n"); + if (e1000_set_mac_type(hw)) { + E1000_ERR("Unknown MAC Type\n"); BUG(); } @@ -821,7 +776,9 @@ /* Set the Tx Interrupt Delay register */ - E1000_WRITE_REG(&adapter->hw, TIDV, 64); + E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); + if(adapter->hw.mac_type >= e1000_82540) + E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); /* Program the Transmit Control Register */ @@ -951,8 +908,8 @@ /* set the Receive Delay Timer Register */ if(adapter->hw.mac_type >= e1000_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay); - E1000_WRITE_REG(&adapter->hw, RDTR, 64); + E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); + E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); /* Set the interrupt throttling rate. Value is calculated * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ @@ -1332,10 +1289,63 @@ #define E1000_TX_FLAGS_CSUM 0x00000001 #define E1000_TX_FLAGS_VLAN 0x00000002 +#define E1000_TX_FLAGS_TSO 0x00000004 #define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline boolean_t +e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) +{ +#ifdef NETIF_F_TSO + struct e1000_context_desc *context_desc; + int i; + uint8_t ipcss, ipcso, tucss, tucso, hdr_len; + uint16_t ipcse, tucse, mss; + + if(skb_shinfo(skb)->tso_size) { + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + mss = skb_shinfo(skb)->tso_size; + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, + IPPROTO_TCP, + 0); + ipcss = skb->nh.raw - skb->data; + ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; + ipcse = skb->h.raw - skb->data - 1; + tucss = skb->h.raw - skb->data; + tucso = (void *)&(skb->h.th->check) - (void *)skb->data; + tucse = 0; + + i = adapter->tx_ring.next_to_use; + context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + + context_desc->lower_setup.ip_fields.ipcss = ipcss; + context_desc->lower_setup.ip_fields.ipcso = ipcso; + context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); + context_desc->upper_setup.tcp_fields.tucss = tucss; + context_desc->upper_setup.tcp_fields.tucso = tucso; + 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(adapter->txd_cmd | + E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | + (skb->len - (hdr_len))); + + i = (i + 1) % adapter->tx_ring.count; + adapter->tx_ring.next_to_use = i; + + return TRUE; + } +#endif + + return FALSE; +} + +static inline boolean_t e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) { struct e1000_context_desc *context_desc; @@ -1434,6 +1444,12 @@ txd_upper = 0; txd_lower = adapter->txd_cmd; + if(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) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; @@ -1457,9 +1473,14 @@ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + tx_ring->next_to_use = i; E1000_WRITE_REG(&adapter->hw, TDT, i); - E1000_WRITE_FLUSH(&adapter->hw); } #define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0)) @@ -1478,22 +1499,29 @@ for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, adapter->max_data_per_txd); +#ifdef NETIF_F_TSO + if((skb_shinfo(skb)->tso_size) || (skb->ip_summed == CHECKSUM_HW)) + count++; +#else if(skb->ip_summed == CHECKSUM_HW) count++; +#endif if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) { netif_stop_queue(netdev); return 1; } - if(e1000_tx_csum(adapter, skb)) - tx_flags |= E1000_TX_FLAGS_CSUM; - if(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); } + if(e1000_tso(adapter, skb, tx_flags)) + tx_flags |= E1000_TX_FLAGS_TSO; + else if(e1000_tx_csum(adapter, skb)) + tx_flags |= E1000_TX_FLAGS_CSUM; + count = e1000_tx_map(adapter, skb); e1000_tx_queue(adapter, count, tx_flags); @@ -1513,8 +1541,19 @@ { struct e1000_adapter *adapter = netdev->priv; + /* Do the reset outside of interrupt context */ + schedule_task(&adapter->tx_timeout_task); +} + +static void +e1000_tx_timeout_task(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + netif_device_detach(netdev); e1000_down(adapter); e1000_up(adapter); + netif_device_attach(netdev); } /** @@ -1758,6 +1797,13 @@ { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; + +#ifdef CONFIG_E1000_NAPI + if (netif_rx_schedule_prep(netdev)) { + e1000_irq_disable(adapter); + __netif_rx_schedule(netdev); + } +#else uint32_t icr; int i = E1000_MAX_INTR; @@ -1773,7 +1819,37 @@ i--; } +#endif +} + +#ifdef CONFIG_E1000_NAPI +static int +e1000_process_intr(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + uint32_t icr; + int i = E1000_MAX_INTR; + int hasReceived = 0; + + while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) { + if (icr & E1000_ICR_RXT0) + hasReceived = 1; + + if (!(icr & ~(E1000_ICR_RXT0))) + break; + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->hw.get_link_status = 1; + mod_timer(&adapter->watchdog_timer, jiffies); + } + + e1000_clean_tx_irq(adapter); + i--; + } + + return hasReceived; } +#endif /** * e1000_clean_tx_irq - Reclaim resources after transmit completes @@ -1826,6 +1902,136 @@ } } +#ifdef CONFIG_E1000_NAPI +static int +e1000_poll(struct net_device *netdev, int *budget) +{ + struct e1000_adapter *adapter = netdev->priv; + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + unsigned long flags; + uint32_t length; + uint8_t last_byte; + int i; + int received = 0; + int rx_work_limit = *budget; + + if(rx_work_limit > netdev->quota) + rx_work_limit = netdev->quota; + + e1000_process_intr(netdev); + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + + while(rx_desc->status & E1000_RXD_STAT_DD) { + if(--rx_work_limit < 0) + goto not_done; + + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + rx_ring->buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + skb = rx_ring->buffer_info[i].skb; + length = le16_to_cpu(rx_desc->length); + + if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { + + /* All receives must fit into a single buffer */ + + E1000_DBG("Receive packet consumed multiple buffers\n"); + + dev_kfree_skb_irq(skb); + rx_desc->status = 0; + rx_ring->buffer_info[i].skb = NULL; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + + if(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; + rx_ring->buffer_info[i].skb = NULL; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + } + + /* Good Receive */ + skb_put(skb, length - ETHERNET_FCS_SIZE); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, rx_desc, skb); + + skb->protocol = eth_type_trans(skb, netdev); + if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + vlan_hwaccel_rx(skb, adapter->vlgrp, + (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); + } else { + netif_receive_skb(skb); + } + netdev->last_rx = jiffies; + + rx_desc->status = 0; + rx_ring->buffer_info[i].skb = NULL; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + received++; + } + + if(!received) + received = 1; + + e1000_alloc_rx_buffers(adapter); + + rx_ring->next_to_clean = i; + netdev->quota -= received; + *budget -= received; + + netif_rx_complete(netdev); + + e1000_irq_enable(adapter); + return 0; + +not_done: + + e1000_alloc_rx_buffers(adapter); + + rx_ring->next_to_clean = i; + netdev->quota -= received; + *budget -= received; + + return 1; +} +#else /** * e1000_clean_rx_irq - Send received data up the network stack, * @adapter: board private structure @@ -1929,6 +2135,7 @@ e1000_alloc_rx_buffers(adapter); } +#endif /** * e1000_alloc_rx_buffers - Replace used receive buffers @@ -1979,8 +2186,15 @@ rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); - if(!(i % E1000_RX_BUFFER_WRITE)) + if(!(i % E1000_RX_BUFFER_WRITE)) { + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + E1000_WRITE_REG(&adapter->hw, RDT, i); + } i = (i + 1) % rx_ring->count; } diff -Nru a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h --- a/drivers/net/e1000/e1000_osdep.h Sat Aug 31 15:05:55 2002 +++ b/drivers/net/e1000/e1000_osdep.h Sat Aug 31 15:05:55 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: - - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. - - "Recipient" means the party to whom Intel delivers this Software. - - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. - - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. - - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -84,8 +39,8 @@ #include #include #include +#include -#define usec_delay(x) udelay(x) #ifndef msec_delay #define msec_delay(x) do { if(in_interrupt()) { \ /* Don't mdelay in interrupt context! */ \ @@ -141,6 +96,6 @@ readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))) -#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS); +#define E1000_WRITE_FLUSH(a) ((void)E1000_READ_REG(a, STATUS)) #endif /* _E1000_OSDEP_H_ */ diff -Nru a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c --- a/drivers/net/e1000/e1000_param.c Sat Aug 31 15:05:54 2002 +++ b/drivers/net/e1000/e1000_param.c Sat Aug 31 15:05:54 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. - - "Recipient" means the party to whom Intel delivers this Software. - - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. - - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. - - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -192,6 +147,24 @@ E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); +/* Transmit Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); + +/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 0 + */ + +E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); + /* Receive Interrupt Delay in units of 1.024 microseconds * * Valid Range: 0-65535 @@ -201,6 +174,15 @@ E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); +/* Receive Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 128 + */ + +E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); + #define AUTONEG_ADV_DEFAULT 0x2F #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL @@ -215,11 +197,23 @@ #define MIN_RXD 80 #define MAX_82544_RXD 4096 -#define DEFAULT_RDTR 0 -#define DEFAULT_RADV 128 +#define DEFAULT_RDTR 128 +#define DEFAULT_RDTR_82544 0 #define MAX_RXDELAY 0xFFFF #define MIN_RXDELAY 0 +#define DEFAULT_RADV 128 +#define MAX_RXABSDELAY 0xFFFF +#define MIN_RXABSDELAY 0 + +#define DEFAULT_TIDV 64 +#define MAX_TXDELAY 0xFFFF +#define MIN_TXDELAY 0 + +#define DEFAULT_TADV 64 +#define MAX_TXABSDELAY 0xFFFF +#define MIN_TXABSDELAY 0 + struct e1000_option { enum { enable_option, range_option, list_option } type; char *name; @@ -376,20 +370,60 @@ e1000_validate_option(&fc, &opt); adapter->hw.fc = adapter->hw.original_fc = fc; } + { /* Transmit Interrupt Delay */ + char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV); + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Interrupt Delay", + .arg = { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }} + }; + opt.def = DEFAULT_TIDV; + opt.err = tidv; + + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt); + } + { /* Transmit Absolute Interrupt Delay */ + char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV); + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Absolute Interrupt Delay", + .arg = { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }} + }; + opt.def = DEFAULT_TADV; + opt.err = tadv; + + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt); + } { /* Receive Interrupt Delay */ char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR); - char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV); + char *rdtr_82544 = "using default of " + __MODULE_STRING(DEFAULT_RDTR_82544); struct e1000_option opt = { .type = range_option, .name = "Receive Interrupt Delay", .arg = { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }} }; e1000_mac_type mac_type = adapter->hw.mac_type; - opt.def = mac_type < e1000_82540 ? DEFAULT_RDTR : DEFAULT_RADV; - opt.err = mac_type < e1000_82540 ? rdtr : radv; + opt.def = mac_type > e1000_82544 ? DEFAULT_RDTR : 0; + opt.err = mac_type > e1000_82544 ? rdtr : rdtr_82544; adapter->rx_int_delay = RxIntDelay[bd]; e1000_validate_option(&adapter->rx_int_delay, &opt); + } + { /* Receive Absolute Interrupt Delay */ + char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV); + struct e1000_option opt = { + .type = range_option, + .name = "Receive Absolute Interrupt Delay", + .arg = { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }} + }; + opt.def = DEFAULT_RADV; + opt.err = radv; + + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt); } switch(adapter->hw.media_type) { diff -Nru a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c --- a/drivers/net/e1000/e1000_proc.c Sat Aug 31 15:06:06 2002 +++ b/drivers/net/e1000/e1000_proc.c Sat Aug 31 15:06:06 2002 @@ -1,73 +1,28 @@ /******************************************************************************* - This software program is available to you under a choice of one of two - licenses. You may choose to be licensed under either the GNU General Public - License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, - or the Intel BSD + Patent License, the text of which follows: - Recipient has requested a license and Intel Corporation ("Intel") is willing - to grant a license for the software entitled Linux Base Driver for the - Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided - by Intel Corporation. The following definitions apply to this license: + Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. - "Licensed Patents" means patent claims licensable by Intel Corporation which - are necessarily infringed by the use of sale of the Software alone or when - combined with the operating system referred to below. - - "Recipient" means the party to whom Intel delivers this Software. - - "Licensee" means Recipient and those third parties that receive a license to - any operating system available under the GNU General Public License 2.0 or - later. - - Copyright (c) 1999 - 2002 Intel Corporation. - All rights reserved. - - The license is provided to Recipient and Recipient's Licensees under the - following terms. - - Redistribution and use in source and binary forms of the Software, with or - without modification, are permitted provided that the following conditions - are met: - - Redistributions of source code of the Software may retain the above - copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form of the Software may reproduce the above - copyright notice, this list of conditions and the following disclaimer in - the documentation and/or materials provided with the distribution. - - Neither the name of Intel Corporation nor the names of its contributors - shall be used to endorse or promote products derived from this Software - without specific prior written permission. - - Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, use, sell, offer - to sell, import and otherwise transfer the Software, if any, in source code - and object code form. This license shall include changes to the Software - that are error corrections or other minor changes to the Software that do - not add functionality or features when the Software is incorporated in any - version of an operating system that has been distributed under the GNU - General Public License 2.0 or later. This patent license shall apply to the - combination of the Software and any operating system licensed under the GNU - General Public License 2.0 or later if, at the time Intel provides the - Software to Recipient, such addition of the Software to the then publicly - available versions of such operating systems available under the GNU General - Public License 2.0 or later (whether in gold, beta or alpha form) causes - such combination to be covered by the Licensed Patents. The patent license - shall not apply to any other combinations which include the Software. NO - hardware per se is licensed hereunder. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED - AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ @@ -667,9 +622,12 @@ LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc); LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc); - /* The 82542 does not have an alignment error count register */ - if(adapter->hw.mac_type >= e1000_82543) + /* The 82542 does not have some of these stats */ + if(adapter->hw.mac_type >= e1000_82543) { LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc); + LIST_ADD_U("Tx_TCP_Seg_Good", &adapter->stats.tsctc); + LIST_ADD_U("Tx_TCP_Seg_Failed", &adapter->stats.tsctfc); + } LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc); LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc); diff -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c --- a/drivers/net/loopback.c Sat Aug 31 15:05:54 2002 +++ b/drivers/net/loopback.c Sat Aug 31 15:05:54 2002 @@ -49,11 +49,72 @@ #include #include #include +#include #include /* For the statistics structure. */ #include /* For ARPHRD_ETHER */ +#include +#include #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) +/* KISS: just allocate small chunks and copy bits. + * + * So, in fact, this is documentation, explaining what we expect + * of largesending device modulo TCP checksum, which is ignored for loopback. + */ + +static void emulate_large_send_offload(struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4)); + unsigned int doffset = (iph->ihl + th->doff) * 4; + unsigned int mtu = skb_shinfo(skb)->tso_size + doffset; + unsigned int offset = 0; + u32 seq = ntohl(th->seq); + u16 id = ntohs(iph->id); + + while (offset + doffset < skb->len) { + unsigned int frag_size = min(mtu, skb->len - offset) - doffset; + struct sk_buff *nskb = alloc_skb(mtu + 32, GFP_ATOMIC); + + if (!nskb) + break; + skb_reserve(nskb, 32); + nskb->mac.raw = nskb->data - 14; + nskb->nh.raw = nskb->data; + iph = nskb->nh.iph; + memcpy(nskb->data, skb->nh.raw, doffset); + if (skb_copy_bits(skb, + doffset + offset, + nskb->data + doffset, + frag_size)) + BUG(); + skb_put(nskb, doffset + frag_size); + nskb->ip_summed = CHECKSUM_UNNECESSARY; + nskb->dev = skb->dev; + nskb->priority = skb->priority; + nskb->protocol = skb->protocol; + nskb->dst = dst_clone(skb->dst); + memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); + nskb->pkt_type = skb->pkt_type; + + th = (struct tcphdr*)(nskb->nh.raw + iph->ihl*4); + iph->tot_len = htons(frag_size + doffset); + iph->id = htons(id); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *) iph, iph->ihl); + th->seq = htonl(seq); + if (offset + doffset + frag_size < skb->len) + th->fin = th->psh = 0; + netif_rx(nskb); + offset += frag_size; + seq += frag_size; + id++; + } + + dev_kfree_skb(skb); +} + /* * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). @@ -86,6 +147,18 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; #endif + if (skb_shinfo(skb)->tso_size) { + struct iphdr *iph = skb->nh.iph; + + if (skb->protocol != htons(ETH_P_IP)) + BUG(); + if (iph->protocol != IPPROTO_TCP) + BUG(); + + emulate_large_send_offload(skb); + return 0; + } + dev->last_rx = jiffies; stats->rx_bytes+=skb->len; stats->tx_bytes+=skb->len; @@ -117,6 +190,12 @@ dev->rebuild_header = eth_rebuild_header; dev->flags = IFF_LOOPBACK; dev->features = NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA; + + /* Current netfilter will die with oom linearizing large skbs, + * however this will be cured before 2.5.x is done. + */ + dev->features |= NETIF_F_TSO; + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Sat Aug 31 15:05:55 2002 +++ b/drivers/net/pcmcia/3c574_cs.c Sat Aug 31 15:05:55 2002 @@ -86,6 +86,8 @@ #include #include #include +#include +#include #include #include @@ -1189,6 +1191,26 @@ return worklimit; } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "3c574_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + /* Provide ioctl() calls to examine the MII xcvr state. */ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -1202,6 +1224,8 @@ data[0], data[1], data[2], data[3]); switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *)rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Sat Aug 31 15:06:00 2002 +++ b/drivers/net/pcmcia/ibmtr_cs.c Sat Aug 31 15:06:00 2002 @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include #include @@ -164,6 +166,37 @@ CardServices(ReportError, handle, &err); } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "ibmtr_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + + switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + default: + return -EOPNOTSUPP; + } +} + /*====================================================================== ibmtr_attach() creates an "instance" of the driver, allocating @@ -216,6 +249,7 @@ link->irq.Instance = info->dev = dev; dev->init = &ibmtr_probe; + dev->do_ioctl = &private_ioctl; /* Register with Card Services */ link->next = dev_list; diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Sat Aug 31 15:06:06 2002 +++ b/drivers/net/pcmcia/pcnet_cs.c Sat Aug 31 15:06:06 2002 @@ -37,9 +37,11 @@ #include #include #include +#include #include #include #include +#include #include #include <../drivers/net/8390.h> @@ -115,6 +117,7 @@ static int pcnet_open(struct net_device *dev); static int pcnet_close(struct net_device *dev); static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd); static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); static void ei_watchdog(u_long arg); static void pcnet_reset_8390(struct net_device *dev); @@ -772,8 +775,10 @@ dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id); if (info->pna_phy) printk("PNA, "); - } else + } else { printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name); + dev->do_ioctl = &do_ioctl_light; + } printk("io %#3lx, irq %d,", dev->base_addr, dev->irq); if (info->flags & USE_SHMEM) printk (" mem %#5lx,", dev->mem_start); @@ -1206,12 +1211,37 @@ /*====================================================================*/ +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "pcnet_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +/*====================================================================*/ + + static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { pcnet_dev_t *info = (pcnet_dev_t *)dev; u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: data[0] = info->phy_id; case SIOCDEVPRIVATE+1: @@ -1224,6 +1254,17 @@ return 0; } return -EOPNOTSUPP; +} + +/*====================================================================*/ + +static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + } + return -EOPNOTSUPP; } /*====================================================================*/ diff -Nru a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c --- a/drivers/net/pcmcia/ray_cs.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/pcmcia/ray_cs.c Sat Aug 31 15:05:59 2002 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include @@ -1224,7 +1226,32 @@ } } } /* end encapsulate_frame */ + + /*===========================================================================*/ + +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "ray_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +/*====================================================================*/ + static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { ray_dev_t *local = (ray_dev_t *)dev->priv; @@ -1242,6 +1269,10 @@ /* Validate the command */ switch (cmd) { + case SIOCETHTOOL: + err = netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data); + break; + #if WIRELESS_EXT > 7 /* --------------- WIRELESS EXTENSIONS --------------- */ /* Get name */ diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Sat Aug 31 15:05:59 2002 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Sat Aug 31 15:05:59 2002 @@ -74,9 +74,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -1715,6 +1717,26 @@ return 0; } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "xirc2ps_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -1730,6 +1752,8 @@ return -EOPNOTSUPP; switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = 0; /* we have only this address */ /* fall trough */ diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c --- a/drivers/net/sb1250-mac.c Sat Aug 31 15:06:06 2002 +++ b/drivers/net/sb1250-mac.c Sat Aug 31 15:06:06 2002 @@ -2544,7 +2544,7 @@ spin_unlock_irqrestore(&sc->sbm_lock, flags); /* Make sure there is no irq-handler running on a different CPU. */ - synchronize_irq(); + synchronize_irq(dev->irq); free_irq(dev->irq, dev); diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c --- a/drivers/net/tulip/interrupt.c Sat Aug 31 15:05:55 2002 +++ b/drivers/net/tulip/interrupt.c Sat Aug 31 15:05:55 2002 @@ -263,7 +263,7 @@ This would turn on IM for devices that is not contributing to backlog congestion with unnecessary latency. - We monitor the the device RX-ring and have: + We monitor the device RX-ring and have: HW Interrupt Mitigation either ON or OFF. diff -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c --- a/drivers/net/tulip/xircom_cb.c Sat Aug 31 15:06:06 2002 +++ b/drivers/net/tulip/xircom_cb.c Sat Aug 31 15:06:06 2002 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -176,6 +178,37 @@ } #endif +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "xircom_cb", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + + switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + default: + return -EOPNOTSUPP; + } +} + /* xircom_probe is the code that gets called on device insertion. it sets up the hardware and registers the device to the networklayer. @@ -265,6 +298,7 @@ dev->stop = &xircom_close; dev->get_stats = &xircom_get_stats; dev->priv = private; + dev->do_ioctl = &private_ioctl; pdev->driver_data = dev; diff -Nru a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c --- a/drivers/net/wan/sdla_x25.c Sat Aug 31 15:05:54 2002 +++ b/drivers/net/wan/sdla_x25.c Sat Aug 31 15:05:54 2002 @@ -4721,7 +4721,7 @@ /*=============================================================== * api_incoming_call * - * Pass an incoming call request up the the listening + * Pass an incoming call request up the listening * sock. If the API sock is not listening reject the * call. * diff -Nru a/drivers/pci/access.c b/drivers/pci/access.c --- a/drivers/pci/access.c Sat Aug 31 15:06:06 2002 +++ b/drivers/pci/access.c Sat Aug 31 15:06:06 2002 @@ -19,29 +19,45 @@ #define PCI_word_BAD (pos & 1) #define PCI_dword_BAD (pos & 3) -#define PCI_OP(rw,size,type) \ -int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \ +#define PCI_OP_READ(size,type,len) \ +int pci_bus_read_config_##size \ + (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ { \ int res; \ unsigned long flags; \ + u32 data = 0; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ spin_lock_irqsave(&pci_lock, flags); \ - res = dev->bus->ops->rw##_##size(dev, pos, value); \ + res = bus->ops->read(bus, devfn, pos, len, &data); \ + *value = (type)data; \ spin_unlock_irqrestore(&pci_lock, flags); \ return res; \ } -PCI_OP(read, byte, u8 *) -PCI_OP(read, word, u16 *) -PCI_OP(read, dword, u32 *) -PCI_OP(write, byte, u8) -PCI_OP(write, word, u16) -PCI_OP(write, dword, u32) +#define PCI_OP_WRITE(size,type,len) \ +int pci_bus_write_config_##size \ + (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ +{ \ + int res; \ + unsigned long flags; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + res = bus->ops->write(bus, devfn, pos, len, value); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return res; \ +} + +PCI_OP_READ(byte, u8, 1) +PCI_OP_READ(word, u16, 2) +PCI_OP_READ(dword, u32, 4) +PCI_OP_WRITE(byte, u8, 1) +PCI_OP_WRITE(word, u16, 2) +PCI_OP_WRITE(dword, u32, 4) -EXPORT_SYMBOL(pci_read_config_byte); -EXPORT_SYMBOL(pci_read_config_word); -EXPORT_SYMBOL(pci_read_config_dword); -EXPORT_SYMBOL(pci_write_config_byte); -EXPORT_SYMBOL(pci_write_config_word); -EXPORT_SYMBOL(pci_write_config_dword); +EXPORT_SYMBOL(pci_bus_read_config_byte); +EXPORT_SYMBOL(pci_bus_read_config_word); +EXPORT_SYMBOL(pci_bus_read_config_dword); +EXPORT_SYMBOL(pci_bus_write_config_byte); +EXPORT_SYMBOL(pci_bus_write_config_word); +EXPORT_SYMBOL(pci_bus_write_config_dword); EXPORT_SYMBOL(pci_lock); diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c --- a/drivers/pci/pool.c Sat Aug 31 15:06:06 2002 +++ b/drivers/pci/pool.c Sat Aug 31 15:06:06 2002 @@ -17,18 +17,70 @@ size_t allocation; char name [32]; wait_queue_head_t waitq; + struct list_head pools; }; struct pci_page { /* cacheable header for 'allocation' bytes */ struct list_head page_list; void *vaddr; dma_addr_t dma; + unsigned in_use; unsigned long bitmap [0]; }; #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_POISON_BYTE 0xa7 +static spinlock_t pools_lock = SPIN_LOCK_UNLOCKED; + +static ssize_t +show_pools (struct device *dev, char *buf, size_t count, loff_t off) +{ + struct pci_dev *pdev; + unsigned long flags; + unsigned temp, size; + char *next; + struct list_head *i, *j; + + if (off != 0) + return 0; + + pdev = container_of (dev, struct pci_dev, dev); + next = buf; + size = count; + + temp = snprintf (next, size, "poolinfo - 0.1\n"); + size -= temp; + next += temp; + + spin_lock_irqsave (&pools_lock, flags); + list_for_each (i, &pdev->pools) { + struct pci_pool *pool; + unsigned pages = 0, blocks = 0; + + pool = list_entry (i, struct pci_pool, pools); + + list_for_each (j, &pool->page_list) { + struct pci_page *page; + + page = list_entry (j, struct pci_page, page_list); + pages++; + blocks += page->in_use; + } + + /* per-pool info, no real statistics yet */ + temp = snprintf (next, size, "%-16s %4u %4u %4u %2u\n", + pool->name, + blocks, pages * pool->blocks_per_page, + pool->size, pages); + size -= temp; + next += temp; + } + spin_unlock_irqrestore (&pools_lock, flags); + + return count - size; +} +static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL); /** * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma. @@ -56,6 +108,7 @@ size_t size, size_t align, size_t allocation, int mem_flags) { struct pci_pool *retval; + unsigned long flags; if (align == 0) align = 1; @@ -84,6 +137,17 @@ retval->name [sizeof retval->name - 1] = 0; retval->dev = pdev; + + if (pdev) { + spin_lock_irqsave (&pools_lock, flags); + /* note: not currently insisting "name" be unique */ + if (list_empty (&pdev->pools)) + device_create_file (&pdev->dev, &dev_attr_pools); + list_add (&retval->pools, &pdev->pools); + spin_unlock_irqrestore (&pools_lock, flags); + } else + INIT_LIST_HEAD (&retval->pools); + INIT_LIST_HEAD (&retval->page_list); spin_lock_init (&retval->lock); retval->size = size; @@ -117,6 +181,7 @@ memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); #endif list_add (&page->page_list, &pool->page_list); + page->in_use = 0; } else { kfree (page); page = 0; @@ -177,6 +242,13 @@ } else pool_free_page (pool, page); } + + spin_lock (&pools_lock); + list_del (&pool->pools); + if (pool->dev && list_empty (&pool->dev->pools)) + device_remove_file (&pool->dev->dev, &dev_attr_pools); + spin_unlock (&pools_lock); + spin_unlock_irqrestore (&pool->lock, flags); kfree (pool); } @@ -243,6 +315,7 @@ clear_bit (0, &page->bitmap [0]); offset = 0; ready: + page->in_use++; retval = offset + page->vaddr; *handle = offset + page->dma; done: @@ -318,6 +391,7 @@ #endif spin_lock_irqsave (&pool->lock, flags); + page->in_use--; set_bit (block, &page->bitmap [map]); if (waitqueue_active (&pool->waitq)) wake_up (&pool->waitq); diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c Sat Aug 31 15:05:54 2002 +++ b/drivers/pci/probe.c Sat Aug 31 15:05:55 2002 @@ -364,6 +364,7 @@ sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); + INIT_LIST_HEAD(&dev->pools); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ diff -Nru a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c --- a/drivers/s390/block/dasd_3990_erp.c Sat Aug 31 15:06:06 2002 +++ b/drivers/s390/block/dasd_3990_erp.c Sat Aug 31 15:06:06 2002 @@ -2338,10 +2338,10 @@ * DASD_3990_ERP_ERROR_MATCH * * DESCRIPTION - * check if the the device status of the given cqr is the same. + * Check if the device status of the given cqr is the same. * This means that the failed CCW and the relevant sense data * must match. - * I don't distinguish between 24 and 32 byte sense becaus in case of + * I don't distinguish between 24 and 32 byte sense because in case of * 24 byte sense byte 25 and 27 is set as well. * * PARAMETER diff -Nru a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c --- a/drivers/sbus/char/openprom.c Sat Aug 31 15:06:04 2002 +++ b/drivers/sbus/char/openprom.c Sat Aug 31 15:06:06 2002 @@ -68,7 +68,7 @@ */ static int copyin(struct openpromio *info, struct openpromio **opp_p) { - int bufsize; + unsigned int bufsize; if (!info || !opp_p) return -EFAULT; diff -Nru a/drivers/scsi/Config.in b/drivers/scsi/Config.in --- a/drivers/scsi/Config.in Sat Aug 31 15:05:59 2002 +++ b/drivers/scsi/Config.in Sat Aug 31 15:05:59 2002 @@ -221,10 +221,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi -if [ "$CONFIG_PPC" = "y" ]; then +if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI if [ "$CONFIG_SCSI_MESH" != "n" ]; then int ' maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5 + int ' initial bus reset delay (ms) (0 = no reset)' CONFIG_SCSI_MESH_RESET_DELAY_MS 4000 fi dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI fi diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c --- a/drivers/scsi/NCR53C9x.c Sat Aug 31 15:05:55 2002 +++ b/drivers/scsi/NCR53C9x.c Sat Aug 31 15:05:55 2002 @@ -1381,7 +1381,7 @@ don = esp->dma_ports_p(esp); if(don) { esp->dma_ints_off(esp); - synchronize_irq(); + synchronize_irq(esp->irq); } if(esp->issue_SC) { Scsi_Cmnd **prev, *this; diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Sat Aug 31 15:05:55 2002 +++ b/drivers/scsi/dpt_i2o.c Sat Aug 31 15:05:55 2002 @@ -112,10 +112,6 @@ static adpt_hba* hba_chain = NULL; static int hba_count = 0; -// Debug flags to be put into the HBA flags field when initialized -// Make sure to enable DEBUG_PRINT for these flags to work -static unsigned long DebugFlags = HBA_FLAGS_DBG_SCAN_B | HBA_FLAGS_DBG_FLAGS_MASK; - static struct file_operations adpt_fops = { ioctl: adpt_ioctl, open: adpt_open, diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c Sat Aug 31 15:05:54 2002 +++ b/drivers/scsi/fdomain.c Sat Aug 31 15:05:54 2002 @@ -2042,7 +2042,7 @@ free_irq(shpnt->irq, shpnt); if (shpnt->io_port && shpnt->n_io_port) release_region(shpnt->io_port, shpnt->n_io_port); - + return 0; } MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Sat Aug 31 15:06:03 2002 +++ b/drivers/scsi/ide-scsi.c Sat Aug 31 15:06:03 2002 @@ -491,7 +491,6 @@ } static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES]; -static int idescsi_initialized = 0; static void idescsi_add_settings(ide_drive_t *drive) { @@ -539,16 +538,20 @@ return 0; } +static int idescsi_reinit(ide_drive_t *drive); + /* * IDE subdriver functions, registered with ide.c */ static ide_driver_t idescsi_driver = { + owner: THIS_MODULE, name: "ide-scsi", version: IDESCSI_VERSION, media: ide_scsi, busy: 0, supports_dma: 1, supports_dsc_overlap: 0, + reinit: idescsi_reinit, cleanup: idescsi_cleanup, standby: NULL, flushcache: NULL, @@ -563,53 +566,36 @@ capacity: NULL, special: NULL, proc: NULL, + drives: LIST_HEAD_INIT(idescsi_driver.drives), }; -int idescsi_init (void); -static ide_module_t idescsi_module = { - IDE_DRIVER_MODULE, - idescsi_init, - &idescsi_driver, - NULL -}; - -/* - * idescsi_init will register the driver for each scsi. - */ -int idescsi_init (void) +static int idescsi_reinit(ide_drive_t *drive) { - ide_drive_t *drive; idescsi_scsi_t *scsi; - byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; - int i, failed, id; + int id; - if (idescsi_initialized) - return 0; - idescsi_initialized = 1; - for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++) - idescsi_drives[i] = NULL; - MOD_INC_USE_COUNT; - for (i = 0; media[i] != 255; i++) { - failed = 0; - while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { - - if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { - printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) { - printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (scsi); - continue; - } - for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); - idescsi_setup (drive, scsi, id); - failed--; - } + if (!strstr("ide-scsi", drive->driver_req)) + goto failed; + if (!drive->present) + goto failed; + /* we accept everything except ide-disk */ + if (drive->media == ide_disk) + goto failed; + if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { + printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); + goto failed; + } + if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); + kfree (scsi); + goto failed; } - ide_register_module(&idescsi_module); - MOD_DEC_USE_COUNT; + for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++) + ; + idescsi_setup (drive, scsi, id); return 0; +failed: + return 1; } int idescsi_detect (Scsi_Host_Template *host_template) @@ -857,27 +843,15 @@ static int __init init_idescsi_module(void) { - idescsi_init(); + ide_register_driver(&idescsi_driver); scsi_register_host(&idescsi_template); return 0; } static void __exit exit_idescsi_module(void) { - ide_drive_t *drive; - byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; - int i, failed; - scsi_unregister_host(&idescsi_template); - for (i = 0; media[i] != 255; i++) { - failed = 0; - while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL) - if (idescsi_cleanup (drive)) { - printk ("%s: exit_idescsi_module() called while still busy\n", drive->name); - failed++; - } - } - ide_unregister_module(&idescsi_module); + ide_unregister_driver(&idescsi_driver); } module_init(init_idescsi_module); diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c Sat Aug 31 15:06:06 2002 +++ b/drivers/scsi/imm.c Sat Aug 31 15:06:06 2002 @@ -1112,7 +1112,7 @@ } /* - * Apparently the the disk->capacity attribute is off by 1 sector + * Apparently the disk->capacity attribute is off by 1 sector * for all disk drives. We add the one here, but it should really * be done in sd.c. Even if it gets fixed there, this will still * work. diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c Sat Aug 31 15:05:54 2002 +++ b/drivers/scsi/ppa.c Sat Aug 31 15:05:54 2002 @@ -993,7 +993,7 @@ } /* - * Apparently the the disk->capacity attribute is off by 1 sector + * Apparently the disk->capacity attribute is off by 1 sector * for all disk drives. We add the one here, but it should really * be done in sd.c. Even if it gets fixed there, this will still * work. diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sat Aug 31 15:05:55 2002 +++ b/drivers/scsi/sd.c Sat Aug 31 15:05:55 2002 @@ -523,13 +523,6 @@ if (!sdp->online) { goto error_out; } - /* - * See if we are requesting a non-existent partition. Do this - * after checking for disk change. - */ - if (sd[SD_PARTITION(inode->i_rdev)].nr_sects == 0) { - goto error_out; - } if (sdp->removable) if (sdp->access_count==1) diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Sat Aug 31 15:06:00 2002 +++ b/drivers/scsi/sg.c Sat Aug 31 15:06:00 2002 @@ -54,6 +54,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Sat Aug 31 15:06:03 2002 +++ b/drivers/scsi/st.c Sat Aug 31 15:06:03 2002 @@ -109,6 +109,7 @@ }, { "try_direct_io", &try_direct_io + } }; #endif diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c --- a/drivers/scsi/sym53c8xx.c Sat Aug 31 15:05:54 2002 +++ b/drivers/scsi/sym53c8xx.c Sat Aug 31 15:05:54 2002 @@ -2650,7 +2650,7 @@ ** The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS ** is a critical path. If it is partially executed, it then ** may happen that the job address is not yet in the DSA - ** and the the next queue position points to the next JOB. + ** and the next queue position points to the next JOB. */ SCR_LOAD_ABS (dsa, 4), PADDRH (startpos), @@ -12884,7 +12884,7 @@ ** differ and attach them using the order in the NVRAM. ** ** If no NVRAM is found or data appears invalid attach boards in -** the the order they are detected. +** the order they are detected. **=================================================================== */ int __init sym53c8xx_detect(Scsi_Host_Template *tpnt) diff -Nru a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h --- a/drivers/scsi/sym53c8xx_2/sym_fw1.h Sat Aug 31 15:06:06 2002 +++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h Sat Aug 31 15:06:06 2002 @@ -283,7 +283,7 @@ * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS * is a critical path. If it is partially executed, it then * may happen that the job address is not yet in the DSA - * and the the next queue position points to the next JOB. + * and the next queue position points to the next JOB. */ }/*-------------------------< GETJOB_BEGIN >---------------------*/,{ /* diff -Nru a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h --- a/drivers/scsi/sym53c8xx_2/sym_fw2.h Sat Aug 31 15:06:06 2002 +++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h Sat Aug 31 15:06:06 2002 @@ -280,7 +280,7 @@ * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS * is a critical path. If it is partially executed, it then * may happen that the job address is not yet in the DSA - * and the the next queue position points to the next JOB. + * and the next queue position points to the next JOB. */ SCR_LOAD_ABS (dsa, 4), PADDR_B (startpos), diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Sat Aug 31 15:06:00 2002 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Sat Aug 31 15:06:00 2002 @@ -2708,7 +2708,7 @@ * differ and attach them using the order in the NVRAM. * * If no NVRAM is found or data appears invalid attach boards in - * the the order they are detected. + * the order they are detected. */ int __init sym53c8xx_detect(Scsi_Host_Template *tpnt) { diff -Nru a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h --- a/drivers/scsi/sym53c8xx_comm.h Sat Aug 31 15:05:54 2002 +++ b/drivers/scsi/sym53c8xx_comm.h Sat Aug 31 15:05:54 2002 @@ -2509,7 +2509,7 @@ ** differ and attach them using the order in the NVRAM. ** ** If no NVRAM is found or data appears invalid attach boards in -** the the order they are detected. +** the order they are detected. ** **=================================================================== */ diff -Nru a/drivers/serial/Config.in b/drivers/serial/Config.in --- a/drivers/serial/Config.in Sat Aug 31 15:05:54 2002 +++ b/drivers/serial/Config.in Sat Aug 31 15:05:54 2002 @@ -51,7 +51,7 @@ dep_bool ' Console on SA1100 serial port' CONFIG_SERIAL_SA1100_CONSOLE $CONFIG_SERIAL_SA1100 fi -if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then +if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then define_bool CONFIG_SERIAL_SUNCORE y define_bool CONFIG_SERIAL_CORE_CONSOLE y tristate 'Sun Zilog8530 serial support' CONFIG_SERIAL_SUNZILOG diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/class/bluetty.c Sat Aug 31 15:05:55 2002 @@ -289,7 +289,7 @@ int i; int status; - dbg (__FUNCTION__); + dbg ("%s", __FUNCTION__); /* try to find a free urb in our list */ for (i = 0; i < NUM_CONTROL_URBS; ++i) { @@ -300,7 +300,7 @@ } } if (urb == NULL) { - dbg (__FUNCTION__ " - no free urbs"); + dbg ("%s - no free urbs", __FUNCTION__); return -ENOMEM; } @@ -308,7 +308,7 @@ if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc (len, GFP_KERNEL); if (urb->transfer_buffer == NULL) { - err (__FUNCTION__" - out of memory"); + err ("%s - out of memory", __FUNCTION__); return -ENOMEM; } } @@ -316,7 +316,7 @@ kfree (urb->transfer_buffer); urb->transfer_buffer = kmalloc (len, GFP_KERNEL); if (urb->transfer_buffer == NULL) { - err (__FUNCTION__" - out of memory"); + err ("%s - out of memory", __FUNCTION__); return -ENOMEM; } } @@ -334,7 +334,7 @@ /* send it down the pipe */ status = usb_submit_urb(urb, GFP_KERNEL); if (status) - dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status); + dbg("%s - usb_submit_urb(control) failed with status = %d", __FUNCTION__, status); return status; } @@ -351,7 +351,7 @@ struct usb_bluetooth *bluetooth; int result; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* initialize the pointer incase something fails */ tty->driver_data = NULL; @@ -389,7 +389,7 @@ bluetooth_read_bulk_callback, bluetooth); result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); if (result) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result); + dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result); #endif FILL_INT_URB (bluetooth->interrupt_in_urb, bluetooth->dev, usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress), @@ -399,7 +399,7 @@ bluetooth->interrupt_in_interval); result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL); if (result) - dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result); + dbg("%s - usb_submit_urb(interrupt in) failed with status %d", __FUNCTION__, result); } up(&bluetooth->lock); @@ -417,10 +417,10 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not opened"); + dbg ("%s - device not opened", __FUNCTION__); return; } @@ -456,24 +456,24 @@ return -ENODEV; } - dbg(__FUNCTION__ " - %d byte(s)", count); + dbg("%s - %d byte(s)", __FUNCTION__, count); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not opened"); + dbg ("%s - device not opened", __FUNCTION__); return -EINVAL; } if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); + dbg("%s - write request of 0 bytes", __FUNCTION__); return 0; } if (count == 1) { - dbg(__FUNCTION__ " - write request only included type %d", buf[0]); + dbg("%s - write request only included type %d", __FUNCTION__, buf[0]); return 1; } #ifdef DEBUG - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); + printk (KERN_DEBUG __FILE__ ": %s - length = %d, data = ", __FUNCTION__, count); for (i = 0; i < count; ++i) { printk ("%.2x ", buf[i]); } @@ -483,7 +483,7 @@ if (from_user) { temp_buffer = kmalloc (count, GFP_KERNEL); if (temp_buffer == NULL) { - err (__FUNCTION__ "- out of memory."); + err ("%s - out of memory.", __FUNCTION__); retval = -ENOMEM; goto exit; } @@ -499,7 +499,7 @@ switch (*current_buffer) { /* First byte indicates the type of packet */ case CMD_PKT: - /* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/ + /* dbg("%s- Send cmd_pkt len:%d", __FUNCTION__, count);*/ retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, ¤t_buffer[1], count-1); if (retval) { @@ -525,7 +525,7 @@ } } if (urb == NULL) { - dbg (__FUNCTION__ " - no free urbs"); + dbg ("%s - no free urbs", __FUNCTION__); retval = bytes_sent; goto exit; } @@ -541,7 +541,7 @@ /* send it down the pipe */ retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval); + dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, retval); goto exit; } #ifdef BTBUGGYHARDWARE @@ -560,7 +560,7 @@ break; default : - dbg(__FUNCTION__" - unsupported (at this time) write type"); + dbg("%s - unsupported (at this time) write type", __FUNCTION__); retval = -EINVAL; break; } @@ -583,10 +583,10 @@ return -ENODEV; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return -EINVAL; } @@ -596,7 +596,7 @@ } } - dbg(__FUNCTION__ " - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return room; } @@ -612,7 +612,7 @@ } if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return -EINVAL; } @@ -622,7 +622,7 @@ } } - dbg (__FUNCTION__ " - returns %d", chars); + dbg ("%s - returns %d", __FUNCTION__, chars); return chars; } @@ -635,14 +635,14 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return; } - dbg(__FUNCTION__ " unsupported (at this time)"); + dbg("%s unsupported (at this time)", __FUNCTION__); return; } @@ -656,14 +656,14 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return; } - dbg(__FUNCTION__ " unsupported (at this time)"); + dbg("%s unsupported (at this time)", __FUNCTION__); } @@ -675,10 +675,10 @@ return -ENODEV; } - dbg(__FUNCTION__ " - cmd 0x%.4x", cmd); + dbg("%s - cmd 0x%.4x", __FUNCTION__, cmd); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return -ENODEV; } @@ -695,10 +695,10 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return; } @@ -717,10 +717,10 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return; } @@ -731,7 +731,7 @@ bluetooth_read_bulk_callback, bluetooth); result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); if (result) - err (__FUNCTION__ " - failed submitting read urb, error %d", result); + err ("%s - failed submitting read urb, error %d", __FUNCTION__, result); } } @@ -742,10 +742,10 @@ return; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth->open_count) { - dbg (__FUNCTION__ " - device not open"); + dbg ("%s - device not open", __FUNCTION__); return; } @@ -768,27 +768,27 @@ unsigned int count = urb->actual_length; unsigned int packet_size; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth) { - dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status); + dbg("%s - nonzero int status received: %d", __FUNCTION__, urb->status); return; } if (!count) { - dbg(__FUNCTION__ " - zero length int"); + dbg("%s - zero length int", __FUNCTION__); return; } #ifdef DEBUG if (count) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count); + printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); for (i = 0; i < count; ++i) { printk ("%.2x ", data[i]); } @@ -818,7 +818,7 @@ } if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) { - err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE"); + err("%s - exceeded EVENT_BUFFER_SIZE", __FUNCTION__); bluetooth->int_packet_pos = 0; return; } @@ -834,7 +834,7 @@ return; if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) { - err(__FUNCTION__ " - packet was too long"); + err("%s - packet was too long", __FUNCTION__); bluetooth->int_packet_pos = 0; return; } @@ -858,15 +858,15 @@ { struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth) { - dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } } @@ -882,30 +882,30 @@ int result; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth) { - dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); if (urb->status == -ENOENT) { - dbg(__FUNCTION__ " - URB canceled, won't reschedule"); + dbg("%s - URB canceled, won't reschedule", __FUNCTION__); return; } goto exit; } if (!count) { - dbg(__FUNCTION__ " - zero length read bulk"); + dbg("%s - zero length read bulk", __FUNCTION__); goto exit; } #ifdef DEBUG if (count) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count); + printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); for (i = 0; i < count; ++i) { printk ("%.2x ", data[i]); } @@ -922,7 +922,7 @@ bluetooth_read_bulk_callback, bluetooth); result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); if (result) - err (__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } @@ -939,7 +939,7 @@ } if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) { - err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE"); + err("%s - exceeded ACL_BUFFER_SIZE", __FUNCTION__); bluetooth->bulk_packet_pos = 0; goto exit; } @@ -956,7 +956,7 @@ } if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) { - err(__FUNCTION__ " - packet was too long"); + err("%s - packet was too long", __FUNCTION__); bluetooth->bulk_packet_pos = 0; goto exit; } @@ -983,7 +983,7 @@ bluetooth_read_bulk_callback, bluetooth); result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); if (result) - err (__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } @@ -993,15 +993,15 @@ { struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth) { - dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -1017,7 +1017,7 @@ struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); struct tty_struct *tty; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (!bluetooth) { return; @@ -1025,7 +1025,7 @@ tty = bluetooth->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg(__FUNCTION__ " - write wakeup call."); + dbg("%s - write wakeup call.", __FUNCTION__); (tty->ldisc.write_wakeup)(tty); } @@ -1087,7 +1087,7 @@ if ((num_bulk_in != 1) || (num_bulk_out != 1) || (num_interrupt_in != 1)) { - dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound."); + dbg ("%s - improper number of endpoints. Bluetooth driver not bound.", __FUNCTION__); return NULL; } @@ -1327,7 +1327,7 @@ bluetooth_tty_driver.init_termios = tty_std_termios; bluetooth_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; if (tty_register_driver (&bluetooth_tty_driver)) { - err(__FUNCTION__ " - failed to register tty driver"); + err("%s - failed to register tty driver", __FUNCTION__); return -1; } diff -Nru a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c --- a/drivers/usb/core/buffer.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/core/buffer.c Sat Aug 31 15:05:59 2002 @@ -182,5 +182,47 @@ : PCI_DMA_TODEVICE); } +int hcd_buffer_map_sg ( + struct usb_bus *bus, + struct scatterlist *sg, + int *n_hw_ents, + int nents, + int direction +) { + struct usb_hcd *hcd = bus->hcpriv; -// FIXME DMA-Mappings for struct scatterlist + // FIXME pci_map_sg() has no standard failure mode! + *n_hw_ents = pci_map_sg(hcd->pdev, sg, nents, + (direction == USB_DIR_IN) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + return 0; +} + +void hcd_buffer_sync_sg ( + struct usb_bus *bus, + struct scatterlist *sg, + int n_hw_ents, + int direction +) { + struct usb_hcd *hcd = bus->hcpriv; + + pci_dma_sync_sg(hcd->pdev, sg, n_hw_ents, + (direction == USB_DIR_IN) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); +} + +void hcd_buffer_unmap_sg ( + struct usb_bus *bus, + struct scatterlist *sg, + int n_hw_ents, + int direction +) { + struct usb_hcd *hcd = bus->hcpriv; + + pci_unmap_sg(hcd->pdev, sg, n_hw_ents, + (direction == USB_DIR_IN) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); +} diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/core/hcd-pci.c Sat Aug 31 15:06:00 2002 @@ -58,7 +58,6 @@ struct hc_driver *driver; unsigned long resource, len; void *base; - u8 latency, limit; struct usb_hcd *hcd; int retval, region; char buf [8], *bufp = buf; @@ -144,15 +143,6 @@ } info ("%s @ %s, %s", hcd->description, dev->slot_name, dev->name); - - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - if (latency) { - pci_read_config_byte (dev, PCI_MAX_LAT, &limit); - if (limit && limit < latency) { - dbg ("PCI latency reduced to max %d", limit); - pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); - } - } #ifndef __sparc__ sprintf (buf, "%d", dev->irq); diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/core/hcd.c Sat Aug 31 15:06:00 2002 @@ -1270,6 +1270,9 @@ .buffer_map = hcd_buffer_map, .buffer_dmasync = hcd_buffer_dmasync, .buffer_unmap = hcd_buffer_unmap, + .buffer_map_sg = hcd_buffer_map_sg, + .buffer_dmasync_sg = hcd_buffer_sync_sg, + .buffer_unmap_sg = hcd_buffer_unmap_sg, }; EXPORT_SYMBOL (usb_hcd_operations); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/core/hcd.h Sat Aug 31 15:05:59 2002 @@ -155,7 +155,15 @@ dma_addr_t dma, size_t size, int direction); - // FIXME also: buffer_sg_map (), buffer_sg_unmap () + int (*buffer_map_sg) (struct usb_bus *bus, + struct scatterlist *sg, int *n_hw_ents, + int nents, int direction); + void (*buffer_dmasync_sg) (struct usb_bus *bus, + struct scatterlist *sg, + int n_hw_ents, int direction); + void (*buffer_unmap_sg) (struct usb_bus *bus, + struct scatterlist *sg, + int n_hw_ents, int direction); }; /* each driver provides one of these, and hardware init support */ @@ -246,6 +254,13 @@ void hcd_buffer_unmap (struct usb_bus *bus, dma_addr_t dma, size_t size, int direction); +int hcd_buffer_map_sg (struct usb_bus *bus, struct scatterlist *sg, + int *n_hw_ents, int nents, int direction); +void hcd_buffer_sync_sg (struct usb_bus *bus, struct scatterlist *sg, + int n_hw_ents, int direction); + +void hcd_buffer_unmap_sg (struct usb_bus *bus, struct scatterlist *sg, + int n_hw_ents, int direction); /* generic bus glue, needed for host controllers that don't use PCI */ extern struct usb_operations usb_hcd_operations; diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/core/urb.c Sat Aug 31 15:06:00 2002 @@ -278,6 +278,7 @@ /* enforce simple/standard policy */ allowed = USB_ASYNC_UNLINK; // affects later unlinks + allowed |= URB_NO_DMA_MAP; switch (temp) { case PIPE_BULK: allowed |= URB_NO_INTERRUPT; diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/core/usb.c Sat Aug 31 15:06:00 2002 @@ -1532,6 +1532,116 @@ : USB_DIR_OUT); } +/** + * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to map + * @nents: the number of entries in the scatterlist + * + * Return value is either < 0 (indicating no buffers could be mapped), or + * the number of DMA mapping array entries in the scatterlist. + * + * The caller is responsible for placing the resulting DMA addresses from + * the scatterlist into URB transfer buffer pointers, and for setting the + * URB_NO_DMA_MAP transfer flag in each of those URBs. + * + * Top I/O rates come from queuing URBs, instead of waiting for each one + * to complete before starting the next I/O. This is particularly easy + * to do with scatterlists. Just allocate and submit one URB for each DMA + * mapping entry returned, stopping on the first error or when all succeed. + * + * This call would normally be used when translating scatterlist requests, + * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it + * may be able to coalesce mappings for improved I/O efficiency. + * + * Reverse the effect of this call with usb_buffer_unmap_sg(). + */ +int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents) +{ + struct usb_bus *bus; + struct usb_operations *op; + int n_hw_ents; + + if (!dev + || usb_pipecontrol (pipe) + || !(bus = dev->bus) + || !(op = bus->op) + || !op->buffer_map_sg) + return -1; + + if (op->buffer_map_sg (bus, + sg, + &n_hw_ents, + nents, + usb_pipein (pipe) + ? USB_DIR_IN + : USB_DIR_OUT)) + return -1; + + return n_hw_ents; +} + +/** + * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to synchronize + * @n_hw_ents: the positive return value from usb_buffer_map_sg + * + * Use this when you are re-using a scatterlist's data buffers for + * another USB request. + */ +void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) +{ + struct usb_bus *bus; + struct usb_operations *op; + + if (!dev + || !(bus = dev->bus) + || !(op = bus->op) + || !op->buffer_dmasync_sg) + return; + + op->buffer_dmasync_sg (bus, + sg, + n_hw_ents, + usb_pipein (pipe) + ? USB_DIR_IN + : USB_DIR_OUT); +} + +/** + * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to unmap + * @n_hw_ents: the positive return value from usb_buffer_map_sg + * + * Reverses the effect of usb_buffer_map_sg(). + */ +void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) +{ + struct usb_bus *bus; + struct usb_operations *op; + + if (!dev + || !(bus = dev->bus) + || !(op = bus->op) + || !op->buffer_unmap_sg) + return; + + op->buffer_unmap_sg (bus, + sg, + n_hw_ents, + usb_pipein (pipe) + ? USB_DIR_IN + : USB_DIR_OUT); +} + #ifdef CONFIG_PROC_FS struct list_head *usb_driver_get_list(void) { @@ -1611,5 +1721,9 @@ EXPORT_SYMBOL (usb_buffer_map); EXPORT_SYMBOL (usb_buffer_dmasync); EXPORT_SYMBOL (usb_buffer_unmap); + +EXPORT_SYMBOL (usb_buffer_map_sg); +EXPORT_SYMBOL (usb_buffer_dmasync_sg); +EXPORT_SYMBOL (usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/host/ehci-dbg.c Sat Aug 31 15:05:55 2002 @@ -26,8 +26,10 @@ #ifdef DEBUG -/* check the values in the HCSPARAMS register - host controller structural parameters */ -/* see EHCI 0.95 Spec, Table 2-4 for each value */ +/* check the values in the HCSPARAMS register + * (host controller _Structural_ parameters) + * see EHCI spec, Table 2-4 for each value + */ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) { u32 params = readl (&ehci->caps->hcs_params); @@ -67,8 +69,10 @@ #ifdef DEBUG -/* check the values in the HCCPARAMS register - host controller capability parameters */ -/* see EHCI 0.95 Spec, Table 2-5 for each value */ +/* check the values in the HCCPARAMS register + * (host controller _Capability_ parameters) + * see EHCI Spec, Table 2-5 for each value + * */ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) { u32 params = readl (&ehci->caps->hcc_params); @@ -79,13 +83,13 @@ label, HCC_EXT_CAPS (params)); } if (HCC_ISOC_CACHE (params)) { - dbg ("%s hcc_params 0x%04x caching frame %s%s%s", + dbg ("%s hcc_params %04x caching frame %s%s%s", label, params, HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", HCC_CANPARK (params) ? " park" : "", HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); } else { - dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s", + dbg ("%s hcc_params %04x caching %d uframes %s%s%s", label, params, HCC_ISOC_THRES (params), @@ -118,62 +122,131 @@ } } +static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status) +{ + return snprintf (buf, len, + "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", status, + (status & STS_ASS) ? " Async" : "", + (status & STS_PSS) ? " Periodic" : "", + (status & STS_RECL) ? " Recl" : "", + (status & STS_HALT) ? " Halt" : "", + (status & STS_IAA) ? " IAA" : "", + (status & STS_FATAL) ? " FATAL" : "", + (status & STS_FLR) ? " FLR" : "", + (status & STS_PCD) ? " PCD" : "", + (status & STS_ERR) ? " ERR" : "", + (status & STS_INT) ? " INT" : "" + ); +} + +static int dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable) +{ + return snprintf (buf, len, + "%s%sintrenable %02x%s%s%s%s%s%s", + label, label [0] ? " " : "", enable, + (enable & STS_IAA) ? " IAA" : "", + (enable & STS_FATAL) ? " FATAL" : "", + (enable & STS_FLR) ? " FLR" : "", + (enable & STS_PCD) ? " PCD" : "", + (enable & STS_ERR) ? " ERR" : "", + (enable & STS_INT) ? " INT" : "" + ); +} + static const char *const fls_strings [] = { "1024", "512", "256", "??" }; +static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command) +{ + return snprintf (buf, len, + "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s", + label, label [0] ? " " : "", command, + (command & CMD_PARK) ? "park" : "(park)", + CMD_PARK_CNT (command), + (command >> 16) & 0x3f, + (command & CMD_LRESET) ? " LReset" : "", + (command & CMD_IAAD) ? " IAAD" : "", + (command & CMD_ASE) ? " Async" : "", + (command & CMD_PSE) ? " Periodic" : "", + fls_strings [(command >> 2) & 0x3], + (command & CMD_RESET) ? " Reset" : "", + (command & CMD_RUN) ? "RUN" : "HALT" + ); +} + +static int +dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status) +{ + char *sig; + + /* signaling state */ + switch (status & (3 << 10)) { + case 0 << 10: sig = "se0"; break; + case 1 << 10: sig = "k"; break; /* low speed */ + case 2 << 10: sig = "j"; break; + default: sig = "?"; break; + } + + return snprintf (buf, len, + "%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", port, status, + (status & PORT_POWER) ? " POWER" : "", + (status & PORT_OWNER) ? " OWNER" : "", + sig, + (status & PORT_RESET) ? " RESET" : "", + (status & PORT_SUSPEND) ? " SUSPEND" : "", + (status & PORT_RESUME) ? " RESUME" : "", + (status & PORT_OCC) ? " OCC" : "", + (status & PORT_OC) ? " OC" : "", + (status & PORT_PEC) ? " PEC" : "", + (status & PORT_PE) ? " PE" : "", + (status & PORT_CSC) ? " CSC" : "", + (status & PORT_CONNECT) ? " CONNECT" : "" + ); +} + #else static inline void __attribute__((__unused__)) -dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {} +dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) +{} + +static inline int __attribute__((__unused__)) +dbg_status_buf (char *buf, unsigned len, char *label, u32 status) +{} + +static inline int __attribute__((__unused__)) +dbg_command_buf (char *buf, unsigned len, char *label, u32 command) +{} + +static inline int __attribute__((__unused__)) +dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable) +{} + +static inline int __attribute__((__unused__)) +dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status) +{} + #endif /* DEBUG */ /* functions have the "wrong" filename when they're output... */ +#define dbg_status(ehci, label, status) { \ + char _buf [80]; \ + dbg_status_buf (_buf, sizeof _buf, label, status); \ + dbg ("%s", _buf); \ +} + +#define dbg_cmd(ehci, label, command) { \ + char _buf [80]; \ + dbg_command_buf (_buf, sizeof _buf, label, command); \ + dbg ("%s", _buf); \ +} -#define dbg_status(ehci, label, status) \ - dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \ - label, status, \ - (status & STS_ASS) ? " Async" : "", \ - (status & STS_PSS) ? " Periodic" : "", \ - (status & STS_RECL) ? " Recl" : "", \ - (status & STS_HALT) ? " Halt" : "", \ - (status & STS_IAA) ? " IAA" : "", \ - (status & STS_FATAL) ? " FATAL" : "", \ - (status & STS_FLR) ? " FLR" : "", \ - (status & STS_PCD) ? " PCD" : "", \ - (status & STS_ERR) ? " ERR" : "", \ - (status & STS_INT) ? " INT" : "" \ - ) - -#define dbg_cmd(ehci, label, command) \ - dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \ - label, command, \ - (command & CMD_PARK) ? "park" : "(park)", \ - CMD_PARK_CNT (command), \ - (command >> 16) & 0x3f, \ - (command & CMD_LRESET) ? " LReset" : "", \ - (command & CMD_IAAD) ? " IAAD" : "", \ - (command & CMD_ASE) ? " Async" : "", \ - (command & CMD_PSE) ? " Periodic" : "", \ - fls_strings [(command >> 2) & 0x3], \ - (command & CMD_RESET) ? " Reset" : "", \ - (command & CMD_RUN) ? "RUN" : "HALT" \ - ) - -#define dbg_port(hcd, label, port, status) \ - dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \ - label, port, status, \ - (status & PORT_OWNER) ? " OWNER" : "", \ - (status & PORT_POWER) ? " POWER" : "", \ - (status >> 10) & 3, \ - (status & PORT_RESET) ? " RESET" : "", \ - (status & PORT_SUSPEND) ? " SUSPEND" : "", \ - (status & PORT_RESUME) ? " RESUME" : "", \ - (status & PORT_OCC) ? " OCC" : "", \ - (status & PORT_OC) ? " OC" : "", \ - (status & PORT_PEC) ? " PEC" : "", \ - (status & PORT_PE) ? " PE" : "", \ - (status & PORT_CSC) ? " CSC" : "", \ - (status & PORT_CONNECT) ? " CONNECT" : "" \ - ) +#define dbg_port(hcd, label, port, status) { \ + char _buf [80]; \ + dbg_port_buf (_buf, sizeof _buf, label, port, status); \ + dbg ("%s", _buf); \ +} #ifdef DEBUG @@ -228,8 +301,9 @@ qtd_list); scratch = cpu_to_le32p (&td->hw_token); temp = snprintf (next, size, - ", td %p len=%d %s", + ", td %p len=%d tok %04x %s", td, scratch >> 16, + scratch & 0xffff, ({ char *tmp; switch ((scratch>>8)&0x03) { case 0: tmp = "out"; break; @@ -364,16 +438,104 @@ #undef DBG_SCHED_LIMIT +static ssize_t +show_registers (struct device *dev, char *buf, size_t count, loff_t off) +{ + struct pci_dev *pdev; + struct ehci_hcd *ehci; + unsigned long flags; + unsigned temp, size, i; + char *next, scratch [80]; + static char fmt [] = "%*s\n"; + static char label [] = ""; + + if (off != 0) + return 0; + + pdev = container_of (dev, struct pci_dev, dev); + ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd); + + next = buf; + size = count; + + spin_lock_irqsave (&ehci->lock, flags); + + /* Capability Registers */ + i = readw (&ehci->caps->hci_version); + temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n", + i >> 8, i & 0x0ff, ehci->hcd.state); + size -= temp; + next += temp; + + // FIXME interpret both types of params + i = readl (&ehci->caps->hcs_params); + temp = snprintf (next, size, "structural params 0x%08x\n", i); + size -= temp; + next += temp; + + i = readl (&ehci->caps->hcc_params); + temp = snprintf (next, size, "capability params 0x%08x\n", i); + size -= temp; + next += temp; + + /* Operational Registers */ + temp = dbg_status_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->status)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_command_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->command)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_intr_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->intr_enable)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = snprintf (next, size, "uframe %04x\n", + readl (&ehci->regs->frame_index)); + size -= temp; + next += temp; + + for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) { + temp = dbg_port_buf (scratch, sizeof scratch, label, i, + readl (&ehci->regs->port_status [i])); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + } + + if (ehci->reclaim) { + temp = snprintf (next, size, "reclaim qh %p%s\n", + ehci->reclaim, + ehci->reclaim_ready ? " ready" : ""); + size -= temp; + next += temp; + } + + spin_unlock_irqrestore (&ehci->lock, flags); + + return count - size; +} +static DEVICE_ATTR (registers, S_IRUSR, show_registers, NULL); + static inline void create_debug_files (struct ehci_hcd *bus) { device_create_file (&bus->hcd.pdev->dev, &dev_attr_async); device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic); + device_create_file (&bus->hcd.pdev->dev, &dev_attr_registers); } static inline void remove_debug_files (struct ehci_hcd *bus) { device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async); device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic); + device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers); } #else /* DEBUG */ diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Sat Aug 31 15:06:06 2002 +++ b/drivers/usb/host/ohci-q.c Sat Aug 31 15:06:06 2002 @@ -79,6 +79,12 @@ urb->status = 0; spin_unlock_irqrestore (&urb->lock, flags); + if (!(urb->transfer_flags & URB_NO_DMA_MAP) + && usb_pipein (urb->pipe)) + pci_dma_sync_single (hc->hcd.pdev, urb->transfer_dma, + urb->transfer_buffer_length, + PCI_DMA_FROMDEVICE); + #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "INTR", usb_pipeout (urb->pipe)); #endif @@ -92,6 +98,8 @@ if (urb_priv->state != URB_DEL) urb->status = -EINPROGRESS; spin_unlock (&urb->lock); + + /* syncing with PCI_DMA_TODEVICE is evidently trouble... */ spin_lock (&hc->lock); td_submit_urb (hc, urb); diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/input/aiptek.c Sat Aug 31 15:05:55 2002 @@ -113,13 +113,15 @@ }; struct aiptek { - signed char data[10]; struct input_dev dev; struct usb_device *usbdev; struct urb *irq; struct aiptek_features *features; int tool; int open; + + signed char *data; + dma_addr_t data_dma; }; static void @@ -235,11 +237,18 @@ memset(aiptek, 0, sizeof (struct aiptek)); - aiptek->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!aiptek->irq) { - kfree(aiptek); - return NULL; - } + aiptek->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &aiptek->data_dma); + if (!aiptek->data) { + kfree(aiptek); + return NULL; + } + + aiptek->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!aiptek->irq) { + usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); + kfree(aiptek); + return NULL; + } // Resolution500LPI aiptek_command(dev, ifnum, 0x18, 0x04); @@ -287,14 +296,15 @@ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - FILL_INT_URB(aiptek->irq, - dev, - usb_rcvintpipe(dev, endpoint->bEndpointAddress), - aiptek->data, - aiptek->features->pktlen, - aiptek->features->irq, - aiptek, - endpoint->bInterval); + if (aiptek->features->pktlen > 10) + BUG(); + + usb_fill_int_urb(aiptek->irq, dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + aiptek->data, aiptek->features->pktlen, + aiptek->features->irq, aiptek, endpoint->bInterval); + aiptek->irq->transfer_dma = aiptek->data_dma; + aiptek->irq->transfer_flags |= URB_NO_DMA_MAP; input_register_device(&aiptek->dev); @@ -310,7 +320,8 @@ struct aiptek *aiptek = ptr; usb_unlink_urb(aiptek->irq); input_unregister_device(&aiptek->dev); - usb_free_urb(aiptek->irq); + usb_free_urb(aiptek->irq); + usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); kfree(aiptek); } diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/input/hid-core.c Sat Aug 31 15:06:00 2002 @@ -1,30 +1,15 @@ /* - * $Id: hid-core.c,v 1.6 2002/06/09 17:34:55 jdeneux Exp $ + * USB HID support for Linux * * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID support for Linux + * Copyright (c) 2000-2001 Vojtech Pavlik */ /* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + * 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 @@ -52,8 +37,8 @@ * Version Information */ -#define DRIVER_VERSION "v1.31" -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " +#define DRIVER_VERSION "v2.0" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" #define DRIVER_DESC "USB HID core driver" #define DRIVER_LICENSE "GPL" @@ -559,6 +544,7 @@ } if (device->rdesc) kfree(device->rdesc); + kfree(device); } /* @@ -651,9 +637,8 @@ return NULL; memset(device, 0, sizeof(struct hid_device)); - if (!(device->collection = kmalloc(sizeof(struct hid_collection) * - HID_DEFAULT_NUM_COLLECTIONS, - GFP_KERNEL))) { + if (!(device->collection =kmalloc(sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { kfree(device); return NULL; } @@ -1071,11 +1056,11 @@ hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); hid->urbctrl->dev = hid->dev; - hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; - hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; - hid->cr.wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); - hid->cr.wIndex = cpu_to_le16(hid->ifnum); - hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); + hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; + hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; + hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); + hid->cr->wIndex = cpu_to_le16(hid->ifnum); + hid->cr->wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); dbg("submitting ctrl urb"); @@ -1338,6 +1323,32 @@ { 0, 0 } }; +static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) +{ + if (!(hid->inbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->inbuf_dma))) + return -1; + if (!(hid->outbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->outbuf_dma))) + return -1; + if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) + return -1; + if (!(hid->ctrlbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->ctrlbuf_dma))) + return -1; + + return 0; +} + +static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) +{ + if (hid->inbuf) + usb_buffer_free(dev, HID_BUFFER_SIZE, hid->inbuf, hid->inbuf_dma); + if (hid->outbuf) + usb_buffer_free(dev, HID_BUFFER_SIZE, hid->outbuf, hid->outbuf_dma); + if (hid->cr) + usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); + if (hid->ctrlbuf) + usb_buffer_free(dev, HID_BUFFER_SIZE, hid->ctrlbuf, hid->ctrlbuf_dma); +} + static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) { struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; @@ -1397,6 +1408,11 @@ kfree(rdesc); hid->quirks = quirks; + if (hid_alloc_buffers(dev, hid)) { + hid_free_buffers(dev, hid); + goto fail; + } + for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; @@ -1411,14 +1427,20 @@ if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); + usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, + hid_irq_in, hid, endpoint->bInterval); + hid->urbin->transfer_dma = hid->inbuf_dma; + hid->urbin->transfer_flags |= URB_NO_DMA_MAP; } else { if (hid->urbout) continue; if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress); - FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); + usb_fill_bulk_urb(hid->urbout, dev, pipe, hid->outbuf, 0, + hid_irq_out, hid); + hid->urbout->transfer_dma = hid->outbuf_dma; + hid->urbout->transfer_flags |= URB_NO_DMA_MAP; } } @@ -1458,16 +1480,21 @@ kfree(buf); hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); - FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); + usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, + hid->ctrlbuf, 1, hid_ctrl, hid); + hid->urbctrl->setup_dma = hid->cr_dma; + hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; + hid->urbctrl->transfer_flags |= URB_NO_DMA_MAP; return hid; fail: - hid_free_device(hid); if (hid->urbin) usb_free_urb(hid->urbin); if (hid->urbout) usb_free_urb(hid->urbout); if (hid->urbctrl) usb_free_urb(hid->urbctrl); + hid_free_buffers(dev, hid); + hid_free_device(hid); return NULL; } @@ -1490,6 +1517,7 @@ if (hid->urbout) usb_free_urb(hid->urbout); + hid_free_buffers(dev, hid); hid_free_device(hid); } diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h --- a/drivers/usb/input/hid.h Sat Aug 31 15:05:54 2002 +++ b/drivers/usb/input/hid.h Sat Aug 31 15:05:54 2002 @@ -337,19 +337,23 @@ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ struct urb *urbin; /* Input URB */ - char inbuf[HID_BUFFER_SIZE]; /* Input buffer */ + char *inbuf; /* Input buffer */ + dma_addr_t inbuf_dma; /* Input buffer dma */ struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest cr; /* Control request struct */ + struct usb_ctrlrequest *cr; /* Control request struct */ + dma_addr_t cr_dma; /* Control request struct dma */ struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char ctrlbuf[HID_BUFFER_SIZE]; /* Control buffer */ + char *ctrlbuf; /* Control buffer */ + dma_addr_t ctrlbuf_dma; /* Control buffer dma */ spinlock_t ctrllock; /* Control fifo spinlock */ struct urb *urbout; /* Output URB */ struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char outbuf[HID_BUFFER_SIZE]; /* Output buffer */ + char *outbuf; /* Output buffer */ + dma_addr_t outbuf_dma; /* Output buffer dma */ spinlock_t outlock; /* Output fifo spinlock */ unsigned claimed; /* Claimed by hidinput, hiddev? */ diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/input/powermate.c Sat Aug 31 15:06:00 2002 @@ -52,9 +52,11 @@ #define POWERMATE_PAYLOAD_SIZE 3 struct powermate_device { - signed char data[POWERMATE_PAYLOAD_SIZE]; - struct urb irq, config; - struct usb_ctrlrequest configcr; + signed char *data; + dma_addr_t data_dma; + struct urb *irq, *config; + struct usb_ctrlrequest *configcr; + dma_addr_t configcr_dma; struct usb_device *udev; struct input_dev input; struct semaphore lock; @@ -77,7 +79,7 @@ { struct powermate_device *pm = urb->context; - if(urb->status) + if (urb->status) return; /* handle updates to device state */ @@ -89,24 +91,24 @@ /* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ static void powermate_sync_state(struct powermate_device *pm) { - if(pm->requires_update == 0) + if (pm->requires_update == 0) return; /* no updates are required */ - if(pm->config.status == -EINPROGRESS) + if (pm->config->status == -EINPROGRESS) return; /* an update is already in progress; it'll issue this update when it completes */ - if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ - pm->configcr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); - pm->configcr.wIndex = cpu_to_le16( pm->static_brightness ); + if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ + pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); + pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; - }else if(pm->requires_update & UPDATE_PULSE_ASLEEP){ - pm->configcr.wValue = cpu_to_le16( SET_PULSE_ASLEEP ); - pm->configcr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); + }else if (pm->requires_update & UPDATE_PULSE_ASLEEP){ + pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP ); + pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); pm->requires_update &= ~UPDATE_PULSE_ASLEEP; - }else if(pm->requires_update & UPDATE_PULSE_AWAKE){ - pm->configcr.wValue = cpu_to_le16( SET_PULSE_AWAKE ); - pm->configcr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); + }else if (pm->requires_update & UPDATE_PULSE_AWAKE){ + pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE ); + pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); pm->requires_update &= ~UPDATE_PULSE_AWAKE; - }else if(pm->requires_update & UPDATE_PULSE_MODE){ + }else if (pm->requires_update & UPDATE_PULSE_MODE){ int op, arg; /* the powermate takes an operation and an argument for its pulse algorithm. the operation can be: @@ -125,18 +127,18 @@ Only values of 'arg' quite close to 255 are particularly useful/spectacular. */ - if(pm->pulse_speed < 255){ + if (pm->pulse_speed < 255){ op = 0; // divide arg = 255 - pm->pulse_speed; - }else if(pm->pulse_speed > 255){ + } else if (pm->pulse_speed > 255){ op = 2; // multiply arg = pm->pulse_speed - 255; - }else{ + } else { op = 1; // normal speed arg = 0; // can be any value } - pm->configcr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); - pm->configcr.wIndex = cpu_to_le16( (arg << 8) | op ); + pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); + pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); pm->requires_update &= ~UPDATE_PULSE_MODE; }else{ printk(KERN_ERR "powermate: unknown update required"); @@ -144,17 +146,19 @@ return; } -/* printk("powermate: %04x %04x\n", pm->configcr.wValue, pm->configcr.wIndex); */ +/* printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */ - pm->config.dev = pm->udev; /* is this necessary? */ - pm->configcr.bRequestType = 0x41; /* vendor request */ - pm->configcr.bRequest = 0x01; - pm->configcr.wLength = 0; + pm->configcr->bRequestType = 0x41; /* vendor request */ + pm->configcr->bRequest = 0x01; + pm->configcr->wLength = 0; + + usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), + (void *) pm->configcr, 0, 0, + powermate_config_complete, pm); + pm->config->setup_dma = pm->configcr_dma; + pm->config->transfer_flags |= URB_NO_DMA_MAP; - FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), - (void*)&pm->configcr, 0, 0, powermate_config_complete, pm); - - if(usb_submit_urb(&pm->config, GFP_ATOMIC)) + if (usb_submit_urb(pm->config, GFP_ATOMIC)) printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); } @@ -163,7 +167,7 @@ { struct powermate_device *pm = urb->context; - if(urb->status) + if (urb->status) printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); down(&pm->lock); @@ -175,13 +179,13 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, int pulse_table, int pulse_asleep, int pulse_awake) { - if(pulse_speed < 0) + if (pulse_speed < 0) pulse_speed = 0; - if(pulse_table < 0) + if (pulse_table < 0) pulse_table = 0; - if(pulse_speed > 510) + if (pulse_speed > 510) pulse_speed = 510; - if(pulse_table > 2) + if (pulse_table > 2) pulse_table = 2; pulse_asleep = !!pulse_asleep; @@ -190,19 +194,19 @@ down(&pm->lock); /* mark state updates which are required */ - if(static_brightness != pm->static_brightness){ + if (static_brightness != pm->static_brightness){ pm->static_brightness = static_brightness; pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; } - if(pulse_asleep != pm->pulse_asleep){ + if (pulse_asleep != pm->pulse_asleep){ pm->pulse_asleep = pulse_asleep; pm->requires_update |= UPDATE_PULSE_ASLEEP; } - if(pulse_awake != pm->pulse_awake){ + if (pulse_awake != pm->pulse_awake){ pm->pulse_awake = pulse_awake; pm->requires_update |= UPDATE_PULSE_AWAKE; } - if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ + if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ pm->pulse_speed = pulse_speed; pm->pulse_table = pulse_table; pm->requires_update |= UPDATE_PULSE_MODE; @@ -219,7 +223,7 @@ unsigned int command = (unsigned int)_value; struct powermate_device *pm = dev->private; - if(type == EV_MSC && code == MSC_PULSELED){ + if (type == EV_MSC && code == MSC_PULSELED){ /* bits 0- 7: 8 bits: LED brightness bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. @@ -239,6 +243,30 @@ return 0; } +static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) +{ + pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE, + SLAB_ATOMIC, &pm->data_dma); + if (!pm->data) + return -1; + pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), + SLAB_ATOMIC, &pm->configcr_dma); + if (!pm->configcr) + return -1; + + return 0; +} + +static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm) +{ + if (pm->data) + usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE, + pm->data, pm->data_dma); + if (pm->configcr) + usb_buffer_free(udev, sizeof(*(pm->configcr)), + pm->configcr, pm->configcr_dma); +} + /* Called whenever a USB device matching one in our supported devices table is connected */ static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) { @@ -264,19 +292,46 @@ memset(pm, 0, sizeof(struct powermate_device)); pm->udev = udev; + if (powermate_alloc_buffers(udev, pm)) { + powermate_free_buffers(udev, pm); + kfree(pm); + return NULL; + } + + pm->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!pm->irq) { + powermate_free_buffers(udev, pm); + kfree(pm); + return NULL; + } + + pm->config = usb_alloc_urb(0, GFP_KERNEL); + if (!pm->config) { + usb_free_urb(pm->irq); + powermate_free_buffers(udev, pm); + kfree(pm); + return NULL; + } + init_MUTEX(&pm->lock); /* get a handle to the interrupt data pipe */ pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if(maxp != POWERMATE_PAYLOAD_SIZE) + if (maxp != POWERMATE_PAYLOAD_SIZE) printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp); - FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval); + + usb_fill_int_urb(pm->irq, udev, pipe, pm->data, + POWERMATE_PAYLOAD_SIZE, powermate_irq, + pm, endpoint->bInterval); + pm->irq->transfer_dma = pm->data_dma; + pm->irq->transfer_flags |= URB_NO_DMA_MAP; /* register our interrupt URB with the USB system */ - if(usb_submit_urb(&pm->irq, GFP_KERNEL)) { + if (usb_submit_urb(pm->irq, GFP_KERNEL)) { + powermate_free_buffers(udev, pm); kfree(pm); return NULL; /* failure */ } @@ -319,8 +374,11 @@ struct powermate_device *pm = ptr; down(&pm->lock); pm->requires_update = 0; - usb_unlink_urb(&pm->irq); + usb_unlink_urb(pm->irq); input_unregister_device(&pm->input); + usb_free_urb(pm->irq); + usb_free_urb(pm->config); + powermate_free_buffers(dev, pm); kfree(pm); } diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c --- a/drivers/usb/input/usbkbd.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/input/usbkbd.c Sat Aug 31 15:05:59 2002 @@ -67,14 +67,19 @@ struct usb_kbd { struct input_dev dev; struct usb_device *usbdev; - unsigned char new[8]; unsigned char old[8]; struct urb *irq, *led; - struct usb_ctrlrequest cr; - unsigned char leds, newleds; + unsigned char newleds; char name[128]; char phys[64]; int open; + + unsigned char *new; + struct usb_ctrlrequest *cr; + unsigned char *leds; + dma_addr_t cr_dma; + dma_addr_t new_dma; + dma_addr_t leds_dma; }; static void usb_kbd_irq(struct urb *urb) @@ -123,10 +128,10 @@ if (kbd->led->status == -EINPROGRESS) return 0; - if (kbd->leds == kbd->newleds) + if (*(kbd->leds) == kbd->newleds) return 0; - kbd->leds = kbd->newleds; + *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) err("usb_submit_urb(leds) failed"); @@ -141,10 +146,10 @@ if (urb->status) warn("led urb status %d received", urb->status); - if (kbd->leds == kbd->newleds) + if (*(kbd->leds) == kbd->newleds) return; - kbd->leds = kbd->newleds; + *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) err("usb_submit_urb(leds) failed"); @@ -172,6 +177,36 @@ usb_unlink_urb(kbd->irq); } +static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) +{ + if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) + return -1; + if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) + return -1; + if (!(kbd->new = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbd->new_dma))) + return -1; + if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), SLAB_ATOMIC, &kbd->cr_dma))) + return -1; + if (!(kbd->leds = usb_buffer_alloc(dev, 1, SLAB_ATOMIC, &kbd->leds_dma))) + return -1; + + return 0; +} + +static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) +{ + if (kbd->irq) + usb_free_urb(kbd->irq); + if (kbd->led) + usb_free_urb(kbd->led); + if (kbd->new) + usb_buffer_free(dev, 8, kbd->new, kbd->new_dma); + if (kbd->cr) + usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma); + if (kbd->leds) + usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); +} + static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { @@ -198,14 +233,8 @@ if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL; memset(kbd, 0, sizeof(struct usb_kbd)); - kbd->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!kbd->irq) { - kfree(kbd); - return NULL; - } - kbd->led = usb_alloc_urb(0, GFP_KERNEL); - if (!kbd->led) { - usb_free_urb(kbd->irq); + if (usb_kbd_alloc_mem(dev, kbd)) { + usb_kbd_free_mem(dev, kbd); kfree(kbd); return NULL; } @@ -224,14 +253,17 @@ kbd->dev.open = usb_kbd_open; kbd->dev.close = usb_kbd_close; - FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, - usb_kbd_irq, kbd, endpoint->bInterval); - - kbd->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kbd->cr.bRequest = 0x09; - kbd->cr.wValue = 0x200; - kbd->cr.wIndex = interface->bInterfaceNumber; - kbd->cr.wLength = 1; + usb_fill_int_urb(kbd->irq, dev, pipe, + kbd->new, (maxp > 8 ? 8 : maxp), + usb_kbd_irq, kbd, endpoint->bInterval); + kbd->irq->transfer_dma = kbd->new_dma; + kbd->irq->transfer_flags |= URB_NO_DMA_MAP; + + kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kbd->cr->bRequest = 0x09; + kbd->cr->wValue = cpu_to_le16(0x200); + kbd->cr->wIndex = cpu_to_le16(interface->bInterfaceNumber); + kbd->cr->wLength = cpu_to_le16(1); usb_make_path(dev, path, 64); sprintf(kbd->phys, "%s/input0", path); @@ -244,6 +276,8 @@ kbd->dev.id.version = dev->descriptor.bcdDevice; if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_free_urb(kbd->irq); + usb_kbd_free_buffers(dev, kbd); kfree(kbd); return NULL; } @@ -261,9 +295,13 @@ kfree(buf); - FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0), - (void*) &kbd->cr, &kbd->leds, 1, usb_kbd_led, kbd); - + usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), + (void *) kbd->cr, kbd->leds, 1, + usb_kbd_led, kbd); + kbd->led->setup_dma = kbd->cr_dma; + kbd->led->transfer_dma = kbd->leds_dma; + kbd->led->transfer_flags |= URB_NO_DMA_MAP; + input_register_device(&kbd->dev); printk(KERN_INFO "input: %s on %s\n", kbd->name, path); @@ -276,8 +314,7 @@ struct usb_kbd *kbd = ptr; usb_unlink_urb(kbd->irq); input_unregister_device(&kbd->dev); - usb_free_urb(kbd->irq); - usb_free_urb(kbd->led); + usb_kbd_free_buffers(dev, kbd); kfree(kbd); } diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c --- a/drivers/usb/input/usbmouse.c Sat Aug 31 15:06:06 2002 +++ b/drivers/usb/input/usbmouse.c Sat Aug 31 15:06:06 2002 @@ -46,13 +46,15 @@ MODULE_LICENSE(DRIVER_LICENSE); struct usb_mouse { - signed char data[8]; char name[128]; char phys[64]; struct usb_device *usbdev; struct input_dev dev; struct urb *irq; int open; + + signed char *data; + dma_addr_t data_dma; }; static void usb_mouse_irq(struct urb *urb) @@ -124,8 +126,15 @@ if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; memset(mouse, 0, sizeof(struct usb_mouse)); + mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); + if (!mouse->data) { + kfree(mouse); + return NULL; + } + mouse->irq = usb_alloc_urb(0, GFP_KERNEL); if (!mouse->irq) { + usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); kfree(mouse); return NULL; } @@ -153,6 +162,7 @@ mouse->dev.id.version = dev->descriptor.bcdDevice; if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); kfree(mouse); return NULL; } @@ -170,8 +180,11 @@ kfree(buf); - FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, - usb_mouse_irq, mouse, endpoint->bInterval); + usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, + (maxp > 8 ? 8 : maxp), + usb_mouse_irq, mouse, endpoint->bInterval); + mouse->irq->transfer_dma = mouse->data_dma; + mouse->irq->transfer_flags |= URB_NO_DMA_MAP; input_register_device(&mouse->dev); @@ -186,6 +199,7 @@ usb_unlink_urb(mouse->irq); input_unregister_device(&mouse->dev); usb_free_urb(mouse->irq); + usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); kfree(mouse); } diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Sat Aug 31 15:05:54 2002 +++ b/drivers/usb/input/wacom.c Sat Aug 31 15:05:54 2002 @@ -96,7 +96,8 @@ }; struct wacom { - signed char data[10]; + signed char *data; + dma_addr_t data_dma; struct input_dev dev; struct usb_device *usbdev; struct urb *irq; @@ -364,8 +365,15 @@ if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL; memset(wacom, 0, sizeof(struct wacom)); + wacom->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &wacom->data_dma); + if (!wacom->data) { + kfree(wacom); + return NULL; + } + wacom->irq = usb_alloc_urb(0, GFP_KERNEL); if (!wacom->irq) { + usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); kfree(wacom); return NULL; } @@ -413,8 +421,15 @@ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - FILL_INT_URB(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); + if (wacom->features->pktlen > 10) + BUG(); + + usb_fill_int_urb(wacom->irq, dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + wacom->data, wacom->features->pktlen, + wacom->features->irq, wacom, endpoint->bInterval); + wacom->irq->transfer_dma = wacom->data_dma; + wacom->irq->transfer_flags |= URB_NO_DMA_MAP; input_register_device(&wacom->dev); @@ -429,6 +444,7 @@ usb_unlink_urb(wacom->irq); input_unregister_device(&wacom->dev); usb_free_urb(wacom->irq); + usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); kfree(wacom); } diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/input/xpad.c Sat Aug 31 15:06:00 2002 @@ -107,7 +107,8 @@ struct usb_device *udev; /* usb device */ struct urb *irq_in; /* urb for interrupt in report */ - unsigned char idata[XPAD_PKT_LEN]; /* input data */ + unsigned char *idata; /* input data */ + dma_addr_t idata_dma; char phys[65]; /* physical device path */ int open_count; /* reference count */ @@ -213,19 +214,29 @@ } memset(xpad, 0, sizeof(struct usb_xpad)); + xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, + SLAB_ATOMIC, &xpad->idata_dma); + if (!xpad->idata) { + kfree(xpad); + return NULL; + } + xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { err("cannot allocate memory for new pad irq urb"); + usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); kfree(xpad); return NULL; } ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0; - FILL_INT_URB(xpad->irq_in, udev, - usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, - ep_irq_in->bInterval); + usb_fill_int_urb(xpad->irq_in, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xpad->idata, XPAD_PKT_LEN, xpad_irq_in, + xpad, ep_irq_in->bInterval); + xpad->irq_in->transfer_dma = xpad->idata_dma; + xpad->irq_in->transfer_flags |= URB_NO_DMA_MAP; xpad->udev = udev; @@ -290,6 +301,7 @@ usb_unlink_urb(xpad->irq_in); input_unregister_device(&xpad->dev); usb_free_urb(xpad->irq_in); + usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); kfree(xpad); } diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c --- a/drivers/usb/media/ibmcam.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/media/ibmcam.c Sat Aug 31 15:05:55 2002 @@ -251,7 +251,7 @@ */ static ParseState_t ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */ { - usbvideo_frame_t *frame; + struct usbvideo_frame *frame; ibmcam_t *icam; if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { @@ -399,7 +399,7 @@ */ static ParseState_t ibmcam_parse_lines( struct uvd *uvd, - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, long *pcopylen) { unsigned char *f; @@ -664,7 +664,7 @@ */ static ParseState_t ibmcam_model2_320x240_parse_lines( struct uvd *uvd, - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, long *pcopylen) { unsigned char *f, *la, *lb; @@ -818,7 +818,7 @@ static ParseState_t ibmcam_model3_parse_lines( struct uvd *uvd, - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, long *pcopylen) { unsigned char *data; @@ -963,7 +963,7 @@ */ static ParseState_t ibmcam_model4_128x96_parse_lines( struct uvd *uvd, - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, long *pcopylen) { const unsigned char *data_rv, *data_gv, *data_bv; @@ -1049,7 +1049,7 @@ * History: * 1/21/00 Created. */ -void ibmcam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame) +void ibmcam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) { ParseState_t newstate; long copylen = 0; @@ -3921,7 +3921,7 @@ */ static int __init ibmcam_init(void) { - usbvideo_cb_t cbTbl; + struct usbvideo_cb cbTbl; memset(&cbTbl, 0, sizeof(cbTbl)); cbTbl.probe = ibmcam_probe; cbTbl.setupOnOpen = ibmcam_setup_on_open; diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c --- a/drivers/usb/media/konicawc.c Sat Aug 31 15:05:54 2002 +++ b/drivers/usb/media/konicawc.c Sat Aug 31 15:05:54 2002 @@ -488,7 +488,7 @@ } -static void konicawc_process_isoc(struct uvd *uvd, usbvideo_frame_t *frame) +static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) { struct konicawc *cam = (struct konicawc *)uvd->user_data; int maxline = cam->maxline; @@ -881,7 +881,7 @@ static int __init konicawc_init(void) { - usbvideo_cb_t cbTbl; + struct usbvideo_cb cbTbl; info(DRIVER_DESC " " DRIVER_VERSION); memset(&cbTbl, 0, sizeof(cbTbl)); cbTbl.probe = konicawc_probe; diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c --- a/drivers/usb/media/ultracam.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/media/ultracam.c Sat Aug 31 15:05:55 2002 @@ -103,7 +103,7 @@ * 02-Nov-2000 First (mostly dummy) version. * 06-Nov-2000 Rewrote to dump all data into frame. */ -void ultracam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame) +void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) { int n; @@ -672,7 +672,7 @@ */ static int __init ultracam_init(void) { - usbvideo_cb_t cbTbl; + struct usbvideo_cb cbTbl; memset(&cbTbl, 0, sizeof(cbTbl)); cbTbl.probe = ultracam_probe; cbTbl.setupOnOpen = ultracam_setup_on_open; diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c --- a/drivers/usb/media/usbvideo.c Sat Aug 31 15:06:06 2002 +++ b/drivers/usb/media/usbvideo.c Sat Aug 31 15:06:06 2002 @@ -70,7 +70,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum); static int usbvideo_NewFrame(struct uvd *uvd, int framenum); static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - usbvideo_frame_t *frame); + struct usbvideo_frame *frame); /*******************************/ /* Memory management functions */ @@ -127,13 +127,13 @@ vfree(mem); } -static void RingQueue_Initialize(RingQueue_t *rq) +static void RingQueue_Initialize(struct RingQueue *rq) { assert(rq != NULL); init_waitqueue_head(&rq->wqh); } -static void RingQueue_Allocate(RingQueue_t *rq, int rqLen) +static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) { /* Make sure the requested size is a power of 2 and round up if necessary. This allows index wrapping @@ -154,14 +154,14 @@ assert(rq->queue != NULL); } -static int RingQueue_IsAllocated(const RingQueue_t *rq) +static int RingQueue_IsAllocated(const struct RingQueue *rq) { if (rq == NULL) return 0; return (rq->queue != NULL) && (rq->length > 0); } -static void RingQueue_Free(RingQueue_t *rq) +static void RingQueue_Free(struct RingQueue *rq) { assert(rq != NULL); if (RingQueue_IsAllocated(rq)) { @@ -171,7 +171,7 @@ } } -int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len) +int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) { int rql, toread; @@ -205,7 +205,7 @@ EXPORT_SYMBOL(RingQueue_Dequeue); -int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n) +int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n) { int enqueued = 0; @@ -237,13 +237,13 @@ EXPORT_SYMBOL(RingQueue_Enqueue); -static void RingQueue_InterruptibleSleepOn(RingQueue_t *rq) +static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) { assert(rq != NULL); interruptible_sleep_on(&rq->wqh); } -void RingQueue_WakeUpInterruptible(RingQueue_t *rq) +void RingQueue_WakeUpInterruptible(struct RingQueue *rq) { assert(rq != NULL); if (waitqueue_active(&rq->wqh)) @@ -252,7 +252,7 @@ EXPORT_SYMBOL(RingQueue_WakeUpInterruptible); -void RingQueue_Flush(RingQueue_t *rq) +void RingQueue_Flush(struct RingQueue *rq) { assert(rq != NULL); rq->ri = 0; @@ -290,7 +290,7 @@ * History: * 01-Feb-2000 Created. */ -static void usbvideo_OverlayChar(struct uvd *uvd, usbvideo_frame_t *frame, +static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, int x, int y, int ch) { static const unsigned short digits[16] = { @@ -345,7 +345,7 @@ * History: * 01-Feb-2000 Created. */ -static void usbvideo_OverlayString(struct uvd *uvd, usbvideo_frame_t *frame, +static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, int x, int y, const char *str) { while (*str) { @@ -363,7 +363,7 @@ * History: * 01-Feb-2000 Created. */ -static void usbvideo_OverlayStats(struct uvd *uvd, usbvideo_frame_t *frame) +static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame) { const int y_diff = 8; char tmp[16]; @@ -542,7 +542,7 @@ * purposes. */ void usbvideo_DrawLine( - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, int x1, int y1, int x2, int y2, unsigned char cr, unsigned char cg, unsigned char cb) @@ -616,7 +616,7 @@ */ void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) { - usbvideo_frame_t *frame; + struct usbvideo_frame *frame; int num_cell = 0; int scan_length = 0; static int num_pass = 0; @@ -769,7 +769,7 @@ const int num_cams, const int num_extra, const char *driverName, - const usbvideo_cb_t *cbTbl, + const struct usbvideo_cb *cbTbl, struct module *md, const struct usb_device_id *id_table) { @@ -1640,7 +1640,7 @@ struct uvd *uvd = file->private_data; int noblock = file->f_flags & O_NONBLOCK; int frmx = -1, i; - usbvideo_frame_t *frame; + struct usbvideo_frame *frame; if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) return -EFAULT; @@ -1990,7 +1990,7 @@ */ static int usbvideo_NewFrame(struct uvd *uvd, int framenum) { - usbvideo_frame_t *frame; + struct usbvideo_frame *frame; int n; if (uvd->debug > 1) @@ -2064,7 +2064,7 @@ * FLAGS_NO_DECODING set. Therefore, any regular build of any driver * based on usbvideo can use this feature at any time. */ -static void usbvideo_CollectRawData(struct uvd *uvd, usbvideo_frame_t *frame) +static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) { int n; @@ -2096,7 +2096,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) { - usbvideo_frame_t *frame = &uvd->frame[frameNum]; + struct usbvideo_frame *frame = &uvd->frame[frameNum]; if (uvd->debug >= 2) info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum); @@ -2226,7 +2226,7 @@ * line above then we just copy next line. Similarly, if we need to * create a last line then preceding line is used. */ -void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame) +void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) { if ((uvd == NULL) || (frame == NULL)) return; @@ -2297,7 +2297,7 @@ * 09-Feb-2001 Created. */ static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - usbvideo_frame_t *frame) + struct usbvideo_frame *frame) { int i, j, v4l_linesize; signed long adj; diff -Nru a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h --- a/drivers/usb/media/usbvideo.h Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/media/usbvideo.h Sat Aug 31 15:05:59 2002 @@ -118,13 +118,13 @@ #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) #define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) -typedef struct { +struct RingQueue { unsigned char *queue; /* Data from the Isoc data pump */ int length; /* How many bytes allocated for the queue */ int wi; /* That's where we write */ int ri; /* Read from here until you hit write index */ wait_queue_head_t wqh; /* Processes waiting */ -} RingQueue_t; +}; typedef enum { ScanState_Scanning, /* Scanning for header */ @@ -158,18 +158,16 @@ Deinterlace_FillEvenLines } Deinterlace_t; -struct usb_device; - #define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ #define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ /* This structure represents one Isoc request - URB and buffer */ -typedef struct { +struct usbvideo_sbuf { char *data; struct urb *urb; -} usbvideo_sbuf_t; +}; -typedef struct { +struct usbvideo_frame { char *data; /* Frame buffer */ unsigned long header; /* Significant bits from the header */ @@ -188,10 +186,10 @@ long seqRead_Index; /* Amount of data that has been already read */ void *user; /* Additional data that user may need */ -} usbvideo_frame_t; +}; /* Statistics that can be overlaid on screen */ -typedef struct { +struct usbvideo_statistics { unsigned long frame_num; /* Sequential number of the frame */ unsigned long urb_count; /* How many URBs we received so far */ unsigned long urb_length; /* Length of last URB */ @@ -199,7 +197,7 @@ unsigned long header_count; /* How many frame headers we found */ unsigned long iso_skip_count; /* How many empty ISO packets received */ unsigned long iso_err_count; /* How many bad ISO packets received */ -} usbvideo_statistics_t; +}; struct s_usbvideo_t; @@ -236,16 +234,16 @@ int curframe; int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ - RingQueue_t dp; /* Isoc data pump */ - usbvideo_frame_t frame[USBVIDEO_NUMFRAMES]; - usbvideo_sbuf_t sbuf[USBVIDEO_NUMSBUF]; + struct RingQueue dp; /* Isoc data pump */ + struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; + struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; volatile int remove_pending; /* If set then about to exit */ struct video_picture vpic, vpic_old; /* Picture settings */ struct video_capability vcap; /* Video capabilities */ struct video_channel vchan; /* May be used for tuner support */ - usbvideo_statistics_t stats; + struct usbvideo_statistics stats; struct proc_dir_entry *procfs_vEntry; /* /proc/video/MYDRIVER/video2 */ char videoName[32]; /* Holds name like "video7" */ }; @@ -255,32 +253,32 @@ * services are registered. All of these default to NULL, except those * that default to usbvideo-provided methods. */ -typedef struct { +struct usbvideo_cb { void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *); void (*userFree)(struct uvd *); void (*disconnect)(struct usb_device *, void *); int (*setupOnOpen)(struct uvd *); void (*videoStart)(struct uvd *); void (*videoStop)(struct uvd *); - void (*processData)(struct uvd *, usbvideo_frame_t *); - void (*postProcess)(struct uvd *, usbvideo_frame_t *); + void (*processData)(struct uvd *, struct usbvideo_frame *); + void (*postProcess)(struct uvd *, struct usbvideo_frame *); void (*adjustPicture)(struct uvd *); int (*getFPS)(struct uvd *); - int (*overlayHook)(struct uvd *, usbvideo_frame_t *); + int (*overlayHook)(struct uvd *, struct usbvideo_frame *); int (*getFrame)(struct uvd *, int); int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data); int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data); int (*startDataPump)(struct uvd *uvd); void (*stopDataPump)(struct uvd *uvd); int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); -} usbvideo_cb_t; +}; struct s_usbvideo_t { int num_cameras; /* As allocated */ struct usb_driver usbdrv; /* Interface to the USB stack */ char drvName[80]; /* Driver name */ struct semaphore lock; /* Mutex protecting camera structures */ - usbvideo_cb_t cb; /* Table of callbacks (virtual methods) */ + struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ struct video_device vdt; /* Video device template */ struct uvd *cam; /* Array of camera structures */ int uses_procfs; /* Non-zero if we create /proc entries */ @@ -306,23 +304,23 @@ #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) -int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len); -int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n); -void RingQueue_WakeUpInterruptible(RingQueue_t *rq); -void RingQueue_Flush(RingQueue_t *rq); +int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); +int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); +void RingQueue_WakeUpInterruptible(struct RingQueue *rq); +void RingQueue_Flush(struct RingQueue *rq); -static inline int RingQueue_GetLength(const RingQueue_t *rq) +static inline int RingQueue_GetLength(const struct RingQueue *rq) { return (rq->wi - rq->ri + rq->length) & (rq->length-1); } -static inline int RingQueue_GetFreeSpace(const RingQueue_t *rq) +static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) { return rq->length - RingQueue_GetLength(rq); } void usbvideo_DrawLine( - usbvideo_frame_t *frame, + struct usbvideo_frame *frame, int x1, int y1, int x2, int y2, unsigned char cr, unsigned char cg, unsigned char cb); @@ -338,7 +336,7 @@ const int num_cams, const int num_extra, const char *driverName, - const usbvideo_cb_t *cbTable, + const struct usbvideo_cb *cbTable, struct module *md, const struct usb_device_id *id_table); struct uvd *usbvideo_AllocateDevice(usbvideo_t *cams); @@ -347,7 +345,7 @@ int usbvideo_v4l_initialize(struct video_device *dev); -void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame); +void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); /* * This code performs bounds checking - use it when working with @@ -363,7 +361,7 @@ * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. */ static inline void RGB24_PUTPIXEL( - usbvideo_frame_t *fr, + struct usbvideo_frame *fr, int ix, int iy, unsigned char vr, unsigned char vg, diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c --- a/drivers/usb/misc/brlvger.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/misc/brlvger.c Sat Aug 31 15:06:00 2002 @@ -208,8 +208,8 @@ #define err(args...) \ ({ printk(KERN_ERR "Voyager: " args); \ printk("\n"); }) -#define dbgprint(args...) \ - ({ printk(KERN_DEBUG "Voyager: " __FUNCTION__ ": " args); \ +#define dbgprint(fmt, args...) \ + ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \ printk("\n"); }) #define dbg(args...) \ ({ if(debug >= 1) dbgprint(args); }) diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Sat Aug 31 15:06:06 2002 +++ b/drivers/usb/net/kaweth.c Sat Aug 31 15:06:06 2002 @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include #include @@ -638,11 +640,35 @@ return 0; } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "kaweth", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + /**************************************************************** * kaweth_ioctl ****************************************************************/ static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(net, (void *) rq->ifr_data); + } return -EOPNOTSUPP; } diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c --- a/drivers/usb/serial/belkin_sa.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/belkin_sa.c Sat Aug 31 15:06:00 2002 @@ -184,7 +184,7 @@ { int i; - dbg (__FUNCTION__); + dbg ("%s", __FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { @@ -199,7 +199,7 @@ { int retval = 0; - dbg(__FUNCTION__" port %d", port->number); + dbg("%s port %d", __FUNCTION__, port->number); /*Start reading from the device*/ /* TODO: Look at possibility of submitting mulitple URBs to device to @@ -233,7 +233,7 @@ if (!serial) return; - dbg(__FUNCTION__" port %d", port->number); + dbg("%s port %d", __FUNCTION__, port->number); if (serial->dev) { /* shutdown our bulk reads and writes */ diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c --- a/drivers/usb/serial/cyberjack.c Sat Aug 31 15:06:06 2002 +++ b/drivers/usb/serial/cyberjack.c Sat Aug 31 15:06:06 2002 @@ -81,7 +81,7 @@ .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, - .attach = cyberjack_startup, + .attach = cyberjack_startup, .shutdown = cyberjack_shutdown, .open = cyberjack_open, .close = cyberjack_close, @@ -103,7 +103,7 @@ { struct cyberjack_private *priv; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); /* allocate the private data structure */ serial->port->private = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); @@ -125,7 +125,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ @@ -142,7 +142,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* force low_latency on so that our tty_push actually forces * the data through, otherwise it is scheduled, and with high @@ -164,14 +164,14 @@ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) err(" usb_submit_urb(read int) failed"); - dbg(__FUNCTION__ " - usb_submit_urb(int urb)"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); return result; } static void cyberjack_close (struct usb_serial_port *port, struct file *filp) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (port->serial->dev) { /* shutdown any bulk reads that might be going on */ @@ -188,16 +188,16 @@ int result; int wrexpected; - dbg(__FUNCTION__ " - port %d", port->number); - dbg(__FUNCTION__ " - from_user %d", from_user); + dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - from_user %d", __FUNCTION__, from_user); if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); + dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return (0); } @@ -221,7 +221,7 @@ if( priv->wrfilled >= 3 ) { wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; - dbg(__FUNCTION__ " - expected data: %d", wrexpected); + dbg("%s - expected data: %d", __FUNCTION__, wrexpected); } else { wrexpected = sizeof(priv->wrbuf); } @@ -230,7 +230,7 @@ /* We have enough data to begin transmission */ int length; - dbg(__FUNCTION__ " - transmitting data (frame 1)"); + dbg("%s - transmitting data (frame 1)", __FUNCTION__); length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected; memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length ); @@ -248,18 +248,18 @@ /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled=0; priv->wrsent=0; return 0; } - dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent); - dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled); + dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent); + dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled); if( priv->wrsent>=priv->wrfilled ) { - dbg(__FUNCTION__ " - buffer cleaned"); + dbg("%s - buffer cleaned", __FUNCTION__); memset( priv->wrbuf, 0, sizeof(priv->wrbuf) ); priv->wrfilled=0; priv->wrsent=0; @@ -278,7 +278,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* the urb might have been killed. */ if (urb->status) @@ -311,14 +311,14 @@ /* "+=" is probably more fault tollerant than "=" */ priv->rdtodo += size; - dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo); + dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo); if( !old_rdtodo ) { port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if( result ) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); - dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dbg("%s - usb_submit_urb(read urb)", __FUNCTION__); } } } @@ -333,16 +333,16 @@ int i; int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -366,15 +366,15 @@ /* Just to be sure */ if( priv->rdtodo<0 ) priv->rdtodo=0; - dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo); + dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo); /* Continue to read if we have still urbs to do. */ if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) { port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); - dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dbg("%s - usb_submit_urb(read urb)", __FUNCTION__); } } @@ -384,15 +384,15 @@ struct cyberjack_private *priv = (struct cyberjack_private *)port->private; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -401,11 +401,11 @@ int length, blksize, result; if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return; } - dbg(__FUNCTION__ " - transmitting data (frame n)"); + dbg("%s - transmitting data (frame n)", __FUNCTION__); length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? port->bulk_out_size : (priv->wrfilled - priv->wrsent); @@ -426,7 +426,7 @@ /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled=0; priv->wrsent=0; @@ -435,13 +435,13 @@ return; } - dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent); - dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled); + dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent); + dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled); blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) { - dbg(__FUNCTION__ " - buffer cleaned"); + dbg("%s - buffer cleaned", __FUNCTION__); memset( priv->wrbuf, 0, sizeof(priv->wrbuf) ); priv->wrfilled=0; priv->wrsent=0; diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c --- a/drivers/usb/serial/digi_acceleport.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/digi_acceleport.c Sat Aug 31 15:06:00 2002 @@ -684,7 +684,7 @@ spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", + err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret ); } @@ -773,7 +773,7 @@ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num ); } @@ -849,7 +849,7 @@ spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", + err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret ); } @@ -970,7 +970,7 @@ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num ); } @@ -1329,7 +1329,7 @@ /* return length of new data written, or error */ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret < 0 ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num ); } @@ -1352,13 +1352,13 @@ /* port and serial sanity check */ if( port == NULL || (priv=(struct digi_port *)(port->private)) == NULL ) { - err( __FUNCTION__ ": port or port->private is NULL, status=%d", + err("%s: port or port->private is NULL, status=%d", __FUNCTION__, urb->status ); return; } serial = port->serial; if( serial == NULL || serial->private == NULL ) { - err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status ); + err("%s: serial or serial->private is NULL, status=%d", __FUNCTION__, urb->status ); return; } @@ -1413,7 +1413,7 @@ spin_unlock( &priv->dp_port_lock ); if( ret ) { - err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num ); } @@ -1655,8 +1655,7 @@ port->write_urb->dev = port->serial->dev; if( (ret=usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0 ) { - err( - __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, i ); break; } @@ -1773,20 +1772,20 @@ /* port sanity check, do not resubmit if port is not valid */ if( port == NULL || (priv=(struct digi_port *)(port->private)) == NULL ) { - err( __FUNCTION__ ": port or port->private is NULL, status=%d", + err("%s: port or port->private is NULL, status=%d", __FUNCTION__, urb->status ); return; } if( port->serial == NULL || serial_paranoia_check( port->serial, __FUNCTION__ ) || port->serial->private == NULL ) { - err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status ); + err("%s: serial is bad or serial->private is NULL, status=%d", __FUNCTION__, urb->status ); return; } /* do not resubmit urb if it has any status error */ if( urb->status ) { - err( __FUNCTION__ ": nonzero read bulk status: status=%d, port=%d", urb->status, priv->dp_port_num ); + err("%s: nonzero read bulk status: status=%d, port=%d", __FUNCTION__, urb->status, priv->dp_port_num ); return; } @@ -1803,7 +1802,7 @@ /* continue read */ urb->dev = port->serial->dev; if( (ret=usb_submit_urb(urb, GFP_ATOMIC)) != 0 ) { - err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d", + err("%s: failed resubmitting urb, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num ); } @@ -1844,7 +1843,7 @@ /* short/multiple packet check */ if( urb->actual_length != len + 2 ) { - err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); + err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", __FUNCTION__, urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); return( -1 ); } @@ -1913,9 +1912,9 @@ spin_unlock( &priv->dp_port_lock ); if( opcode == DIGI_CMD_RECEIVE_DISABLE ) { - dbg( __FUNCTION__ ": got RECEIVE_DISABLE" ); + dbg("%s: got RECEIVE_DISABLE", __FUNCTION__ ); } else if( opcode != DIGI_CMD_RECEIVE_DATA ) { - dbg( __FUNCTION__ ": unknown opcode: %d", opcode ); + dbg("%s: unknown opcode: %d", __FUNCTION__, opcode ); } return( throttled ? 1 : 0 ); diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c --- a/drivers/usb/serial/empeg.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/empeg.c Sat Aug 31 15:06:00 2002 @@ -152,7 +152,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* Force default termio settings */ empeg_set_termios (port, NULL) ; @@ -174,7 +174,7 @@ result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return result; } @@ -187,7 +187,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -213,7 +213,7 @@ int bytes_sent = 0; int transfer_size; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); @@ -234,14 +234,14 @@ spin_unlock_irqrestore (&write_urb_pool_lock, flags); if (urb == NULL) { - dbg (__FUNCTION__ " - no more free urbs"); + dbg("%s - no more free urbs", __FUNCTION__); goto exit; } if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { - err(__FUNCTION__" no more kernel memory..."); + err("%s no more kernel memory...", __FUNCTION__); goto exit; } } @@ -271,7 +271,7 @@ /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status); bytes_sent = status; break; } @@ -295,7 +295,7 @@ int i; int room = 0; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave (&write_urb_pool_lock, flags); @@ -308,7 +308,7 @@ spin_unlock_irqrestore (&write_urb_pool_lock, flags); - dbg(__FUNCTION__ " - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return (room); @@ -321,7 +321,7 @@ int i; int chars = 0; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave (&write_urb_pool_lock, flags); @@ -334,7 +334,7 @@ spin_unlock_irqrestore (&write_urb_pool_lock, flags); - dbg (__FUNCTION__ " - returns %d", chars); + dbg("%s - returns %d", __FUNCTION__, chars); return (chars); @@ -348,10 +348,10 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -375,15 +375,15 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -423,7 +423,7 @@ result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; @@ -432,7 +432,7 @@ static void empeg_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); usb_unlink_urb (port->read_urb); } @@ -441,14 +441,14 @@ { int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return; } @@ -457,9 +457,9 @@ static int empeg_startup (struct usb_serial *serial) { - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); - dbg(__FUNCTION__ " - Set config to 1"); + dbg("%s - Set config to 1", __FUNCTION__); usb_set_configuration (serial->dev, 1); /* continue on with initialization */ @@ -470,13 +470,13 @@ static void empeg_shutdown (struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg ("%s", __FUNCTION__); } static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { - dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); + dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); return -ENOIOCTLCMD; } @@ -485,10 +485,10 @@ static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); return; } @@ -565,7 +565,8 @@ urb->transfer_buffer = NULL; urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { - err (__FUNCTION__ " - out of memory for urb buffers."); + err("%s - out of memory for urb buffers.", + __FUNCTION__); continue; } } diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/serial/ftdi_sio.c Sat Aug 31 15:05:55 2002 @@ -262,7 +262,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); + err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private)); return -ENOMEM; } @@ -280,7 +280,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); + err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private)); return -ENOMEM; } @@ -292,7 +292,7 @@ static void ftdi_sio_shutdown (struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); if (serial->port[0].private){ kfree(serial->port[0].private); @@ -309,7 +309,7 @@ int result = 0; char buf[1]; /* Needed for the usb_control_msg I think */ - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* This will push the characters through immediately rather than queue a task to deliver them */ @@ -332,10 +332,10 @@ /* Turn on RTS and DTR since we are not flow controlling by default */ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) { - err(__FUNCTION__ " Error from DTR HIGH urb"); + err("%s Error from DTR HIGH urb", __FUNCTION__); } if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){ - err(__FUNCTION__ " Error from RTS HIGH urb"); + err("%s Error from RTS HIGH urb", __FUNCTION__); } /* Start reading from the device */ @@ -345,7 +345,7 @@ ftdi_sio_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return result; } /* ftdi_sio_open */ @@ -357,7 +357,7 @@ unsigned int c_cflag = port->tty->termios->c_cflag; char buf[1]; - dbg( __FUNCTION__); + dbg("%s", __FUNCTION__); if (serial->dev) { if (c_cflag & HUPCL){ @@ -403,7 +403,7 @@ int data_offset ; int result; - dbg(__FUNCTION__ " port %d, %d bytes", port->number, count); + dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); if (count == 0) { err("write request of 0 bytes"); @@ -414,14 +414,14 @@ dbg("data_offset set to %d",data_offset); if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return (0); } count += data_offset; count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - /* Copy in the data to send */ + /* Copy in the data to send */ if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer + data_offset, buf, count - data_offset )){ @@ -438,7 +438,7 @@ *first_byte = 1 | ((count-data_offset) << 2) ; } - dbg(__FUNCTION__ " Bytes: %d, First Byte: 0x%02x",count, first_byte[0]); + dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]); usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); /* send the data out the bulk port */ @@ -449,11 +449,11 @@ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); return 0; } - dbg(__FUNCTION__ " write returning: %d", count - data_offset); + dbg("%s write returning: %d", __FUNCTION__, count - data_offset); return (count - data_offset); } /* ftdi_sio_write */ @@ -462,7 +462,7 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - dbg("ftdi_sio_write_bulk_callback"); + dbg("%s", __FUNCTION__); if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) { return; @@ -488,6 +488,7 @@ { struct ftdi_private *priv = (struct ftdi_private *)port->private; int room; + if ( port->write_urb->status == -EINPROGRESS) { /* There is a race here with the _write routines but it won't hurt */ room = 0; @@ -495,8 +496,6 @@ room = port->bulk_out_size - priv->write_offset; } return(room); - - } /* ftdi_sio_write_room */ @@ -512,7 +511,7 @@ int i; int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) { return; @@ -611,7 +610,7 @@ result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } /* ftdi_sio_serial_read_bulk_callback */ @@ -635,8 +634,8 @@ case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; - default: dbg(__FUNCTION__ " FTDI_SIO does not support the baudrate (%d) requested", - (cflag & CBAUD)); + default: dbg("%s - FTDI_SIO does not support the baudrate (%d) requested", + __FUNCTION__, (cflag & CBAUD)); break; } } else { /* it is 8U232AM */ @@ -655,8 +654,8 @@ case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break; case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break; case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break; - default: dbg(__FUNCTION__ " The baudrate (%d) requested is not implemented", - (cflag & CBAUD)); + default: dbg("%s - The baudrate (%d) requested is not implemented", + __FUNCTION__, (cflag & CBAUD)); break; } } @@ -686,10 +685,11 @@ FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , 0, buf, 0, WDR_TIMEOUT) < 0) { - err(__FUNCTION__ " FAILED to enable/disable break state (state was %d)",break_state); + err("%s - FAILED to enable/disable break state (state was %d)", + __FUNCTION__, break_state); } - dbg(__FUNCTION__ " break state is %d - urb is %d",break_state, urb_value); + dbg("%s - break state is %d - urb is %d", __FUNCTION__, break_state, urb_value); } @@ -709,7 +709,7 @@ char buf[1]; /* Perhaps I should dynamically alloc this? */ - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* FIXME -For this cut I don't care if the line is really changing or @@ -748,7 +748,7 @@ FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , 0, buf, 0, 100) < 0) { - err(__FUNCTION__ " FAILED to set databits/stopbits/parity"); + err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } /* Now do the baudrate */ @@ -761,14 +761,14 @@ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, 0, buf, 0, WDR_TIMEOUT) < 0) { - err(__FUNCTION__ " error from disable flowcontrol urb"); + err("%s error from disable flowcontrol urb", __FUNCTION__); } /* Drop RTS and DTR */ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ - err(__FUNCTION__ " Error from DTR LOW urb"); + err("%s Error from DTR LOW urb", __FUNCTION__); } if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ - err(__FUNCTION__ " Error from RTS LOW urb"); + err("%s Error from RTS LOW urb", __FUNCTION__); } } else { @@ -779,13 +779,13 @@ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, urb_value, 0, buf, 0, 100) < 0) { - err(__FUNCTION__ " urb failed to set baurdrate"); + err("%s urb failed to set baurdrate", __FUNCTION__); } } /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { - dbg(__FUNCTION__ " Setting to CRTSCTS flow control"); + dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -797,7 +797,7 @@ } else { /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ - dbg(__FUNCTION__ " Turning off hardware flow control"); + dbg("%s Turning off hardware flow control", __FUNCTION__); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -819,13 +819,13 @@ char buf[2]; int ret, mask; - dbg(__FUNCTION__ " cmd 0x%04x", cmd); + dbg("%s cmd 0x%04x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ switch (cmd) { case TIOCMGET: - dbg(__FUNCTION__ " TIOCMGET"); + dbg("%s TIOCMGET", __FUNCTION__); if (priv->ftdi_type == sio){ /* Request the status from the device */ if ((ret = usb_control_msg(serial->dev, @@ -834,7 +834,7 @@ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, 0, buf, 1, WDR_TIMEOUT)) < 0 ) { - err(__FUNCTION__ " Could not get modem status of device - err: %d", + err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); return(ret); } @@ -847,7 +847,7 @@ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, 0, buf, 2, WDR_TIMEOUT)) < 0 ) { - err(__FUNCTION__ " Could not get modem status of device - err: %d", + err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); return(ret); } @@ -861,7 +861,7 @@ break; case TIOCMSET: /* Turns on and off the lines as specified by the mask */ - dbg(__FUNCTION__ " TIOCMSET"); + dbg("%s TIOCMSET", __FUNCTION__); if (get_user(mask, (unsigned long *) arg)) return -EFAULT; urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW); @@ -875,7 +875,7 @@ break; case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg(__FUNCTION__ " TIOCMBIS"); + dbg("%s TIOCMBIS", __FUNCTION__); if (get_user(mask, (unsigned long *) arg)) return -EFAULT; if (mask & TIOCM_DTR){ @@ -897,7 +897,7 @@ break; case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg(__FUNCTION__ " TIOCMBIC"); + dbg("%s TIOCMBIC", __FUNCTION__); if (get_user(mask, (unsigned long *) arg)) return -EFAULT; if (mask & TIOCM_DTR){ @@ -931,7 +931,7 @@ /* This is not an error - turns out the higher layers will do * some ioctls itself (see comment above) */ - dbg(__FUNCTION__ " arg not supported - it was 0x%04x",cmd); + dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd); return(-ENOIOCTLCMD); break; } @@ -941,7 +941,7 @@ static int __init ftdi_sio_init (void) { - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); usb_serial_register (&ftdi_sio_device); usb_serial_register (&ftdi_8U232AM_device); info(DRIVER_VERSION ":" DRIVER_DESC); @@ -951,7 +951,7 @@ static void __exit ftdi_sio_exit (void) { - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); usb_serial_deregister (&ftdi_sio_device); usb_serial_deregister (&ftdi_8U232AM_device); } diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c --- a/drivers/usb/serial/io_edgeport.c Sat Aug 31 15:05:54 2002 +++ b/drivers/usb/serial/io_edgeport.c Sat Aug 31 15:05:54 2002 @@ -590,7 +590,7 @@ struct usb_string_descriptor StringDesc; struct usb_string_descriptor *pStringDesc; - dbg(__FUNCTION__ " - USB String ID = %d", Id ); + dbg("%s - USB String ID = %d", __FUNCTION__, Id ); if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) { return 0; @@ -625,7 +625,7 @@ struct usb_string_descriptor StringDesc; struct usb_string_descriptor *pStringDesc; - dbg(__FUNCTION__ " - USB String ID = %d", Id ); + dbg("%s - USB String ID = %d", __FUNCTION__, Id ); if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) { return 0; @@ -760,14 +760,14 @@ int portNumber; int result; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) { return; } if (urb->status) { - dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status); + dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status); return; } @@ -779,7 +779,7 @@ bytes_avail = data[0] | (data[1] << 8); if (bytes_avail) { edge_serial->rxBytesAvail += bytes_avail; - dbg(__FUNCTION__" - bytes_avail = %d, rxBytesAvail %d", bytes_avail, edge_serial->rxBytesAvail); + dbg("%s - bytes_avail = %d, rxBytesAvail %d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail); if ((edge_serial->rxBytesAvail > 0) && (edge_serial->read_urb->status != -EINPROGRESS)) { @@ -789,7 +789,7 @@ edge_serial->read_urb->dev = edge_serial->serial->dev; result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { - dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result); + dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result); } } } @@ -805,7 +805,7 @@ edge_port = (struct edgeport_port *)port->private; if (edge_port->open) { edge_port->txCredits += txCredits; - dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits); + dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits); /* tell the tty driver that something has changed */ if (edge_port->port->tty) @@ -835,14 +835,14 @@ int status; __u16 raw_data_length; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) { return; } if (urb->status) { - dbg(__FUNCTION__" - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -854,7 +854,7 @@ /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; - dbg(__FUNCTION__" - Received = %d, rxBytesAvail %d", raw_data_length, edge_serial->rxBytesAvail); + dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail); process_rcvd_data (edge_serial, data, urb->actual_length); @@ -867,7 +867,7 @@ edge_serial->read_urb->dev = edge_serial->serial->dev; status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (status) { - err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status); + err("%s - usb_submit_urb(read bulk) failed, status = %d", __FUNCTION__, status); } } } @@ -884,14 +884,14 @@ struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; struct tty_struct *tty; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (port_paranoia_check (edge_port->port, __FUNCTION__)) { return; } if (urb->status) { - dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); } tty = edge_port->port->tty; @@ -925,10 +925,10 @@ struct tty_struct *tty; int status = urb->status; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); CmdUrbs--; - dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs); + dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs); /* clean up the transfer buffer */ @@ -945,7 +945,7 @@ } if (status) { - dbg(__FUNCTION__" - nonzero write bulk status received: %d", status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, status); return; } @@ -983,7 +983,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; @@ -1034,7 +1034,7 @@ * this interrupt will continue as long as the edgeport is connected */ response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) { - err(__FUNCTION__" - Error %d submitting control urb", response); + err("%s - Error %d submitting control urb", __FUNCTION__, response); } } @@ -1058,7 +1058,7 @@ response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { - err(__FUNCTION__" - error sending open port command"); + err("%s - error sending open port command", __FUNCTION__); edge_port->openPending = FALSE; return -ENODEV; } @@ -1071,7 +1071,7 @@ if (edge_port->open == FALSE) { /* open timed out */ - dbg(__FUNCTION__" - open timedout"); + dbg("%s - open timedout", __FUNCTION__); edge_port->openPending = FALSE; return -ENODEV; } @@ -1084,7 +1084,7 @@ edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL); if (!edge_port->txfifo.fifo) { - dbg(__FUNCTION__" - no memory"); + dbg("%s - no memory", __FUNCTION__); edge_close (port, filp); return -ENOMEM; } @@ -1093,14 +1093,14 @@ edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL); if (!edge_port->write_urb) { - dbg(__FUNCTION__" - no memory"); + dbg("%s - no memory", __FUNCTION__); edge_close (port, filp); return -ENOMEM; } - dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits); + dbg("%s(%d) - Initialize TX fifo to %d bytes", __FUNCTION__, port->number, edge_port->maxTxCredits); - dbg(__FUNCTION__" exited"); + dbg("%s exited", __FUNCTION__); return 0; } @@ -1128,11 +1128,11 @@ // Did we get our Chase response if (edge_port->chaseResponsePending == FALSE) { - dbg(__FUNCTION__" - Got Chase Response"); + dbg("%s - Got Chase Response", __FUNCTION__); // did we get all of our credit back? if (edge_port->txCredits == edge_port->maxTxCredits ) { - dbg(__FUNCTION__" - Got all credits"); + dbg("%s - Got all credits", __FUNCTION__); return; } } @@ -1145,12 +1145,12 @@ wait--; if (wait == 0) { edge_port->chaseResponsePending = FALSE; - dbg(__FUNCTION__" - Chase TIMEOUT"); + dbg("%s - Chase TIMEOUT", __FUNCTION__); return; } } else { // Reset timout value back to 10 seconds - dbg(__FUNCTION__" - Last %d, Current %d", lastCredits, edge_port->txCredits); + dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits); wait = 10; } } @@ -1180,20 +1180,20 @@ // Is the Edgeport Buffer empty? if (lastCount == 0) { - dbg(__FUNCTION__" - TX Buffer Empty"); + dbg("%s - TX Buffer Empty", __FUNCTION__); return; } // Block the thread for a while interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout); - dbg(__FUNCTION__ " wait"); + dbg("%s wait", __FUNCTION__); if (lastCount == fifo->count) { // No activity.. count down. wait--; if (wait == 0) { - dbg(__FUNCTION__" - TIMEOUT"); + dbg("%s - TIMEOUT", __FUNCTION__); return; } } else { @@ -1218,7 +1218,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -1238,7 +1238,7 @@ /* flush and chase */ edge_port->chaseResponsePending = TRUE; - dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT"); + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) { // block until chase finished @@ -1248,7 +1248,7 @@ } /* close the port */ - dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT"); + dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); //port->close = TRUE; @@ -1272,7 +1272,7 @@ kfree(edge_port->txfifo.fifo); } - dbg(__FUNCTION__" exited"); + dbg("%s exited", __FUNCTION__); } /***************************************************************************** @@ -1291,7 +1291,7 @@ int firsthalf; int secondhalf; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; @@ -1302,12 +1302,12 @@ // calculate number of bytes to put in fifo copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count)); - dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", + dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", __FUNCTION__, port->number, count, edge_port->txCredits - fifo->count, copySize); /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */ if (copySize == 0) { - dbg (__FUNCTION__" - copySize = Zero"); + dbg("%s - copySize = Zero", __FUNCTION__); return 0; } @@ -1319,7 +1319,7 @@ bytesleft = fifo->size - fifo->head; firsthalf = min (bytesleft, copySize); - dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft); + dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft); /* now copy our data */ if (from_user) { @@ -1341,7 +1341,7 @@ secondhalf = copySize-firsthalf; if (secondhalf) { - dbg (__FUNCTION__" - copy rest of data %d", secondhalf); + dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf); if (from_user) { if (copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf)) return -EFAULT; @@ -1360,7 +1360,7 @@ send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port); - dbg(__FUNCTION__" wrote %d byte(s) TxCredits %d, Fifo %d", copySize, edge_port->txCredits, fifo->count); + dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count); return copySize; } @@ -1390,12 +1390,12 @@ int firsthalf; int secondhalf; - dbg(__FUNCTION__"(%d)", edge_port->port->number); + dbg("%s(%d)", __FUNCTION__, edge_port->port->number); if (edge_port->write_in_progress || !edge_port->open || (fifo->count == 0)) { - dbg(__FUNCTION__"(%d) EXIT - fifo %d, PendingWrite = %d", edge_port->port->number, fifo->count, edge_port->write_in_progress); + dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress); return; } @@ -1407,7 +1407,7 @@ // it's better to wait for more credits so we can do a larger // write. if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) { - dbg(__FUNCTION__"(%d) Not enough credit - fifo %d TxCredit %d", edge_port->port->number, fifo->count, edge_port->txCredits ); + dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits ); return; } @@ -1427,7 +1427,7 @@ count = fifo->count; buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { - err(__FUNCTION__" - no more kernel memory..."); + err("%s - no more kernel memory...", __FUNCTION__); edge_port->write_in_progress = FALSE; return; } @@ -1464,14 +1464,14 @@ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ - dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__); edge_port->write_in_progress = FALSE; } else { /* decrement the number of credits we have by the number we just sent */ edge_port->txCredits -= count; edge_port->icount.tx += count; } - dbg(__FUNCTION__" wrote %d byte(s) TxCredit %d, Fifo %d", count, edge_port->txCredits, fifo->count); + dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count); } @@ -1488,24 +1488,24 @@ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); int room; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; if (edge_port->closePending == TRUE) return -ENODEV; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!edge_port->open) { - dbg (__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return -EINVAL; } // total of both buffers is still txCredit room = edge_port->txCredits - edge_port->txfifo.count; - dbg(__FUNCTION__" - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return room; } @@ -1524,7 +1524,7 @@ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); int num_chars; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; @@ -1532,13 +1532,13 @@ return -ENODEV; if (!edge_port->open) { - dbg (__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return -EINVAL; } num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count; if (num_chars) { - dbg(__FUNCTION__"(port %d) - returns %d", port->number, num_chars); + dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars); } return num_chars; @@ -1556,13 +1556,13 @@ struct tty_struct *tty; int status; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { - dbg (__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return; } @@ -1605,13 +1605,13 @@ struct tty_struct *tty; int status; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { - dbg (__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return; } @@ -1663,7 +1663,7 @@ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg(__FUNCTION__" - nothing to change"); + dbg("%s - nothing to change", __FUNCTION__); return; } } @@ -1677,13 +1677,13 @@ RELEVANT_IFLAG(old_termios->c_iflag)); } - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { - dbg (__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return; } @@ -1710,7 +1710,7 @@ if (edge_port->maxTxCredits == edge_port->txCredits && edge_port->txfifo.count == 0) { - dbg(__FUNCTION__" -- Empty"); + dbg("%s -- Empty", __FUNCTION__); result = TIOCSER_TEMT; } @@ -1729,7 +1729,7 @@ result = tty->read_cnt; - dbg(__FUNCTION__"(%d) = %d", edge_port->port->number, result); + dbg("%s(%d) = %d", __FUNCTION__, edge_port->port->number, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; //return 0; @@ -1794,7 +1794,7 @@ | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - dbg(__FUNCTION__" -- %x", result); + dbg("%s -- %x", __FUNCTION__, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -1845,40 +1845,40 @@ struct serial_icounter_struct icount; - dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd); + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { // return number of bytes available case TIOCINQ: - dbg(__FUNCTION__" (%d) TIOCINQ", port->number); + dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); return get_number_bytes_avail(edge_port, (unsigned int *) arg); break; case TIOCSERGETLSR: - dbg(__FUNCTION__" (%d) TIOCSERGETLSR", port->number); + dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); return get_lsr_info(edge_port, (unsigned int *) arg); return 0; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: - dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); return set_modem_info(edge_port, cmd, (unsigned int *) arg); case TIOCMGET: - dbg(__FUNCTION__" (%d) TIOCMGET", port->number); + dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); return get_modem_info(edge_port, (unsigned int *) arg); case TIOCGSERIAL: - dbg(__FUNCTION__" (%d) TIOCGSERIAL", port->number); + dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); return get_serial_info(edge_port, (struct serial_struct *) arg); case TIOCSSERIAL: - dbg(__FUNCTION__" (%d) TIOCSSERIAL", port->number); + dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); break; case TIOCMIWAIT: - dbg(__FUNCTION__" (%d) TIOCMIWAIT", port->number); + dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); cprev = edge_port->icount; while (1) { interruptible_sleep_on(&edge_port->delta_msr_wait); @@ -1914,7 +1914,7 @@ icount.brk = cnow.brk; icount.buf_overrun = cnow.buf_overrun; - dbg(__FUNCTION__" (%d) TIOCGICOUNT RX=%d, TX=%d", port->number, icount.rx, icount.tx ); + dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, icount.rx, icount.tx ); if (copy_to_user((void *)arg, &icount, sizeof(icount))) return -EFAULT; return 0; @@ -1936,7 +1936,7 @@ /* flush and chase */ edge_port->chaseResponsePending = TRUE; - dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT"); + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) { // block until chase finished @@ -1946,14 +1946,14 @@ } if (break_state == -1) { - dbg(__FUNCTION__" - Sending IOSP_CMD_SET_BREAK"); + dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); } else { - dbg(__FUNCTION__" - Sending IOSP_CMD_CLEAR_BREAK"); + dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); } if (status) { - dbg(__FUNCTION__" - error sending break set/clear command."); + dbg("%s - error sending break set/clear command.", __FUNCTION__); } return; @@ -1973,14 +1973,14 @@ __u16 rxLen; int i; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); lastBufferLength = bufferLength + 1; while (bufferLength > 0) { /* failsafe incase we get a message that we don't understand */ if (lastBufferLength == bufferLength) { - dbg(__FUNCTION__" - stuck in loop, exiting it."); + dbg("%s - stuck in loop, exiting it.", __FUNCTION__); break; } lastBufferLength = bufferLength; @@ -2002,7 +2002,7 @@ ++buffer; --bufferLength; - dbg(__FUNCTION__" - Hdr1=%02X Hdr2=%02X", edge_serial->rxHeader1, edge_serial->rxHeader2); + dbg("%s - Hdr1=%02X Hdr2=%02X", __FUNCTION__, edge_serial->rxHeader1, edge_serial->rxHeader2); // Process depending on whether this header is // data or status @@ -2033,7 +2033,7 @@ edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2); - dbg(__FUNCTION__" - Data for Port %u Len %u", edge_serial->rxPort, edge_serial->rxBytesRemaining); + dbg("%s - Data for Port %u Len %u", __FUNCTION__, edge_serial->rxPort, edge_serial->rxBytesRemaining); //ASSERT( DevExt->RxPort < DevExt->NumPorts ); //ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH ); @@ -2067,7 +2067,7 @@ if (edge_port->open) { tty = edge_port->port->tty; if (tty) { - dbg (__FUNCTION__" - Sending %d bytes to TTY for port %d", rxLen, edge_serial->rxPort); + dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort); for (i = 0; i < rxLen ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { @@ -2120,17 +2120,17 @@ } edge_port = (struct edgeport_port *)port->private; if (edge_port == NULL) { - err (__FUNCTION__ " - edge_port == NULL for port %d", edge_serial->rxPort); + err("%s - edge_port == NULL for port %d", __FUNCTION__, edge_serial->rxPort); return; } - dbg(__FUNCTION__" - port %d", edge_serial->rxPort); + dbg("%s - port %d", __FUNCTION__, edge_serial->rxPort); if (code == IOSP_EXT_STATUS) { switch (byte2) { case IOSP_EXT_STATUS_CHASE_RSP: // we want to do EXT status regardless of port open/closed - dbg(__FUNCTION__" - Port %u EXT CHASE_RSP Data = %02x", edge_serial->rxPort, byte3 ); + dbg("%s - Port %u EXT CHASE_RSP Data = %02x", __FUNCTION__, edge_serial->rxPort, byte3 ); // Currently, the only EXT_STATUS is Chase, so process here instead of one more call // to one more subroutine. If/when more EXT_STATUS, there'll be more work to do. // Also, we currently clear flag and close the port regardless of content of above's Byte3. @@ -2141,7 +2141,7 @@ return; case IOSP_EXT_STATUS_RX_CHECK_RSP: - dbg( __FUNCTION__" ========== Port %u CHECK_RSP Sequence = %02x =============\n", edge_serial->rxPort, byte3 ); + dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 ); //Port->RxCheckRsp = TRUE; return; } @@ -2150,7 +2150,7 @@ if (code == IOSP_STATUS_OPEN_RSP) { edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); edge_port->maxTxCredits = edge_port->txCredits; - dbg (__FUNCTION__" - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", edge_serial->rxPort, byte2, edge_port->txCredits); + dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __FUNCTION__, edge_serial->rxPort, byte2, edge_port->txCredits); handle_new_msr (edge_port, byte2); /* send the current line settings to the port so we are in sync with any further termios calls */ @@ -2174,23 +2174,23 @@ switch (code) { // Not currently sent by Edgeport case IOSP_STATUS_LSR: - dbg(__FUNCTION__" - Port %u LSR Status = %02x", edge_serial->rxPort, byte2); + dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2); handle_new_lsr (edge_port, FALSE, byte2, 0); break; case IOSP_STATUS_LSR_DATA: - dbg(__FUNCTION__" - Port %u LSR Status = %02x, Data = %02x", edge_serial->rxPort, byte2, byte3); + dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3); // byte2 is LSR Register // byte3 is broken data byte handle_new_lsr (edge_port, TRUE, byte2, byte3); break; // // case IOSP_EXT_4_STATUS: - // dbg(__FUNCTION__" - Port %u LSR Status = %02x Data = %02x", edge_serial->rxPort, byte2, byte3); + // dbg("%s - Port %u LSR Status = %02x Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3); // break; // case IOSP_STATUS_MSR: - dbg(__FUNCTION__" - Port %u MSR Status = %02x", edge_serial->rxPort, byte2); + dbg("%s - Port %u MSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2); // Process this new modem status and generate appropriate // events, etc, based on the new status. This routine @@ -2199,7 +2199,7 @@ break; default: - dbg(__FUNCTION__" - Unrecognized IOSP status code %u\n", code); + dbg("%s - Unrecognized IOSP status code %u\n", __FUNCTION__, code); break; } @@ -2215,7 +2215,7 @@ { struct async_icount *icount; - dbg(__FUNCTION__" %02x", newMsr); + dbg("%s %02x", __FUNCTION__, newMsr); if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) { icount = &edge_port->icount; @@ -2252,7 +2252,7 @@ __u8 newLsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); struct async_icount *icount; - dbg(__FUNCTION__" - %02x", newLsr); + dbg("%s - %02x", __FUNCTION__, newLsr); edge_port->shadowLSR = lsr; @@ -2303,11 +2303,11 @@ __u16 current_length; unsigned char *transfer_buffer; -// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); +// dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length); transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2319,7 +2319,7 @@ } else { current_length = length; } -// dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length); +// dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length); memcpy (transfer_buffer, data, current_length); result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_RAM, 0x40, addr, extAddr, transfer_buffer, current_length, 300); @@ -2348,11 +2348,11 @@ __u16 current_length; unsigned char *transfer_buffer; -// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); +// dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length); transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2364,7 +2364,7 @@ } else { current_length = length; } -// dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length); +// dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length); memcpy (transfer_buffer, data, current_length); result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_ROM, 0x40, addr, extAddr, transfer_buffer, current_length, 300); @@ -2393,11 +2393,11 @@ __u16 current_length; unsigned char *transfer_buffer; - dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); + dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length); transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2409,7 +2409,7 @@ } else { current_length = length; } -// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, current_length); +// dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, current_length); result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, 0xC0, addr, extAddr, transfer_buffer, current_length, 300); if (result < 0) @@ -2436,11 +2436,11 @@ int length = 0; int status = 0; - dbg(__FUNCTION__" - %d, %d", command, param); + dbg("%s - %d, %d", __FUNCTION__, command, param); buffer = kmalloc (10, GFP_ATOMIC); if (!buffer) { - err(__FUNCTION__" - kmalloc(%d) failed.\n", 10); + err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 10); return -ENOMEM; } @@ -2479,7 +2479,7 @@ return -ENOMEM; CmdUrbs++; - dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs); + dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs); FILL_BULK_URB (urb, edge_serial->serial->dev, usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint), @@ -2490,7 +2490,7 @@ if (status) { /* something went wrong */ - dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__); usb_unlink_urb (urb); usb_free_urb (urb); return status; @@ -2505,7 +2505,7 @@ if (edge_port->commandPending == TRUE) { /* command timed out */ - dbg(__FUNCTION__" - command timed out"); + dbg("%s - command timed out", __FUNCTION__); status = -EINVAL; } #endif @@ -2527,18 +2527,18 @@ int status; unsigned char number = edge_port->port->number - edge_port->port->serial->minor; - dbg(__FUNCTION__" - port = %d, baud = %d", edge_port->port->number, baudRate); + dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); if (status) { - err(__FUNCTION__" - bad baud rate"); + err("%s - bad baud rate", __FUNCTION__); return status; } // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x100, GFP_ATOMIC); if (!cmdBuffer) { - err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100); + err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x100); return -ENOMEM; } currCmd = cmdBuffer; @@ -2576,7 +2576,7 @@ __u16 round; - dbg(__FUNCTION__" - %d", baudrate); + dbg("%s - %d", __FUNCTION__, baudrate); for (i = 0; i < NUM_ENTRIES(divisor_table); i++) { if ( divisor_table[i].BaudRate == baudrate ) { @@ -2600,7 +2600,7 @@ } *divisor = custom; - dbg(__FUNCTION__" - Baud %d = %d\n", baudrate, custom); + dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom); return 0; } @@ -2619,7 +2619,7 @@ unsigned long cmdLen = 0; int status; - dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue); + dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue); // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x10, GFP_ATOMIC); @@ -2662,50 +2662,50 @@ __u8 txFlow; int status; - dbg(__FUNCTION__" - port %d", edge_port->port->number); + dbg("%s - port %d", __FUNCTION__, edge_port->port->number); if ((!edge_port->open) && (!edge_port->openPending)) { - dbg(__FUNCTION__" - port not opened"); + dbg("%s - port not opened", __FUNCTION__); return; } tty = edge_port->port->tty; if ((!tty) || (!tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); return; } cflag = tty->termios->c_cflag; switch (cflag & CSIZE) { - case CS5: lData = LCR_BITS_5; mask = 0x1f; dbg(__FUNCTION__" - data bits = 5"); break; - case CS6: lData = LCR_BITS_6; mask = 0x3f; dbg(__FUNCTION__" - data bits = 6"); break; - case CS7: lData = LCR_BITS_7; mask = 0x7f; dbg(__FUNCTION__" - data bits = 7"); break; + case CS5: lData = LCR_BITS_5; mask = 0x1f; dbg("%s - data bits = 5", __FUNCTION__); break; + case CS6: lData = LCR_BITS_6; mask = 0x3f; dbg("%s - data bits = 6", __FUNCTION__); break; + case CS7: lData = LCR_BITS_7; mask = 0x7f; dbg("%s - data bits = 7", __FUNCTION__); break; default: - case CS8: lData = LCR_BITS_8; dbg(__FUNCTION__" - data bits = 8"); break; + case CS8: lData = LCR_BITS_8; dbg("%s - data bits = 8", __FUNCTION__); break; } lParity = LCR_PAR_NONE; if (cflag & PARENB) { if (cflag & PARODD) { lParity = LCR_PAR_ODD; - dbg(__FUNCTION__" - parity = odd"); + dbg("%s - parity = odd", __FUNCTION__); } else { lParity = LCR_PAR_EVEN; - dbg(__FUNCTION__" - parity = even"); + dbg("%s - parity = even", __FUNCTION__); } } else { - dbg(__FUNCTION__" - parity = none"); + dbg("%s - parity = none", __FUNCTION__); } if (cflag & CSTOPB) { lStop = LCR_STOP_2; - dbg(__FUNCTION__" - stop bits = 2"); + dbg("%s - stop bits = 2", __FUNCTION__); } else { lStop = LCR_STOP_1; - dbg(__FUNCTION__" - stop bits = 1"); + dbg("%s - stop bits = 1", __FUNCTION__); } /* figure out the flow control settings */ @@ -2713,9 +2713,9 @@ if (cflag & CRTSCTS) { rxFlow |= IOSP_RX_FLOW_RTS; txFlow |= IOSP_TX_FLOW_CTS; - dbg(__FUNCTION__" - RTS/CTS is enabled"); + dbg("%s - RTS/CTS is enabled", __FUNCTION__); } else { - dbg(__FUNCTION__" - RTS/CTS is disabled"); + dbg("%s - RTS/CTS is disabled", __FUNCTION__); } /* if we are implementing XON/XOFF, set the start and stop character in the device */ @@ -2729,17 +2729,17 @@ /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { rxFlow |= IOSP_RX_FLOW_XON_XOFF; - dbg(__FUNCTION__" - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char); + dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char); } else { - dbg(__FUNCTION__" - INBOUND XON/XOFF is disabled"); + dbg("%s - INBOUND XON/XOFF is disabled", __FUNCTION__); } /* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) { txFlow |= IOSP_TX_FLOW_XON_XOFF; - dbg(__FUNCTION__" - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char); + dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char); } else { - dbg(__FUNCTION__" - OUTBOUND XON/XOFF is disabled"); + dbg("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__); } } @@ -2776,7 +2776,7 @@ baud = 9600; } - dbg(__FUNCTION__ " - baud rate = %d", baud); + dbg("%s - baud rate = %d", __FUNCTION__, baud); status = send_cmd_write_baud_rate (edge_port, baud); return; @@ -2951,7 +2951,7 @@ /* create our private serial structure */ edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { - err(__FUNCTION__" - Out of memory"); + err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } memset (edge_serial, 0, sizeof(struct edgeport_serial)); @@ -2978,22 +2978,23 @@ /* set the number of ports from the manufacturing description */ /* serial->num_ports = serial->product_info.NumPorts; */ if (edge_serial->product_info.NumPorts != serial->num_ports) { - warn(__FUNCTION__ " - Device Reported %d serial ports vs core " + warn("%s - Device Reported %d serial ports vs core " "thinking we have %d ports, email greg@kroah.com this info.", - edge_serial->product_info.NumPorts, serial->num_ports); + __FUNCTION__, edge_serial->product_info.NumPorts, + serial->num_ports); } - dbg(__FUNCTION__ " - time 1 %ld", jiffies); + dbg("%s - time 1 %ld", __FUNCTION__, jiffies); /* now load the application firmware into this device */ load_application_firmware (edge_serial); - dbg(__FUNCTION__ " - time 2 %ld", jiffies); + dbg("%s - time 2 %ld", __FUNCTION__, jiffies); /* Check current Edgeport EEPROM and update if necessary */ update_edgeport_E2PROM (edge_serial); - dbg(__FUNCTION__ " - time 3 %ld", jiffies); + dbg("%s - time 3 %ld", __FUNCTION__, jiffies); /* set the configuration to use #1 */ // dbg("set_configuration 1"); @@ -3006,7 +3007,7 @@ for (i = 0; i < serial->num_ports; ++i) { edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { - err(__FUNCTION__" - Out of memory"); + err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } memset (edge_port, 0, sizeof(struct edgeport_port)); @@ -3027,7 +3028,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/serial/io_ti.c Sat Aug 31 15:05:59 2002 @@ -1626,7 +1626,7 @@ } if (urb->status) { - dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status); + dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status); return; } @@ -1959,7 +1959,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -1999,7 +1999,7 @@ edge_port->close_pending = 0; } - dbg(__FUNCTION__" exited"); + dbg("%s - exited", __FUNCTION__); } static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count) @@ -2047,7 +2047,7 @@ /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else result = count; @@ -2062,19 +2062,19 @@ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); int room = 0; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; if (edge_port->close_pending == 1) return -ENODEV; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (port->write_urb->status != -EINPROGRESS) room = port->bulk_out_size; - dbg(__FUNCTION__ " - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return room; } @@ -2083,7 +2083,7 @@ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); int chars = 0; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; @@ -2138,7 +2138,7 @@ struct tty_struct *tty; int status; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; @@ -2229,32 +2229,32 @@ if (cflag & PARODD) { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_ODDPARITY; - dbg(__FUNCTION__" - parity = odd"); + dbg("%s - parity = odd", __FUNCTION__); } else { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_EVENPARITY; - dbg(__FUNCTION__" - parity = even"); + dbg("%s - parity = even", __FUNCTION__); } } else { config->bParity = UMP_UART_NOPARITY; - dbg(__FUNCTION__" - parity = none"); + dbg("%s - parity = none", __FUNCTION__); } if (cflag & CSTOPB) { config->bStopBits = UMP_UART_STOPBIT2; - dbg(__FUNCTION__" - stop bits = 2"); + dbg("%s - stop bits = 2", __FUNCTION__); } else { config->bStopBits = UMP_UART_STOPBIT1; - dbg(__FUNCTION__" - stop bits = 1"); + dbg("%s - stop bits = 1", __FUNCTION__); } /* figure out the flow control settings */ if (cflag & CRTSCTS) { config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW; config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW; - dbg(__FUNCTION__" - RTS/CTS is enabled"); + dbg("%s - RTS/CTS is enabled", __FUNCTION__); } else { - dbg(__FUNCTION__" - RTS/CTS is disabled"); + dbg("%s - RTS/CTS is disabled", __FUNCTION__); } /* if we are implementing XON/XOFF, set the start and stop character in the device */ @@ -2422,7 +2422,7 @@ | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - dbg(__FUNCTION__" -- %x", result); + dbg("%s -- %x", __FUNCTION__, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -2463,42 +2463,42 @@ struct async_icount cnow; struct async_icount cprev; - dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd); + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { case TIOCINQ: - dbg(__FUNCTION__" (%d) TIOCINQ", port->number); + dbg("%s - (%d) TIOCINQ", __FUNCTION__, port->number); // return get_number_bytes_avail(edge_port, (unsigned int *) arg); break; case TIOCSERGETLSR: - dbg(__FUNCTION__" (%d) TIOCSERGETLSR", port->number); + dbg("%s - (%d) TIOCSERGETLSR", __FUNCTION__, port->number); // return get_lsr_info(edge_port, (unsigned int *) arg); break; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: - dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); + dbg("%s - (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); return set_modem_info(edge_port, cmd, (unsigned int *) arg); break; case TIOCMGET: - dbg(__FUNCTION__" (%d) TIOCMGET", port->number); + dbg("%s - (%d) TIOCMGET", __FUNCTION__, port->number); return get_modem_info(edge_port, (unsigned int *) arg); break; case TIOCGSERIAL: - dbg(__FUNCTION__" (%d) TIOCGSERIAL", port->number); + dbg("%s - (%d) TIOCGSERIAL", __FUNCTION__, port->number); return get_serial_info(edge_port, (struct serial_struct *) arg); break; case TIOCSSERIAL: - dbg(__FUNCTION__" (%d) TIOCSSERIAL", port->number); + dbg("%s - (%d) TIOCSSERIAL", __FUNCTION__, port->number); break; case TIOCMIWAIT: - dbg(__FUNCTION__" (%d) TIOCMIWAIT", port->number); + dbg("%s - (%d) TIOCMIWAIT", __FUNCTION__, port->number); cprev = edge_port->icount; while (1) { interruptible_sleep_on(&edge_port->delta_msr_wait); @@ -2565,7 +2565,7 @@ /* create our private serial structure */ edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { - err(__FUNCTION__" - Out of memory"); + err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } memset (edge_serial, 0, sizeof(struct edgeport_serial)); @@ -2582,7 +2582,7 @@ for (i = 0; i < serial->num_ports; ++i) { edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { - err(__FUNCTION__" - Out of memory"); + err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } memset (edge_port, 0, sizeof(struct edgeport_port)); @@ -2598,7 +2598,7 @@ { int i; - dbg (__FUNCTION__); + dbg ("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { kfree (serial->port[i].private); diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/serial/ipaq.c Sat Aug 31 15:05:55 2002 @@ -130,13 +130,13 @@ return -ENODEV; } - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); bytes_in = 0; bytes_out = 0; priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); if (priv == NULL) { - err(__FUNCTION__ " - Out of memory"); + err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } port->private = (void *)priv; @@ -198,7 +198,7 @@ ipaq_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) { - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); goto error; } @@ -218,12 +218,12 @@ return 0; } } - err(__FUNCTION__ " - failed doing control urb, error %d", result); + err("%s - failed doing control urb, error %d", __FUNCTION__, result); goto error; enomem: result = -ENOMEM; - err(__FUNCTION__ " - Out of memory"); + err("%s - Out of memory", __FUNCTION__); error: ipaq_destroy_lists(port); kfree(priv); @@ -240,7 +240,7 @@ return; } - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial(port, __FUNCTION__); if (!serial) @@ -271,15 +271,15 @@ if (port_paranoia_check(port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -306,7 +306,7 @@ ipaq_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } @@ -317,7 +317,7 @@ int bytes_sent = 0; int transfer_size; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf); @@ -344,7 +344,7 @@ unsigned long flags; if (priv->free_len <= 0) { - dbg(__FUNCTION__ " - we're stuffed"); + dbg("%s - we're stuffed", __FUNCTION__); return -EAGAIN; } @@ -356,7 +356,7 @@ } spin_unlock_irqrestore(&write_list_lock, flags); if (pkt == NULL) { - dbg(__FUNCTION__ " - we're stuffed"); + dbg("%s - we're stuffed", __FUNCTION__); return -EAGAIN; } @@ -379,7 +379,7 @@ spin_unlock_irqrestore(&write_list_lock, flags); result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); } } else { spin_unlock_irqrestore(&write_list_lock, flags); @@ -398,7 +398,7 @@ if (urb->status == -EINPROGRESS) { /* Should never happen */ - err(__FUNCTION__ " - flushing while urb is active !"); + err("%s - flushing while urb is active !", __FUNCTION__); return; } room = URBDATA_SIZE; @@ -439,10 +439,10 @@ return; } - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); } spin_lock_irqsave(&write_list_lock, flags); @@ -451,7 +451,7 @@ spin_unlock_irqrestore(&write_list_lock, flags); result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); } } else { priv->active = 0; @@ -467,7 +467,7 @@ { struct ipaq_private *priv = (struct ipaq_private *)port->private; - dbg(__FUNCTION__ " - freelen %d", priv->free_len); + dbg("%s - freelen %d", __FUNCTION__, priv->free_len); return priv->free_len; } @@ -475,7 +475,7 @@ { struct ipaq_private *priv = (struct ipaq_private *)port->private; - dbg(__FUNCTION__ " - queuelen %d", priv->queue_len); + dbg("%s - queuelen %d", __FUNCTION__, priv->queue_len); return priv->queue_len; } @@ -503,14 +503,14 @@ static int ipaq_startup(struct usb_serial *serial) { - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); usb_set_configuration(serial->dev, 1); return 0; } static void ipaq_shutdown(struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); } static int __init ipaq_init(void) diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c --- a/drivers/usb/serial/ir-usb.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/ir-usb.c Sat Aug 31 15:06:00 2002 @@ -261,7 +261,7 @@ case 0x20: ir_add_bof = 2; break; case 0x40: ir_add_bof = 1; break; case 0x80: ir_add_bof = 0; break; - default: + default:; } kfree (irda_desc); diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c --- a/drivers/usb/serial/keyspan.c Sat Aug 31 15:05:54 2002 +++ b/drivers/usb/serial/keyspan.c Sat Aug 31 15:05:54 2002 @@ -402,7 +402,7 @@ port = (struct usb_serial_port *) urb->context; tty = port->tty; if (urb->actual_length) { - /* 0x80 bit is error flag */ + /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no error on any byte */ for (i = 1; i < urb->actual_length ; ++i) { @@ -787,7 +787,7 @@ port = (struct usb_serial_port *) urb->context; tty = port->tty; if (urb->actual_length) { - /* 0x80 bit is error flag */ + /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no error on any byte */ for (i = 1; i < urb->actual_length ; ++i) { @@ -1104,25 +1104,25 @@ /* msg_usa26 callbacks */ .instat_callback = usa26_instat_callback, .glocont_callback = usa26_glocont_callback, - .indat_callback = usa26_indat_callback, + .indat_callback = usa26_indat_callback, .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa26_inack_callback, + .inack_callback = usa26_inack_callback, .outcont_callback = usa26_outcont_callback, }, { /* msg_usa28 callbacks */ .instat_callback = usa28_instat_callback, .glocont_callback = usa28_glocont_callback, - .indat_callback = usa28_indat_callback, + .indat_callback = usa28_indat_callback, .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa28_inack_callback, + .inack_callback = usa28_inack_callback, .outcont_callback = usa28_outcont_callback, }, { /* msg_usa49 callbacks */ .instat_callback = usa49_instat_callback, .glocont_callback = usa49_glocont_callback, - .indat_callback = usa49_indat_callback, + .indat_callback = usa49_indat_callback, .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa49_inack_callback, + .inack_callback = usa49_inack_callback, .outcont_callback = usa49_outcont_callback, } }; @@ -1362,8 +1362,6 @@ dbg ("%s - %d OK.", __FUNCTION__, baud_rate); return (KEYSPAN_BAUD_RATE_OK); } - - static int keyspan_usa26_send_setup(struct usb_serial *serial, struct usb_serial_port *port, diff -Nru a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h --- a/drivers/usb/serial/keyspan.h Sat Aug 31 15:06:03 2002 +++ b/drivers/usb/serial/keyspan.h Sat Aug 31 15:06:03 2002 @@ -521,6 +521,7 @@ unthrottle: keyspan_rx_unthrottle, ioctl: keyspan_ioctl, set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, attach: keyspan_startup, shutdown: keyspan_shutdown, }; diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c --- a/drivers/usb/serial/keyspan_pda.c Sat Aug 31 15:06:03 2002 +++ b/drivers/usb/serial/keyspan_pda.c Sat Aug 31 15:06:03 2002 @@ -679,11 +679,11 @@ 1, 2*HZ); if (rc < 0) { - dbg(__FUNCTION__" - roomquery failed"); + dbg("%s - roomquery failed", __FUNCTION__); goto error; } if (rc == 0) { - dbg(__FUNCTION__" - roomquery returned 0 bytes"); + dbg("%s - roomquery returned 0 bytes", __FUNCTION__); rc = -EIO; goto error; } @@ -702,7 +702,7 @@ port->interrupt_in_urb->dev = serial->dev; rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (rc) { - dbg(__FUNCTION__" - usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(read int) failed", __FUNCTION__); goto error; } @@ -746,7 +746,7 @@ record = &xircom_pgs_firmware[0]; #endif if (record == NULL) { - err(__FUNCTION__": unknown vendor, aborting."); + err("%s: unknown vendor, aborting.", __FUNCTION__); return -ENODEV; } @@ -797,7 +797,7 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); kfree(serial->port[0].private); } diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c --- a/drivers/usb/serial/kl5kusb105.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/kl5kusb105.c Sat Aug 31 15:06:00 2002 @@ -135,7 +135,7 @@ .read_bulk_callback =klsi_105_read_bulk_callback, .ioctl = klsi_105_ioctl, .set_termios = klsi_105_set_termios, - /*break_ctl: klsi_105_break_ctl,*/ + /*.break_ctl = klsi_105_break_ctl,*/ .attach = klsi_105_startup, .shutdown = klsi_105_shutdown, .throttle = klsi_105_throttle, @@ -187,7 +187,8 @@ KLSI_TIMEOUT); if (rc < 0) err("Change port settings failed (error = %d)", rc); - info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d", + info("%s - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d", + __FUNCTION__, settings->pktlen, settings->baudrate, settings->databits, settings->unknown1, settings->unknown2); @@ -218,7 +219,7 @@ __u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1}; __u16 status; - info(__FUNCTION__ " - sending SIO Poll request"); + info("%s - sending SIO Poll request", __FUNCTION__); rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), KL5KUSB105A_SIO_POLL, USB_TYPE_VENDOR | USB_DIR_IN, @@ -232,7 +233,7 @@ else { status = status_buf[0] + (status_buf[1]<<8); - info(__FUNCTION__ " - read status %x %x", + info("%s - read status %x %x", __FUNCTION__, status_buf[0], status_buf[1]); *line_state_p = klsi_105_status2linestate(status); @@ -260,7 +261,7 @@ serial->port[i].private = kmalloc(sizeof(struct klsi_105_private), GFP_KERNEL); if (!serial->port[i].private) { - dbg(__FUNCTION__ "kmalloc for klsi_105_private failed."); + dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__); return (-1); /* error */ } priv = (struct klsi_105_private *)serial->port[i].private; @@ -290,8 +291,7 @@ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { - err (__FUNCTION__ - " - out of memory for urb buffers."); + err("%s - out of memory for urb buffers.", __FUNCTION__); continue; } } @@ -308,7 +308,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { @@ -354,7 +354,7 @@ int i; unsigned long line_state; - dbg(__FUNCTION__" port %d", port->number); + dbg("%s port %d", __FUNCTION__, port->number); /* force low_latency on so that our tty_push actually forces * the data through @@ -394,8 +394,7 @@ rc = usb_submit_urb(port->read_urb, GFP_KERNEL); if (rc) { - err(__FUNCTION__ - " - failed submitting read urb, error %d", rc); + err("%s - failed submitting read urb, error %d", __FUNCTION__, rc); retval = rc; goto exit; } @@ -412,13 +411,12 @@ err("Enabling read failed (error = %d)", rc); retval = rc; } else - dbg(__FUNCTION__ " - enabled reading"); + dbg("%s - enabled reading", __FUNCTION__); rc = klsi_105_get_line_state(serial, &line_state); if (rc >= 0) { priv->line_state = line_state; - dbg(__FUNCTION__ - " - read line state 0x%lx", line_state); + dbg("%s - read line state 0x%lx", __FUNCTION__, line_state); retval = 0; } else retval = rc; @@ -434,7 +432,8 @@ struct klsi_105_private *priv = (struct klsi_105_private *)port->private; int rc; - dbg(__FUNCTION__" port %d", port->number); + + dbg("%s port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); @@ -480,7 +479,7 @@ int result, size; int bytes_sent=0; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); while (count > 0) { /* try to find a free urb (write 0 bytes if none) */ @@ -492,21 +491,21 @@ for (i=0; iwrite_urb_pool[i]->status != -EINPROGRESS) { urb = priv->write_urb_pool[i]; - dbg(__FUNCTION__ " - using pool URB %d", i); + dbg("%s - using pool URB %d", __FUNCTION__, i); break; } } spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); if (urb==NULL) { - dbg (__FUNCTION__ " - no more free urbs"); + dbg("%s - no more free urbs", __FUNCTION__); goto exit; } if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { - err(__FUNCTION__ " - no more kernel memory..."); + err("%s - no more kernel memory...", __FUNCTION__); goto exit; } } @@ -540,8 +539,7 @@ /* send the data out the bulk port */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ - " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); goto exit; } buf += size; @@ -559,15 +557,15 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -599,7 +597,7 @@ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); - dbg (__FUNCTION__ " - returns %d", chars); + dbg("%s - returns %d", __FUNCTION__, chars); return (chars); } @@ -620,7 +618,7 @@ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); - dbg(__FUNCTION__ " - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return (room); } @@ -636,16 +634,16 @@ unsigned char *data = urb->transfer_buffer; int rc; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* The urb might have been killed. */ if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } @@ -654,10 +652,10 @@ */ if (urb->actual_length == 0) { /* empty urbs seem to happen, we ignore them */ - /* dbg(__FUNCTION__ " - emtpy URB"); */ + /* dbg("%s - emtpy URB", __FUNCTION__); */ ; } else if (urb->actual_length <= 2) { - dbg(__FUNCTION__ " - size %d URB not understood", + dbg("%s - size %d URB not understood", __FUNCTION__, urb->actual_length); usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); } else { @@ -675,9 +673,8 @@ urb->actual_length, data); if (bytes_sent + 2 > urb->actual_length) { - dbg(__FUNCTION__ - " - trying to read more data than available" - " (%d vs. %d)", + dbg("%s - trying to read more data than available" + " (%d vs. %d)", __FUNCTION__, bytes_sent+2, urb->actual_length); /* cap at implied limit */ bytes_sent = urb->actual_length - 2; @@ -706,8 +703,7 @@ port); rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (rc) - err(__FUNCTION__ - " - failed resubmitting read urb, error %d", rc); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, rc); } /* klsi_105_read_bulk_callback */ @@ -727,7 +723,7 @@ if( (cflag & CBAUD) != (old_cflag & CBAUD) ) { /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag & CBAUD) == B0 ) { - dbg(__FUNCTION__ ": baud was B0"); + dbg("%s: baud was B0", __FUNCTION__); #if 0 priv->control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ @@ -765,7 +761,7 @@ break; } if ((cflag & CBAUD) == B0 ) { - dbg(__FUNCTION__ ": baud is B0"); + dbg("%s: baud is B0", __FUNCTION__); /* Drop RTS and DTR */ /* maybe this should be simulated by sending read * disable and read enable messages? @@ -782,10 +778,10 @@ /* set the number of data bits */ switch (cflag & CSIZE) { case CS5: - dbg(__FUNCTION__ " - 5 bits/byte not supported"); + dbg("%s - 5 bits/byte not supported", __FUNCTION__); return ; case CS6: - dbg(__FUNCTION__ " - 6 bits/byte not supported"); + dbg("%s - 6 bits/byte not supported", __FUNCTION__); return ; case CS7: priv->cfg.databits = kl5kusb105a_dtb_7; @@ -856,7 +852,7 @@ struct mct_u232_private *priv = (struct mct_u232_private *)port->private; unsigned char lcr = priv->last_lcr; - dbg (__FUNCTION__ "state=%d", break_state); + dbg("%sstate=%d", __FUNCTION__, break_state); if (break_state) lcr |= MCT_U232_SET_BREAK; @@ -872,14 +868,14 @@ struct klsi_105_private *priv = (struct klsi_105_private *)port->private; int mask; - dbg (__FUNCTION__ "cmd=0x%x", cmd); + dbg("%scmd=0x%x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ switch (cmd) { case TIOCMGET: { int rc; unsigned long line_state; - dbg (__FUNCTION__ " - TIOCMGET request, just guessing"); + dbg("%s - TIOCMGET request, just guessing", __FUNCTION__); rc = klsi_105_get_line_state(serial, &line_state); if (rc < 0) { @@ -888,7 +884,7 @@ return -ENOIOCTLCMD; } else { priv->line_state = line_state; - dbg(__FUNCTION__ " - read line state 0x%lx", line_state); + dbg("%s - read line state 0x%lx", __FUNCTION__, line_state); } return put_user(priv->line_state, (unsigned long *) arg); }; @@ -903,10 +899,10 @@ /* RTS needs set */ if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ) - dbg (__FUNCTION__ " - set RTS not handled"); + dbg("%s - set RTS not handled", __FUNCTION__); /* priv->control_state |= TIOCM_RTS; */ else - dbg (__FUNCTION__ " - clear RTS not handled"); + dbg("%s - clear RTS not handled", __FUNCTION__); /* priv->control_state &= ~TIOCM_RTS; */ } @@ -914,10 +910,10 @@ /* DTR needs set */ if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ) - dbg (__FUNCTION__ " - set DTR not handled"); + dbg("%s - set DTR not handled", __FUNCTION__); /* priv->control_state |= TIOCM_DTR; */ else - dbg (__FUNCTION__ " - clear DTR not handled"); + dbg("%s - clear DTR not handled", __FUNCTION__); /* priv->control_state &= ~TIOCM_DTR; */ } /* @@ -928,19 +924,19 @@ case TIOCMIWAIT: /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ /* TODO */ - dbg (__FUNCTION__ " - TIOCMIWAIT not handled"); + dbg("%s - TIOCMIWAIT not handled", __FUNCTION__); return -ENOIOCTLCMD; case TIOCGICOUNT: /* return count of modemline transitions */ /* TODO */ - dbg (__FUNCTION__ " - TIOCGICOUNT not handled"); + dbg("%s - TIOCGICOUNT not handled", __FUNCTION__); return -ENOIOCTLCMD; case TCGETS: { /* return current info to caller */ int retval; - dbg (__FUNCTION__ " - TCGETS data faked/incomplete"); + dbg("%s - TCGETS data faked/incomplete", __FUNCTION__); retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios)); @@ -956,7 +952,7 @@ /* set port termios to the one given by the user */ int retval; - dbg (__FUNCTION__ " - TCSETS not handled"); + dbg("%s - TCSETS not handled", __FUNCTION__); retval = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios)); @@ -982,7 +978,7 @@ return -ENOIOCTLCMD; } default: - dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd); + dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); return(-ENOIOCTLCMD); break; } @@ -991,7 +987,7 @@ static void klsi_105_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); usb_unlink_urb (port->read_urb); } @@ -999,12 +995,12 @@ { int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); } diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c --- a/drivers/usb/serial/mct_u232.c Sat Aug 31 15:06:03 2002 +++ b/drivers/usb/serial/mct_u232.c Sat Aug 31 15:06:03 2002 @@ -317,7 +317,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { @@ -333,7 +333,7 @@ struct mct_u232_private *priv = (struct mct_u232_private *)port->private; int retval = 0; - dbg(__FUNCTION__" port %d", port->number); + dbg("%s port %d", __FUNCTION__, port->number); /* Compensate for a hardware bug: although the Sitecom U232-P25 * device reports a maximum output packet size of 32 bytes, @@ -391,7 +391,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp) { - dbg(__FUNCTION__" port %d", port->number); + dbg("%s port %d", __FUNCTION__, port->number); if (port->serial->dev) { /* shutdown our urbs */ @@ -411,10 +411,10 @@ struct usb_serial *serial = port->serial; int result, bytes_sent, size; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); + dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } @@ -424,7 +424,7 @@ /* another write is still pending? */ if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return (0); } @@ -456,8 +456,7 @@ /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - err(__FUNCTION__ - " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); return result; } @@ -480,15 +479,15 @@ struct usb_serial *serial = port->serial; struct tty_struct *tty = port->tty; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -518,16 +517,16 @@ struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* The urb might have been killed. */ if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } @@ -604,7 +603,7 @@ if( (cflag & CBAUD) != (old_cflag & CBAUD) ) { /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag & CBAUD) == B0 ) { - dbg(__FUNCTION__ ": baud was B0"); + dbg("%s: baud was B0", __FUNCTION__); priv->control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ if (!(old_cflag & CRTSCTS)) { @@ -640,7 +639,7 @@ mct_u232_set_baud_rate(serial, 9600); break; } if ((cflag & CBAUD) == B0 ) { - dbg(__FUNCTION__ ": baud is B0"); + dbg("%s: baud is B0", __FUNCTION__); /* Drop RTS and DTR */ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); mct_u232_set_modem_ctrl(serial, priv->control_state); @@ -711,7 +710,7 @@ struct mct_u232_private *priv = (struct mct_u232_private *)port->private; unsigned char lcr = priv->last_lcr; - dbg (__FUNCTION__ "state=%d", break_state); + dbg("%sstate=%d", __FUNCTION__, break_state); if (break_state) lcr |= MCT_U232_SET_BREAK; @@ -727,7 +726,7 @@ struct mct_u232_private *priv = (struct mct_u232_private *)port->private; int mask; - dbg (__FUNCTION__ "cmd=0x%x", cmd); + dbg("%scmd=0x%x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ switch (cmd) { @@ -772,7 +771,7 @@ return 0; default: - dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd); + dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); return(-ENOIOCTLCMD); break; } diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c --- a/drivers/usb/serial/omninet.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/serial/omninet.c Sat Aug 31 15:05:59 2002 @@ -148,7 +148,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -156,7 +156,7 @@ od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); if( !od ) { - err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data)); + err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); return -ENOMEM; } @@ -171,7 +171,7 @@ omninet_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return result; } @@ -185,7 +185,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -221,12 +221,12 @@ // dbg("omninet_read_bulk_callback"); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -254,7 +254,7 @@ omninet_read_bulk_callback, port); result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } @@ -272,11 +272,11 @@ // dbg("omninet_write port %d", port->number); if (count == 0) { - dbg(__FUNCTION__" - write request of 0 bytes"); + dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } if (wport->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__" - already writing"); + dbg("%s - already writing", __FUNCTION__); return (0); } @@ -305,7 +305,7 @@ wport->write_urb->dev = serial->dev; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else result = count; @@ -348,7 +348,7 @@ } if (urb->status) { - dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -363,7 +363,7 @@ static void omninet_shutdown (struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg ("%s", __FUNCTION__); } diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/pl2303.c Sat Aug 31 15:06:00 2002 @@ -72,6 +72,7 @@ { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -167,7 +168,7 @@ retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); - dbg (__FUNCTION__" - value = %d, retval = %d", value, retval); + dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval); return retval; } @@ -175,10 +176,10 @@ { int result; - dbg (__FUNCTION__ " - port %d, %d bytes", port->number, count); + dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return 0; } @@ -196,7 +197,7 @@ port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else result = count; @@ -214,11 +215,11 @@ int baud; int i; - dbg (__FUNCTION__ " - port %d, initialized = %d", port->number, + dbg("%s - port %d, initialized = %d", __FUNCTION__, port->number, ((struct pl2303_private *) port->private)->termios_initialized); if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); return; } @@ -232,14 +233,14 @@ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg(__FUNCTION__ " - nothing to change..."); + dbg("%s - nothing to change...", __FUNCTION__); return; } } buf = kmalloc (7, GFP_KERNEL); if (!buf) { - err(__FUNCTION__ " - out of memory."); + err("%s - out of memory.", __FUNCTION__); return; } memset (buf, 0x00, 0x07); @@ -265,7 +266,7 @@ default: case CS8: buf[6] = 8; break; } - dbg (__FUNCTION__ " - data bits = %d", buf[6]); + dbg("%s - data bits = %d", __FUNCTION__, buf[6]); } baud = 0; @@ -290,7 +291,7 @@ err ("pl2303 driver does not support the baudrate requested (fix it)"); break; } - dbg (__FUNCTION__ " - baud = %d", baud); + dbg("%s - baud = %d", __FUNCTION__, baud); if (baud) { buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; @@ -303,10 +304,10 @@ /* For reference buf[4]=2 is 2 stop bits */ if (cflag & CSTOPB) { buf[4] = 2; - dbg(__FUNCTION__ " - stop bits = 2"); + dbg("%s - stop bits = 2", __FUNCTION__); } else { buf[4] = 0; - dbg(__FUNCTION__ " - stop bits = 1"); + dbg("%s - stop bits = 1", __FUNCTION__); } if (cflag & PARENB) { @@ -317,14 +318,14 @@ /* For reference buf[5]=4 is space parity */ if (cflag & PARODD) { buf[5] = 1; - dbg(__FUNCTION__ " - parity = odd"); + dbg("%s - parity = odd", __FUNCTION__); } else { buf[5] = 2; - dbg(__FUNCTION__ " - parity = even"); + dbg("%s - parity = even", __FUNCTION__); } } else { buf[5] = 0; - dbg(__FUNCTION__ " - parity = none"); + dbg("%s - parity = none", __FUNCTION__); } i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), @@ -370,7 +371,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg (__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); #define FISH(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ @@ -401,20 +402,20 @@ //FIXME: need to assert RTS and DTR if CRTSCTS off - dbg (__FUNCTION__ " - submitting read urb"); + dbg("%s - submitting read urb", __FUNCTION__); port->read_urb->dev = serial->dev; result = usb_submit_urb (port->read_urb, GFP_KERNEL); if (result) { - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } - dbg (__FUNCTION__ " - submitting interrupt urb"); + dbg("%s - submitting interrupt urb", __FUNCTION__); port->interrupt_in_urb->dev = serial->dev; result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL); if (result) { - err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result); + err("%s - failed submitting interrupt urb, error %d", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } @@ -435,7 +436,7 @@ if (!serial) return; - dbg (__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (serial->dev) { if (port->tty) { @@ -450,23 +451,23 @@ } /* shutdown our urbs */ - dbg (__FUNCTION__ " - shutting down urbs"); + dbg("%s - shutting down urbs", __FUNCTION__); result = usb_unlink_urb (port->write_urb); if (result) - dbg (__FUNCTION__ " - usb_unlink_urb " - "(write_urb) failed with reason: %d", + dbg("%s - usb_unlink_urb (write_urb)" + " failed with reason: %d", __FUNCTION__, result); result = usb_unlink_urb (port->read_urb); if (result) - dbg (__FUNCTION__ " - usb_unlink_urb " - "(read_urb) failed with reason: %d", + dbg("%s - usb_unlink_urb (read_urb) " + "failed with reason: %d", __FUNCTION__, result); result = usb_unlink_urb (port->interrupt_in_urb); if (result) - dbg (__FUNCTION__ " - usb_unlink_urb " - "(interrupt_in_urb) failed with reason: %d", + dbg("%s - usb_unlink_urb (interrupt_in_urb)" + " failed with reason: %d", __FUNCTION__, result); } } @@ -515,7 +516,7 @@ result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0); - dbg (__FUNCTION__ " - result = %x", result); + dbg("%s - result = %x", __FUNCTION__, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -524,22 +525,22 @@ static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { - dbg (__FUNCTION__" (%d) cmd = 0x%04x", port->number, cmd); + dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd); switch (cmd) { case TIOCMGET: - dbg (__FUNCTION__" (%d) TIOCMGET", port->number); + dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); return get_modem_info (port, (unsigned int *)arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: - dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); return set_modem_info(port, cmd, (unsigned int *) arg); default: - dbg (__FUNCTION__" not supported = 0x%04x", cmd); + dbg("%s not supported = 0x%04x", __FUNCTION__, cmd); break; } @@ -553,19 +554,19 @@ u16 state; int result; - dbg (__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg (__FUNCTION__" - turning break %s", state==BREAK_OFF ? "off" : "on"); + dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__); result = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result) - dbg (__FUNCTION__" - error sending break = %d", result); + dbg("%s - error sending break = %d", __FUNCTION__, result); } @@ -573,7 +574,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); for (i = 0; i < serial->num_ports; ++i) kfree (serial->port[i].private); @@ -619,30 +620,30 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg (__FUNCTION__ " - urb->status = %d", urb->status); + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); if (!port->open_count) { - dbg (__FUNCTION__ " - port is closed, exiting."); + dbg("%s - port is closed, exiting.", __FUNCTION__); return; } if (urb->status == -EPROTO) { /* PL2303 mysteriously fails with -EPROTO reschedule the read */ - dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb"); + dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__); urb->status = 0; urb->dev = serial->dev; result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } - dbg (__FUNCTION__ " - unable to handle the error, exiting."); + dbg("%s - unable to handle the error, exiting.", __FUNCTION__); return; } @@ -664,7 +665,7 @@ urb->dev = serial->dev; result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); } return; @@ -680,20 +681,20 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { /* error in the urb, so we have to resubmit it */ if (serial_paranoia_check (port->serial, __FUNCTION__)) { return; } - dbg (__FUNCTION__ " - Overflow in write"); - dbg (__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - Overflow in write", __FUNCTION__); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); port->write_urb->transfer_buffer_length = 1; port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting write urb, error %d", result); + err("%s - failed resubmitting write urb, error %d", __FUNCTION__, result); return; } diff -Nru a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h --- a/drivers/usb/serial/pl2303.h Sat Aug 31 15:06:00 2002 +++ b/drivers/usb/serial/pl2303.h Sat Aug 31 15:06:00 2002 @@ -22,3 +22,6 @@ #define ITEGNO_VENDOR_ID 0x0eba #define ITEGNO_PRODUCT_ID 0x1080 + +#define MA620_VENDOR_ID 0x0df7 +#define MA620_PRODUCT_ID 0x0620 diff -Nru a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c --- a/drivers/usb/serial/safe_serial.c Sat Aug 31 15:05:55 2002 +++ b/drivers/usb/serial/safe_serial.c Sat Aug 31 15:05:55 2002 @@ -211,12 +211,12 @@ dbg ("%s", __FUNCTION__); if (!serial) { - dbg (__FUNCTION__ " - bad serial pointer, exiting"); + dbg ("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg (__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg ("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -242,18 +242,18 @@ if (actual_length <= (length - 2)) { - info (__FUNCTION__ " - actual: %d", actual_length); + info ("%s - actual: %d", __FUNCTION__, actual_length); for (i = 0; i < actual_length; i++) { tty_insert_flip_char (port->tty, data[i], 0); } tty_flip_buffer_push (port->tty); } else { - err (__FUNCTION__ " - inconsistant lengths %d:%d", actual_length, - length); + err ("%s - inconsistant lengths %d:%d", __FUNCTION__, + actual_length, length); } } else { - err (__FUNCTION__ " - bad CRC %x", fcs); + err ("%s - bad CRC %x", __FUNCTION__, fcs); } } else { for (i = 0; i < length; i++) { @@ -269,7 +269,7 @@ safe_read_bulk_callback, port); if ((result = usb_submit_urb (urb, GFP_ATOMIC))) { - err (__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); } } @@ -285,7 +285,7 @@ count); if (!port->write_urb) { - dbg (__FUNCTION__ " - write urb NULL"); + dbg ("%s - write urb NULL", __FUNCTION__); return (0); } @@ -293,15 +293,15 @@ port->write_urb->transfer_buffer_length); if (!port->write_urb->transfer_buffer_length) { - dbg (__FUNCTION__ " - write urb transfer_buffer_length zero"); + dbg ("%s - write urb transfer_buffer_length zero", __FUNCTION__); return (0); } if (count == 0) { - dbg (__FUNCTION__ " - write request of 0 bytes"); + dbg ("%s - write request of 0 bytes", __FUNCTION__); return (0); } if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg ("%s - already writing", __FUNCTION__); return (0); } @@ -360,10 +360,10 @@ #endif port->write_urb->dev = serial->dev; if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) { - err (__FUNCTION__ " - failed submitting write urb, error %d", result); + err ("%s - failed submitting write urb, error %d", __FUNCTION__, result); return 0; } - dbg (__FUNCTION__ " urb: %p submitted", port->write_urb); + dbg ("%s urb: %p submitted", __FUNCTION__, port->write_urb); return (count); } diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c --- a/drivers/usb/serial/usbserial.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/serial/usbserial.c Sat Aug 31 15:05:59 2002 @@ -5,10 +5,9 @@ * Copyright (c) 2000 Peter Berger (pberger@brimson.com) * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. * * This driver was originally based on the ACM driver by Armin Fuerst (which was * based on a driver by Brad Keryan) @@ -443,7 +442,7 @@ unsigned int i, j; int good_spot; - dbg(__FUNCTION__ " %d", num_ports); + dbg("%s %d", __FUNCTION__, num_ports); *minor = 0; for (i = 0; i < SERIAL_TTY_MINORS; ++i) { @@ -462,7 +461,7 @@ serial->magic = USB_SERIAL_MAGIC; *minor = i; - dbg(__FUNCTION__ " - minor base = %d", *minor); + dbg("%s - minor base = %d", __FUNCTION__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; return serial; @@ -474,7 +473,7 @@ { int i; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); if (serial == NULL) return; @@ -497,13 +496,13 @@ /* dbg("ezusb_writememory %x, %d", address, length); */ if (!serial->dev) { - dbg(__FUNCTION__ " - no physical device present, failing."); + dbg("%s - no physical device present, failing.", __FUNCTION__); return -ENODEV; } transfer_buffer = kmalloc (length, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", length); + err("%s - kmalloc(%d) failed.", __FUNCTION__, length); return -ENOMEM; } memcpy (transfer_buffer, data, length); @@ -515,10 +514,10 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) { int response; - dbg(__FUNCTION__ " - %d", reset_bit); + dbg("%s - %d", __FUNCTION__, reset_bit); response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) { - err(__FUNCTION__ "- %d failed", reset_bit); + err("%s- %d failed", __FUNCTION__, reset_bit); } return response; } @@ -535,7 +534,7 @@ unsigned int portNumber; int retval = 0; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* initialize the pointer incase something fails */ tty->driver_data = NULL; @@ -581,7 +580,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp) { if (!port->open_count) { - dbg (__FUNCTION__ " - port not opened"); + dbg ("%s - port not opened", __FUNCTION__); return; } @@ -610,7 +609,7 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* if disconnect beat us to the punch here, there's nothing to do */ if (tty->driver_data) { @@ -631,10 +630,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count); + dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); if (!port->open_count) { - dbg (__FUNCTION__ " - port not opened"); + dbg("%s - port not opened", __FUNCTION__); goto exit; } @@ -660,10 +659,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg("%s - port not open", __FUNCTION__); goto exit; } @@ -689,10 +688,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s = port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg("%s - port not open", __FUNCTION__); goto exit; } @@ -717,10 +716,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg ("%s - port not open", __FUNCTION__); goto exit; } @@ -742,10 +741,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg("%s - port not open", __FUNCTION__); goto exit; } @@ -768,10 +767,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); + dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg ("%s - port not open", __FUNCTION__); goto exit; } @@ -796,10 +795,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg("%s - port not open", __FUNCTION__); goto exit; } @@ -821,10 +820,10 @@ down (&port->sem); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->open_count) { - dbg (__FUNCTION__ " - port not open"); + dbg("%s - port not open", __FUNCTION__); goto exit; } @@ -838,7 +837,7 @@ static void serial_shutdown (struct usb_serial *serial) { - dbg(__FUNCTION__); + dbg ("%s", __FUNCTION__); if (serial->type->shutdown) serial->type->shutdown(serial); @@ -854,7 +853,7 @@ off_t begin = 0; char tmp[40]; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION); for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { serial = get_serial_by_minor(i); @@ -899,7 +898,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* force low_latency on so that our tty_push actually forces the data through, otherwise it is scheduled, and with high data rates (like with OHCI) data @@ -920,7 +919,7 @@ port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); } return result; @@ -930,7 +929,7 @@ { struct usb_serial *serial = port->serial; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (serial->dev) { /* shutdown any bulk reads that might be going on */ @@ -943,7 +942,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); generic_cleanup (port); } @@ -952,17 +951,17 @@ struct usb_serial *serial = port->serial; int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); + dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg("%s - already writing", __FUNCTION__); return (0); } @@ -990,7 +989,7 @@ /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else result = count; @@ -1006,14 +1005,14 @@ struct usb_serial *serial = port->serial; int room = 0; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (serial->num_bulk_out) { if (port->write_urb->status != -EINPROGRESS) room = port->bulk_out_size; } - dbg(__FUNCTION__ " - returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return (room); } @@ -1022,14 +1021,14 @@ struct usb_serial *serial = port->serial; int chars = 0; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) chars = port->write_urb->transfer_buffer_length; } - dbg (__FUNCTION__ " - returns %d", chars); + dbg("%s - returns %d", __FUNCTION__, chars); return (chars); } @@ -1042,15 +1041,15 @@ int i; int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -1080,7 +1079,7 @@ generic_read_bulk_callback), port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); } static void generic_write_bulk_callback (struct urb *urb) @@ -1088,15 +1087,15 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -1110,7 +1109,7 @@ { int i; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { @@ -1124,7 +1123,7 @@ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) return; @@ -1134,7 +1133,7 @@ return; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg(__FUNCTION__ " - write wakeup call."); + dbg("%s - write wakeup call.", __FUNCTION__); (tty->ldisc.write_wakeup)(tty); } @@ -1402,7 +1401,7 @@ max_endpoints = max(num_bulk_in, num_bulk_out); max_endpoints = max(max_endpoints, num_interrupt_in); max_endpoints = max(max_endpoints, (int)serial->num_ports); - dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints); + dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = &serial->port[i]; port->number = i + serial->minor; @@ -1496,7 +1495,7 @@ struct usb_serial_port *port; int i; - dbg(__FUNCTION__); + dbg ("%s", __FUNCTION__); if (serial) { /* fail all future close/read/write/ioctl/etc calls */ for (i = 0; i < serial->num_ports; ++i) { @@ -1566,7 +1565,11 @@ static struct tty_driver serial_tty_driver = { .magic = TTY_DRIVER_MAGIC, .driver_name = "usb-serial", +#ifndef CONFIG_DEVFS_FS + .name = "ttyUSB", +#else .name = "usb/tts/%d", +#endif .major = SERIAL_TTY_MAJOR, .minor_start = 0, .num = SERIAL_TTY_MINORS, @@ -1607,7 +1610,7 @@ serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; if (tty_register_driver (&serial_tty_driver)) { - err(__FUNCTION__ " - failed to register tty driver"); + err("%s - failed to register tty driver", __FUNCTION__); return -1; } diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/serial/visor.c Sat Aug 31 15:05:59 2002 @@ -280,7 +280,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!port->read_urb) { /* this is needed for some brain dead Sony devices */ @@ -298,7 +298,7 @@ */ if (port->tty) port->tty->low_latency = 1; - + /* Start reading from the device */ usb_fill_bulk_urb (port->read_urb, serial->dev, usb_rcvbulkpipe (serial->dev, @@ -308,7 +308,7 @@ visor_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return result; } @@ -322,7 +322,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -333,7 +333,7 @@ * device is still here */ transfer_buffer = kmalloc (0x12, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); + err("%s - kmalloc(%d) failed.", __FUNCTION__, 0x12); } else { /* send a shutdown message to the device */ usb_control_msg (serial->dev, @@ -358,7 +358,7 @@ unsigned char *buffer; int status; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { @@ -394,7 +394,8 @@ /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + err("%s - usb_submit_urb(write bulk) failed with status = %d", + __FUNCTION__, status); count = status; } else { bytes_out += count; @@ -410,7 +411,7 @@ static int visor_write_room (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* * We really can take anything the user throws at us @@ -423,7 +424,7 @@ static int visor_chars_in_buffer (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* * We can't really account for how much data we @@ -442,10 +443,10 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -471,15 +472,15 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } @@ -508,14 +509,14 @@ visor_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; } static void visor_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); usb_unlink_urb (port->read_urb); } @@ -524,12 +525,12 @@ { int result; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); } static int visor_probe (struct usb_serial *serial) @@ -540,20 +541,20 @@ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL); if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 256); + err("%s - kmalloc(%d) failed.", __FUNCTION__, 256); return -ENOMEM; } - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); - dbg(__FUNCTION__ " - Set config to 1"); + dbg("%s - Set config to 1", __FUNCTION__); usb_set_configuration (serial->dev, 1); /* send a get connection info request */ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); if (response < 0) { - err(__FUNCTION__ " - error getting connection information"); + err("%s - error getting connection information", __FUNCTION__); } else { struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; @@ -598,7 +599,7 @@ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x14, 300); if (response < 0) { - err(__FUNCTION__ " - error getting first unknown palm command"); + err("%s - error getting first unknown palm command", __FUNCTION__); } else { usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); } @@ -607,7 +608,7 @@ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x14, 300); if (response < 0) { - err(__FUNCTION__ " - error getting second unknown palm command"); + err("%s - error getting second unknown palm command", __FUNCTION__); } else { usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); } @@ -617,7 +618,7 @@ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300); if (response < 0) { - err(__FUNCTION__ " - error getting bytes available request"); + err("%s - error getting bytes available request", __FUNCTION__); } kfree (transfer_buffer); @@ -642,7 +643,7 @@ int result; u8 data; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* * Note that PEG-300 series devices expect the following two calls. @@ -653,11 +654,11 @@ USB_REQ_GET_CONFIGURATION, USB_DIR_IN, 0, 0, &data, 1, HZ * 3); if (result < 0) { - err(__FUNCTION__ ": get config number failed: %d", result); + err("%s: get config number failed: %d", __FUNCTION__, result); return result; } if (result != 1) { - err(__FUNCTION__ ": get config number bad return length: %d", result); + err("%s: get config number bad return length: %d", __FUNCTION__, result); return -EIO; } @@ -667,11 +668,11 @@ USB_DIR_IN | USB_DT_DEVICE, 0, 0, &data, 1, HZ * 3); if (result < 0) { - err(__FUNCTION__ ": get interface number failed: %d", result); + err("%s: get interface number failed: %d", __FUNCTION__, result); return result; } if (result != 1) { - err(__FUNCTION__ ": get interface number bad return length: %d", result); + err("%s: get interface number bad return length: %d", __FUNCTION__, result); return -EIO; } @@ -680,12 +681,12 @@ static void visor_shutdown (struct usb_serial *serial) { - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); } static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { - dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); + dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); return -ENOIOCTLCMD; } @@ -696,10 +697,10 @@ { unsigned int cflag; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); return; } @@ -708,50 +709,51 @@ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg(__FUNCTION__ " - nothing to change..."); + dbg("%s - nothing to change...", __FUNCTION__); return; } } /* get the byte size */ switch (cflag & CSIZE) { - case CS5: dbg(__FUNCTION__ " - data bits = 5"); break; - case CS6: dbg(__FUNCTION__ " - data bits = 6"); break; - case CS7: dbg(__FUNCTION__ " - data bits = 7"); break; + case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; + case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; + case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; default: - case CS8: dbg(__FUNCTION__ " - data bits = 8"); break; + case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; } /* determine the parity */ if (cflag & PARENB) if (cflag & PARODD) - dbg(__FUNCTION__ " - parity = odd"); + dbg("%s - parity = odd", __FUNCTION__); else - dbg(__FUNCTION__ " - parity = even"); + dbg("%s - parity = even", __FUNCTION__); else - dbg(__FUNCTION__ " - parity = none"); + dbg("%s - parity = none", __FUNCTION__); /* figure out the stop bits requested */ if (cflag & CSTOPB) - dbg(__FUNCTION__ " - stop bits = 2"); + dbg("%s - stop bits = 2", __FUNCTION__); else - dbg(__FUNCTION__ " - stop bits = 1"); + dbg("%s - stop bits = 1", __FUNCTION__); /* figure out the flow control settings */ if (cflag & CRTSCTS) - dbg(__FUNCTION__ " - RTS/CTS is enabled"); + dbg("%s - RTS/CTS is enabled", __FUNCTION__); else - dbg(__FUNCTION__ " - RTS/CTS is disabled"); + dbg("%s - RTS/CTS is disabled", __FUNCTION__); /* determine software flow control */ if (I_IXOFF(port->tty)) - dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty)); + dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", + __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); else - dbg(__FUNCTION__ " - XON/XOFF is disabled"); + dbg("%s - XON/XOFF is disabled", __FUNCTION__); /* get the baud rate wanted */ - dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty)); + dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); return; } diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c Sat Aug 31 15:05:59 2002 +++ b/drivers/usb/serial/whiteheat.c Sat Aug 31 15:05:59 2002 @@ -179,7 +179,7 @@ *****************************************************************************/ static void command_port_write_callback (struct urb *urb) { - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); if (urb->status) { dbg ("nonzero urb status: %d", urb->status); @@ -200,15 +200,15 @@ unsigned char *data = urb->transfer_buffer; int result; - dbg (__FUNCTION__); + dbg("%s", __FUNCTION__); if (urb->status) { - dbg (__FUNCTION__ " - nonzero urb status: %d", urb->status); + dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status); return; } if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } @@ -216,7 +216,7 @@ info = (struct whiteheat_private *)port->private; if (!info) { - dbg (__FUNCTION__ " - info is NULL, exiting."); + dbg("%s - info is NULL, exiting.", __FUNCTION__); return; } @@ -239,7 +239,7 @@ command_port_read_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dbg(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); } @@ -251,7 +251,7 @@ __u8 *transfer_buffer; int retval = 0; - dbg(__FUNCTION__" - command %d", command); + dbg("%s - command %d", __FUNCTION__, command); port = &serial->port[COMMAND_PORT]; info = (struct whiteheat_private *)port->private; @@ -264,7 +264,7 @@ port->write_urb->dev = serial->dev; retval = usb_submit_urb (port->write_urb, GFP_KERNEL); if (retval) { - dbg (__FUNCTION__" - submit urb failed"); + dbg("%s - submit urb failed", __FUNCTION__); goto exit; } @@ -275,19 +275,19 @@ } if (info->command_finished == FALSE) { - dbg (__FUNCTION__ " - command timed out."); + dbg("%s - command timed out.", __FUNCTION__); retval = -ETIMEDOUT; goto exit; } if (info->command_finished == WHITEHEAT_CMD_FAILURE) { - dbg (__FUNCTION__ " - command failed."); + dbg("%s - command failed.", __FUNCTION__); retval = -EIO; goto exit; } if (info->command_finished == WHITEHEAT_CMD_COMPLETE) - dbg (__FUNCTION__ " - command completed."); + dbg("%s - command completed.", __FUNCTION__); exit: return retval; @@ -301,14 +301,14 @@ struct whiteheat_private *info; int retval = 0; - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* set up some stuff for our command port */ command_port = &port->serial->port[COMMAND_PORT]; if (command_port->private == NULL) { info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL); if (info == NULL) { - err(__FUNCTION__ " - out of memory"); + err("%s - out of memory", __FUNCTION__); retval = -ENOMEM; goto exit; } @@ -321,7 +321,7 @@ command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */ retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL); if (retval) { - err(__FUNCTION__ " - failed submitting read urb, error %d", retval); + err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); goto exit; } } @@ -330,7 +330,7 @@ port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb, GFP_KERNEL); if (retval) { - err(__FUNCTION__ " - failed submitting read urb, error %d", retval); + err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); goto exit; } @@ -345,7 +345,7 @@ /* FIXME!!! */ exit: - dbg(__FUNCTION__ " - exit, retval = %d", retval); + dbg("%s - exit, retval = %d", __FUNCTION__, retval); return retval; } @@ -354,7 +354,7 @@ { struct whiteheat_min_set close_command; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* send a close command to the port */ /* firmware uses 1 based port numbering */ @@ -372,7 +372,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { - dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); + dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); return -ENOIOCTLCMD; } @@ -383,10 +383,10 @@ unsigned int cflag; struct whiteheat_port_settings port_settings; - dbg(__FUNCTION__ " -port %d", port->number); + dbg("%s -port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); goto exit; } @@ -395,7 +395,7 @@ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg(__FUNCTION__ " - nothing to change..."); + dbg("%s - nothing to change...", __FUNCTION__); goto exit; } } @@ -412,7 +412,7 @@ default: case CS8: port_settings.bits = 8; break; } - dbg(__FUNCTION__ " - data bits = %d", port_settings.bits); + dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits); /* determine the parity */ if (cflag & PARENB) @@ -422,14 +422,14 @@ port_settings.parity = 'e'; else port_settings.parity = 'n'; - dbg(__FUNCTION__ " - parity = %c", port_settings.parity); + dbg("%s - parity = %c", __FUNCTION__, port_settings.parity); /* figure out the stop bits requested */ if (cflag & CSTOPB) port_settings.stop = 2; else port_settings.stop = 1; - dbg(__FUNCTION__ " - stop bits = %d", port_settings.stop); + dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop); /* figure out the flow control settings */ @@ -437,7 +437,7 @@ port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW); else port_settings.hflow = 0; - dbg(__FUNCTION__ " - hardware flow control = %s %s %s %s", + dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__, (port_settings.hflow & WHITEHEAT_CTS_FLOW) ? "CTS" : "", (port_settings.hflow & WHITEHEAT_RTS_FLOW) ? "RTS" : "", (port_settings.hflow & WHITEHEAT_DSR_FLOW) ? "DSR" : "", @@ -448,15 +448,15 @@ port_settings.sflow = 'b'; else port_settings.sflow = 'n'; - dbg(__FUNCTION__ " - software flow control = %c", port_settings.sflow); + dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow); port_settings.xon = START_CHAR(port->tty); port_settings.xoff = STOP_CHAR(port->tty); - dbg(__FUNCTION__ " - XON = %2x, XOFF = %2x", port_settings.xon, port_settings.xoff); + dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ port_settings.baud = tty_get_baud_rate(port->tty); - dbg(__FUNCTION__ " - baud rate = %d", port_settings.baud); + dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud); /* handle any settings that aren't specified in the tty structure */ port_settings.lloop = 0; @@ -471,7 +471,7 @@ static void whiteheat_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* Change the control signals */ /* FIXME!!! */ @@ -482,7 +482,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port) { - dbg(__FUNCTION__" - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); /* Change the control signals */ /* FIXME!!! */ @@ -509,7 +509,7 @@ int response; const struct whiteheat_hex_record *record; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); response = ezusb_set_reset (serial, 1); @@ -626,7 +626,7 @@ { struct usb_serial_port *command_port; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); /* free up our private data for our command port */ command_port = &serial->port[COMMAND_PORT]; @@ -637,8 +637,6 @@ return; } - - static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command) diff -Nru a/drivers/video/cgfourteenfb.c b/drivers/video/cgfourteenfb.c --- a/drivers/video/cgfourteenfb.c Sat Aug 31 15:05:55 2002 +++ b/drivers/video/cgfourteenfb.c Sat Aug 31 15:05:55 2002 @@ -362,7 +362,7 @@ char __init *cgfourteenfb_init(struct fb_info_sbusfb *fb) { - struct fb_fix_screeninfo *fix = &fb->fix; + struct fb_fix_screeninfo *fix = &fb->info.fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; unsigned long rphys, phys; @@ -414,7 +414,7 @@ strcpy(fb->info.modename, "CGfourteen"); strcpy(fix->id, "CGfourteen"); - fix->line_length = fb->var.xres_virtual; + fix->line_length = fb->info.var.xres_virtual; fix->accel = FB_ACCEL_SUN_CG14; disp->scrollmode = SCROLL_YREDRAW; diff -Nru a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c --- a/drivers/video/cgsixfb.c Sat Aug 31 15:05:59 2002 +++ b/drivers/video/cgsixfb.c Sat Aug 31 15:05:59 2002 @@ -224,14 +224,14 @@ static void cg6_setup(struct display *p) { - p->next_line = sbusfbinfo(p->fb_info)->var.xres_virtual; + p->next_line = p->fb_info->var.xres_virtual; p->next_plane = 0; } static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct cg6_fbc *fbc = fb->s.cg6.fbc; unsigned long flags; int x, y, w, h; @@ -302,7 +302,7 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct cg6_fbc *fbc = fb->s.cg6.fbc; unsigned long flags; int i, x, y; @@ -359,7 +359,7 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct cg6_fbc *fbc = fb->s.cg6.fbc; unsigned long flags; int i, x, y; @@ -692,8 +692,8 @@ char __init *cgsixfb_init(struct fb_info_sbusfb *fb) { - struct fb_fix_screeninfo *fix = &fb->fix; - struct fb_var_screeninfo *var = &fb->var; + struct fb_fix_screeninfo *fix = &fb->info.fix; + struct fb_var_screeninfo *var = &fb->info.var; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; struct sbus_dev *sdev = fb->sbdp; @@ -717,7 +717,7 @@ fix->smem_len *= 4; } - fix->line_length = fb->var.xres_virtual; + fix->line_length = fb->info.var.xres_virtual; fix->accel = FB_ACCEL_SUN_CGSIX; var->accel_flags = FB_ACCELF_TEXT; diff -Nru a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c --- a/drivers/video/cgthreefb.c Sat Aug 31 15:06:06 2002 +++ b/drivers/video/cgthreefb.c Sat Aug 31 15:06:06 2002 @@ -176,7 +176,7 @@ char __init *cgthreefb_init(struct fb_info_sbusfb *fb) { - struct fb_fix_screeninfo *fix = &fb->fix; + struct fb_fix_screeninfo *fix = &fb->info.fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; struct sbus_dev *sdev = fb->sbdp; @@ -216,7 +216,7 @@ strcpy(fb->info.modename, "CGthree"); strcpy(fix->id, "CGthree"); - fix->line_length = fb->var.xres_virtual; + fix->line_length = fb->info.var.xres_virtual; fix->accel = FB_ACCEL_SUN_CGTHREE; disp->scrollmode = SCROLL_YREDRAW; diff -Nru a/drivers/video/creatorfb.c b/drivers/video/creatorfb.c --- a/drivers/video/creatorfb.c Sat Aug 31 15:05:54 2002 +++ b/drivers/video/creatorfb.c Sat Aug 31 15:05:54 2002 @@ -360,7 +360,7 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct ffb_fbc *fbc = fb->s.ffb.fbc; unsigned long flags; u64 yx, hw; @@ -417,7 +417,7 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct ffb_fbc *fbc = fb->s.ffb.fbc; unsigned long flags; int i, xy; @@ -470,7 +470,7 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info); register struct ffb_fbc *fbc = fb->s.ffb.fbc; unsigned long flags; int i, xy; @@ -805,8 +805,8 @@ char __init *creatorfb_init(struct fb_info_sbusfb *fb) { - struct fb_fix_screeninfo *fix = &fb->fix; - struct fb_var_screeninfo *var = &fb->var; + struct fb_fix_screeninfo *fix = &fb->info.fix; + struct fb_var_screeninfo *var = &fb->info.var; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; struct linux_prom64_registers regs[2*PROMREG_MAX]; @@ -861,7 +861,7 @@ var->accel_flags = FB_ACCELF_TEXT; disp->scrollmode = SCROLL_YREDRAW; - fb->info.screen_base = (char *)__va(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin; + fb->info.screen_base = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin; fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin; fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin; fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF); diff -Nru a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c --- a/drivers/video/sbusfb.c Sat Aug 31 15:05:55 2002 +++ b/drivers/video/sbusfb.c Sat Aug 31 15:05:55 2002 @@ -242,48 +242,49 @@ rects [0] = 0; rects [1] = 0; - rects [2] = fb->var.xres_virtual; + rects [2] = fb->info.var.xres_virtual; rects [3] = fb->y_margin; rects [4] = 0; rects [5] = fb->y_margin; rects [6] = fb->x_margin; - rects [7] = fb->var.yres_virtual; - rects [8] = fb->var.xres_virtual - fb->x_margin; + rects [7] = fb->info.var.yres_virtual; + rects [8] = fb->info.var.xres_virtual - fb->x_margin; rects [9] = fb->y_margin; - rects [10] = fb->var.xres_virtual; - rects [11] = fb->var.yres_virtual; + rects [10] = fb->info.var.xres_virtual; + rects [11] = fb->info.var.yres_virtual; rects [12] = fb->x_margin; - rects [13] = fb->var.yres_virtual - fb->y_margin; - rects [14] = fb->var.xres_virtual - fb->x_margin; - rects [15] = fb->var.yres_virtual; + rects [13] = fb->info.var.yres_virtual - fb->y_margin; + rects [14] = fb->info.var.xres_virtual - fb->x_margin; + rects [15] = fb->info.var.yres_virtual; (*fb->fill)(fb, p, s, 4, rects); } else { unsigned char *fb_base = fb->info.screen_base, *q; - int skip_bytes = fb->y_margin * fb->var.xres_virtual; - int scr_size = fb->var.xres_virtual * fb->var.yres_virtual; + int skip_bytes = fb->y_margin * fb->info.var.xres_virtual; + int scr_size = fb->info.var.xres_virtual + * fb->info.var.yres_virtual; int h, he, incr, size; - he = fb->var.yres; - if (fb->var.bits_per_pixel == 1) { + he = fb->info.var.yres; + if (fb->info.var.bits_per_pixel == 1) { fb_base -= (skip_bytes + fb->x_margin) / 8; skip_bytes /= 8; scr_size /= 8; fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8); fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8); - incr = fb->var.xres_virtual / 8; + incr = fb->info.var.xres_virtual / 8; size = fb->x_margin / 8 * 2; for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0; h <= he; q += incr, h++) fb_memset255 (q, size); } else { fb_base -= (skip_bytes + fb->x_margin); - memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); - memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin); - incr = fb->var.xres_virtual; + fb_memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); + fb_memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin); + incr = fb->info.var.xres_virtual; size = fb->x_margin * 2; for (q = fb_base + skip_bytes - fb->x_margin, h = 0; h <= he; q += incr, h++) - memset (q, attr_bgcol(p,s), size); + fb_memset (q, attr_bgcol(p,s), size); } } } @@ -913,8 +914,8 @@ prom_palette = sbusfb_palette; memset(fb, 0, sizeof(struct fb_info_sbusfb)); - fix = &fb->fix; - var = &fb->var; + fix = &fb->info.fix; + var = &fb->info.var; disp = &fb->disp; type = &fb->type; @@ -929,7 +930,7 @@ memset(&fb->emulations, 0xff, sizeof(fb->emulations)); fb->emulations[0] = fbtype; -#ifndef __sparc_v9__ +#ifdef CONFIG_SPARC32 fb->info.screen_base = (unsigned char *)prom_getintdefault(node, "address", 0); #endif diff -Nru a/fs/Config.help b/fs/Config.help --- a/fs/Config.help Sat Aug 31 15:06:06 2002 +++ b/fs/Config.help Sat Aug 31 15:06:06 2002 @@ -606,6 +606,15 @@ When reporting bugs, please try to have available a full dump of debugging messages while the misbehaviour was occurring. +CONFIG_NTFS_RW + This enables the experimental write support in the NTFS driver. + + WARNING: Do not use this option unless you are actively developing + NTFS as it is currently guaranteed to be broken and you + may lose all your data! + + It is strongly recommended and perfectly safe to say N here. + CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel machines, and Version 7 was used on the DEC PDP-11. Saying Y diff -Nru a/fs/Config.in b/fs/Config.in --- a/fs/Config.in Sat Aug 31 15:06:03 2002 +++ b/fs/Config.in Sat Aug 31 15:06:03 2002 @@ -70,6 +70,7 @@ tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS dep_mbool ' NTFS debugging support' CONFIG_NTFS_DEBUG $CONFIG_NTFS_FS +dep_mbool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Sat Aug 31 15:06:00 2002 +++ b/fs/binfmt_elf.c Sat Aug 31 15:06:00 2002 @@ -39,19 +39,15 @@ #include #include -#define DLINFO_ITEMS 13 - #include static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(struct file*); static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); -extern void dump_thread(struct pt_regs *, struct user *); #ifndef elf_addr_t #define elf_addr_t unsigned long -#define elf_caddr_t char * #endif /* @@ -88,9 +84,9 @@ { start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); - if (end <= start) - return; - do_brk(start, end - start); + if (end > start) + do_brk(start, end - start); + current->mm->start_brk = current->mm->brk = end; } @@ -111,134 +107,150 @@ } } -static elf_addr_t * -create_elf_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long load_bias, - unsigned long interp_load_addr, int ibcs) +/* Let's use some macros to make this stack manipulation a litle clearer */ +#ifdef ARCH_STACK_GROWSUP +#define STACK_ADD(sp, items) ((elf_addr_t *)(sp) + (items)) +#define STACK_ROUND(sp, items) \ + ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) +#define STACK_ALLOC(sp, len) ({ elf_addr_t *old_sp = sp; sp += len; old_sp; }) +#else +#define STACK_ADD(sp, items) ((elf_addr_t *)(sp) - (items)) +#define STACK_ROUND(sp, items) \ + (((unsigned long) (sp - items)) &~ 15UL) +#define STACK_ALLOC(sp, len) sp -= len +#endif + +static void +create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, + int interp_aout, unsigned long load_addr, + unsigned long interp_load_addr) { - elf_caddr_t *argv; - elf_caddr_t *envp; - elf_addr_t *sp, *csp; - char *k_platform, *u_platform; - long hwcap; - size_t platform_len = 0; - size_t len; + unsigned long p = bprm->p; + int argc = bprm->argc; + int envc = bprm->envc; + elf_addr_t *argv, *envp; + elf_addr_t *sp, *u_platform; + const char *k_platform = ELF_PLATFORM; + int items; + elf_addr_t elf_info[30]; + int ei_index = 0; /* - * Get hold of platform and hardware capabilities masks for - * the machine we are running on. In some cases (Sparc), - * this info is impossible to get, in others (i386) it is + * If this architecture has a platform capability string, copy it + * to userspace. In some cases (Sparc), this info is impossible + * for userspace to get any other way, in others (i386) it is * merely difficult. */ - hwcap = ELF_HWCAP; - k_platform = ELF_PLATFORM; - + u_platform = NULL; if (k_platform) { - platform_len = strlen(k_platform) + 1; - u_platform = p - platform_len; - __copy_to_user(u_platform, k_platform, platform_len); - } else - u_platform = p; + size_t len = strlen(k_platform) + 1; #if defined(__i386__) && defined(CONFIG_SMP) - /* - * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions - * by the processes running on the same package. One thing we can do - * is to shuffle the initial stack for them. - * - * The conditionals here are unneeded, but kept in to make the - * code behaviour the same as pre change unless we have hyperthreaded - * processors. This should be cleaned up before 2.6 - */ + /* + * In some cases (e.g. Hyper-Threading), we want to avoid L1 + * evictions by the processes running on the same package. One + * thing we can do is to shuffle the initial stack for them. + * + * The conditionals here are unneeded, but kept in to make the + * code behaviour the same as pre change unless we have + * hyperthreaded processors. This should be cleaned up + * before 2.6 + */ - if(smp_num_siblings > 1) - u_platform = u_platform - ((current->pid % 64) << 7); -#endif - - /* - * Force 16 byte _final_ alignment here for generality. - */ - sp = (elf_addr_t *)(~15UL & (unsigned long)(u_platform)); - csp = sp; - csp -= (1+DLINFO_ITEMS)*2 + (k_platform ? 2 : 0); -#ifdef DLINFO_ARCH_ITEMS - csp -= DLINFO_ARCH_ITEMS*2; + if (smp_num_siblings > 1) + STACK_ALLOC(p, ((current->pid % 64) << 7)); #endif - csp -= envc+1; - csp -= argc+1; - csp -= (!ibcs ? 3 : 1); /* argc itself */ - if ((unsigned long)csp & 15UL) - sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); + u_platform = (elf_addr_t *) STACK_ALLOC(p, len); + __copy_to_user(u_platform, k_platform, len); + } - /* - * Put the ELF interpreter info on the stack - */ -#define NEW_AUX_ENT(nr, id, val) \ - __put_user ((id), sp+(nr*2)); \ - __put_user ((val), sp+(nr*2+1)); \ + /* Create the ELF interpreter info */ +#define NEW_AUX_ENT(id, val) \ + do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0) - sp -= 2; - NEW_AUX_ENT(0, AT_NULL, 0); - if (k_platform) { - sp -= 2; - NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform); - } - sp -= DLINFO_ITEMS*2; - NEW_AUX_ENT( 0, AT_HWCAP, hwcap); - NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE); - NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC); - NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT( 6, AT_BASE, interp_load_addr); - NEW_AUX_ENT( 7, AT_FLAGS, 0); - NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid); #ifdef ARCH_DLINFO /* - * ARCH_DLINFO must come last so platform specific code can enforce - * special alignment requirements on the AUXV if necessary (eg. PPC). + * ARCH_DLINFO must come first so PPC can do its special alignment of + * AUXV. */ ARCH_DLINFO; #endif + NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT(AT_PHENT, sizeof (struct elf_phdr)); + NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT(AT_BASE, interp_load_addr); + NEW_AUX_ENT(AT_FLAGS, 0); + NEW_AUX_ENT(AT_ENTRY, exec->e_entry); + NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid); + NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid); + NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid); + NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid); + if (k_platform) { + NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform); + } + NEW_AUX_ENT(AT_NULL, 0); #undef NEW_AUX_ENT - sp -= envc+1; - envp = (elf_caddr_t *) sp; - sp -= argc+1; - argv = (elf_caddr_t *) sp; - if (!ibcs) { - __put_user((elf_addr_t)(unsigned long) envp,--sp); - __put_user((elf_addr_t)(unsigned long) argv,--sp); + sp = STACK_ADD(p, ei_index); + + items = (argc + 1) + (envc + 1); + if (interp_aout) { + items += 3; /* a.out interpreters require argv & envp too */ + } else { + items += 1; /* ELF interpreters only put argc on the stack */ + } + bprm->p = STACK_ROUND(sp, items); + + /* Point sp at the lowest address on the stack */ +#ifdef ARCH_STACK_GROWSUP + sp = (elf_addr_t *)bprm->p - items - ei_index; + bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */ +#else + sp = (elf_addr_t *)bprm->p; +#endif + + /* Now, let's put argc (and argv, envp if appropriate) on the stack */ + __put_user(argc, sp++); + if (interp_aout) { + argv = sp + 2; + envp = argv + argc + 1; + __put_user((elf_addr_t)(long)argv, sp++); + __put_user((elf_addr_t)(long)envp, sp++); + } else { + argv = sp; + envp = argv + argc + 1; } - __put_user((elf_addr_t)argc,--sp); - current->mm->arg_start = (unsigned long) p; - while (argc-->0) { - __put_user((elf_caddr_t)(unsigned long)p,argv++); - len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); + /* Populate argv and envp */ + p = current->mm->arg_start; + while (argc-- > 0) { + size_t len; + __put_user((elf_addr_t)p, argv++); + len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) - return NULL; + return; p += len; } __put_user(NULL, argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; - while (envc-->0) { - __put_user((elf_caddr_t)(unsigned long)p,envp++); - len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + size_t len; + __put_user((elf_addr_t)p, envp++); + len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) - return NULL; + return; p += len; } __put_user(NULL, envp); - current->mm->env_end = (unsigned long) p; - return sp; + current->mm->env_end = p; + + /* Put the elf_info on the stack in the right place. */ + sp = (elf_addr_t *)envp + 1; + copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)); } #ifndef elf_map @@ -438,7 +450,7 @@ unsigned char ibcs2_interpreter = 0; unsigned long error; struct elf_phdr * elf_ppnt, *elf_phdata; - unsigned long elf_bss, k, elf_brk; + unsigned long elf_bss, elf_brk; int elf_exec_fileno; int retval, i; unsigned int size; @@ -576,19 +588,15 @@ /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ - if (!bprm->sh_bang) { - char * passed_p; + if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) { + char *passed_p = passed_fileno; + sprintf(passed_fileno, "%d", elf_exec_fileno); - if (interpreter_type == INTERPRETER_AOUT) { - sprintf(passed_fileno, "%d", elf_exec_fileno); - passed_p = passed_fileno; - - if (elf_interpreter) { - retval = copy_strings_kernel(1,&passed_p,bprm); + if (elf_interpreter) { + retval = copy_strings_kernel(1, &passed_p, bprm); if (retval) goto out_free_dentry; - bprm->argc++; - } + bprm->argc++; } } @@ -603,7 +611,10 @@ current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; - elf_entry = (unsigned long) elf_ex.e_entry; + + /* Do this immediately, since STACK_TOP as used in setup_arg_pages + may depend on the personality. */ + SET_PERSONALITY(elf_ex, ibcs2_interpreter); /* Do this so that we can load the interpreter, if need be. We will change some of these later */ @@ -623,7 +634,7 @@ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; - unsigned long vaddr; + unsigned long k, vaddr; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -656,7 +667,7 @@ } else if (elf_ex.e_type == ET_DYN) { /* Try and get dynamic programs out of the way of the default mmap base, as well as whatever program they might try to exec. This - is because the brk will follow the loader, and is not movable. */ + is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); } @@ -681,7 +692,7 @@ if (k > elf_bss) elf_bss = k; - if ((elf_ppnt->p_flags & PF_X) && end_code < k) + if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; @@ -690,7 +701,7 @@ elf_brk = k; } - elf_entry += load_bias; + elf_ex.e_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; @@ -717,6 +728,8 @@ send_sig(SIGSEGV, current, 0); return 0; } + } else { + elf_entry = elf_ex.e_entry; } kfree(elf_phdata); @@ -728,18 +741,11 @@ compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; - bprm->p = (unsigned long) - create_elf_tables((char *)bprm->p, - bprm->argc, - bprm->envc, - &elf_ex, - load_addr, load_bias, - interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + create_elf_tables(bprm, &elf_ex, (interpreter_type == INTERPRETER_AOUT), + load_addr, interp_load_addr); /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; - current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->start_data = start_data; diff -Nru a/fs/block_dev.c b/fs/block_dev.c --- a/fs/block_dev.c Sat Aug 31 15:06:06 2002 +++ b/fs/block_dev.c Sat Aug 31 15:06:06 2002 @@ -619,13 +619,20 @@ } if (bdev->bd_contains == bdev) { struct gendisk *g = get_gendisk(dev); + + if (!bdev->bd_queue) { + struct blk_dev_struct *p = blk_dev + major(dev); + bdev->bd_queue = &p->request_queue; + if (p->queue) + bdev->bd_queue = p->queue(dev); + } + if (bdev->bd_op->open) { ret = bdev->bd_op->open(inode, file); if (ret) goto out2; } if (!bdev->bd_openers) { - struct blk_dev_struct *p = blk_dev + major(dev); struct backing_dev_info *bdi; sector_t sect = 0; @@ -636,10 +643,6 @@ sect = p->nr_sects; } else if (blk_size[major(dev)]) sect = blk_size[major(dev)][minor(dev)] << 1; - if (p->queue) - bdev->bd_queue = p->queue(dev); - else - bdev->bd_queue = &p->request_queue; bd_set_size(bdev, (loff_t)sect << 9); bdi = blk_get_backing_dev_info(bdev); if (bdi == NULL) diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Sat Aug 31 15:06:00 2002 +++ b/fs/buffer.c Sat Aug 31 15:06:00 2002 @@ -307,10 +307,7 @@ /* We need to protect against concurrent writers.. */ down(&inode->i_sem); - ret = filemap_fdatawait(inode->i_mapping); - err = filemap_fdatawrite(inode->i_mapping); - if (!ret) - ret = err; + ret = filemap_fdatawrite(inode->i_mapping); err = file->f_op->fsync(file, dentry, 0); if (!ret) ret = err; @@ -345,10 +342,7 @@ goto out_putf; down(&inode->i_sem); - ret = filemap_fdatawait(inode->i_mapping); - err = filemap_fdatawrite(inode->i_mapping); - if (!ret) - ret = err; + ret = filemap_fdatawrite(inode->i_mapping); err = file->f_op->fsync(file, dentry, 1); if (!ret) ret = err; @@ -469,7 +463,7 @@ */ static void free_more_memory(void) { - zone_t *zone; + struct zone *zone; zone = contig_page_data.node_zonelists[GFP_NOFS & GFP_ZONEMASK].zones[0]; @@ -1648,11 +1642,18 @@ * the page lock, whoever dirtied the buffers may decide to clean them * again at any time. We handle that by only looking at the buffer * state inside lock_buffer(). + * + * If block_write_full_page() is called for regular writeback + * (called_for_sync() is false) then it will return -EAGAIN for a locked + * buffer. This only can happen if someone has written the buffer directly, + * with submit_bh(). At the address_space level PageWriteback prevents this + * contention from occurring. */ static int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block) { int err; + int ret = 0; unsigned long block; unsigned long last_block; struct buffer_head *bh, *head; @@ -1724,7 +1725,14 @@ do { get_bh(bh); if (buffer_mapped(bh) && buffer_dirty(bh)) { - lock_buffer(bh); + if (called_for_sync()) { + lock_buffer(bh); + } else { + if (test_set_buffer_locked(bh)) { + ret = -EAGAIN; + continue; + } + } if (test_clear_buffer_dirty(bh)) { if (!buffer_uptodate(bh)) buffer_error(); @@ -1733,8 +1741,7 @@ unlock_buffer(bh); } } - bh = bh->b_this_page; - } while (bh != head); + } while ((bh = bh->b_this_page) != head); BUG_ON(PageWriteback(page)); SetPageWriteback(page); /* Keeps try_to_free_buffers() away */ @@ -1774,6 +1781,8 @@ SetPageUptodate(page); end_page_writeback(page); } + if (err == 0) + return ret; return err; recover: /* @@ -2580,7 +2589,7 @@ bh_cachep = kmem_cache_create("buffer_head", sizeof(struct buffer_head), 0, - SLAB_HWCACHE_ALIGN, init_buffer_head, NULL); + 0, init_buffer_head, NULL); bh_mempool = mempool_create(MAX_UNUSED_BUFFERS, bh_mempool_alloc, bh_mempool_free, NULL); for (i = 0; i < ARRAY_SIZE(bh_wait_queue_heads); i++) diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c --- a/fs/devfs/base.c Sat Aug 31 15:05:55 2002 +++ b/fs/devfs/base.c Sat Aug 31 15:05:55 2002 @@ -645,6 +645,9 @@ 20020728 Richard Gooch Removed deprecated . v1.20 + 20020820 Richard Gooch + Fixed module unload race in . + v1.21 */ #include #include @@ -677,7 +680,7 @@ #include #include -#define DEVFS_VERSION "1.20 (20020728)" +#define DEVFS_VERSION "1.21 (20020820)" #define DEVFS_NAME "devfs" @@ -2228,16 +2231,15 @@ /** - * devfs_only - returns if "devfs=only" is a boot option + * devfs_only - returns true if "devfs=only" is a boot option * * If "devfs=only" this function will return 1, otherwise 0 is returned. */ + int devfs_only (void) { - if (boot_options & OPTION_ONLY) - return 1; - return 0; -} + return (boot_options & OPTION_ONLY) ? 1 : 0; +} /* End Function devfs_only */ /** @@ -2312,6 +2314,7 @@ EXPORT_SYMBOL(devfs_mk_symlink); EXPORT_SYMBOL(devfs_mk_dir); EXPORT_SYMBOL(devfs_get_handle); +EXPORT_SYMBOL(devfs_find_and_unregister); EXPORT_SYMBOL(devfs_get_flags); EXPORT_SYMBOL(devfs_set_flags); EXPORT_SYMBOL(devfs_get_maj_min); @@ -2327,6 +2330,7 @@ EXPORT_SYMBOL(devfs_auto_unregister); EXPORT_SYMBOL(devfs_get_unregister_slave); EXPORT_SYMBOL(devfs_get_name); +EXPORT_SYMBOL(devfs_only); /** @@ -2382,7 +2386,7 @@ extern int warn_no_part; if ( !S_ISBLK (de->mode) ) return 0; - bdev = bdget(kdev_t_to_nr(dev)); + bdev = bdget (kdev_t_to_nr (dev) ); if (!bdev) return 0; bdops = devfs_get_ops (de); if (!bdops) return 0; @@ -2390,7 +2394,7 @@ /* Ugly hack to disable messages about unable to read partition table */ tmp = warn_no_part; warn_no_part = 0; - retval = full_check_disk_change(bdev); + retval = full_check_disk_change (bdev); warn_no_part = tmp; out: devfs_put_ops (de); @@ -2692,21 +2696,23 @@ struct fcb_type *df; struct devfs_entry *de; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; + void *ops; de = get_devfs_entry_from_vfs_inode (inode); if (de == NULL) return -ENODEV; if ( S_ISDIR (de->mode) ) return 0; df = &de->u.fcb; file->private_data = de->info; + ops = devfs_get_ops (de); /* Now have module refcount */ if ( S_ISBLK (inode->i_mode) ) { file->f_op = &def_blk_fops; - if (df->ops) inode->i_bdev->bd_op = df->ops; - err = def_blk_fops.open (inode, file); + if (ops) inode->i_bdev->bd_op = ops; + err = def_blk_fops.open (inode, file); /* Module refcount unchanged */ } else { - file->f_op = fops_get ( (struct file_operations *) df->ops ); + file->f_op = ops; if (file->f_op) { lock_kernel (); @@ -2714,7 +2720,7 @@ unlock_kernel (); } else - { /* Fallback to legacy scheme */ + { /* Fallback to legacy scheme (I don't have a module refcount) */ if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file); else err = -ENODEV; } diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Sat Aug 31 15:05:59 2002 +++ b/fs/exec.c Sat Aug 31 15:05:59 2002 @@ -323,9 +323,50 @@ { unsigned long stack_base; struct vm_area_struct *mpnt; + struct mm_struct *mm = current->mm; int i; - stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; +#ifdef ARCH_STACK_GROWSUP + /* Move the argument and environment strings to the bottom of the + * stack space. + */ + int offset, j; + char *to, *from; + + /* Start by shifting all the pages down */ + i = 0; + for (j = 0; j < MAX_ARG_PAGES; j++) { + struct page *page = bprm->page[j]; + if (!page) + continue; + bprm->page[i++] = page; + } + + /* Now move them within their pages */ + offset = bprm->p % PAGE_SIZE; + to = kmap(bprm->page[0]); + for (j = 1; j < i; j++) { + memmove(to, to + offset, PAGE_SIZE - offset); + from = kmap(bprm->page[j]); + memcpy(to + PAGE_SIZE - offset, from, offset); + kunmap(bprm[j - 1]); + to = from; + } + memmove(to, to + offset, PAGE_SIZE - offset); + kunmap(bprm[j - 1]); + + /* Adjust bprm->p to point to the end of the strings. */ + bprm->p = PAGE_SIZE * i - offset; + stack_base = STACK_TOP - current->rlim[RLIMIT_STACK].rlim_max; + mm->arg_start = stack_base; + + /* zero pages that were copied above */ + while (i < MAX_ARG_PAGES) + bprm->page[i++] = NULL; +#else + stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; + mm->arg_start = bprm->p + stack_base; +#endif bprm->p += stack_base; if (bprm->loader) @@ -333,7 +374,7 @@ bprm->exec += stack_base; mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!mpnt) + if (!mpnt) return -ENOMEM; if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { @@ -341,19 +382,25 @@ return -ENOMEM; } - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); { - mpnt->vm_mm = current->mm; + mpnt->vm_mm = mm; +#ifdef ARCH_STACK_GROWSUP + mpnt->vm_start = stack_base; + mpnt->vm_end = PAGE_MASK & + (PAGE_SIZE - 1 + (unsigned long) bprm->p); +#else mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; +#endif mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; - insert_vm_struct(current->mm, mpnt); - current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + insert_vm_struct(mm, mpnt); + mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -364,7 +411,7 @@ } stack_base += PAGE_SIZE; } - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return 0; } @@ -732,7 +779,6 @@ security_ops->bprm_compute_creds(bprm); } - void remove_arg_zero(struct linux_binprm *bprm) { if (bprm->argc) { @@ -853,7 +899,6 @@ } return retval; } - /* * sys_execve() executes a new program. diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Sat Aug 31 15:06:03 2002 +++ b/fs/ext3/inode.c Sat Aug 31 15:06:03 2002 @@ -734,9 +734,9 @@ * The BKL may not be held on entry here. Be sure to take it early. */ -static int ext3_get_block_handle(handle_t *handle, struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, int create) +static int +ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create, int extend_disksize) { int err = -EIO; int offsets[4]; @@ -818,16 +818,17 @@ if (err) goto cleanup; - new_size = inode->i_size; - /* - * This is not racy against ext3_truncate's modification of i_disksize - * because VM/VFS ensures that the file cannot be extended while - * truncate is in progress. It is racy between multiple parallel - * instances of get_block, but we have the BKL. - */ - if (new_size > ei->i_disksize) - ei->i_disksize = new_size; - + if (extend_disksize) { + /* + * This is not racy against ext3_truncate's modification of + * i_disksize because VM/VFS ensures that the file cannot be + * extended while truncate is in progress. It is racy between + * multiple parallel instances of get_block, but we have BKL. + */ + new_size = inode->i_size; + if (new_size > ei->i_disksize) + ei->i_disksize = new_size; + } set_buffer_new(bh_result); goto got_it; @@ -851,10 +852,43 @@ handle = ext3_journal_current_handle(); J_ASSERT(handle != 0); } - ret = ext3_get_block_handle(handle, inode, iblock, bh_result, create); + ret = ext3_get_block_handle(handle, inode, iblock, + bh_result, create, 1); + return ret; +} + +#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32) + +static int +ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock, + unsigned long max_blocks, struct buffer_head *bh_result, + int create) +{ + handle_t *handle = journal_current_handle(); + int ret = 0; + + lock_kernel(); + if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { + /* + * Getting low on buffer credits... + */ + if (!ext3_journal_extend(handle, DIO_CREDITS)) { + /* + * Couldn't extend the transaction. Start a new one + */ + ret = ext3_journal_restart(handle, DIO_CREDITS); + } + } + if (ret == 0) + ret = ext3_get_block_handle(handle, inode, iblock, + bh_result, create, 0); + if (ret == 0) + bh_result->b_size = (1 << inode->i_blkbits); + unlock_kernel(); return ret; } + /* * `handle' can be NULL if create is zero */ @@ -869,7 +903,7 @@ dummy.b_state = 0; dummy.b_blocknr = -1000; buffer_trace_init(&dummy.b_history); - *errp = ext3_get_block_handle(handle, inode, block, &dummy, create); + *errp = ext3_get_block_handle(handle, inode, block, &dummy, create, 1); if (!*errp && buffer_mapped(&dummy)) { struct buffer_head *bh; bh = sb_getblk(inode->i_sb, dummy.b_blocknr); @@ -1344,10 +1378,11 @@ /* * We have to fail this writepage to avoid cross-fs transactions. - * Put the page back on mapping->dirty_pages, but leave its buffer's - * dirty state as-is. + * Return EAGAIN so the caller will the page back on + * mapping->dirty_pages. The page's buffers' dirty state will be left + * as-is. */ - __set_page_dirty_nobuffers(page); + ret = -EAGAIN; unlock_page(page); return ret; } @@ -1376,17 +1411,83 @@ return journal_try_to_free_buffers(journal, page, wait); } +/* + * If the O_DIRECT write will extend the file then add this inode to the + * orphan list. So recovery will truncate it back to the original size + * if the machine crashes during the write. + * + * If the O_DIRECT write is intantiating holes inside i_size and the machine + * crashes then stale disk data _may_ be exposed inside the file. + */ +static int ext3_direct_IO(int rw, struct inode *inode, char *buf, + loff_t offset, size_t count) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + handle_t *handle = NULL; + int ret; + int orphan = 0; + + if (rw == WRITE) { + loff_t final_size = offset + count; + + lock_kernel(); + handle = ext3_journal_start(inode, DIO_CREDITS); + unlock_kernel(); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + if (final_size > inode->i_size) { + lock_kernel(); + ret = ext3_orphan_add(handle, inode); + unlock_kernel(); + if (ret) + goto out_stop; + orphan = 1; + ei->i_disksize = inode->i_size; + } + } + + ret = generic_direct_IO(rw, inode, buf, offset, + count, ext3_direct_io_get_blocks); + +out_stop: + if (handle) { + int err; + + lock_kernel(); + if (orphan) + ext3_orphan_del(handle, inode); + if (orphan && ret > 0) { + loff_t end = offset + ret; + if (end > inode->i_size) { + ei->i_disksize = end; + inode->i_size = end; + err = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = err; + } + } + err = ext3_journal_stop(handle, inode); + if (ret == 0) + ret = err; + unlock_kernel(); + } +out: + return ret; +} struct address_space_operations ext3_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ + .readpage = ext3_readpage, /* BKL not held. Don't need */ + .readpages = ext3_readpages, /* BKL not held. Don't need */ + .writepage = ext3_writepage, /* BKL not held. We take it */ .sync_page = block_sync_page, .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ .commit_write = ext3_commit_write, /* BKL not held. We take it */ .bmap = ext3_bmap, /* BKL held */ .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ .releasepage = ext3_releasepage, /* BKL not held. Don't need */ + .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ }; /* For writeback mode, we can use mpage_writepages() */ @@ -1405,9 +1506,9 @@ } struct address_space_operations ext3_writeback_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ + .readpage = ext3_readpage, /* BKL not held. Don't need */ + .readpages = ext3_readpages, /* BKL not held. Don't need */ + .writepage = ext3_writepage, /* BKL not held. We take it */ .writepages = ext3_writepages, /* BKL not held. Don't need */ .sync_page = block_sync_page, .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ @@ -1415,6 +1516,7 @@ .bmap = ext3_bmap, /* BKL held */ .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ .releasepage = ext3_releasepage, /* BKL not held. Don't need */ + .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ }; /* diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c --- a/fs/ext3/super.c Sat Aug 31 15:06:06 2002 +++ b/fs/ext3/super.c Sat Aug 31 15:06:06 2002 @@ -443,12 +443,16 @@ return; } -static kmem_cache_t * ext3_inode_cachep; +static kmem_cache_t *ext3_inode_cachep; +/* + * Called inside transaction, so use GFP_NOFS + */ static struct inode *ext3_alloc_inode(struct super_block *sb) { struct ext3_inode_info *ei; - ei = (struct ext3_inode_info *)kmem_cache_alloc(ext3_inode_cachep, SLAB_KERNEL); + + ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); if (!ei) return NULL; return &ei->vfs_inode; diff -Nru a/fs/fcntl.c b/fs/fcntl.c --- a/fs/fcntl.c Sat Aug 31 15:05:54 2002 +++ b/fs/fcntl.c Sat Aug 31 15:05:54 2002 @@ -52,7 +52,7 @@ { int err, expand = 0; #ifdef FDSET_DEBUG - printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); + printk (KERN_ERR "%s %d: nr = %d\n", __FUNCTION__, current->pid, nr); #endif if (nr >= files->max_fdset) { @@ -69,7 +69,7 @@ out: #ifdef FDSET_DEBUG if (err) - printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); + printk (KERN_ERR "%s %d: return %d\n", __FUNCTION__, current->pid, err); #endif return err; } @@ -227,23 +227,16 @@ static int setfl(int fd, struct file * filp, unsigned long arg) { struct inode * inode = filp->f_dentry->d_inode; - int error; + int error = 0; - /* - * In the case of an append-only file, O_APPEND - * cannot be cleared - */ + /* O_APPEND cannot be cleared if the file is marked as append-only */ if (!(arg & O_APPEND) && IS_APPEND(inode)) return -EPERM; - /* Did FASYNC state change? */ - if ((arg ^ filp->f_flags) & FASYNC) { - if (filp->f_op && filp->f_op->fasync) { - error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); - if (error < 0) - return error; - } - } + /* required for strict SunOS emulation */ + if (O_NONBLOCK != O_NDELAY) + if (arg & O_NDELAY) + arg |= O_NONBLOCK; if (arg & O_DIRECT) { if (!inode->i_mapping || !inode->i_mapping->a_ops || @@ -251,13 +244,19 @@ return -EINVAL; } - /* required for strict SunOS emulation */ - if (O_NONBLOCK != O_NDELAY) - if (arg & O_NDELAY) - arg |= O_NONBLOCK; + lock_kernel(); + if ((arg ^ filp->f_flags) & FASYNC) { + if (filp->f_op && filp->f_op->fasync) { + error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); + if (error < 0) + goto out; + } + } filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); - return 0; + out: + unlock_kernel(); + return error; } static long do_fcntl(unsigned int fd, unsigned int cmd, @@ -283,9 +282,7 @@ err = filp->f_flags; break; case F_SETFL: - lock_kernel(); err = setfl(fd, filp, arg); - unlock_kernel(); break; case F_GETLK: err = fcntl_getlk(filp, (struct flock *) arg); diff -Nru a/fs/jbd/revoke.c b/fs/jbd/revoke.c --- a/fs/jbd/revoke.c Sat Aug 31 15:05:54 2002 +++ b/fs/jbd/revoke.c Sat Aug 31 15:05:54 2002 @@ -135,7 +135,7 @@ oom: if (!journal_oom_retry) return -ENOMEM; - jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); + jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__); yield(); goto repeat; } diff -Nru a/fs/jfs/Makefile b/fs/jfs/Makefile --- a/fs/jfs/Makefile Sat Aug 31 15:06:06 2002 +++ b/fs/jfs/Makefile Sat Aug 31 15:06:06 2002 @@ -8,7 +8,7 @@ jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ jfs_unicode.o jfs_dtree.o jfs_inode.o \ jfs_extent.o symlink.o jfs_metapage.o \ - jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o + jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o EXTRA_CFLAGS += -D_JFS_4K diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c --- a/fs/jfs/file.c Sat Aug 31 15:05:55 2002 +++ b/fs/jfs/file.c Sat Aug 31 15:05:55 2002 @@ -20,6 +20,7 @@ #include #include "jfs_incore.h" #include "jfs_txnmgr.h" +#include "jfs_xattr.h" #include "jfs_debug.h" @@ -98,6 +99,10 @@ struct inode_operations jfs_file_inode_operations = { .truncate = jfs_truncate, + .setxattr = jfs_setxattr, + .getxattr = jfs_getxattr, + .listxattr = jfs_listxattr, + .removexattr = jfs_removexattr, }; struct file_operations jfs_file_operations = { @@ -109,3 +114,11 @@ .sendfile = generic_file_sendfile, .fsync = jfs_fsync, }; + +struct inode_operations jfs_special_inode_operations = { + .setxattr = jfs_setxattr, + .getxattr = jfs_getxattr, + .listxattr = jfs_listxattr, + .removexattr = jfs_removexattr, +}; + diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c --- a/fs/jfs/inode.c Sat Aug 31 15:05:53 2002 +++ b/fs/jfs/inode.c Sat Aug 31 15:05:53 2002 @@ -31,6 +31,7 @@ extern struct inode_operations jfs_dir_inode_operations; extern struct inode_operations jfs_file_inode_operations; extern struct inode_operations jfs_symlink_inode_operations; +extern struct inode_operations jfs_special_inode_operations; extern struct file_operations jfs_dir_operations; extern struct file_operations jfs_file_operations; struct address_space_operations jfs_aops; @@ -65,6 +66,7 @@ } else inode->i_op = &jfs_symlink_inode_operations; } else { + inode->i_op = &jfs_special_inode_operations; init_special_inode(inode, inode->i_mode, kdev_t_to_nr(inode->i_rdev)); } @@ -163,8 +165,9 @@ set_cflag(COMMIT_Dirty, inode); } -static int jfs_get_block(struct inode *ip, sector_t lblock, - struct buffer_head *bh_result, int create) +static int +jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks, + struct buffer_head *bh_result, int create) { s64 lblock64 = lblock; int no_size_check = 0; @@ -200,7 +203,7 @@ if ((no_size_check || ((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size)) && - (xtLookup(ip, lblock64, 1, &xflag, &xaddr, &xlen, no_size_check) + (xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, no_size_check) == 0) && xlen) { if (xflag & XAD_NOTRECORDED) { if (!create) @@ -228,6 +231,7 @@ } map_bh(bh_result, ip->i_sb, xaddr); + bh_result->b_size = xlen << ip->i_blkbits; goto unlock; } if (!create) @@ -239,12 +243,13 @@ #ifdef _JFS_4K if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad))) goto unlock; - rc = extAlloc(ip, 1, lblock64, &xad, FALSE); + rc = extAlloc(ip, max_blocks, lblock64, &xad, FALSE); if (rc) goto unlock; set_buffer_new(bh_result); map_bh(bh_result, ip->i_sb, addressXAD(&xad)); + bh_result->b_size = lengthXAD(&xad) << ip->i_blkbits; #else /* _JFS_4K */ /* @@ -267,6 +272,12 @@ return -rc; } +static int jfs_get_block(struct inode *ip, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + return jfs_get_blocks(ip, lblock, 1, bh_result, create); +} + static int jfs_writepage(struct page *page) { return block_write_full_page(page, jfs_get_block); @@ -297,18 +308,6 @@ static int jfs_bmap(struct address_space *mapping, long block) { return generic_block_bmap(mapping, block, jfs_get_block); -} - -static int -jfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks, - struct buffer_head *bh_result, int create) -{ - int ret; - - ret = jfs_get_block(inode, iblock, bh_result, create); - if (ret == 0) - bh_result->b_size = (1 << inode->i_blkbits); - return ret; } static int jfs_direct_IO(int rw, struct inode *inode, char *buf, diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c --- a/fs/jfs/jfs_dmap.c Sat Aug 31 15:06:06 2002 +++ b/fs/jfs/jfs_dmap.c Sat Aug 31 15:06:06 2002 @@ -325,7 +325,6 @@ /* * write out dirty pages of bmap */ - filemap_fdatawait(ipbmap->i_mapping); filemap_fdatawrite(ipbmap->i_mapping); filemap_fdatawait(ipbmap->i_mapping); diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c --- a/fs/jfs/jfs_imap.c Sat Aug 31 15:05:54 2002 +++ b/fs/jfs/jfs_imap.c Sat Aug 31 15:05:54 2002 @@ -281,7 +281,6 @@ /* * write out dirty pages of imap */ - filemap_fdatawait(ipimap->i_mapping); filemap_fdatawrite(ipimap->i_mapping); filemap_fdatawait(ipimap->i_mapping); @@ -595,7 +594,6 @@ jERROR(1, ("diFreeSpecial called with NULL ip!\n")); return; } - filemap_fdatawait(ip->i_mapping); filemap_fdatawrite(ip->i_mapping); filemap_fdatawait(ip->i_mapping); truncate_inode_pages(ip->i_mapping, 0); @@ -815,21 +813,19 @@ memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE); dilinelock->index++; } -#ifdef _STILL_TO_PORT /* * copy inline data from in-memory inode to on-disk inode: * 128 byte slot granularity */ - if (test_cflag(COMMIT_Inlineea, ip)) + if (test_cflag(COMMIT_Inlineea, ip)) { lv = (lv_t *) & dilinelock->lv[dilinelock->index]; lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE; lv->length = 1; - memcpy(&dp->di_inlineea, &ip->i_inlineea, INODESLOTSIZE); + memcpy(&dp->di_inlineea, jfs_ip->i_inline_ea, INODESLOTSIZE); dilinelock->index++; clear_cflag(COMMIT_Inlineea, ip); } -#endif /* _STILL_TO_PORT */ /* * lock/copy inode base: 128 byte slot granularity @@ -914,8 +910,6 @@ u32 bitmap, mask; struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap; imap_t *imap = JFS_IP(ipimap)->i_imap; - s64 xaddr; - s64 xlen; pxd_t freepxd; tid_t tid; struct inode *iplist[3]; @@ -1181,9 +1175,7 @@ * invalidate any page of the inode extent freed from buffer cache; */ freepxd = iagp->inoext[extno]; - xaddr = addressPXD(&iagp->inoext[extno]); - xlen = lengthPXD(&iagp->inoext[extno]); - invalidate_metapages(JFS_SBI(ip->i_sb)->direct_inode, xaddr, xlen); + invalidate_pxd_metapages(JFS_SBI(ip->i_sb)->direct_inode, freepxd); /* * update iag list(s) (careful update step 2) @@ -3046,16 +3038,17 @@ jfs_ip->next_index = le32_to_cpu(dip->di_next_index); jfs_ip->otime = le32_to_cpu(dip->di_otime.tv_sec); jfs_ip->acltype = le32_to_cpu(dip->di_acltype); - /* - * We may only need to do this for "special" inodes (dmap, imap) - */ + if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) ip->i_rdev = to_kdev_t(le32_to_cpu(dip->di_rdev)); - else if (S_ISDIR(ip->i_mode)) { + + if (S_ISDIR(ip->i_mode)) { memcpy(&jfs_ip->i_dirtable, &dip->di_dirtable, 384); - } else if (!S_ISFIFO(ip->i_mode)) { + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); - } + } else + memcpy(&jfs_ip->i_inline_ea, &dip->di_inlineea, 128); + /* Zero the in-memory-only stuff */ jfs_ip->cflag = 0; jfs_ip->btindex = 0; diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h --- a/fs/jfs/jfs_incore.h Sat Aug 31 15:05:54 2002 +++ b/fs/jfs/jfs_incore.h Sat Aug 31 15:05:54 2002 @@ -82,6 +82,10 @@ unchar _unused[16]; /* 16: */ dxd_t _dxd; /* 16: */ unchar _inline[128]; /* 128: inline symlink */ + /* _inline_ea may overlay the last part of + * file._xtroot if maxentry = XTROOTINITSLOT + */ + unchar _inline_ea[128]; /* 128: inline extended attr */ } link; } u; struct inode vfs_inode; @@ -91,6 +95,7 @@ #define i_dirtable u.dir._table #define i_dtroot u.dir._dtroot #define i_inline u.link._inline +#define i_inline_ea u.link._inline_ea #define IREAD_LOCK(ip) down_read(&JFS_IP(ip)->rdwrlock) diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c --- a/fs/jfs/jfs_logmgr.c Sat Aug 31 15:06:00 2002 +++ b/fs/jfs/jfs_logmgr.c Sat Aug 31 15:06:00 2002 @@ -965,9 +965,6 @@ * We need to make sure all of the "written" metapages * actually make it to disk */ - filemap_fdatawait(sbi->ipbmap->i_mapping); - filemap_fdatawait(sbi->ipimap->i_mapping); - filemap_fdatawait(sbi->direct_inode->i_mapping); filemap_fdatawrite(sbi->ipbmap->i_mapping); filemap_fdatawrite(sbi->ipimap->i_mapping); filemap_fdatawrite(sbi->direct_inode->i_mapping); diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c --- a/fs/jfs/jfs_metapage.c Sat Aug 31 15:05:55 2002 +++ b/fs/jfs/jfs_metapage.c Sat Aug 31 15:05:55 2002 @@ -557,8 +557,7 @@ jFYI(1, ("release_metapage: done\n")); } -void invalidate_metapages(struct inode *ip, unsigned long addr, - unsigned long len) +void __invalidate_metapages(struct inode *ip, s64 addr, int len) { metapage_t **hash_ptr; unsigned long lblock; diff -Nru a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h --- a/fs/jfs/jfs_metapage.h Sat Aug 31 15:06:00 2002 +++ b/fs/jfs/jfs_metapage.h Sat Aug 31 15:06:00 2002 @@ -107,9 +107,13 @@ } /* - * This routine uses hash to explicitly find small number of pages + * This routines invalidate all pages for an extent. */ -extern void invalidate_metapages(struct inode *, unsigned long, unsigned long); +extern void __invalidate_metapages(struct inode *, s64, int); +#define invalidate_pxd_metapages(ip, pxd) \ + __invalidate_metapages((ip), addressPXD(&(pxd)), lengthPXD(&(pxd))) +#define invalidate_dxd_metapages(ip, dxd) \ + __invalidate_metapages((ip), addressDXD(&(dxd)), lengthDXD(&(dxd))) /* * This one uses mp_list to invalidate all pages for an inode diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c --- a/fs/jfs/jfs_txnmgr.c Sat Aug 31 15:06:00 2002 +++ b/fs/jfs/jfs_txnmgr.c Sat Aug 31 15:06:01 2002 @@ -1165,7 +1165,6 @@ * * if ((!S_ISDIR(ip->i_mode)) * && (tblk->flag & COMMIT_DELETE) == 0) { - * filemap_fdatawait(ip->i_mapping); * filemap_fdatawrite(ip->i_mapping); * filemap_fdatawait(ip->i_mapping); * } diff -Nru a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h --- a/fs/jfs/jfs_types.h Sat Aug 31 15:06:00 2002 +++ b/fs/jfs/jfs_types.h Sat Aug 31 15:06:00 2002 @@ -144,6 +144,8 @@ #define DXDaddress PXDaddress #define lengthDXD lengthPXD #define addressDXD addressPXD +#define DXDsize(dxd, size32) ((dxd)->size = cpu_to_le32(size32)) +#define sizeDXD(dxd) le32_to_cpu((dxd)->size) /* * directory entry argument diff -Nru a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c --- a/fs/jfs/jfs_umount.c Sat Aug 31 15:05:53 2002 +++ b/fs/jfs/jfs_umount.c Sat Aug 31 15:05:53 2002 @@ -112,7 +112,6 @@ * Make sure all metadata makes it to disk before we mark * the superblock as clean */ - filemap_fdatawait(sbi->direct_inode->i_mapping); filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_fdatawait(sbi->direct_inode->i_mapping); @@ -159,7 +158,6 @@ */ dbSync(sbi->ipbmap); diSync(sbi->ipimap); - filemap_fdatawait(sbi->direct_inode->i_mapping); filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_fdatawait(sbi->direct_inode->i_mapping); diff -Nru a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/jfs/jfs_xattr.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,60 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef H_JFS_XATTR +#define H_JFS_XATTR + +/* + * jfs_ea_list describe the on-disk format of the extended attributes. + * I know the null-terminator is redundant since namelen is stored, but + * I am maintaining compatibility with OS/2 where possible. + */ +struct jfs_ea { + u8 flag; /* Unused? */ + u8 namelen; /* Length of name */ + u16 valuelen; /* Length of value */ + char name[0]; /* Attribute name (includes null-terminator) */ +}; /* Value immediately follows name */ + +struct jfs_ea_list { + u32 size; /* overall size */ + struct jfs_ea ea[0]; /* Variable length list */ +}; + +/* Macros for defining maxiumum number of bytes supported for EAs */ +#define MAXEASIZE 65535 +#define MAXEALISTSIZE MAXEASIZE + +/* + * some macros for dealing with variable length EA lists. + */ +#define EA_SIZE(ea) \ + (sizeof (struct jfs_ea) + (ea)->namelen + 1 + \ + le16_to_cpu((ea)->valuelen)) +#define NEXT_EA(ea) ((struct jfs_ea *) (((char *) (ea)) + (EA_SIZE (ea)))) +#define FIRST_EA(ealist) ((ealist)->ea) +#define EALIST_SIZE(ealist) le32_to_cpu((ealist)->size) +#define END_EALIST(ealist) \ + ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist))) + +extern int jfs_setxattr(struct dentry *, const char *, void *, size_t, int); +extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); +extern int jfs_removexattr(struct dentry *, const char *); + +#endif /* H_JFS_XATTR */ diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c --- a/fs/jfs/namei.c Sat Aug 31 15:06:06 2002 +++ b/fs/jfs/namei.c Sat Aug 31 15:06:06 2002 @@ -24,10 +24,12 @@ #include "jfs_dmap.h" #include "jfs_unicode.h" #include "jfs_metapage.h" +#include "jfs_xattr.h" #include "jfs_debug.h" extern struct inode_operations jfs_file_inode_operations; extern struct inode_operations jfs_symlink_inode_operations; +extern struct inode_operations jfs_special_inode_operations; extern struct file_operations jfs_file_operations; extern struct address_space_operations jfs_aops; @@ -672,17 +674,13 @@ * free EA */ if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { - s64 xaddr; - int xlen; + s64 xaddr = addressDXD(&JFS_IP(ip)->ea); + int xlen = lengthDXD(&JFS_IP(ip)->ea); maplock_t maplock; /* maplock for COMMIT_WMAP */ pxdlock_t *pxdlock; /* maplock for COMMIT_WMAP */ /* free EA pages from cache */ - xaddr = addressDXD(&JFS_IP(ip)->ea); - xlen = lengthDXD(&JFS_IP(ip)->ea); -#ifdef _STILL_TO_PORT - bmExtentInvalidate(ip, xaddr, xlen); -#endif + invalidate_dxd_metapages(ip, JFS_IP(ip)->ea); /* free EA extent from working block map */ maplock.index = 1; @@ -697,17 +695,12 @@ * free ACL */ if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { - s64 xaddr; - int xlen; + s64 xaddr = addressDXD(&JFS_IP(ip)->acl); + int xlen = lengthDXD(&JFS_IP(ip)->acl); maplock_t maplock; /* maplock for COMMIT_WMAP */ pxdlock_t *pxdlock; /* maplock for COMMIT_WMAP */ - /* free ACL pages from cache */ - xaddr = addressDXD(&JFS_IP(ip)->acl); - xlen = lengthDXD(&JFS_IP(ip)->acl); -#ifdef _STILL_TO_PORT - bmExtentInvalidate(ip, xaddr, xlen); -#endif + invalidate_dxd_metapages(ip, JFS_IP(ip)->acl); /* free ACL extent from working block map */ maplock.index = 1; @@ -922,6 +915,14 @@ i_fastsymlink = JFS_IP(ip)->i_inline; memcpy(i_fastsymlink, name, ssize); ip->i_size = ssize - 1; + + /* + * if symlink is > 128 bytes, we don't have the space to + * store inline extended attributes + */ + if (ssize > sizeof (JFS_IP(ip)->i_inline)) + JFS_IP(ip)->mode2 &= ~INLINEEA; + jFYI(1, ("jfs_symlink: fast symlink added ssize:%d name:%s \n", ssize, name)); @@ -1337,6 +1338,7 @@ if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) goto out3; + ip->i_op = &jfs_special_inode_operations; init_special_inode(ip, ip->i_mode, rdev); insert_inode_hash(ip); @@ -1440,6 +1442,10 @@ .rmdir = jfs_rmdir, .mknod = jfs_mknod, .rename = jfs_rename, + .setxattr = jfs_setxattr, + .getxattr = jfs_getxattr, + .listxattr = jfs_listxattr, + .removexattr = jfs_removexattr, }; struct file_operations jfs_dir_operations = { diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c --- a/fs/jfs/super.c Sat Aug 31 15:06:00 2002 +++ b/fs/jfs/super.c Sat Aug 31 15:06:00 2002 @@ -146,7 +146,6 @@ * We need to clean out the direct_inode pages since this inode * is not in the inode hash. */ - filemap_fdatawait(sbi->direct_inode->i_mapping); filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_fdatawait(sbi->direct_inode->i_mapping); truncate_inode_pages(sbi->direct_mapping, 0); @@ -362,7 +361,6 @@ jERROR(1, ("jfs_umount failed with return code %d\n", rc)); } out_mount_failed: - filemap_fdatawait(sbi->direct_inode->i_mapping); filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_fdatawait(sbi->direct_inode->i_mapping); truncate_inode_pages(sbi->direct_mapping, 0); @@ -377,6 +375,31 @@ return -EINVAL; } +static void jfs_write_super_lockfs(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + log_t *log = sbi->log; + + if (!(sb->s_flags & MS_RDONLY)) { + txQuiesce(sb); + lmLogShutdown(log); + } +} + +static void jfs_unlockfs(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + log_t *log = sbi->log; + int rc = 0; + + if (!(sb->s_flags & MS_RDONLY)) { + if ((rc = lmLogInit(log))) + jERROR(1, + ("jfs_unlock failed with return code %d\n", rc)); + else + txResume(sb); + } +} static struct super_block *jfs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data) { @@ -390,6 +413,8 @@ .write_inode = jfs_write_inode, .delete_inode = jfs_delete_inode, .put_super = jfs_put_super, + .write_super_lockfs = jfs_write_super_lockfs, + .unlockfs = jfs_unlockfs, .statfs = jfs_statfs, .remount_fs = jfs_remount, }; diff -Nru a/fs/jfs/symlink.c b/fs/jfs/symlink.c --- a/fs/jfs/symlink.c Sat Aug 31 15:06:06 2002 +++ b/fs/jfs/symlink.c Sat Aug 31 15:06:06 2002 @@ -18,6 +18,7 @@ #include #include "jfs_incore.h" +#include "jfs_xattr.h" static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) { @@ -34,5 +35,9 @@ struct inode_operations jfs_symlink_inode_operations = { .readlink = jfs_readlink, .follow_link = jfs_follow_link, + .setxattr = jfs_setxattr, + .getxattr = jfs_getxattr, + .listxattr = jfs_listxattr, + .removexattr = jfs_removexattr, }; diff -Nru a/fs/jfs/xattr.c b/fs/jfs/xattr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/jfs/xattr.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,812 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) Christoph Hellwig, 2002 + * + * 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 "jfs_incore.h" +#include "jfs_dmap.h" +#include "jfs_debug.h" +#include "jfs_dinode.h" +#include "jfs_extent.h" +#include "jfs_metapage.h" +#include "jfs_xattr.h" + +/* + * jfs_xattr.c: extended attribute service + * + * Overall design -- + * + * Format: + * + * Extended attribute lists (jfs_ea_list) consist of an overall size (32 bit + * value) and a variable (0 or more) number of extended attribute + * entries. Each extended attribute entry (jfs_ea) is a double + * where is constructed from a null-terminated ascii string + * (1 ... 255 bytes in the name) and is arbitrary 8 bit data + * (1 ... 65535 bytes). The in-memory format is + * + * 0 1 2 4 4 + namelen + 1 + * +-------+--------+--------+----------------+-------------------+ + * | Flags | Name | Value | Name String \0 | Data . . . . | + * | | Length | Length | | | + * +-------+--------+--------+----------------+-------------------+ + * + * A jfs_ea_list then is structured as + * + * 0 4 4 + EA_SIZE(ea1) + * +------------+-------------------+--------------------+----- + * | Overall EA | First FEA Element | Second FEA Element | ..... + * | List Size | | | + * +------------+-------------------+--------------------+----- + * + * On-disk: + * + * FEALISTs are stored on disk using blocks allocated by dbAlloc() and + * written directly. An EA list may be in-lined in the inode if there is + * sufficient room available. + */ + +struct ea_buffer { + int flag; /* Indicates what storage xattr points to */ + int max_size; /* largest xattr that fits in current buffer */ + dxd_t new_ea; /* dxd to replace ea when modifying xattr */ + struct metapage *mp; /* metapage containing ea list */ + struct jfs_ea_list *xattr; /* buffer containing ea list */ +}; + +/* + * ea_buffer.flag values + */ +#define EA_INLINE 0x0001 +#define EA_EXTENT 0x0002 +#define EA_NEW 0x0004 +#define EA_MALLOC 0x0008 + +/* Forward references */ +void ea_release(struct inode *inode, struct ea_buffer *ea_buf); + +/* + * NAME: jfs_WriteEAInLine + * + * FUNCTION: Attempt to write an EA inline if area is available + * + * PRE CONDITIONS: + * Already verified that the specified EA is small enough to fit inline + * + * PARAMETERS: + * ip - Inode pointer + * ealist - EA list pointer + * size - size of ealist in bytes + * ea - dxd_t structure to be filled in with necessary EA information + * if we successfully copy the EA inline + * + * NOTES: + * Checks if the inode's inline area is available. If so, copies EA inline + * and sets fields appropriately. Otherwise, returns failure, EA will + * have to be put into an extent. + * + * RETURNS: 0 for successful copy to inline area; -1 if area not available + */ +static int jfs_WriteEAInLine(struct inode *ip, struct jfs_ea_list *ealist, + int size, dxd_t * ea) +{ + struct jfs_inode_info *ji = JFS_IP(ip); + + /* + * Make sure we have an EA -- the NULL EA list is valid, but you + * can't copy it! + */ + if (ealist && size > sizeof (struct jfs_ea_list)) { + assert(size <= sizeof (ji->i_inline_ea)); + + /* + * See if the space is available or if it is already being + * used for an inline EA. + */ + if (!(ji->mode2 & INLINEEA) && !(ji->ea.flag & DXD_INLINE)) + return -1; + + DXDsize(ea, size); + DXDlength(ea, 0); + DXDaddress(ea, 0); + memcpy(ji->i_inline_ea, ealist, size); + ea->flag = DXD_INLINE; + ji->mode2 &= ~INLINEEA; + } else { + ea->flag = 0; + DXDsize(ea, 0); + DXDlength(ea, 0); + DXDaddress(ea, 0); + + /* Free up INLINE area */ + if (ji->ea.flag & DXD_INLINE) + ji->mode2 |= INLINEEA; + } + + mark_inode_dirty(ip); + return 0; +} + +/* + * NAME: jfs_WriteEA + * + * FUNCTION: Write an EA for an inode + * + * PRE CONDITIONS: EA has been verified + * + * PARAMETERS: + * ip - Inode pointer + * ealist - EA list pointer + * size - size of ealist in bytes + * ea - dxd_t structure to be filled in appropriately with where the + * EA was copied + * + * NOTES: Will write EA inline if able to, otherwise allocates blocks for an + * extent and synchronously writes it to those blocks. + * + * RETURNS: 0 for success; Anything else indicates failure + */ +static int jfs_WriteEA(struct inode *ip, struct jfs_ea_list *ealist, int size, + dxd_t * ea) +{ + struct super_block *sb = ip->i_sb; + struct jfs_inode_info *ji = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(sb); + int nblocks; + s64 blkno; + int rc = 0, i; + char *cp; + s32 nbytes, nb; + s32 bytes_to_write; + metapage_t *mp; + + /* + * Quick check to see if this is an in-linable EA. Short EAs + * and empty EAs are all in-linable, provided the space exists. + */ + if (!ealist || size <= sizeof (ji->i_inline_ea)) { + if (!jfs_WriteEAInLine(ip, ealist, size, ea)) + return 0; + } + + /* figure out how many blocks we need */ + nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits; + + rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno); + if (rc) + return -rc; + + /* + * Now have nblocks worth of storage to stuff into the FEALIST. + * loop over the FEALIST copying data into the buffer one page at + * a time. + */ + cp = (char *) ealist; + nbytes = size; + for (i = 0; i < nblocks; i += sbi->nbperpage) { + /* + * Determine how many bytes for this request, and round up to + * the nearest aggregate block size + */ + nb = min(PSIZE, nbytes); + bytes_to_write = + ((((nb + sb->s_blocksize - 1)) >> sb->s_blocksize_bits)) + << sb->s_blocksize_bits; + + if (!(mp = get_metapage(ip, blkno + i, bytes_to_write, 1))) { + rc = -EIO; + goto failed; + } + + memcpy(mp->data, cp, nb); + + /* + * We really need a way to propagate errors for + * forced writes like this one. --hch + * + * (__write_metapage => release_metapage => flush_metapage) + */ +#ifdef _JFS_FIXME + if ((rc = flush_metapage(mp))) { + /* + * the write failed -- this means that the buffer + * is still assigned and the blocks are not being + * used. this seems like the best error recovery + * we can get ... + */ + goto failed; + } +#else + flush_metapage(mp); +#endif + + cp += PSIZE; + nbytes -= nb; + } + + ea->flag = DXD_EXTENT; + DXDsize(ea, ealist->size); + DXDlength(ea, nblocks); + DXDaddress(ea, blkno); + + /* Free up INLINE area */ + if (ji->ea.flag & DXD_INLINE) + ip->i_mode |= INLINEEA; + + return 0; + + failed: + dbFree(ip, blkno, nblocks); + return rc; +} + +/* + * NAME: jfs_ReadEAInLine + * + * FUNCTION: Read an inlined EA into user's buffer + * + * PARAMETERS: + * ip - Inode pointer + * ealist - Pointer to buffer to fill in with EA + * + * RETURNS: 0 + */ +static int jfs_ReadEAInLine(struct inode *ip, struct jfs_ea_list *ealist) +{ + struct jfs_inode_info *ji = JFS_IP(ip); + int ea_size = sizeDXD(&ji->ea); + + if (ea_size == 0) { + ealist->size = 0; + return 0; + } + + /* Sanity Check */ + if ((sizeDXD(&ji->ea) > sizeof (ji->i_inline_ea))) + return -EIO; + if (((struct jfs_ea_list *) &ji->i_inline_ea)->size != ea_size) + return -EIO; + + memcpy(ealist, ji->i_inline_ea, ea_size); + return 0; +} + +/* + * NAME: jfs_ReadEA + * + * FUNCTION: copy EA data into user's buffer + * + * PARAMETERS: + * ip - Inode pointer + * ealist - Pointer to buffer to fill in with EA + * + * NOTES: If EA is inline calls jfs_ReadEAInLine() to copy EA. + * + * RETURNS: 0 for success; other indicates failure + */ +static int jfs_ReadEA(struct inode *ip, struct jfs_ea_list *ealist) +{ + struct super_block *sb = ip->i_sb; + struct jfs_inode_info *ji = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(sb); + int nblocks; + s64 blkno; + char *cp = (char *) ealist; + int i; + int nbytes, nb; + s32 bytes_to_read; + metapage_t *mp; + + /* quick check for in-line EA */ + if (ji->ea.flag & DXD_INLINE) + return jfs_ReadEAInLine(ip, ealist); + + nbytes = sizeDXD(&ji->ea); + assert(nbytes); + + /* + * Figure out how many blocks were allocated when this EA list was + * originally written to disk. + */ + nblocks = lengthDXD(&ji->ea) << sbi->l2nbperpage; + blkno = addressDXD(&ji->ea) << sbi->l2nbperpage; + + /* + * I have found the disk blocks which were originally used to store + * the FEALIST. now i loop over each contiguous block copying the + * data into the buffer. + */ + for (i = 0; i < nblocks; i += sbi->nbperpage) { + /* + * Determine how many bytes for this request, and round up to + * the nearest aggregate block size + */ + nb = min(PSIZE, nbytes); + bytes_to_read = + ((((nb + sb->s_blocksize - 1)) >> sb->s_blocksize_bits)) + << sb->s_blocksize_bits; + + if (!(mp = read_metapage(ip, blkno + i, bytes_to_read, 1))) + return -EIO; + + memcpy(cp, mp->data, nb); + release_metapage(mp); + + cp += PSIZE; + nbytes -= nb; + } + + return 0; +} + +/* + * NAME: ea_get + * + * FUNCTION: Returns buffer containing existing extended attributes. + * The size of the buffer will be the larger of the existing + * attributes size, or min_size. + * + * The buffer, which may be inlined in the inode or in the + * page cache must be release by calling ea_release or ea_put + * + * PARAMETERS: + * inode - Inode pointer + * ea_buf - Structure to be populated with ealist and its metadata + * min_size- minimum size of buffer to be returned + * + * RETURNS: 0 for success; Other indicates failure + */ +int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) +{ + struct jfs_inode_info *ji = JFS_IP(inode); + struct super_block *sb = inode->i_sb; + int size; + int ea_size = sizeDXD(&ji->ea); + int blocks_needed, current_blocks; + s64 blkno; + int rc; + + /* When fsck.jfs clears a bad ea, it doesn't clear the size */ + if (ji->ea.flag == 0) + ea_size = 0; + + if (ea_size == 0) { + if (min_size == 0) { + ea_buf->flag = 0; + ea_buf->max_size = 0; + ea_buf->xattr = NULL; + return 0; + } + if ((min_size <= sizeof (ji->i_inline_ea)) && + (ji->mode2 & INLINEEA)) { + ea_buf->flag = EA_INLINE | EA_NEW; + ea_buf->max_size = sizeof (ji->i_inline_ea); + ea_buf->xattr = (struct jfs_ea_list *) ji->i_inline_ea; + DXDlength(&ea_buf->new_ea, 0); + DXDaddress(&ea_buf->new_ea, 0); + ea_buf->new_ea.flag = DXD_INLINE; + DXDsize(&ea_buf->new_ea, min_size); + return 0; + } + current_blocks = 0; + } else if (ji->ea.flag & DXD_INLINE) { + if (min_size <= sizeof (ji->i_inline_ea)) { + ea_buf->flag = EA_INLINE; + ea_buf->max_size = sizeof (ji->i_inline_ea); + ea_buf->xattr = (struct jfs_ea_list *) ji->i_inline_ea; + goto size_check; + } + current_blocks = 0; + } else { + assert(ji->ea.flag & DXD_EXTENT); + current_blocks = (ea_size + sb->s_blocksize - 1) >> + sb->s_blocksize_bits; + } + size = max(min_size, ea_size); + + if (size > PSIZE) { + /* + * To keep the rest of the code simple. Allocate a + * contiguous buffer to work with + */ + ea_buf->xattr = kmalloc(size, GFP_KERNEL); + if (ea_buf->xattr == NULL) + return -ENOMEM; + + ea_buf->flag |= EA_MALLOC; + ea_buf->max_size = (size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + + if (ea_size == 0) + return 0; + + rc = jfs_ReadEA(inode, ea_buf->xattr); + if (rc) { + kfree(ea_buf->xattr); + ea_buf->xattr = NULL; + return rc; + } + goto size_check; + } + blocks_needed = (min_size + sb->s_blocksize - 1) >> + sb->s_blocksize_bits; + + if (blocks_needed > current_blocks) { + rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed, + &blkno); + if (rc) + return -rc; + + DXDlength(&ea_buf->new_ea, blocks_needed); + DXDaddress(&ea_buf->new_ea, blkno); + ea_buf->new_ea.flag = DXD_EXTENT; + DXDsize(&ea_buf->new_ea, min_size); + + ea_buf->flag = EA_EXTENT | EA_NEW; + + ea_buf->mp = get_metapage(inode, blkno, + blocks_needed << sb->s_blocksize_bits, + 1); + if (ea_buf->mp == NULL) { + dbFree(inode, blkno, (s64) blocks_needed); + return -EIO; + } + ea_buf->xattr = ea_buf->mp->data; + ea_buf->max_size = (min_size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + if (ea_size == 0) + return 0; + rc = jfs_ReadEA(inode, ea_buf->xattr); + if (rc) { + discard_metapage(ea_buf->mp); + dbFree(inode, blkno, (s64) blocks_needed); + return rc; + } + goto size_check; + } + ea_buf->flag = EA_EXTENT; + ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea), + lengthDXD(&ji->ea), 1); + if (ea_buf->mp == NULL) + return -EIO; + ea_buf->xattr = ea_buf->mp->data; + ea_buf->max_size = (ea_size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + + size_check: + if (EALIST_SIZE(ea_buf->xattr) != ea_size) { + printk(KERN_ERR "ea_get: invalid extended attribute\n"); + dump_mem("xattr", ea_buf->xattr, ea_size); + ea_release(inode, ea_buf); + return -EIO; + } + + return ea_size; +} + +void ea_release(struct inode *inode, struct ea_buffer *ea_buf) +{ + if (ea_buf->flag & EA_MALLOC) + kfree(ea_buf->xattr); + else if (ea_buf->flag & EA_EXTENT) { + assert(ea_buf->mp); + release_metapage(ea_buf->mp); + + if (ea_buf->flag & EA_NEW) + dbFree(inode, addressDXD(&ea_buf->new_ea), + lengthDXD(&ea_buf->new_ea)); + } +} + +int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size) +{ + struct jfs_inode_info *ji = JFS_IP(inode); + unsigned long old_blocks, new_blocks; + int rc = 0; + tid_t tid; + + if (new_size == 0) { + ea_release(inode, ea_buf); + ea_buf = 0; + } else if (ea_buf->flag & EA_INLINE) { + assert(new_size <= sizeof (ji->i_inline_ea)); + ji->mode2 &= ~INLINEEA; + ea_buf->new_ea.flag = DXD_INLINE; + DXDsize(&ea_buf->new_ea, new_size); + DXDaddress(&ea_buf->new_ea, 0); + DXDlength(&ea_buf->new_ea, 0); + } else if (ea_buf->flag & EA_MALLOC) { + rc = jfs_WriteEA(inode, ea_buf->xattr, new_size, + &ea_buf->new_ea); + kfree(ea_buf->xattr); + } else if (ea_buf->flag & EA_NEW) { + /* We have already allocated a new dxd */ + flush_metapage(ea_buf->mp); + } else { + /* ->xattr must point to original ea's metapage */ + rc = jfs_WriteEA(inode, ea_buf->xattr, new_size, + &ea_buf->new_ea); + discard_metapage(ea_buf->mp); + } + if (rc) + return rc; + + tid = txBegin(inode->i_sb, 0); + down(&ji->commit_sem); + + old_blocks = new_blocks = 0; + + if (ji->ea.flag & DXD_EXTENT) { + invalidate_dxd_metapages(inode, ji->ea); + old_blocks = lengthDXD(&ji->ea); + } + + if (ea_buf) { + txEA(tid, inode, &ji->ea, &ea_buf->new_ea); + if (ea_buf->new_ea.flag & DXD_EXTENT) { + new_blocks = lengthDXD(&ea_buf->new_ea); + if (ji->ea.flag & DXD_INLINE) + ji->mode2 |= INLINEEA; + } + ji->ea = ea_buf->new_ea; + } else { + txEA(tid, inode, &ji->ea, 0); + if (ji->ea.flag & DXD_INLINE) + ji->mode2 |= INLINEEA; + ji->ea.flag = 0; + ji->ea.size = 0; + } + + inode->i_blocks += LBLK2PBLK(inode->i_sb, new_blocks - old_blocks); + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + up(&ji->commit_sem); + + return rc; +} + +int jfs_setxattr(struct dentry *dentry, const char *name, + void *value, size_t value_len, int flags) +{ + struct inode *inode = dentry->d_inode; + struct jfs_ea_list *ealist; + struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL; + struct ea_buffer ea_buf; + int old_ea_size = 0; + int xattr_size; + int new_size; + int namelen = strlen(name); + int found = 0; + int rc = 0; + int length; + + if (!value) + value_len = 0; + + IWRITE_LOCK(inode); + + xattr_size = ea_get(inode, &ea_buf, 0); + if (xattr_size < 0) { + rc = xattr_size; + goto unlock; + } + + again: + ealist = (struct jfs_ea_list *) ea_buf.xattr; + new_size = sizeof (struct jfs_ea_list); + + if (xattr_size) { + for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); + ea = NEXT_EA(ea)) { + if ((namelen == ea->namelen) && + (memcmp(name, ea->name, namelen) == 0)) { + found = 1; + if (flags & XATTR_CREATE) { + rc = -EEXIST; + goto release; + } + old_ea = ea; + old_ea_size = EA_SIZE(ea); + next_ea = NEXT_EA(ea); + } else + new_size += EA_SIZE(ea); + } + } + + if (!found) { + if (flags & XATTR_REPLACE) { + rc = -ENODATA; + goto release; + } + if (value_len == 0) { + rc = 0; + goto release; + } + } + if (value_len) + new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len; + + if (new_size > ea_buf.max_size) { + /* + * We need to allocate more space for merged ea list. + * We should only have loop to again: once. + */ + ea_release(inode, &ea_buf); + xattr_size = ea_get(inode, &ea_buf, new_size); + if (xattr_size < 0) { + rc = xattr_size; + goto unlock; + } + goto again; + } + + /* Remove old ea of the same name */ + if (found) { + /* number of bytes following target EA */ + length = (char *) END_EALIST(ealist) - (char *) next_ea; + if (length > 0) + memmove(old_ea, next_ea, length); + xattr_size -= old_ea_size; + } + + /* Add new entry to the end */ + if (value_len) { + if (xattr_size == 0) + /* Completely new ea list */ + xattr_size = sizeof (struct jfs_ea_list); + + ea = (struct jfs_ea *) ((char *) ealist + xattr_size); + ea->flag = 0; + ea->namelen = namelen; + ea->valuelen = (cpu_to_le16(value_len)); + memcpy(ea->name, name, namelen); + ea->name[namelen] = 0; + memcpy(&ea->name[namelen + 1], value, value_len); + xattr_size += EA_SIZE(ea); + } + + /* DEBUG - If we did this right, these number match */ + if (xattr_size != new_size) { + printk(KERN_ERR + "jfs_xsetattr: xattr_size = %d, new_size = %d\n", + xattr_size, new_size); + + rc = EINVAL; + goto release; + } + + ealist->size = cpu_to_le32(new_size); + + rc = ea_put(inode, &ea_buf, new_size); + + goto unlock; + release: + ea_release(inode, &ea_buf); + unlock: + IWRITE_UNLOCK(inode); + return rc; +} + +ssize_t jfs_getxattr(struct dentry * dentry, const char *name, + void *data, size_t buf_size) +{ + struct inode *inode = dentry->d_inode; + struct jfs_ea_list *ealist; + struct jfs_ea *ea; + struct ea_buffer ea_buf; + int xattr_size; + ssize_t size; + int namelen = strlen(name); + char *value; + + IREAD_LOCK(inode); + + xattr_size = ea_get(inode, &ea_buf, 0); + if (xattr_size < 0) { + size = xattr_size; + goto unlock; + } + + if (xattr_size == 0) { + size = 0; + goto release; + } + + ealist = (struct jfs_ea_list *) ea_buf.xattr; + + /* Find the named attribute */ + for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) + if ((namelen == ea->namelen) && + memcmp(name, ea->name, namelen) == 0) { + /* Found it */ + size = le16_to_cpu(ea->valuelen); + if (!data) + goto release; + else if (size > buf_size) { + size = -ERANGE; + goto release; + } + value = ((char *) &ea->name) + ea->namelen + 1; + memcpy(data, value, size); + goto release; + } + /* not found */ + size = -ENODATA; + release: + ea_release(inode, &ea_buf); + unlock: + IREAD_UNLOCK(inode); + + return size; +} + +ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) +{ + struct inode *inode = dentry->d_inode; + char *buffer; + ssize_t size = 0; + int xattr_size; + struct jfs_ea_list *ealist; + struct jfs_ea *ea; + struct ea_buffer ea_buf; + + IREAD_LOCK(inode); + + xattr_size = ea_get(inode, &ea_buf, 0); + if (xattr_size < 0) { + size = xattr_size; + goto unlock; + } + + if (xattr_size == 0) + goto release; + + ealist = (struct jfs_ea_list *) ea_buf.xattr; + + /* compute required size of list */ + for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) + size += ea->namelen + 1; + + if (!data) + goto release; + + if (size > buf_size) { + size = -ERANGE; + goto release; + } + + /* Copy attribute names to buffer */ + buffer = data; + for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { + memcpy(buffer, ea->name, ea->namelen); + buffer[ea->namelen] = 0; + buffer += ea->namelen + 1; + } + + release: + ea_release(inode, &ea_buf); + unlock: + IREAD_UNLOCK(inode); + return size; +} + +int jfs_removexattr(struct dentry *dentry, const char *name) +{ + return jfs_setxattr(dentry, name, 0, 0, XATTR_REPLACE); +} diff -Nru a/fs/lockd/svc.c b/fs/lockd/svc.c --- a/fs/lockd/svc.c Sat Aug 31 15:06:03 2002 +++ b/fs/lockd/svc.c Sat Aug 31 15:06:03 2002 @@ -203,6 +203,7 @@ rpciod_down(); /* Release module */ + unlock_kernel(); MOD_DEC_USE_COUNT; } diff -Nru a/fs/locks.c b/fs/locks.c --- a/fs/locks.c Sat Aug 31 15:06:06 2002 +++ b/fs/locks.c Sat Aug 31 15:06:06 2002 @@ -1609,6 +1609,14 @@ { struct file_lock lock; + /* + * If there are no locks held on this file, we don't need to call + * posix_lock_file(). Another process could be setting a lock on this + * file at the same time, but we wouldn't remove that lock anyway. + */ + if (!filp->f_dentry->d_inode->i_flock) + return; + lock.fl_type = F_UNLCK; lock.fl_flags = FL_POSIX; lock.fl_start = 0; diff -Nru a/fs/mpage.c b/fs/mpage.c --- a/fs/mpage.c Sat Aug 31 15:05:55 2002 +++ b/fs/mpage.c Sat Aug 31 15:05:55 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include /* @@ -530,6 +531,7 @@ sector_t last_block_in_bio = 0; int ret = 0; int done = 0; + int sync = called_for_sync(); struct pagevec pvec; int (*writepage)(struct page *); @@ -546,7 +548,7 @@ struct page *page = list_entry(mapping->io_pages.prev, struct page, list); list_del(&page->list); - if (PageWriteback(page)) { + if (PageWriteback(page) && !sync) { if (PageDirty(page)) { list_add(&page->list, &mapping->dirty_pages); continue; @@ -565,6 +567,9 @@ lock_page(page); + if (sync) + wait_on_page_writeback(page); + if (page->mapping && !PageWriteback(page) && TestClearPageDirty(page)) { if (writepage) { @@ -578,6 +583,10 @@ if (!pagevec_add(&pvec, page)) pagevec_deactivate_inactive(&pvec); page = NULL; + } + if (ret == -EAGAIN && page) { + __set_page_dirty_nobuffers(page); + ret = 0; } if (ret || (nr_to_write && --(*nr_to_write) <= 0)) done = 1; diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c --- a/fs/nfs/file.c Sat Aug 31 15:06:03 2002 +++ b/fs/nfs/file.c Sat Aug 31 15:06:03 2002 @@ -279,10 +279,7 @@ * Flush all pending writes before doing anything * with locks.. */ - status = filemap_fdatawait(inode->i_mapping); - status2 = filemap_fdatawrite(inode->i_mapping); - if (!status) - status = status2; + status = filemap_fdatawrite(inode->i_mapping); down(&inode->i_sem); status2 = nfs_wb_all(inode); if (!status) @@ -308,7 +305,6 @@ */ out_ok: if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { - filemap_fdatawait(inode->i_mapping); filemap_fdatawrite(inode->i_mapping); down(&inode->i_sem); nfs_wb_all(inode); /* we may have slept */ diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Sat Aug 31 15:06:06 2002 +++ b/fs/nfs/inode.c Sat Aug 31 15:06:06 2002 @@ -775,7 +775,6 @@ if (!S_ISREG(inode->i_mode)) attr->ia_valid &= ~ATTR_SIZE; - filemap_fdatawait(inode->i_mapping); filemap_fdatawrite(inode->i_mapping); error = nfs_wb_all(inode); filemap_fdatawait(inode->i_mapping); diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c --- a/fs/nfsd/vfs.c Sat Aug 31 15:05:59 2002 +++ b/fs/nfsd/vfs.c Sat Aug 31 15:05:59 2002 @@ -501,7 +501,6 @@ struct inode *inode = dp->d_inode; int (*fsync) (struct file *, struct dentry *, int); - filemap_fdatawait(inode->i_mapping); filemap_fdatawrite(inode->i_mapping); if (fop && (fsync = fop->fsync)) fsync(filp, dp, 0); diff -Nru a/fs/nls/nls_base.c b/fs/nls/nls_base.c --- a/fs/nls/nls_base.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_base.c Sat Aug 31 15:05:54 2002 @@ -471,11 +471,11 @@ } static struct nls_table default_table = { - charset: "default", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, + .charset = "default", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, }; /* Returns a simple default translation table */ diff -Nru a/fs/nls/nls_big5.c b/fs/nls/nls_big5.c --- a/fs/nls/nls_big5.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_big5.c Sat Aug 31 15:06:06 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "big5", - owner: THIS_MODULE, + .charset = "big5", + .owner = THIS_MODULE, }; static int __init init_nls_big5(void) diff -Nru a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c --- a/fs/nls/nls_cp1250.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_cp1250.c Sat Aug 31 15:06:00 2002 @@ -324,12 +324,12 @@ } static struct nls_table table = { - charset: "cp1250", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp1250", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp1250(void) diff -Nru a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c --- a/fs/nls/nls_cp1251.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp1251.c Sat Aug 31 15:06:06 2002 @@ -278,12 +278,12 @@ } static struct nls_table table = { - charset: "cp1251", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp1251", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp1251(void) diff -Nru a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c --- a/fs/nls/nls_cp1255.c Sat Aug 31 15:05:53 2002 +++ b/fs/nls/nls_cp1255.c Sat Aug 31 15:05:53 2002 @@ -359,12 +359,12 @@ } static struct nls_table table = { - charset: "cp1255", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp1255", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp1255(void) diff -Nru a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c --- a/fs/nls/nls_cp437.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp437.c Sat Aug 31 15:06:06 2002 @@ -364,12 +364,12 @@ } static struct nls_table table = { - charset: "cp437", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp437", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp437(void) diff -Nru a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c --- a/fs/nls/nls_cp737.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_cp737.c Sat Aug 31 15:05:54 2002 @@ -327,12 +327,12 @@ } static struct nls_table table = { - charset: "cp737", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp737", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp737(void) diff -Nru a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c --- a/fs/nls/nls_cp775.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp775.c Sat Aug 31 15:06:06 2002 @@ -296,12 +296,12 @@ } static struct nls_table table = { - charset: "cp775", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp775", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp775(void) diff -Nru a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c --- a/fs/nls/nls_cp850.c Sat Aug 31 15:06:03 2002 +++ b/fs/nls/nls_cp850.c Sat Aug 31 15:06:03 2002 @@ -292,12 +292,12 @@ } static struct nls_table table = { - charset: "cp850", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp850", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp850(void) diff -Nru a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c --- a/fs/nls/nls_cp852.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp852.c Sat Aug 31 15:06:06 2002 @@ -314,12 +314,12 @@ } static struct nls_table table = { - charset: "cp852", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp852", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp852(void) diff -Nru a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c --- a/fs/nls/nls_cp855.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_cp855.c Sat Aug 31 15:05:59 2002 @@ -276,12 +276,12 @@ } static struct nls_table table = { - charset: "cp855", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp855", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp855(void) diff -Nru a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c --- a/fs/nls/nls_cp857.c Sat Aug 31 15:05:55 2002 +++ b/fs/nls/nls_cp857.c Sat Aug 31 15:05:55 2002 @@ -278,12 +278,12 @@ } static struct nls_table table = { - charset: "cp857", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp857", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp857(void) diff -Nru a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c --- a/fs/nls/nls_cp860.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_cp860.c Sat Aug 31 15:05:59 2002 @@ -341,12 +341,12 @@ } static struct nls_table table = { - charset: "cp860", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp860", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp860(void) diff -Nru a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c --- a/fs/nls/nls_cp861.c Sat Aug 31 15:05:55 2002 +++ b/fs/nls/nls_cp861.c Sat Aug 31 15:05:55 2002 @@ -364,12 +364,12 @@ } static struct nls_table table = { - charset: "cp861", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp861", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp861(void) diff -Nru a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c --- a/fs/nls/nls_cp862.c Sat Aug 31 15:06:03 2002 +++ b/fs/nls/nls_cp862.c Sat Aug 31 15:06:03 2002 @@ -398,12 +398,12 @@ } static struct nls_table table = { - charset: "cp862", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp862", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp862(void) diff -Nru a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c --- a/fs/nls/nls_cp863.c Sat Aug 31 15:06:03 2002 +++ b/fs/nls/nls_cp863.c Sat Aug 31 15:06:03 2002 @@ -358,12 +358,12 @@ } static struct nls_table table = { - charset: "cp863", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp863", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp863(void) diff -Nru a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c --- a/fs/nls/nls_cp864.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp864.c Sat Aug 31 15:06:06 2002 @@ -384,12 +384,12 @@ } static struct nls_table table = { - charset: "cp864", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp864", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp864(void) diff -Nru a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c --- a/fs/nls/nls_cp865.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_cp865.c Sat Aug 31 15:06:00 2002 @@ -364,12 +364,12 @@ } static struct nls_table table = { - charset: "cp865", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp865", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp865(void) diff -Nru a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c --- a/fs/nls/nls_cp866.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp866.c Sat Aug 31 15:06:06 2002 @@ -282,12 +282,12 @@ } static struct nls_table table = { - charset: "cp866", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp866", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp866(void) diff -Nru a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c --- a/fs/nls/nls_cp869.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp869.c Sat Aug 31 15:06:06 2002 @@ -292,12 +292,12 @@ } static struct nls_table table = { - charset: "cp869", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp869", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp869(void) diff -Nru a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c --- a/fs/nls/nls_cp874.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_cp874.c Sat Aug 31 15:05:59 2002 @@ -250,12 +250,12 @@ } static struct nls_table table = { - charset: "cp874", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp874", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp874(void) diff -Nru a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c --- a/fs/nls/nls_cp932.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_cp932.c Sat Aug 31 15:05:59 2002 @@ -7884,12 +7884,12 @@ } static struct nls_table table = { - charset: "cp932", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp932", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp932(void) diff -Nru a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c --- a/fs/nls/nls_cp936.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_cp936.c Sat Aug 31 15:05:59 2002 @@ -11004,12 +11004,12 @@ } static struct nls_table table = { - charset: "cp936", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp936", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp936(void) diff -Nru a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c --- a/fs/nls/nls_cp949.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp949.c Sat Aug 31 15:06:06 2002 @@ -13921,12 +13921,12 @@ } static struct nls_table table = { - charset: "cp949", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp949", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp949(void) diff -Nru a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c --- a/fs/nls/nls_cp950.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_cp950.c Sat Aug 31 15:06:06 2002 @@ -9460,12 +9460,12 @@ } static struct nls_table table = { - charset: "cp950", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "cp950", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_cp950(void) diff -Nru a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c --- a/fs/nls/nls_euc-jp.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_euc-jp.c Sat Aug 31 15:05:54 2002 @@ -552,10 +552,10 @@ } static struct nls_table table = { - charset: "euc-jp", - uni2char: uni2char, - char2uni: char2uni, - owner: THIS_MODULE, + .charset = "euc-jp", + .uni2char = uni2char, + .char2uni = char2uni, + .owner = THIS_MODULE, }; static int __init init_nls_euc_jp(void) diff -Nru a/fs/nls/nls_euc-kr.c b/fs/nls/nls_euc-kr.c --- a/fs/nls/nls_euc-kr.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_euc-kr.c Sat Aug 31 15:06:00 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "euc-kr", - owner: THIS_MODULE, + .charset = "euc-kr", + .owner = THIS_MODULE, }; static int __init init_nls_euc_kr(void) diff -Nru a/fs/nls/nls_gb2312.c b/fs/nls/nls_gb2312.c --- a/fs/nls/nls_gb2312.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_gb2312.c Sat Aug 31 15:06:00 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "gb2312", - owner: THIS_MODULE, + .charset = "gb2312", + .owner = THIS_MODULE, }; static int __init init_nls_gb2312(void) diff -Nru a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c --- a/fs/nls/nls_iso8859-1.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_iso8859-1.c Sat Aug 31 15:06:00 2002 @@ -234,12 +234,12 @@ } static struct nls_table table = { - charset: "iso8859-1", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-1", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_1(void) diff -Nru a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c --- a/fs/nls/nls_iso8859-13.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_iso8859-13.c Sat Aug 31 15:06:00 2002 @@ -262,12 +262,12 @@ } static struct nls_table table = { - charset: "iso8859-13", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-13", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_13(void) diff -Nru a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c --- a/fs/nls/nls_iso8859-14.c Sat Aug 31 15:05:55 2002 +++ b/fs/nls/nls_iso8859-14.c Sat Aug 31 15:05:55 2002 @@ -318,12 +318,12 @@ } static struct nls_table table = { - charset: "iso8859-14", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-14", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_14(void) diff -Nru a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c --- a/fs/nls/nls_iso8859-15.c Sat Aug 31 15:06:03 2002 +++ b/fs/nls/nls_iso8859-15.c Sat Aug 31 15:06:03 2002 @@ -284,12 +284,12 @@ } static struct nls_table table = { - charset: "iso8859-15", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-15", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_15(void) diff -Nru a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c --- a/fs/nls/nls_iso8859-2.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_iso8859-2.c Sat Aug 31 15:05:59 2002 @@ -285,12 +285,12 @@ } static struct nls_table table = { - charset: "iso8859-2", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-2", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_2(void) diff -Nru a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c --- a/fs/nls/nls_iso8859-3.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_iso8859-3.c Sat Aug 31 15:05:59 2002 @@ -285,12 +285,12 @@ } static struct nls_table table = { - charset: "iso8859-3", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-3", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_3(void) diff -Nru a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c --- a/fs/nls/nls_iso8859-4.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_iso8859-4.c Sat Aug 31 15:06:00 2002 @@ -285,12 +285,12 @@ } static struct nls_table table = { - charset: "iso8859-4", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-4", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_4(void) diff -Nru a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c --- a/fs/nls/nls_iso8859-5.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_iso8859-5.c Sat Aug 31 15:05:59 2002 @@ -249,12 +249,12 @@ } static struct nls_table table = { - charset: "iso8859-5", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-5", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_5(void) diff -Nru a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c --- a/fs/nls/nls_iso8859-6.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_iso8859-6.c Sat Aug 31 15:05:54 2002 @@ -240,12 +240,12 @@ } static struct nls_table table = { - charset: "iso8859-6", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-6", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_6(void) diff -Nru a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c --- a/fs/nls/nls_iso8859-7.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_iso8859-7.c Sat Aug 31 15:05:54 2002 @@ -294,12 +294,12 @@ } static struct nls_table table = { - charset: "iso8859-7", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-7", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_7(void) diff -Nru a/fs/nls/nls_iso8859-8.c b/fs/nls/nls_iso8859-8.c --- a/fs/nls/nls_iso8859-8.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_iso8859-8.c Sat Aug 31 15:06:06 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "iso8859-8", - owner: THIS_MODULE, + .charset = "iso8859-8", + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_8(void) diff -Nru a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c --- a/fs/nls/nls_iso8859-9.c Sat Aug 31 15:06:03 2002 +++ b/fs/nls/nls_iso8859-9.c Sat Aug 31 15:06:03 2002 @@ -249,12 +249,12 @@ } static struct nls_table table = { - charset: "iso8859-9", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "iso8859-9", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_iso8859_9(void) diff -Nru a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c --- a/fs/nls/nls_koi8-r.c Sat Aug 31 15:05:53 2002 +++ b/fs/nls/nls_koi8-r.c Sat Aug 31 15:05:53 2002 @@ -300,12 +300,12 @@ } static struct nls_table table = { - charset: "koi8-r", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "koi8-r", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_koi8_r(void) diff -Nru a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c --- a/fs/nls/nls_koi8-ru.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_koi8-ru.c Sat Aug 31 15:05:54 2002 @@ -52,10 +52,10 @@ } static struct nls_table table = { - charset: "koi8-ru", - uni2char: uni2char, - char2uni: char2uni, - owner: THIS_MODULE, + .charset = "koi8-ru", + .uni2char = uni2char, + .char2uni = char2uni, + .owner = THIS_MODULE, }; static int __init init_nls_koi8_ru(void) diff -Nru a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c --- a/fs/nls/nls_koi8-u.c Sat Aug 31 15:06:06 2002 +++ b/fs/nls/nls_koi8-u.c Sat Aug 31 15:06:06 2002 @@ -307,12 +307,12 @@ } static struct nls_table table = { - charset: "koi8-u", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: charset2lower, - charset2upper: charset2upper, - owner: THIS_MODULE, + .charset = "koi8-u", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = charset2lower, + .charset2upper = charset2upper, + .owner = THIS_MODULE, }; static int __init init_nls_koi8_u(void) diff -Nru a/fs/nls/nls_sjis.c b/fs/nls/nls_sjis.c --- a/fs/nls/nls_sjis.c Sat Aug 31 15:06:00 2002 +++ b/fs/nls/nls_sjis.c Sat Aug 31 15:06:00 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "sjis", - owner: THIS_MODULE, + .charset = "sjis", + .owner = THIS_MODULE, }; static int __init init_nls_sjis(void) diff -Nru a/fs/nls/nls_tis-620.c b/fs/nls/nls_tis-620.c --- a/fs/nls/nls_tis-620.c Sat Aug 31 15:05:54 2002 +++ b/fs/nls/nls_tis-620.c Sat Aug 31 15:05:54 2002 @@ -11,8 +11,8 @@ static struct nls_table *p_nls; static struct nls_table table = { - charset: "tis-620", - owner: THIS_MODULE, + .charset = "tis-620", + .owner = THIS_MODULE, }; static int __init init_nls_tis_620(void) diff -Nru a/fs/nls/nls_utf8.c b/fs/nls/nls_utf8.c --- a/fs/nls/nls_utf8.c Sat Aug 31 15:05:59 2002 +++ b/fs/nls/nls_utf8.c Sat Aug 31 15:05:59 2002 @@ -34,12 +34,12 @@ } static struct nls_table table = { - charset: "utf8", - uni2char: uni2char, - char2uni: char2uni, - charset2lower: identity, /* no conversion */ - charset2upper: identity, - owner: THIS_MODULE, + .charset = "utf8", + .uni2char = uni2char, + .char2uni = char2uni, + .charset2lower = identity, /* no conversion */ + .charset2upper = identity, + .owner = THIS_MODULE, }; static int __init init_nls_utf8(void) diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog Sat Aug 31 15:05:55 2002 +++ b/fs/ntfs/ChangeLog Sat Aug 31 15:05:55 2002 @@ -1,6 +1,55 @@ ToDo: - Find and fix bugs. - Enable NFS exporting of NTFS. + - Implement aops->set_page_dirty() in order to take control of buffer + dirtying. Not having it means if page_has_buffers(), all buffers + will be dirtied with the page. And if not they won't be. That is + fine for the moment but will break once we enable metadata updates. + - Implement sops->dirty_inode() to implement {a,m,c} time updates and + such things. + - Implement sops->write_inode(). + - In between ntfs_prepare/commit_write, need exclusion between + simultaneous file extensions. Need perhaps an NInoResizeUnderway() + flag which we can set in ntfs_prepare_write() and clear again in + ntfs_commit_write(). Just have to be careful in readpage/writepage, + as well as in truncate, that we play nice... We might need to have + a data_size field in the ntfs_inode to store the real attribute + length. Also need to be careful with initialized_size extention in + ntfs_prepare_write. Basically, just be _very_ careful in this code... + OTOH, perhaps i_sem, which is held accross generic_file_write is + sufficient for synchronisation here. We then just need to make sure + ntfs_readpage/writepage/truncate interoperate properly with us. + +2.1.0 - First steps towards write support: implement file overwrite. + + - Add configuration option for developmental write support with an + appropriately scary configuration help text. + - Initial implementation of fs/ntfs/aops.c::ntfs_writepage() and its + helper fs/ntfs/aops.c::ntfs_write_block(). This enables mmap(2) based + overwriting of existing files on ntfs. Note: Resident files are + only written into memory, and not written out to disk at present, so + avoid writing to files smaller than about 1kiB. + - Initial implementation of fs/ntfs/aops.c::ntfs_prepare_write(), its + helper fs/ntfs/aops.c::ntfs_prepare_nonresident_write() and their + counterparts, fs/ntfs/aops.c::ntfs_commit_write(), and + fs/ntfs/aops.c::ntfs_commit_nonresident_write(), respectively. Also, + add generic_file_write() to the ntfs file operations (fs/ntfs/file.c). + This enables write(2) based overwriting of existing files on ntfs. + Note: As with mmap(2) based overwriting, resident files are only + written into memory, and not written out to disk at present, so avoid + writing to files smaller than about 1kiB. + - Implement ->truncate (fs/ntfs/inode.c::ntfs_truncate()) and + ->setattr() (fs/ntfs/inode.c::ntfs_setattr()) inode operations for + files with the purpose of intercepting and aborting all i_size + changes which we do not support yet. ntfs_truncate() actually only + emits a warning message but AFAICS our interception of i_size changes + elsewhere means ntfs_truncate() never gets called for i_size changes. + It is only called from generic_file_write() when we fail in + ntfs_prepare_{,nonresident_}write() in order to discard any + instantiated buffers beyond i_size. Thus i_size is not actually + changed so our warning message is enough. Unfortunately it is not + possible to easily determine if i_size is being changed or not hence + we just emit an appropriately worded error message. 2.0.25 - Small bug fixes and cleanups. diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile Sat Aug 31 15:05:54 2002 +++ b/fs/ntfs/Makefile Sat Aug 31 15:05:54 2002 @@ -5,15 +5,15 @@ ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.25\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.0\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif -#ifeq ($(CONFIG_NTFS_RW),y) -#EXTRA_CFLAGS += -DNTFS_RW -#endif +ifeq ($(CONFIG_NTFS_RW),y) +EXTRA_CFLAGS += -DNTFS_RW +endif include $(TOPDIR)/Rules.make diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c --- a/fs/ntfs/aops.c Sat Aug 31 15:06:06 2002 +++ b/fs/ntfs/aops.c Sat Aug 31 15:06:06 2002 @@ -385,7 +385,7 @@ else base_ni = ni->_INE(base_ntfs_ino); - /* Map, pin and lock the mft record. */ + /* Map, pin, and lock the mft record. */ mrec = map_mft_record(base_ni); if (unlikely(IS_ERR(mrec))) { err = PTR_ERR(mrec); @@ -435,6 +435,1337 @@ return err; } +#ifdef NTFS_RW + +/** + * ntfs_write_block - write a @page to the backing store + * @page: page cache page to write out + * + * This function is for writing pages belonging to non-resident, non-mst + * protected attributes to their backing store. + * + * For a page with buffers, map and write the dirty buffers asynchronously + * under page writeback. For a page without buffers, create buffers for the + * page, then proceed as above. + * + * If a page doesn't have buffers the page dirty state is definitive. If a page + * does have buffers, the page dirty state is just a hint, and the buffer dirty + * state is definitive. (A hint which has rules: dirty buffers against a clean + * page is illegal. Other combinations are legal and need to be handled. In + * particular a dirty page containing clean buffers for example.) + * + * Return 0 on success and -errno on error. + * + * Based on ntfs_read_block() and __block_write_full_page(). + */ +static int ntfs_write_block(struct page *page) +{ + VCN vcn; + LCN lcn; + sector_t block, dblock, iblock; + struct inode *vi; + ntfs_inode *ni; + ntfs_volume *vol; + run_list_element *rl; + struct buffer_head *bh, *head; + unsigned int blocksize, vcn_ofs; + int err; + BOOL need_end_writeback; + unsigned char blocksize_bits; + + vi = page->mapping->host; + ni = NTFS_I(vi); + vol = ni->vol; + + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx.\n", vi->i_ino, ni->type, page->index); + + BUG_ON(!NInoNonResident(ni)); + BUG_ON(NInoMstProtected(ni)); + + blocksize_bits = vi->i_blkbits; + blocksize = 1 << blocksize_bits; + + if (!page_has_buffers(page)) { + BUG_ON(!PageUptodate(page)); + create_empty_buffers(page, blocksize, + (1 << BH_Uptodate) | (1 << BH_Dirty)); + } + bh = head = page_buffers(page); + if (unlikely(!bh)) { + ntfs_warning(vol->sb, "Error allocating page buffers. " + "Redirtying page so we try again later."); + /* + * Put the page back on mapping->dirty_pages, but leave its + * buffer's dirty state as-is. + */ + // FIXME: Once Andrew's -EAGAIN patch goes in, remove the + // __set_page_dirty_nobuffers(page) and return -EAGAIN instead + // of zero. + __set_page_dirty_nobuffers(page); + unlock_page(page); + return 0; + } + + /* NOTE: Different naming scheme to ntfs_read_block()! */ + + /* The first block in the page. */ + block = page->index << (PAGE_CACHE_SHIFT - blocksize_bits); + + /* The first out of bounds block for the data size. */ + dblock = (vi->i_size + blocksize - 1) >> blocksize_bits; + + /* The last (fully or partially) initialized block. */ + iblock = ni->initialized_size >> blocksize_bits; + + /* + * Be very careful. We have no exclusion from __set_page_dirty_buffers + * here, and the (potentially unmapped) buffers may become dirty at + * any time. If a buffer becomes dirty here after we've inspected it + * then we just miss that fact, and the page stays dirty. + * + * Buffers outside i_size may be dirtied by __set_page_dirty_buffers; + * handle that here by just cleaning them. + */ + + /* + * Loop through all the buffers in the page, mapping all the dirty + * buffers to disk addresses and handling any aliases from the + * underlying block device's mapping. + */ + rl = NULL; + err = 0; + do { + BOOL is_retry = FALSE; + + if (unlikely(block >= dblock)) { + /* + * Mapped buffers outside i_size will occur, because + * this page can be outside i_size when there is a + * truncate in progress. The contents of such buffers + * were zeroed by ntfs_writepage(). + * + * FIXME: What about the small race window where + * ntfs_writepage() has not done any clearing because + * the page was within i_size but before we get here, + * vmtruncate() modifies i_size? + */ + clear_buffer_dirty(bh); + set_buffer_uptodate(bh); + continue; + } + + /* Clean buffers are not written out, so no need to map them. */ + if (!buffer_dirty(bh)) + continue; + + /* Make sure we have enough initialized size. */ + if (unlikely((block >= iblock) && + (ni->initialized_size < vi->i_size))) { + /* + * If this page is fully outside initialized size, zero + * out all pages between the current initialized size + * and the current page. Just use ntfs_readpage() to do + * the zeroing transparently. + */ + if (block > iblock) { + // TODO: + // For each page do: + // - read_cache_page() + // Again for each page do: + // - wait_on_page_locked() + // - Check (PageUptodate(page) && + // !PageError(page)) + // Update initialized size in the attribute and + // in the inode. + // Again, for each page do: + // __set_page_dirty_buffers(); + // page_cache_release() + // We don't need to wait on the writes. + // Update iblock. + } + /* + * The current page straddles initialized size. Zero + * all non-uptodate buffers and set them uptodate (and + * dirty?). Note, there aren't any non-uptodate buffers + * if the page is uptodate. + * FIXME: For an uptodate page, the buffers may need to + * be written out because they were not initialized on + * disk before. + */ + if (!PageUptodate(page)) { + // TODO: + // Zero any non-uptodate buffers up to i_size. + // Set them uptodate and dirty. + } + // TODO: + // Update initialized size in the attribute and in the + // inode (up to i_size). + // Update iblock. + // FIXME: This is inefficient. Try to batch the two + // size changes to happen in one go. + ntfs_error(vol->sb, "Writing beyond initialized size " + "is not supported yet. Sorry."); + err = -EOPNOTSUPP; + break; + // Do NOT set_buffer_new() BUT DO clear buffer range + // outside write request range. + // set_buffer_uptodate() on complete buffers as well as + // set_buffer_dirty(). + } + + /* No need to map buffers that are already mapped. */ + if (buffer_mapped(bh)) + continue; + + /* Unmapped, dirty buffer. Need to map it. */ + bh->b_bdev = vol->sb->s_bdev; + + /* Convert block into corresponding vcn and offset. */ + vcn = (VCN)block << blocksize_bits >> vol->cluster_size_bits; + vcn_ofs = ((VCN)block << blocksize_bits) & + vol->cluster_size_mask; + if (!rl) { +lock_retry_remap: + down_read(&ni->run_list.lock); + rl = ni->run_list.rl; + } + if (likely(rl != NULL)) { + /* Seek to element containing target vcn. */ + while (rl->length && rl[1].vcn <= vcn) + rl++; + lcn = vcn_to_lcn(rl, vcn); + } else + lcn = (LCN)LCN_RL_NOT_MAPPED; + /* Successful remap. */ + if (lcn >= 0) { + /* Setup buffer head to point to correct block. */ + bh->b_blocknr = ((lcn << vol->cluster_size_bits) + + vcn_ofs) >> blocksize_bits; + set_buffer_mapped(bh); + continue; + } + /* It is a hole, need to instantiate it. */ + if (lcn == LCN_HOLE) { + // TODO: Instantiate the hole. + // clear_buffer_new(bh); + // unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); + ntfs_error(vol->sb, "Writing into sparse regions is " + "not supported yet. Sorry."); + err = -EOPNOTSUPP; + break; + } + /* If first try and run list unmapped, map and retry. */ + if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { + is_retry = TRUE; + /* + * Attempt to map run list, dropping lock for + * the duration. + */ + up_read(&ni->run_list.lock); + err = map_run_list(ni, vcn); + if (likely(!err)) + goto lock_retry_remap; + rl = NULL; + } + /* Failed to map the buffer, even after retrying. */ + bh->b_blocknr = -1UL; + ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) failed " + "with error code 0x%Lx%s.", + (long long)vcn, (long long)-lcn, + is_retry ? " even after retrying" : ""); + // FIXME: Depending on vol->on_errors, do something. + if (!err) + err = -EIO; + break; + } while (block++, (bh = bh->b_this_page) != head); + + /* Release the lock if we took it. */ + if (rl) + up_read(&ni->run_list.lock); + + /* For the error case, need to reset bh to the beginning. */ + bh = head; + + /* Just an optimization, so ->readpage() isn't called later. */ + if (unlikely(!PageUptodate(page))) { + int uptodate = 1; + do { + if (!buffer_uptodate(bh)) { + uptodate = 0; + bh = head; + break; + } + } while ((bh = bh->b_this_page) != head); + if (uptodate) + SetPageUptodate(page); + } + + /* Setup all mapped, dirty buffers for async write i/o. */ + do { + get_bh(bh); + if (buffer_mapped(bh) && buffer_dirty(bh)) { + lock_buffer(bh); + if (test_clear_buffer_dirty(bh)) { + BUG_ON(!buffer_uptodate(bh)); + mark_buffer_async_write(bh); + } else + unlock_buffer(bh); + } else if (unlikely(err)) { + /* + * For the error case. The buffer may have been set + * dirty during attachment to a dirty page. + */ + if (err != -ENOMEM) + clear_buffer_dirty(bh); + } + } while ((bh = bh->b_this_page) != head); + + if (unlikely(err)) { + // TODO: Remove the -EOPNOTSUPP check later on... + if (unlikely(err == -EOPNOTSUPP)) + err = 0; + else if (err == -ENOMEM) { + ntfs_warning(vol->sb, "Error allocating memory. " + "Redirtying page so we try again " + "later."); + /* + * Put the page back on mapping->dirty_pages, but + * leave its buffer's dirty state as-is. + */ + // FIXME: Once Andrew's -EAGAIN patch goes in, remove + // the __set_page_dirty_nobuffers(page) and set err to + // -EAGAIN instead of zero. + __set_page_dirty_nobuffers(page); + err = 0; + } else + SetPageError(page); + } + + BUG_ON(PageWriteback(page)); + SetPageWriteback(page); /* Keeps try_to_free_buffers() away. */ + unlock_page(page); + + /* + * Submit the prepared buffers for i/o. Note the page is unlocked, + * and the async write i/o completion handler can end_page_writeback() + * at any time after the *first* submit_bh(). So the buffers can then + * disappear... + */ + need_end_writeback = TRUE; + do { + struct buffer_head *next = bh->b_this_page; + if (buffer_async_write(bh)) { + submit_bh(WRITE, bh); + need_end_writeback = FALSE; + } + put_bh(bh); + bh = next; + } while (bh != head); + + /* If no i/o was started, need to end_page_writeback(). */ + if (unlikely(need_end_writeback)) + end_page_writeback(page); + + ntfs_debug("Done."); + return err; +} + +/** + * ntfs_writepage - write a @page to the backing store + * @page: page cache page to write out + * + * For non-resident attributes, ntfs_writepage() writes the @page by calling + * the ntfs version of the generic block_write_full_page() function, + * ntfs_write_block(), which in turn if necessary creates and writes the + * buffers associated with the page asynchronously. + * + * For resident attributes, OTOH, ntfs_writepage() writes the @page by copying + * the data to the mft record (which at this stage is most likely in memory). + * Thus, in this case, I/O is synchronous, as even if the mft record is not + * cached at this point in time, we need to wait for it to be read in before we + * can do the copy. + * + * Note the caller clears the page dirty flag before calling ntfs_writepage(). + * + * Based on ntfs_readpage() and fs/buffer.c::block_write_full_page(). + * + * Return 0 on success and -errno on error. + */ +static int ntfs_writepage(struct page *page) +{ + s64 attr_pos; + struct inode *vi; + ntfs_inode *ni, *base_ni; + char *kaddr; + attr_search_context *ctx; + MFT_RECORD *m; + u32 attr_len, bytes; + int err; + + BUG_ON(!PageLocked(page)); + + vi = page->mapping->host; + + /* Is the page fully outside i_size? (truncate in progress) */ + if (unlikely(page->index >= (vi->i_size + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT)) { + unlock_page(page); + ntfs_debug("Write outside i_size. Returning i/o error."); + return -EIO; + } + + ni = NTFS_I(vi); + + if (NInoNonResident(ni)) { + /* + * Only unnamed $DATA attributes can be compressed, encrypted, + * and/or sparse. + */ + if (ni->type == AT_DATA && !ni->name_len) { + /* If file is encrypted, deny access, just like NT4. */ + if (NInoEncrypted(ni)) { + unlock_page(page); + ntfs_debug("Denying write access to encrypted " + "file."); + return -EACCES; + } + /* Compressed data streams are handled in compress.c. */ + if (NInoCompressed(ni)) { + // TODO: Implement and replace this check with + // return ntfs_write_compressed_block(page); + unlock_page(page); + ntfs_error(vi->i_sb, "Writing to compressed " + "files is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + // TODO: Implement and remove this check. + if (NInoSparse(ni)) { + unlock_page(page); + ntfs_error(vi->i_sb, "Writing to sparse files " + "is not supported yet. Sorry."); + return -EOPNOTSUPP; + } + } + + /* We have to zero every time due to mmap-at-end-of-file. */ + if (page->index >= (vi->i_size >> PAGE_CACHE_SHIFT)) { + /* The page straddles i_size. */ + unsigned int ofs = vi->i_size & ~PAGE_CACHE_MASK; + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + ofs, 0, PAGE_CACHE_SIZE - ofs); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } + + // TODO: Implement and remove this check. + if (NInoMstProtected(ni)) { + unlock_page(page); + ntfs_error(vi->i_sb, "Writing to MST protected " + "attributes is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + + /* Normal data stream. */ + return ntfs_write_block(page); + } + + /* + * Attribute is resident, implying it is not compressed, encrypted, or + * mst protected. + */ + BUG_ON(page_has_buffers(page)); + BUG_ON(!PageUptodate(page)); + + // TODO: Consider using PageWriteback() + unlock_page() in 2.5 once the + // "VM fiddling has ended". Note, don't forget to replace all the + // unlock_page() calls further below with end_page_writeback() ones. + // FIXME: Make sure it is ok to SetPageError() on unlocked page under + // writeback before doing the change! +#if 0 + SetPageWriteback(page); + unlock_page(page); +#endif + + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->_INE(base_ntfs_ino); + + /* Map, pin, and lock the mft record. */ + m = map_mft_record(base_ni); + if (unlikely(IS_ERR(m))) { + err = PTR_ERR(m); + m = NULL; + ctx = NULL; + goto err_out; + } + ctx = get_attr_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + if (unlikely(!lookup_attr(ni->type, ni->name, ni->name_len, + IGNORE_CASE, 0, NULL, 0, ctx))) { + err = -ENOENT; + goto err_out; + } + + /* Starting position of the page within the attribute value. */ + attr_pos = page->index << PAGE_CACHE_SHIFT; + + /* The total length of the attribute value. */ + attr_len = le32_to_cpu(ctx->attr->_ARA(value_length)); + + if (unlikely(vi->i_size != attr_len)) { + ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match " + "attr_len (0x%x). Aborting write.", vi->i_size, + attr_len); + err = -EIO; + goto err_out; + } + if (unlikely(attr_pos >= attr_len)) { + ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%Lx) > attr_len (0x%x)" + ". Aborting write.", attr_pos, attr_len); + err = -EIO; + goto err_out; + } + + bytes = attr_len - attr_pos; + if (unlikely(bytes > PAGE_CACHE_SIZE)) + bytes = PAGE_CACHE_SIZE; + + /* + * Here, we don't need to zero the out of bounds area everytime because + * the below memcpy() already takes care of the mmap-at-end-of-file + * requirements. If the file is converted to a non-resident one, then + * the code path use is switched to the non-resident one where the + * zeroing happens on each ntfs_writepage() invokation. + * + * The above also applies nicely when i_size is decreased. + * + * When i_size is increased, the memory between the old and new i_size + * _must_ be zeroed (or overwritten with new data). Otherwise we will + * expose data to userspace/disk which should never have been exposed. + * + * FIXME: Ensure that i_size increases do the zeroing/overwriting and + * if we cannot guarantee that, then enable the zeroing below. + */ + + kaddr = kmap_atomic(page, KM_USER0); + /* Copy the data from the page to the mft record. */ + memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->_ARA(value_offset)) + + attr_pos, kaddr, bytes); + flush_dcache_mft_record_page(ctx->ntfs_ino); +#if 0 + /* Zero out of bounds area. */ + if (likely(bytes < PAGE_CACHE_SIZE)) { + memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + flush_dcache_page(page); + } +#endif + kunmap_atomic(kaddr, KM_USER0); + + unlock_page(page); + + // TODO: Mark mft record dirty so it gets written back. + ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. " + "Wrote to memory only..."); + + put_attr_search_ctx(ctx); + unmap_mft_record(base_ni); + return 0; +err_out: + if (err == -ENOMEM) { + ntfs_warning(vi->i_sb, "Error allocating memory. Redirtying " + "page so we try again later."); + /* + * Put the page back on mapping->dirty_pages, but leave its + * buffer's dirty state as-is. + */ + // FIXME: Once Andrew's -EAGAIN patch goes in, remove the + // __set_page_dirty_nobuffers(page) and set err to -EAGAIN + // instead of zero. + __set_page_dirty_nobuffers(page); + err = 0; + } else { + ntfs_error(vi->i_sb, "Resident attribute write failed with " + "error %i. Setting page error flag.", -err); + SetPageError(page); + } + unlock_page(page); + if (ctx) + put_attr_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + return err; +} + +/** + * ntfs_prepare_nonresident_write - + * + */ +static int ntfs_prepare_nonresident_write(struct page *page, + unsigned from, unsigned to) +{ + VCN vcn; + LCN lcn; + sector_t block, ablock, iblock; + struct inode *vi; + ntfs_inode *ni; + ntfs_volume *vol; + run_list_element *rl; + struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; + char *kaddr = page_address(page); + unsigned int vcn_ofs, block_start, block_end, blocksize; + int err; + BOOL is_retry; + unsigned char blocksize_bits; + + vi = page->mapping->host; + ni = NTFS_I(vi); + vol = ni->vol; + + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, + page->index, from, to); + + BUG_ON(!NInoNonResident(ni)); + BUG_ON(NInoMstProtected(ni)); + + blocksize_bits = vi->i_blkbits; + blocksize = 1 << blocksize_bits; + + /* + * create_empty_buffers() will create uptodate/dirty buffers if the + * page is uptodate/dirty. + */ + if (!page_has_buffers(page)) + create_empty_buffers(page, blocksize, 0); + bh = head = page_buffers(page); + if (unlikely(!bh)) + return -ENOMEM; + + /* The first block in the page. */ + block = page->index << (PAGE_CACHE_SHIFT - blocksize_bits); + + /* + * The first out of bounds block for the allocated size. No need to + * round up as allocated_size is in multiples of cluster size and the + * minimum cluster size is 512 bytes, which is equal to the smallest + * blocksize. + */ + ablock = ni->allocated_size >> blocksize_bits; + + /* The last (fully or partially) initialized block. */ + iblock = ni->initialized_size >> blocksize_bits; + + /* Loop through all the buffers in the page. */ + block_start = 0; + rl = NULL; + err = 0; + do { + block_end = block_start + blocksize; + /* + * If buffer @bh is outside the write, just mark it uptodate + * if the page is uptodate and continue with the next buffer. + */ + if (block_end <= from || block_start >= to) { + if (PageUptodate(page)) { + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + } + continue; + } + /* + * @bh is at least partially being written to. + * Make sure it is not marked as new. + */ + //if (buffer_new(bh)) + // clear_buffer_new(bh); + + if (block >= ablock) { + // TODO: block is above allocated_size, need to + // allocate it. Best done in one go to accomodate not + // only block but all above blocks up to and including: + // ((page->index << PAGE_CACHE_SHIFT) + to + blocksize + // - 1) >> blobksize_bits. Obviously will need to round + // up to next cluster boundary, too. This should be + // done with a helper function, so it can be reused. + ntfs_error(vol->sb, "Writing beyond allocated size " + "is not supported yet. Sorry."); + err = -EOPNOTSUPP; + goto err_out; + // Need to update ablock. + // Need to set_buffer_new() on all block bhs that are + // newly allocated. + } + /* + * Now we have enough allocated size to fulfill the whole + * request, i.e. block < ablock is true. + */ + if (unlikely((block >= iblock) && + (ni->initialized_size < vi->i_size))) { + /* + * If this page is fully outside initialized size, zero + * out all pages between the current initialized size + * and the current page. Just use ntfs_readpage() to do + * the zeroing transparently. + */ + if (block > iblock) { + // TODO: + // For each page do: + // - read_cache_page() + // Again for each page do: + // - wait_on_page_locked() + // - Check (PageUptodate(page) && + // !PageError(page)) + // Update initialized size in the attribute and + // in the inode. + // Again, for each page do: + // __set_page_dirty_buffers(); + // page_cache_release() + // We don't need to wait on the writes. + // Update iblock. + } + /* + * The current page straddles initialized size. Zero + * all non-uptodate buffers and set them uptodate (and + * dirty?). Note, there aren't any non-uptodate buffers + * if the page is uptodate. + * FIXME: For an uptodate page, the buffers may need to + * be written out because they were not initialized on + * disk before. + */ + if (!PageUptodate(page)) { + // TODO: + // Zero any non-uptodate buffers up to i_size. + // Set them uptodate and dirty. + } + // TODO: + // Update initialized size in the attribute and in the + // inode (up to i_size). + // Update iblock. + // FIXME: This is inefficient. Try to batch the two + // size changes to happen in one go. + ntfs_error(vol->sb, "Writing beyond initialized size " + "is not supported yet. Sorry."); + err = -EOPNOTSUPP; + goto err_out; + // Do NOT set_buffer_new() BUT DO clear buffer range + // outside write request range. + // set_buffer_uptodate() on complete buffers as well as + // set_buffer_dirty(). + } + + /* Need to map unmapped buffers. */ + if (!buffer_mapped(bh)) { + /* Unmapped buffer. Need to map it. */ + bh->b_bdev = vol->sb->s_bdev; + + /* Convert block into corresponding vcn and offset. */ + vcn = (VCN)block << blocksize_bits >> + vol->cluster_size_bits; + vcn_ofs = ((VCN)block << blocksize_bits) & + vol->cluster_size_mask; + + is_retry = FALSE; + if (!rl) { +lock_retry_remap: + down_read(&ni->run_list.lock); + rl = ni->run_list.rl; + } + if (likely(rl != NULL)) { + /* Seek to element containing target vcn. */ + while (rl->length && rl[1].vcn <= vcn) + rl++; + lcn = vcn_to_lcn(rl, vcn); + } else + lcn = (LCN)LCN_RL_NOT_MAPPED; + if (unlikely(lcn < 0)) { + /* + * We extended the attribute allocation above. + * If we hit an ENOENT here it means that the + * allocation was insufficient which is a bug. + */ + BUG_ON(lcn == LCN_ENOENT); + + /* It is a hole, need to instantiate it. */ + if (lcn == LCN_HOLE) { + // TODO: Instantiate the hole. + // clear_buffer_new(bh); + // unmap_underlying_metadata(bh->b_bdev, + // bh->b_blocknr); + // For non-uptodate buffers, need to + // zero out the region outside the + // request in this bh or all bhs, + // depending on what we implemented + // above. + // Need to flush_dcache_page(). + // Or could use set_buffer_new() + // instead? + ntfs_error(vol->sb, "Writing into " + "sparse regions is " + "not supported yet. " + "Sorry."); + err = -EOPNOTSUPP; + goto err_out; + } else if (!is_retry && + lcn == LCN_RL_NOT_MAPPED) { + is_retry = TRUE; + /* + * Attempt to map run list, dropping + * lock for the duration. + */ + up_read(&ni->run_list.lock); + err = map_run_list(ni, vcn); + if (likely(!err)) + goto lock_retry_remap; + rl = NULL; + } + /* + * Failed to map the buffer, even after + * retrying. + */ + bh->b_blocknr = -1UL; + ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) " + "failed with error code " + "0x%Lx%s.", (long long)vcn, + (long long)-lcn, is_retry ? + " even after retrying" : ""); + // FIXME: Depending on vol->on_errors, do + // something. + if (!err) + err = -EIO; + goto err_out; + } + /* We now have a successful remap, i.e. lcn >= 0. */ + + /* Setup buffer head to correct block. */ + bh->b_blocknr = ((lcn << vol->cluster_size_bits) + + vcn_ofs) >> blocksize_bits; + set_buffer_mapped(bh); + + // FIXME: Something analogous to this is needed for + // each newly allocated block, i.e. BH_New. + // FIXME: Might need to take this out of the + // if (!buffer_mapped(bh)) {}, depending on how we + // implement things during the allocated_size and + // initialized_size extension code above. + if (buffer_new(bh)) { + clear_buffer_new(bh); + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + if (PageUptodate(page)) { + set_buffer_uptodate(bh); + continue; + } + /* + * Page is _not_ uptodate, zero surrounding + * region. NOTE: This is how we decide if to + * zero or not! + */ + if (block_end > to) + memset(kaddr + to, 0, block_end - to); + if (block_start < from) + memset(kaddr + block_start, 0, + from - block_start); + if (block_end > to || block_start < from) + flush_dcache_page(page); + continue; + } + } + /* @bh is mapped, set it uptodate if the page is uptodate. */ + if (PageUptodate(page)) { + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + continue; + } + /* + * The page is not uptodate. The buffer is mapped. If it is not + * uptodate, and it is only partially being written to, we need + * to read the buffer in before the write, i.e. right now. + */ + if (!buffer_uptodate(bh) && + (block_start < from || block_end > to)) { + ll_rw_block(READ, 1, &bh); + *wait_bh++ = bh; + } + } while (block++, block_start = block_end, + (bh = bh->b_this_page) != head); + + /* Release the lock if we took it. */ + if (rl) { + up_read(&ni->run_list.lock); + rl = NULL; + } + + /* If we issued read requests, let them complete. */ + while (wait_bh > wait) { + wait_on_buffer(*--wait_bh); + if (!buffer_uptodate(*wait_bh)) + return -EIO; + } + + ntfs_debug("Done."); + return 0; +err_out: + /* + * Zero out any newly allocated blocks to avoid exposing stale data. + * If BH_New is set, we know that the block was newly allocated in the + * above loop. + * FIXME: What about initialized_size increments? Have we done all the + * required zeroing above? If not this error handling is broken, and + * in particular the if (block_end <= from) check is completely bogus. + */ + bh = head; + block_start = 0; + is_retry = FALSE; + do { + block_end = block_start + blocksize; + if (block_end <= from) + continue; + if (block_start >= to) + break; + if (buffer_new(bh)) { + clear_buffer_new(bh); + if (buffer_uptodate(bh)) + buffer_error(); + memset(kaddr + block_start, 0, bh->b_size); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + is_retry = TRUE; + } + } while (block_start = block_end, (bh = bh->b_this_page) != head); + if (is_retry) + flush_dcache_page(page); + if (rl) + up_read(&ni->run_list.lock); + return err; +} + +/** + * ntfs_prepare_write - prepare a page for receiving data + * + * This is called from generic_file_write() with i_sem held on the inode + * (@page->mapping->host). The @page is locked and kmap()ped so page_address() + * can simply be used. The source data has not yet been copied into the @page. + * + * Need to extend the attribute/fill in holes if necessary, create blocks and + * make partially overwritten blocks uptodate, + * + * i_size is not to be modified yet. + * + * Return 0 on success or -errno on error. + * + * Should be using block_prepare_write() [support for sparse files] or + * cont_prepare_write() [no support for sparse files]. Can't do that due to + * ntfs specifics but can look at them for implementation guidancea. + * + * Note: In the range, @from is inclusive and @to is exclusive, i.e. @from is + * the first byte in the page that will be written to and @to is the first byte + * after the last byte that will be written to. + */ +static int ntfs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *vi = page->mapping->host; + ntfs_inode *ni = NTFS_I(vi); + + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, + page->index, from, to); + + BUG_ON(!PageLocked(page)); + BUG_ON(from > PAGE_CACHE_SIZE); + BUG_ON(to > PAGE_CACHE_SIZE); + BUG_ON(from > to); + + if (NInoNonResident(ni)) { + /* + * Only unnamed $DATA attributes can be compressed, encrypted, + * and/or sparse. + */ + if (ni->type == AT_DATA && !ni->name_len) { + /* If file is encrypted, deny access, just like NT4. */ + if (NInoEncrypted(ni)) { + ntfs_debug("Denying write access to encrypted " + "file."); + return -EACCES; + } + /* Compressed data streams are handled in compress.c. */ + if (NInoCompressed(ni)) { + // TODO: Implement and replace this check with + // return ntfs_write_compressed_block(page); + ntfs_error(vi->i_sb, "Writing to compressed " + "files is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + // TODO: Implement and remove this check. + if (NInoSparse(ni)) { + ntfs_error(vi->i_sb, "Writing to sparse files " + "is not supported yet. Sorry."); + return -EOPNOTSUPP; + } + } + + // TODO: Implement and remove this check. + if (NInoMstProtected(ni)) { + ntfs_error(vi->i_sb, "Writing to MST protected " + "attributes is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + + /* Normal data stream. */ + return ntfs_prepare_nonresident_write(page, from, to); + } + + /* + * Attribute is resident, implying it is not compressed, encrypted, or + * mst protected. + */ + BUG_ON(page_has_buffers(page)); + + /* Do we need to resize the attribute? */ + if (((s64)page->index << PAGE_CACHE_SHIFT) + to > vi->i_size) { + // TODO: Implement resize... + ntfs_error(vi->i_sb, "Writing beyond the existing file size is " + "not supported yet. Sorry."); + return -EOPNOTSUPP; + } + + /* + * Because resident attributes are handled by memcpy() to/from the + * corresponding MFT record, and because this form of i/o is byte + * aligned rather than block aligned, there is no need to bring the + * page uptodate here as in the non-resident case where we need to + * bring the buffers straddled by the write uptodate before + * generic_file_write() does the copying from userspace. + * + * We thus defer the uptodate bringing of the page region outside the + * region written to to ntfs_commit_write(). The reason for doing this + * is that we save one round of: + * map_mft_record(), get_attr_search_ctx(), lookup_attr(), + * kmap_atomic(), kunmap_atomic(), put_attr_search_ctx(), + * unmap_mft_record(). + * Which is obviously a very worthwhile save. + * + * Thus we just return success now... + */ + ntfs_debug("Done."); + return 0; +} + +/* + * NOTES: There is a disparity between the apparent need to extend the + * attribute in prepare write but to update i_size only in commit write. + * Need to make sure i_sem protection is sufficient. And if not will need to + * handle this in some way or another. + */ + +/** + * ntfs_commit_nonresident_write - + * + */ +static int ntfs_commit_nonresident_write(struct page *page, + unsigned from, unsigned to) +{ + s64 pos = ((s64)page->index << PAGE_CACHE_SHIFT) + to; + struct inode *vi; + struct buffer_head *bh, *head; + unsigned int block_start, block_end, blocksize; + BOOL partial; + + vi = page->mapping->host; + + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx, from = %u, to = %u.", vi->i_ino, + NTFS_I(vi)->type, page->index, from, to); + + blocksize = 1 << vi->i_blkbits; + + // FIXME: We need a whole slew of special cases in here for MST + // protected attributes for example. For compressed files, too... + // For now, we know ntfs_prepare_write() would have failed so we can't + // get here in any of the cases which we have to special case, so we + // are just a ripped off unrolled generic_commit_write() at present. + + bh = head = page_buffers(page); + block_start = 0; + partial = FALSE; + do { + block_end = block_start + blocksize; + if (block_end <= from || block_start >= to) { + if (!buffer_uptodate(bh)) + partial = TRUE; + } else { + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + } + } while (block_start = block_end, (bh = bh->b_this_page) != head); + + /* + * If this is a partial write which happened to make all buffers + * uptodate then we can optimize away a bogus ->readpage() for the next + * read(). Here we 'discover' whether the page went uptodate as a + * result of this (potentially partial) write. + */ + if (!partial) + SetPageUptodate(page); + + /* + * Not convinced about this at all. See disparity comment above. For + * now we know ntfs_prepare_write() would have failed in the write + * exceeds i_size case, so this will never trigger which is fine. + */ + if (pos > vi->i_size) { + ntfs_error(vi->i_sb, "Writing beyond the existing file size is " + "not supported yet. Sorry."); + // vi->i_size = pos; + // mark_inode_dirty(vi); + } + ntfs_debug("Done."); + return 0; +} + +/** + * ntfs_commit_write - commit the received data + * + * This is called from generic_file_write() with i_sem held on the inode + * (@page->mapping->host). The @page is locked and kmap()ped so page_address() + * can simply be used. The source data has already been copied into the @page. + * + * Need to mark modified blocks dirty so they get written out later when + * ntfs_writepage() is invoked by the VM. + * + * Return 0 on success or -errno on error. + * + * Should be using generic_commit_write(). This marks buffers uptodate and + * dirty, sets the page uptodate if all buffers in the page are uptodate, and + * updates i_size if the end of io is beyond i_size. In that case, it also + * marks the inode dirty. - We could still use this (obviously except for + * NInoMstProtected() attributes, where we will need to duplicate the core code + * because we need our own async_io completion handler) but we could just do + * the i_size update in prepare write, when we resize the attribute. Then + * we would avoid the i_size update and mark_inode_dirty() happening here. + * + * Can't use generic_commit_write() due to ntfs specialities but can look at + * it for implementation guidance. + * + * If things have gone as outlined in ntfs_prepare_write(), then we do not + * need to do any page content modifications here at all, except in the write + * to resident attribute case, where we need to do the uptodate bringing here + * which we combine with the copying into the mft record which means we only + * need to map the mft record and find the attribute record in it only once. + */ +static int ntfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + s64 attr_pos; + struct inode *vi; + ntfs_inode *ni, *base_ni; + char *kaddr, *kattr; + attr_search_context *ctx; + MFT_RECORD *m; + u32 attr_len, bytes; + int err; + + vi = page->mapping->host; + ni = NTFS_I(vi); + + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, + page->index, from, to); + + if (NInoNonResident(ni)) { + /* + * Only unnamed $DATA attributes can be compressed, encrypted, + * and/or sparse. + */ + if (ni->type == AT_DATA && !ni->name_len) { + /* If file is encrypted, deny access, just like NT4. */ + if (NInoEncrypted(ni)) { + // Should never get here! + ntfs_debug("Denying write access to encrypted " + "file."); + return -EACCES; + } + /* Compressed data streams are handled in compress.c. */ + if (NInoCompressed(ni)) { + // TODO: Implement and replace this check with + // return ntfs_write_compressed_block(page); + // Should never get here! + ntfs_error(vi->i_sb, "Writing to compressed " + "files is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + // TODO: Implement and remove this check. + if (NInoSparse(ni)) { + // Should never get here! + ntfs_error(vi->i_sb, "Writing to sparse files " + "is not supported yet. Sorry."); + return -EOPNOTSUPP; + } + } + + // TODO: Implement and remove this check. + if (NInoMstProtected(ni)) { + // Should never get here! + ntfs_error(vi->i_sb, "Writing to MST protected " + "attributes is not supported yet. " + "Sorry."); + return -EOPNOTSUPP; + } + + /* Normal data stream. */ + return ntfs_commit_nonresident_write(page, from, to); + } + + /* + * Attribute is resident, implying it is not compressed, encrypted, or + * mst protected. + */ + + /* Do we need to resize the attribute? */ + if (((s64)page->index << PAGE_CACHE_SHIFT) + to > vi->i_size) { + // TODO: Implement resize... + // pos = ((s64)page->index << PAGE_CACHE_SHIFT) + to; + // vi->i_size = pos; + // mark_inode_dirty(vi); + // Should never get here! + ntfs_error(vi->i_sb, "Writing beyond the existing file size is " + "not supported yet. Sorry."); + return -EOPNOTSUPP; + } + + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->_INE(base_ntfs_ino); + + /* Map, pin, and lock the mft record. */ + m = map_mft_record(base_ni); + if (unlikely(IS_ERR(m))) { + err = PTR_ERR(m); + m = NULL; + ctx = NULL; + goto err_out; + } + ctx = get_attr_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + if (unlikely(!lookup_attr(ni->type, ni->name, ni->name_len, + IGNORE_CASE, 0, NULL, 0, ctx))) { + err = -ENOENT; + goto err_out; + } + + /* Starting position of the page within the attribute value. */ + attr_pos = page->index << PAGE_CACHE_SHIFT; + + /* The total length of the attribute value. */ + attr_len = le32_to_cpu(ctx->attr->_ARA(value_length)); + + if (unlikely(vi->i_size != attr_len)) { + ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match " + "attr_len (0x%x). Aborting write.", vi->i_size, + attr_len); + err = -EIO; + goto err_out; + } + if (unlikely(attr_pos >= attr_len)) { + ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%Lx) > attr_len (0x%x)" + ". Aborting write.", attr_pos, attr_len); + err = -EIO; + goto err_out; + } + + bytes = attr_len - attr_pos; + if (unlikely(bytes > PAGE_CACHE_SIZE)) + bytes = PAGE_CACHE_SIZE; + + /* + * Calculate the address of the attribute value corresponding to the + * beginning of the current data @page. + */ + kattr = (u8*)ctx->attr + le16_to_cpu(ctx->attr->_ARA(value_offset)) + + attr_pos; + + kaddr = kmap_atomic(page, KM_USER0); + + /* Copy the received data from the page to the mft record. */ + memcpy(kattr + from, kaddr + from, to - from); + flush_dcache_mft_record_page(ctx->ntfs_ino); + + if (!PageUptodate(page)) { + /* + * Bring the out of bounds area(s) uptodate by copying data + * from the mft record to the page. + */ + if (from > 0) + memcpy(kaddr, kattr, from); + if (to < bytes) + memcpy(kaddr + to, kattr + to, bytes - to); + + /* Zero the region outside the end of the attribute value. */ + if (likely(bytes < PAGE_CACHE_SIZE)) + memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + + /* + * The probability of not having done any of the above is + * extremely small, so we just flush unconditionally. + */ + flush_dcache_page(page); + SetPageUptodate(page); + } + kunmap_atomic(kaddr, KM_USER0); + + // TODO: Mark mft record dirty so it gets written back. + ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. " + "Wrote to memory only..."); + + put_attr_search_ctx(ctx); + unmap_mft_record(base_ni); + ntfs_debug("Done."); + return 0; +err_out: + if (err == -ENOMEM) { + ntfs_warning(vi->i_sb, "Error allocating memory required to " + "commit the write."); + if (PageUptodate(page)) { + ntfs_warning(vi->i_sb, "Page is uptodate, setting " + "dirty so the write will be retried " + "later on by the VM."); + /* + * Put the page on mapping->dirty_pages, but leave its + * buffer's dirty state as-is. + */ + __set_page_dirty_nobuffers(page); + err = 0; + } else + ntfs_error(vi->i_sb, "Page is not uptodate. Written " + "data has been lost. )-:"); + } else { + ntfs_error(vi->i_sb, "Resident attribute write failed with " + "error %i. Setting page error flag.", -err); + SetPageError(page); + } + if (ctx) + put_attr_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + return err; +} + +#endif /* NTFS_RW */ + /** * ntfs_aops - general address space operations for inodes and attributes */ @@ -442,5 +1773,11 @@ .readpage = ntfs_readpage, /* Fill page with data. */ .sync_page = block_sync_page, /* Currently, just unplugs the disk request queue. */ +#ifdef NTFS_RW + .writepage = ntfs_writepage, /* Write dirty page to disk. */ + .prepare_write = ntfs_prepare_write, /* Prepare page and buffers + ready to receive data. */ + .commit_write = ntfs_commit_write, /* Commit received data. */ +#endif }; diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c --- a/fs/ntfs/attrib.c Sat Aug 31 15:06:06 2002 +++ b/fs/ntfs/attrib.c Sat Aug 31 15:06:06 2002 @@ -1182,8 +1182,9 @@ else { register int rc; - rc = memcmp(val, (u8*)a +le16_to_cpu(a->_ARA(value_offset)), - min(val_len, le32_to_cpu(a->_ARA(value_length)))); + rc = memcmp(val, (u8*)a + le16_to_cpu( + a->_ARA(value_offset)), min(val_len, + le32_to_cpu(a->_ARA(value_length)))); /* * If @val collates before the current attribute's * value, there is no matching attribute. @@ -1676,7 +1677,7 @@ return; } /* Attribute list. */ if (ctx->ntfs_ino != ctx->base_ntfs_ino) - unmap_mft_record(ctx->ntfs_ino); + unmap_extent_mft_record(ctx->ntfs_ino); init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); return; } @@ -1709,7 +1710,7 @@ void put_attr_search_ctx(attr_search_context *ctx) { if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino) - unmap_mft_record(ctx->ntfs_ino); + unmap_extent_mft_record(ctx->ntfs_ino); kmem_cache_free(ntfs_attr_ctx_cache, ctx); return; } diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c --- a/fs/ntfs/compress.c Sat Aug 31 15:06:00 2002 +++ b/fs/ntfs/compress.c Sat Aug 31 15:06:00 2002 @@ -609,18 +609,18 @@ if (buffer_uptodate(tbh)) continue; wait_on_buffer(tbh); - /* + /* * We need an optimization barrier here, otherwise we start * hitting the below fixup code when accessing a loopback * mounted ntfs partition. This indicates either there is a * race condition in the loop driver or, more likely, gcc - * overoptimises the code without the barrier and it doesn't + * overoptimises the code without the barrier and it doesn't * do the Right Thing(TM). - */ + */ barrier(); if (unlikely(!buffer_uptodate(tbh))) { ntfs_warning(vol->sb, "Buffer is unlocked but not " - "uptodate! Unplugging the disk queue " + "uptodate! Unplugging the disk queue " "and rescheduling."); get_bh(tbh); blk_run_queues(); diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c --- a/fs/ntfs/dir.c Sat Aug 31 15:05:59 2002 +++ b/fs/ntfs/dir.c Sat Aug 31 15:05:59 2002 @@ -1048,9 +1048,7 @@ /* * VFS calls readdir without BKL but with i_sem held. This protects the VFS * parts (e.g. ->f_pos and ->i_size, and it also protects against directory - * modifications). Together with the rw semaphore taken by the call to - * map_mft_record(), the directory is truly locked down so we have a race free - * ntfs_readdir() without the BKL. (-: + * modifications). * * We use the same basic approach as the old NTFS driver, i.e. we parse the * index root entries and then the index allocation entries that are marked @@ -1181,7 +1179,7 @@ */ put_attr_search_ctx(ctx); unmap_mft_record(ndir); - m = NULL; + m = NULL; ctx = NULL; /* If there is no index allocation attribute we are finished. */ if (!NInoIndexAllocPresent(ndir)) diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c --- a/fs/ntfs/file.c Sat Aug 31 15:06:06 2002 +++ b/fs/ntfs/file.c Sat Aug 31 15:06:06 2002 @@ -51,6 +51,9 @@ struct file_operations ntfs_file_ops = { .llseek = generic_file_llseek, /* Seek inside file. */ .read = generic_file_read, /* Read from file. */ +#ifdef NTFS_RW + .write = generic_file_write, /* Write to a file. */ +#endif .mmap = generic_file_mmap, /* Mmap file. */ .sendfile = generic_file_sendfile,/* Zero-copy data send with the data source being on the @@ -60,7 +63,12 @@ .open = ntfs_file_open, /* Open file. */ }; -struct inode_operations ntfs_file_inode_ops = {}; +struct inode_operations ntfs_file_inode_ops = { +#ifdef NTFS_RW + .truncate = ntfs_truncate, + .setattr = ntfs_setattr, +#endif +}; struct file_operations ntfs_empty_file_ops = {}; diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c Sat Aug 31 15:05:59 2002 +++ b/fs/ntfs/inode.c Sat Aug 31 15:05:59 2002 @@ -21,6 +21,8 @@ #include #include +#include +#include #include "ntfs.h" #include "dir.h" @@ -844,7 +846,7 @@ ctx->attr->_ANR(allocated_size)); /* * We are done with the mft record, so we release it. Otherwise - * + * we would deadlock in ntfs_attr_iget(). */ put_attr_search_ctx(ctx); unmap_mft_record(ni); @@ -1925,4 +1927,97 @@ seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier); return 0; } + +#ifdef NTFS_RW + +/** + * ntfs_truncate - called when the i_size of an ntfs inode is changed + * @vi: inode for which the i_size was changed + * + * We don't support i_size changes yet. + * + * Called with ->i_sem held. + */ +void ntfs_truncate(struct inode *vi) +{ + // TODO: Implement... + ntfs_warning(vi->i_sb, "Eeek: i_size may have changed! If you see " + "this right after a message from " + "ntfs_{prepare,commit}_{,nonresident_}write() then " + "just ignore it. Otherwise it is bad news."); + // TODO: reset i_size now! + return; +} + +/** + * ntfs_setattr - called from notify_change() when an attribute is being changed + * @dentry: dentry whose attributes to change + * @attr: structure describing the attributes and the changes + * + * We have to trap VFS attempts to truncate the file described by @dentry as + * soon as possible, because we do not implement changes in i_size yet. So we + * abort all i_size changes here. + * + * Called with ->i_sem held. + * + * Basically this is a copy of generic notify_change() and inode_setattr() + * functionality, except we intercept and abort changes in i_size. + */ +int ntfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *vi; + int err; + unsigned int ia_valid = attr->ia_valid; + + vi = dentry->d_inode; + + err = inode_change_ok(vi, attr); + if (err) + return err; + + if ((ia_valid & ATTR_UID && attr->ia_uid != vi->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != vi->i_gid)) { + err = DQUOT_TRANSFER(vi, attr) ? -EDQUOT : 0; + if (err) + return err; + } + + lock_kernel(); + + if (ia_valid & ATTR_SIZE) { + ntfs_error(vi->i_sb, "Changes in i_size are not supported " + "yet. Sorry."); + // TODO: Implement... + // err = vmtruncate(vi, attr->ia_size); + err = -EOPNOTSUPP; + if (err) + goto trunc_err; + } + + if (ia_valid & ATTR_UID) + vi->i_uid = attr->ia_uid; + if (ia_valid & ATTR_GID) + vi->i_gid = attr->ia_gid; + if (ia_valid & ATTR_ATIME) + vi->i_atime = attr->ia_atime; + if (ia_valid & ATTR_MTIME) + vi->i_mtime = attr->ia_mtime; + if (ia_valid & ATTR_CTIME) + vi->i_ctime = attr->ia_ctime; + if (ia_valid & ATTR_MODE) { + vi->i_mode = attr->ia_mode; + if (!in_group_p(vi->i_gid) && + !capable(CAP_FSETID)) + vi->i_mode &= ~S_ISGID; + } + mark_inode_dirty(vi); + +trunc_err: + + unlock_kernel(); + + return err; +} + +#endif diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h --- a/fs/ntfs/inode.h Sat Aug 31 15:06:06 2002 +++ b/fs/ntfs/inode.h Sat Aug 31 15:06:06 2002 @@ -36,8 +36,8 @@ * fields already provided in the VFS inode. */ struct _ntfs_inode { - s64 initialized_size; /* Copy from $DATA/$INDEX_ALLOCATION. */ - s64 allocated_size; /* Copy from $DATA/$INDEX_ALLOCATION. */ + s64 initialized_size; /* Copy from the attribute record. */ + s64 allocated_size; /* Copy from the attribute record. */ unsigned long state; /* NTFS specific flags describing this inode. See ntfs_inode_state_bits below. */ unsigned long mft_no; /* Number of the mft record / inode. */ @@ -244,6 +244,14 @@ extern void ntfs_put_inode(struct inode *vi); extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt); + +#ifdef NTFS_RW + +extern void ntfs_truncate(struct inode *vi); + +extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr); + +#endif #endif /* _LINUX_NTFS_FS_INODE_H */ diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c --- a/fs/ntfs/mft.c Sat Aug 31 15:05:54 2002 +++ b/fs/ntfs/mft.c Sat Aug 31 15:05:54 2002 @@ -98,7 +98,7 @@ } /** - * From fs/ntfs/aops.c + * ntfs_readpage - external declaration, function is in fs/ntfs/aops.c */ extern int ntfs_readpage(struct file *, struct page *); @@ -109,12 +109,9 @@ * ntfs_map_page() in map_mft_record_page(). */ struct address_space_operations ntfs_mft_aops = { - .writepage = NULL, /* Write dirty page to disk. */ .readpage = ntfs_readpage, /* Fill page with data. */ .sync_page = block_sync_page, /* Currently, just unplugs the disk request queue. */ - .prepare_write = NULL, /* . */ - .commit_write = NULL, /* . */ }; /** @@ -176,8 +173,8 @@ * First, take the mrec_lock semaphore. We might now be sleeping, while waiting * for the semaphore if it was already locked by someone else. * - * The page of the record is first mapped using map_mft_record_page() before - * being returned to the caller. + * The page of the record is mapped using map_mft_record_page() before being + * returned to the caller. * * This in turn uses ntfs_map_page() to get the page containing the wanted mft * record (it in turn calls read_cache_page() which reads it in from disk if diff -Nru a/fs/ntfs/mft.h b/fs/ntfs/mft.h --- a/fs/ntfs/mft.h Sat Aug 31 15:05:55 2002 +++ b/fs/ntfs/mft.h Sat Aug 31 15:05:55 2002 @@ -43,5 +43,19 @@ return; } +/* + * flush_dcache_mft_record_page - flush_dcache_page() for mft records + * @ni: ntfs inode structure of mft record + * + * Call flush_dcache_page() for the page in which an mft record resides. + * + * This must be called every time an mft record is modified, just after the + * modification. + */ +static inline void flush_dcache_mft_record_page(ntfs_inode *ni) +{ + flush_dcache_page(ni->page); +} + #endif /* _LINUX_NTFS_MFT_H */ diff -Nru a/fs/ntfs/namei.c b/fs/ntfs/namei.c --- a/fs/ntfs/namei.c Sat Aug 31 15:06:06 2002 +++ b/fs/ntfs/namei.c Sat Aug 31 15:06:06 2002 @@ -139,8 +139,8 @@ dent_inode = ERR_PTR(-EIO); } else ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with " - "error code %li.", dent_ino, - PTR_ERR(dent_inode)); + "error code %li.", dent_ino, + PTR_ERR(dent_inode)); if (name) kfree(name); /* Return the error code. */ diff -Nru a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c --- a/fs/openpromfs/inode.c Sat Aug 31 15:06:00 2002 +++ b/fs/openpromfs/inode.c Sat Aug 31 15:06:00 2002 @@ -77,7 +77,8 @@ return 0; if (count > 9 - file->f_pos) count = 9 - file->f_pos; - copy_to_user(buf, buffer + file->f_pos, count); + if (copy_to_user(buf, buffer + file->f_pos, count)) + return -EFAULT; file->f_pos += count; return count; } @@ -93,7 +94,7 @@ openprom_property *op; char buffer[64]; - if (filp->f_pos >= 0xffffff) + if (filp->f_pos >= 0xffffff || count >= 0xffffff) return -EINVAL; if (!filp->private_data) { node = nodes[(u16)((long)inode->u.generic_ip)].node; @@ -184,7 +185,8 @@ if (count > i - k) count = i - k; if (op->flag & OPP_STRING) { if (!k) { - __put_user('\'', buf); + if (put_user('\'', buf)) + return -EFAULT; k++; count--; } @@ -195,17 +197,21 @@ j = count; if (j >= 0) { - copy_to_user(buf + k - filp->f_pos, - op->value + k - 1, j); + if (copy_to_user(buf + k - filp->f_pos, + op->value + k - 1, j)) + return -EFAULT; count -= j; k += j; } - if (count) - __put_user('\'', &buf [k++ - filp->f_pos]); - if (count > 1) - __put_user('\n', &buf [k++ - filp->f_pos]); - + if (count) { + if (put_user('\'', &buf [k++ - filp->f_pos])) + return -EFAULT; + } + if (count > 1) { + if (put_user('\n', &buf [k++ - filp->f_pos])) + return -EFAULT; + } } else if (op->flag & OPP_STRINGLIST) { char *tmp; @@ -225,7 +231,8 @@ } strcpy(s, "'\n"); - copy_to_user(buf, tmp + k, count); + if (copy_to_user(buf, tmp + k, count)) + return -EFAULT; kfree(tmp); k += count; @@ -243,53 +250,68 @@ if (first == last) { sprintf (buffer, "%08x.", *first); - copy_to_user (buf, buffer + first_off, last_cnt - first_off); + if (copy_to_user(buf, buffer + first_off, + last_cnt - first_off)) + return -EFAULT; buf += last_cnt - first_off; } else { for (q = first; q <= last; q++) { sprintf (buffer, "%08x.", *q); if (q == first) { - copy_to_user (buf, buffer + first_off, - 9 - first_off); + if (copy_to_user(buf, buffer + first_off, + 9 - first_off)) + return -EFAULT; buf += 9 - first_off; } else if (q == last) { - copy_to_user (buf, buffer, last_cnt); + if (copy_to_user(buf, buffer, last_cnt)) + return -EFAULT; buf += last_cnt; } else { - copy_to_user (buf, buffer, 9); + if (copy_to_user(buf, buffer, 9)) + return -EFAULT; buf += 9; } } } - if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9) - __put_user('\n', (buf - 1)); + if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9) { + if (put_user('\n', (buf - 1))) + return -EFAULT; + } k += count; } else if (op->flag & OPP_HEXSTRING) { - char buffer[2]; + char buffer[3]; if ((k < i - 1) && (k & 1)) { - sprintf (buffer, "%02x", *(op->value + (k >> 1))); - __put_user(buffer[1], &buf[k++ - filp->f_pos]); + sprintf (buffer, "%02x", + (unsigned char) *(op->value + (k >> 1)) & 0xff); + if (put_user(buffer[1], &buf[k++ - filp->f_pos])) + return -EFAULT; count--; } for (; (count > 1) && (k < i - 1); k += 2) { - sprintf (buffer, "%02x", *(op->value + (k >> 1))); - copy_to_user (buf + k - filp->f_pos, buffer, 2); + sprintf (buffer, "%02x", + (unsigned char) *(op->value + (k >> 1)) & 0xff); + if (copy_to_user(buf + k - filp->f_pos, buffer, 2)) + return -EFAULT; count -= 2; } if (count && (k < i - 1)) { - sprintf (buffer, "%02x", *(op->value + (k >> 1))); - __put_user(buffer[0], &buf[k++ - filp->f_pos]); + sprintf (buffer, "%02x", + (unsigned char) *(op->value + (k >> 1)) & 0xff); + if (put_user(buffer[0], &buf[k++ - filp->f_pos])) + return -EFAULT; count--; } - if (count) - __put_user('\n', &buf [k++ - filp->f_pos]); + if (count) { + if (put_user('\n', &buf [k++ - filp->f_pos])) + return -EFAULT; + } } count = k - filp->f_pos; filp->f_pos = k; @@ -305,7 +327,7 @@ void *b; openprom_property *op; - if (filp->f_pos >= 0xffffff) + if (filp->f_pos >= 0xffffff || count >= 0xffffff) return -EINVAL; if (!filp->private_data) { i = property_read (filp, NULL, 0, 0); @@ -326,7 +348,8 @@ if (j == 9) j = 0; if (!j) { char ctmp; - __get_user(ctmp, &buf[i]); + if (get_user(ctmp, &buf[i])) + return -EFAULT; if (ctmp != '.') { if (ctmp != '\n') { if (op->flag & OPP_BINARY) @@ -341,7 +364,8 @@ } } else { char ctmp; - __get_user(ctmp, &buf[i]); + if (get_user(ctmp, &buf[i])) + return -EFAULT; if (ctmp < '0' || (ctmp > '9' && ctmp < 'A') || (ctmp > 'F' && ctmp < 'a') || @@ -379,8 +403,10 @@ last_cnt = (k + count) % 9; if (first + 1 == last) { memset (tmp, '0', 8); - copy_from_user (tmp + first_off, buf, - (count + first_off > 8) ? 8 - first_off : count); + if (copy_from_user(tmp + first_off, buf, + (count + first_off > 8) ? + 8 - first_off : count)) + return -EFAULT; mask = 0xffffffff; mask2 = 0xffffffff; for (j = 0; j < first_off; j++) @@ -399,8 +425,10 @@ if (q == first) { if (first_off < 8) { memset (tmp, '0', 8); - copy_from_user (tmp + first_off, buf, - 8 - first_off); + if (copy_from_user(tmp + first_off, + buf, + 8 - first_off)) + return -EFAULT; mask = 0xffffffff; for (j = 0; j < first_off; j++) mask >>= 1; @@ -411,7 +439,8 @@ } else if ((q == last - 1) && last_cnt && (last_cnt < 8)) { memset (tmp, '0', 8); - copy_from_user (tmp, buf, last_cnt); + if (copy_from_user(tmp, buf, last_cnt)) + return -EFAULT; mask = 0xffffffff; for (j = 0; j < 8 - last_cnt; j++) mask <<= 1; @@ -421,7 +450,8 @@ } else { char tchars[17]; /* XXX yuck... */ - copy_from_user(tchars, buf, 16); + if (copy_from_user(tchars, buf, 16)) + return -EFAULT; *q = simple_strtoul (tchars, 0, 16); buf += 9; } @@ -444,7 +474,8 @@ */ if (k > 0) return -EINVAL; - __get_user(ctmp, buf); + if (get_user(ctmp, buf)) + return -EFAULT; if (ctmp == '\'') { op->flag |= OPP_QUOTED; buf++; @@ -476,7 +507,8 @@ kfree (b); } p = op->value + filp->f_pos - ((op->flag & OPP_QUOTED) ? 1 : 0); - copy_from_user (p, buf, count); + if (copy_from_user(p, buf, count)) + return -EFAULT; op->flag |= OPP_DIRTY; for (i = 0; i < count; i++, p++) if (*p == '\n') { diff -Nru a/fs/partitions/efi.h b/fs/partitions/efi.h --- a/fs/partitions/efi.h Sat Aug 31 15:05:54 2002 +++ b/fs/partitions/efi.h Sat Aug 31 15:05:54 2002 @@ -33,11 +33,7 @@ #include #include #include -/* - * Yes, specifying asm-ia64 is ugly, but this lets it build on - * other platforms too, until efi.h moves to include/linux. - */ -#include +#include #define MSDOS_MBR_SIGNATURE 0xaa55 #define EFI_PMBR_OSTYPE_EFI 0xEF diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Sat Aug 31 15:05:54 2002 +++ b/fs/proc/proc_misc.c Sat Aug 31 15:05:54 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,8 @@ #include #include #include - +#include +#include #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) @@ -134,8 +136,20 @@ struct sysinfo i; int len, committed; struct page_state ps; + int cpu; + unsigned long inactive; + unsigned long active; + unsigned long flushes = 0; + unsigned long non_flushes = 0; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + flushes += mmu_gathers[cpu].flushes; + non_flushes += mmu_gathers[cpu].avoided_flushes; + } get_page_state(&ps); + get_zone_counts(&active, &inactive); + /* * display in kilobytes. */ @@ -165,14 +179,16 @@ "Writeback: %8lu kB\n" "Committed_AS: %8u kB\n" "PageTables: %8lu kB\n" - "ReverseMaps: %8lu\n", + "ReverseMaps: %8lu\n" + "TLB flushes: %8lu\n" + "non flushes: %8lu\n", K(i.totalram), K(i.freeram), K(i.sharedram), K(ps.nr_pagecache-swapper_space.nrpages), K(swapper_space.nrpages), - K(ps.nr_active), - K(ps.nr_inactive), + K(active), + K(inactive), K(i.totalhigh), K(i.freehigh), K(i.totalram-i.totalhigh), @@ -183,7 +199,9 @@ K(ps.nr_writeback), K(committed), K(ps.nr_page_table_pages), - ps.nr_reverse_maps + ps.nr_reverse_maps, + flushes, + non_flushes ); return proc_calc_metrics(page, start, off, count, eof, len); diff -Nru a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c --- a/fs/reiserfs/fix_node.c Sat Aug 31 15:05:57 2002 +++ b/fs/reiserfs/fix_node.c Sat Aug 31 15:05:57 2002 @@ -2042,7 +2042,7 @@ /* getting memory with GFP_KERNEL priority may involve balancing now (due to indirect_to_direct conversion on dcache shrinking). So, release path and collected - resourses here */ + resources here */ free_buffers_in_tb (tb); buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb); if ( !buf ) { diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c --- a/fs/romfs/inode.c Sat Aug 31 15:06:03 2002 +++ b/fs/romfs/inode.c Sat Aug 31 15:06:03 2002 @@ -144,7 +144,7 @@ } s->s_magic = ROMFS_MAGIC; - s->u.generic_sbp = (void *)sz; + s->u.generic_sbp = (void *)(long)sz; s->s_flags |= MS_RDONLY; diff -Nru a/fs/smbfs/file.c b/fs/smbfs/file.c --- a/fs/smbfs/file.c Sat Aug 31 15:06:06 2002 +++ b/fs/smbfs/file.c Sat Aug 31 15:06:06 2002 @@ -352,7 +352,6 @@ /* We must flush any dirty pages now as we won't be able to write anything after close. mmap can trigger this. "openers" should perhaps include mmap'ers ... */ - filemap_fdatawait(inode->i_mapping); filemap_fdatawrite(inode->i_mapping); filemap_fdatawait(inode->i_mapping); smb_close(inode); diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c --- a/fs/smbfs/inode.c Sat Aug 31 15:05:54 2002 +++ b/fs/smbfs/inode.c Sat Aug 31 15:05:54 2002 @@ -650,7 +650,6 @@ DENTRY_PATH(dentry), (long) inode->i_size, (long) attr->ia_size); - filemap_fdatawait(inode->i_mapping); filemap_fdatawrite(inode->i_mapping); filemap_fdatawait(inode->i_mapping); diff -Nru a/fs/udf/inode.c b/fs/udf/inode.c --- a/fs/udf/inode.c Sat Aug 31 15:06:06 2002 +++ b/fs/udf/inode.c Sat Aug 31 15:06:06 2002 @@ -208,7 +208,8 @@ mark_buffer_dirty_inode(bh, inode); udf_release_data(bh); - inode->i_data.a_ops->writepage(page); + if (inode->i_data.a_ops->writepage(page) == -EAGAIN) + __set_page_dirty_nobuffers(page); page_cache_release(page); mark_inode_dirty(inode); diff -Nru a/include/asm-alpha/cache.h b/include/asm-alpha/cache.h --- a/include/asm-alpha/cache.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-alpha/cache.h Sat Aug 31 15:05:59 2002 @@ -20,5 +20,6 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_SHIFT_MAX 6 /* largest L1 which this arch supports */ #endif diff -Nru a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h --- a/include/asm-alpha/mmzone.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-alpha/mmzone.h Sat Aug 31 15:05:59 2002 @@ -86,7 +86,7 @@ /* * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory - * and returns the the mem_map of that node. + * and returns the mem_map of that node. */ #define ADDR_TO_MAPBASE(kaddr) \ NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) diff -Nru a/include/asm-alpha/tlb.h b/include/asm-alpha/tlb.h --- a/include/asm-alpha/tlb.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-alpha/tlb.h Sat Aug 31 15:05:59 2002 @@ -3,13 +3,13 @@ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0) #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) #include -#define pte_free_tlb(tlb,pte) pte_free(pte) -#define pmd_free_tlb(tlb,pmd) pmd_free(pmd) +#define __pte_free_tlb(tlb,pte) pte_free(pte) +#define __pmd_free_tlb(tlb,pmd) pmd_free(pmd) #endif diff -Nru a/include/asm-arm/cache.h b/include/asm-arm/cache.h --- a/include/asm-arm/cache.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-arm/cache.h Sat Aug 31 15:06:06 2002 @@ -16,4 +16,6 @@ __section__(".data.cacheline_aligned"))) #endif +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ + #endif diff -Nru a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h --- a/include/asm-arm/tlb.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-arm/tlb.h Sat Aug 31 15:05:54 2002 @@ -11,11 +11,11 @@ #define tlb_end_vma(tlb,vma) \ flush_tlb_range(vma, vma->vm_start, vma->vm_end) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) #include -#define pmd_free_tlb(tlb, pmd) pmd_free(pmd) -#define pte_free_tlb(tlb, pte) pte_free(pte) +#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) +#define __pte_free_tlb(tlb, pte) pte_free(pte) #endif diff -Nru a/include/asm-cris/cache.h b/include/asm-cris/cache.h --- a/include/asm-cris/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-cris/cache.h Sat Aug 31 15:05:54 2002 @@ -7,4 +7,6 @@ #define L1_CACHE_BYTES 32 +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ + #endif /* _ASM_CACHE_H */ diff -Nru a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h --- a/include/asm-generic/tlb.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-generic/tlb.h Sat Aug 31 15:05:53 2002 @@ -36,9 +36,12 @@ typedef struct free_pte_ctx { struct mm_struct *mm; unsigned int nr; /* set to ~0U means fast mode */ + unsigned int need_flush;/* Really unmapped some ptes? */ unsigned int fullmm; /* non-zero means full mm flush */ unsigned long freed; struct page * pages[FREE_PTE_NR]; + unsigned long flushes;/* stats: count avoided flushes */ + unsigned long avoided_flushes; } mmu_gather_t; /* Users of the generic TLB shootdown code must declare this storage space. */ @@ -66,13 +69,18 @@ { unsigned long nr; + if (!tlb->need_flush) { + tlb->avoided_flushes++; + return; + } + tlb->need_flush = 0; + tlb->flushes++; + tlb_flush(tlb); nr = tlb->nr; if (!tlb_fast_mode(tlb)) { - unsigned long i; + free_pages_and_swap_cache(tlb->pages, tlb->nr); tlb->nr = 0; - for (i=0; i < nr; i++) - free_page_and_swap_cache(tlb->pages[i]); } } @@ -103,6 +111,7 @@ */ static inline void tlb_remove_page(mmu_gather_t *tlb, struct page *page) { + tlb->need_flush = 1; if (tlb_fast_mode(tlb)) { free_page_and_swap_cache(page); return; @@ -112,5 +121,29 @@ tlb_flush_mmu(tlb, 0, 0); } -#endif /* _ASM_GENERIC__TLB_H */ +/** + * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. + * + * Record the fact that pte's were really umapped in ->need_flush, so we can + * later optimise away the tlb invalidate. This helps when userspace is + * unmapping already-unmapped pages, which happens quite a lot. + */ +#define tlb_remove_tlb_entry(tlb, ptep, address) \ + do { \ + tlb->need_flush = 1; \ + __tlb_remove_tlb_entry(tlb, ptep, address); \ + } while (0) + +#define pte_free_tlb(tlb, ptep) \ + do { \ + tlb->need_flush = 1; \ + __pte_free_tlb(tlb, ptep); \ + } while (0) + +#define pmd_free_tlb(tlb, pmdp) \ + do { \ + tlb->need_flush = 1; \ + __pmd_free_tlb(tlb, pmdp); \ + } while (0) +#endif /* _ASM_GENERIC__TLB_H */ diff -Nru a/include/asm-i386/cache.h b/include/asm-i386/cache.h --- a/include/asm-i386/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-i386/cache.h Sat Aug 31 15:05:54 2002 @@ -10,4 +10,6 @@ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ + #endif diff -Nru a/include/asm-i386/desc.h b/include/asm-i386/desc.h --- a/include/asm-i386/desc.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-i386/desc.h Sat Aug 31 15:05:53 2002 @@ -86,14 +86,17 @@ static inline void clear_LDT(void) { - set_ldt_desc(smp_processor_id(), &default_ldt[0], 5); + int cpu = get_cpu(); + + set_ldt_desc(cpu, &default_ldt[0], 5); load_LDT_desc(); + put_cpu(); } /* * load one particular LDT into the current CPU */ -static inline void load_LDT (mm_context_t *pc) +static inline void load_LDT_nolock(mm_context_t *pc, int cpu) { void *segments = pc->ldt; int count = pc->size; @@ -103,8 +106,15 @@ count = 5; } - set_ldt_desc(smp_processor_id(), segments, count); + set_ldt_desc(cpu, segments, count); load_LDT_desc(); +} + +static inline void load_LDT(mm_context_t *pc) +{ + int cpu = get_cpu(); + load_LDT_nolock(pc, cpu); + put_cpu(); } #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-i386/mmu.h b/include/asm-i386/mmu.h --- a/include/asm-i386/mmu.h Sat Aug 31 15:06:03 2002 +++ b/include/asm-i386/mmu.h Sat Aug 31 15:06:03 2002 @@ -10,7 +10,7 @@ typedef struct { int size; struct semaphore sem; - void * ldt; + void *ldt; } mm_context_t; #endif diff -Nru a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h --- a/include/asm-i386/mmu_context.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-i386/mmu_context.h Sat Aug 31 15:05:53 2002 @@ -44,7 +44,7 @@ * load the LDT, if the LDT is different: */ if (unlikely(prev->context.ldt != next->context.ldt)) - load_LDT(&next->context); + load_LDT_nolock(&next->context, cpu); } #ifdef CONFIG_SMP else { @@ -56,7 +56,7 @@ * tlb flush IPI delivery. We must reload %cr3. */ load_cr3(next->pgd); - load_LDT(&next->context); + load_LDT_nolock(&next->context, cpu); } } #endif diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h --- a/include/asm-i386/msr.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-i386/msr.h Sat Aug 31 15:05:54 2002 @@ -94,12 +94,15 @@ #define MSR_K6_STAR 0xC0000081 #define MSR_K6_WHCR 0xC0000082 #define MSR_K6_UWCCR 0xC0000085 +#define MSR_K6_EPMR 0xC0000086 #define MSR_K6_PSOR 0xC0000087 #define MSR_K6_PFIR 0xC0000088 #define MSR_K7_EVNTSEL0 0xC0010000 #define MSR_K7_PERFCTR0 0xC0010004 #define MSR_K7_HWCR 0xC0010015 +#define MSR_K7_FID_VID_CTL 0xC0010041 +#define MSR_K7_VID_STATUS 0xC0010042 /* Centaur-Hauls/IDT defined MSRs. */ #define MSR_IDT_FCR1 0x107 @@ -119,5 +122,7 @@ /* VIA Cyrix defined MSRs*/ #define MSR_VIA_FCR 0x1107 +#define MSR_VIA_LONGHAUL 0x110a +#define MSR_VIA_BCR2 0x1147 #endif /* __ASM_MSR_H */ diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h --- a/include/asm-i386/pci.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-i386/pci.h Sat Aug 31 15:05:59 2002 @@ -22,8 +22,6 @@ void pcibios_config_init(void); struct pci_bus * pcibios_scan_root(int bus); -extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); -extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); void pcibios_set_master(struct pci_dev *dev); void pcibios_penalize_isa_irq(int irq); diff -Nru a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h --- a/include/asm-i386/pgalloc.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-i386/pgalloc.h Sat Aug 31 15:05:54 2002 @@ -37,7 +37,7 @@ } -#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) /* * allocating and freeing a pmd is trivial: the 1-entry pmd is @@ -47,7 +47,7 @@ #define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) -#define pmd_free_tlb(tlb,x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) #define pgd_populate(mm, pmd, pte) BUG() #define check_pgt_cache() do { } while (0) diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h --- a/include/asm-i386/thread_info.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-i386/thread_info.h Sat Aug 31 15:05:54 2002 @@ -57,12 +57,12 @@ #ifndef __ASSEMBLY__ #define INIT_THREAD_INFO(tsk) \ { \ - task: &tsk, \ - exec_domain: &default_exec_domain, \ - flags: 0, \ - cpu: 0, \ - preempt_count: 1, \ - addr_limit: KERNEL_DS, \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .addr_limit = KERNEL_DS, \ } #define init_thread_info (init_thread_union.thread_info) diff -Nru a/include/asm-i386/tlb.h b/include/asm-i386/tlb.h --- a/include/asm-i386/tlb.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-i386/tlb.h Sat Aug 31 15:05:55 2002 @@ -7,7 +7,7 @@ */ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) /* * .. because we flush the whole mm when it diff -Nru a/include/asm-i386/xor.h b/include/asm-i386/xor.h --- a/include/asm-i386/xor.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-i386/xor.h Sat Aug 31 15:05:54 2002 @@ -20,6 +20,7 @@ #define FPU_SAVE \ do { \ + preempt_disable(); \ if (!test_thread_flag(TIF_USEDFPU)) \ __asm__ __volatile__ (" clts;\n"); \ __asm__ __volatile__ ("fsave %0; fwait": "=m"(fpu_save[0])); \ @@ -30,6 +31,7 @@ __asm__ __volatile__ ("frstor %0": : "m"(fpu_save[0])); \ if (!test_thread_flag(TIF_USEDFPU)) \ stts(); \ + preempt_enable(); \ } while (0) #define LD(x,y) " movq 8*("#x")(%1), %%mm"#y" ;\n" @@ -519,19 +521,19 @@ } static struct xor_block_template xor_block_pII_mmx = { - name: "pII_mmx", - do_2: xor_pII_mmx_2, - do_3: xor_pII_mmx_3, - do_4: xor_pII_mmx_4, - do_5: xor_pII_mmx_5, + .name = "pII_mmx", + .do_2 = xor_pII_mmx_2, + .do_3 = xor_pII_mmx_3, + .do_4 = xor_pII_mmx_4, + .do_5 = xor_pII_mmx_5, }; static struct xor_block_template xor_block_p5_mmx = { - name: "p5_mmx", - do_2: xor_p5_mmx_2, - do_3: xor_p5_mmx_3, - do_4: xor_p5_mmx_4, - do_5: xor_p5_mmx_5, + .name = "p5_mmx", + .do_2 = xor_p5_mmx_2, + .do_3 = xor_p5_mmx_3, + .do_4 = xor_p5_mmx_4, + .do_5 = xor_p5_mmx_5, }; #undef FPU_SAVE @@ -542,7 +544,8 @@ * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) */ -#define XMMS_SAVE \ +#define XMMS_SAVE do { \ + preempt_disable(); \ __asm__ __volatile__ ( \ "movl %%cr0,%0 ;\n\t" \ "clts ;\n\t" \ @@ -552,9 +555,10 @@ "movups %%xmm3,0x30(%1) ;\n\t" \ : "=&r" (cr0) \ : "r" (xmm_save) \ - : "memory") + : "memory"); \ +} while(0) -#define XMMS_RESTORE \ +#define XMMS_RESTORE do { \ __asm__ __volatile__ ( \ "sfence ;\n\t" \ "movups (%1),%%xmm0 ;\n\t" \ @@ -564,7 +568,9 @@ "movl %0,%%cr0 ;\n\t" \ : \ : "r" (cr0), "r" (xmm_save) \ - : "memory") + : "memory"); \ + preempt_enable(); \ +} while(0) #define ALIGN16 __attribute__((aligned(16))) @@ -848,11 +854,11 @@ } static struct xor_block_template xor_block_pIII_sse = { - name: "pIII_sse", - do_2: xor_sse_2, - do_3: xor_sse_3, - do_4: xor_sse_4, - do_5: xor_sse_5, + .name = "pIII_sse", + .do_2 = xor_sse_2, + .do_3 = xor_sse_3, + .do_4 = xor_sse_4, + .do_5 = xor_sse_5, }; /* Also try the generic routines. */ diff -Nru a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h --- a/include/asm-ia64/acpi.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-ia64/acpi.h Sat Aug 31 15:05:59 2002 @@ -100,7 +100,8 @@ int acpi_boot_init (char *cdline); int acpi_request_vector (u32 int_type); int acpi_get_prt (struct pci_vector_struct **vectors, int *count); -int acpi_get_interrupt_model(int *type); +int acpi_get_interrupt_model (int *type); +int acpi_irq_to_vector (u32 irq); #ifdef CONFIG_DISCONTIGMEM #define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */ diff -Nru a/include/asm-ia64/agp.h b/include/asm-ia64/agp.h --- a/include/asm-ia64/agp.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-ia64/agp.h Sat Aug 31 15:05:53 2002 @@ -18,4 +18,7 @@ #define flush_agp_mappings() /* nothing */ #define flush_agp_cache() mb() +/* Page-protection value to be used for AGP memory mapped into kernel space. */ +#define PAGE_AGP PAGE_KERNEL + #endif /* _ASM_IA64_AGP_H */ diff -Nru a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h --- a/include/asm-ia64/atomic.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-ia64/atomic.h Sat Aug 31 15:05:55 2002 @@ -9,8 +9,8 @@ * "int" types were carefully placed so as to ensure proper operation * of the macros. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include diff -Nru a/include/asm-ia64/cache.h b/include/asm-ia64/cache.h --- a/include/asm-ia64/cache.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-ia64/cache.h Sat Aug 31 15:06:00 2002 @@ -12,6 +12,8 @@ #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ + #ifdef CONFIG_SMP # define SMP_CACHE_SHIFT L1_CACHE_SHIFT # define SMP_CACHE_BYTES L1_CACHE_BYTES diff -Nru a/include/asm-ia64/efi.h b/include/asm-ia64/efi.h --- a/include/asm-ia64/efi.h Sat Aug 31 15:06:00 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,284 +0,0 @@ -#ifndef _ASM_IA64_EFI_H -#define _ASM_IA64_EFI_H - -/* - * Extensible Firmware Interface - * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999, 2002 Hewlett-Packard Co. - * David Mosberger-Tang - * Stephane Eranian - */ -#include -#include -#include -#include -#include - -#include -#include - -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR (1L | (1L << 63)) -#define EFI_INVALID_PARAMETER (2L | (1L << 63)) -#define EFI_UNSUPPORTED (3L | (1L << 63)) -#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) -#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) -#define EFI_NOT_FOUND (14L | (1L << 63)) - -typedef unsigned long efi_status_t; -typedef u8 efi_bool_t; -typedef u16 efi_char16_t; /* UNICODE character */ - - -typedef struct { - u8 b[16]; -} efi_guid_t; - -#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ -((efi_guid_t) \ -{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, \ - (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) - -/* - * Generic EFI table header - */ -typedef struct { - u64 signature; - u32 revision; - u32 headersize; - u32 crc32; - u32 reserved; -} efi_table_hdr_t; - -/* - * Memory map descriptor: - */ - -/* Memory types: */ -#define EFI_RESERVED_TYPE 0 -#define EFI_LOADER_CODE 1 -#define EFI_LOADER_DATA 2 -#define EFI_BOOT_SERVICES_CODE 3 -#define EFI_BOOT_SERVICES_DATA 4 -#define EFI_RUNTIME_SERVICES_CODE 5 -#define EFI_RUNTIME_SERVICES_DATA 6 -#define EFI_CONVENTIONAL_MEMORY 7 -#define EFI_UNUSABLE_MEMORY 8 -#define EFI_ACPI_RECLAIM_MEMORY 9 -#define EFI_ACPI_MEMORY_NVS 10 -#define EFI_MEMORY_MAPPED_IO 11 -#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 -#define EFI_PAL_CODE 13 -#define EFI_MAX_MEMORY_TYPE 14 - -/* Attribute values: */ -#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ -#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ -#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ -#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ -#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ -#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ -#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ -#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ -#define EFI_MEMORY_DESCRIPTOR_VERSION 1 - -#define EFI_PAGE_SHIFT 12 - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg); - -/* - * Types and defines for Time Services - */ -#define EFI_TIME_ADJUST_DAYLIGHT 0x1 -#define EFI_TIME_IN_DAYLIGHT 0x2 -#define EFI_UNSPECIFIED_TIMEZONE 0x07ff - -typedef struct { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 pad1; - u32 nanosecond; - s16 timezone; - u8 daylight; - u8 pad2; -} efi_time_t; - -typedef struct { - u32 resolution; - u32 accuracy; - u8 sets_to_zero; -} efi_time_cap_t; - -/* - * Types and defines for EFI ResetSystem - */ -#define EFI_RESET_COLD 0 -#define EFI_RESET_WARM 1 - -/* - * EFI Runtime Services table - */ -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552 -#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 - -typedef struct { - efi_table_hdr_t hdr; - u64 get_time; - u64 set_time; - u64 get_wakeup_time; - u64 set_wakeup_time; - u64 set_virtual_address_map; - u64 convert_pointer; - u64 get_variable; - u64 get_next_variable; - u64 set_variable; - u64 get_next_high_mono_count; - u64 reset_system; -} efi_runtime_services_t; - -typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); -typedef efi_status_t efi_set_time_t (efi_time_t *tm); -typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, - efi_time_t *tm); -typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); -typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, - unsigned long *data_size, void *data); -typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, - efi_guid_t *vendor); -typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr, - unsigned long data_size, void *data); -typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count); -typedef void efi_reset_system_t (int reset_type, efi_status_t status, - unsigned long data_size, efi_char16_t *data); - -/* - * EFI Configuration Table and GUID definitions - */ -#define NULL_GUID \ - EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) - -#define MPS_TABLE_GUID \ - EFI_GUID( 0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) - -#define ACPI_TABLE_GUID \ - EFI_GUID( 0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) - -#define ACPI_20_TABLE_GUID \ - EFI_GUID( 0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 ) - -#define SMBIOS_TABLE_GUID \ - EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) - -#define SAL_SYSTEM_TABLE_GUID \ - EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) - -#define HCDP_TABLE_GUID \ - EFI_GUID( 0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 ) - -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_t; - -#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) - -typedef struct { - efi_table_hdr_t hdr; - u64 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u64 con_in_handle; - u64 con_in; - u64 con_out_handle; - u64 con_out; - u64 stderr_handle; - u64 stderr; - u64 runtime; - u64 boottime; - u64 nr_tables; - u64 tables; -} efi_system_table_t; - -/* - * All runtime access to EFI goes through this structure: - */ -extern struct efi { - efi_system_table_t *systab; /* EFI system table */ - void *mps; /* MPS table */ - void *acpi; /* ACPI table (IA64 ext 0.71) */ - void *acpi20; /* ACPI table (ACPI 2.0) */ - void *smbios; /* SM BIOS table */ - void *sal_systab; /* SAL system table */ - void *boot_info; /* boot info table */ - void *hcdp; /* HCDP table */ - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; -} efi; - -static inline int -efi_guidcmp (efi_guid_t left, efi_guid_t right) -{ - return memcmp(&left, &right, sizeof (efi_guid_t)); -} - -static inline char * -efi_guid_unparse(efi_guid_t *guid, char *out) -{ - sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->b[3], guid->b[2], guid->b[1], guid->b[0], - guid->b[5], guid->b[4], guid->b[7], guid->b[6], - guid->b[8], guid->b[9], guid->b[10], guid->b[11], - guid->b[12], guid->b[13], guid->b[14], guid->b[15]); - return out; -} - -extern void efi_init (void); -extern void efi_map_pal_code (void); -extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); -extern void efi_gettimeofday (struct timeval *tv); -extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ -extern u64 efi_get_iobase (void); -extern u32 efi_mem_type (unsigned long phys_addr); -extern u64 efi_mem_attributes (unsigned long phys_addr); - -/* - * Variable Attributes - */ -#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 -#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 -#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 - - -/* - * efi_dir is allocated in arch/ia64/kernel/efi.c. - */ -#ifdef CONFIG_PROC_FS -extern struct proc_dir_entry *efi_dir; -#endif - -#endif /* _ASM_IA64_EFI_H */ diff -Nru a/include/asm-ia64/fpu.h b/include/asm-ia64/fpu.h --- a/include/asm-ia64/fpu.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ia64/fpu.h Sat Aug 31 15:06:06 2002 @@ -2,8 +2,8 @@ #define _ASM_IA64_FPU_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h --- a/include/asm-ia64/hardirq.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-ia64/hardirq.h Sat Aug 31 15:05:55 2002 @@ -92,12 +92,12 @@ # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif -#define irq_exit() \ -do { \ - preempt_count() -= IRQ_EXIT_OFFSET; \ - if (!in_interrupt() && softirq_pending(smp_processor_id())) \ - do_softirq(); \ - preempt_enable_no_resched(); \ +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && local_softirq_pending()) \ + do_softirq(); \ + preempt_enable_no_resched(); \ } while (0) #ifdef CONFIG_SMP diff -Nru a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h --- a/include/asm-ia64/hw_irq.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-ia64/hw_irq.h Sat Aug 31 15:06:00 2002 @@ -53,6 +53,10 @@ #define IA64_IPI_RESCHEDULE 0xfd /* SMP reschedule */ #define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */ +/* Used for encoding redirected irqs */ + +#define IA64_IRQ_REDIRECTED (1 << 31) + /* IA64 inter-cpu interrupt related definitions */ #define IA64_IPI_DEFAULT_BASE_ADDR 0xfee00000 @@ -68,14 +72,12 @@ extern __u8 isa_irq_to_vector_map[16]; #define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)] -extern __u8 gsi_to_vector_map[255]; -#define gsi_to_vector(x) gsi_to_vector_map[(x)] extern unsigned long ipi_base_addr; extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */ -extern int ia64_alloc_irq (void); /* allocate a free irq */ +extern int ia64_alloc_vector (void); /* allocate a free vector */ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h --- a/include/asm-ia64/ia32.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ia64/ia32.h Sat Aug 31 15:06:06 2002 @@ -334,7 +334,6 @@ #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define elf_addr_t u32 -#define elf_caddr_t u32 /* ELF register definitions. This is needed for core dump support. */ diff -Nru a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h --- a/include/asm-ia64/ide.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-ia64/ide.h Sat Aug 31 15:06:00 2002 @@ -85,10 +85,24 @@ for(index = 0; index < MAX_HWIFS; index++) { ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); hw.irq = ide_default_irq(ide_default_io_base(index)); - ide_register_hw(&hw); + ide_register_hw(&hw, NULL); } #endif } + +#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) +#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) +#define ide_check_region(from,extent) check_region((from), (extent)) +#define ide_request_region(from,extent,name) request_region((from), (extent), (name)) +#define ide_release_region(from,extent) release_region((from), (extent)) + +/* + * The following are not needed for the non-m68k ports + */ +#define ide_ack_intr(hwif) (1) +#define ide_fix_driveid(id) do {} while (0) +#define ide_release_lock(lock) do {} while (0) +#define ide_get_lock(lock, hdlr, data) do {} while (0) #endif /* __KERNEL__ */ diff -Nru a/include/asm-ia64/io.h b/include/asm-ia64/io.h --- a/include/asm-ia64/io.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ia64/io.h Sat Aug 31 15:05:54 2002 @@ -13,7 +13,7 @@ * over and over again with slight variations and possibly making a * mistake somewhere. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2002 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 1999 Asit Mallick * Copyright (C) 1999 Don Dugger @@ -277,9 +277,9 @@ } /* - * Unfortunately, some platforms are broken and do not follow the - * IA-64 architecture specification regarding legacy I/O support. - * Thus, we have to make these operations platform dependent... + * Unfortunately, some platforms are broken and do not follow the IA-64 architecture + * specification regarding legacy I/O support. Thus, we have to make these operations + * platform dependent... */ #define __inb platform_inb #define __inw platform_inw @@ -289,19 +289,19 @@ #define __outl platform_outl #define __mmiob platform_mmiob -#define inb __inb -#define inw __inw -#define inl __inl -#define insb __insb -#define insw __insw -#define insl __insl -#define outb __outb -#define outw __outw -#define outl __outl -#define outsb __outsb -#define outsw __outsw -#define outsl __outsl -#define mmiob __mmiob +#define inb(p) __inb(p) +#define inw(p) __inw(p) +#define inl(p) __inl(p) +#define insb(p,d,c) __insb(p,d,c) +#define insw(p,d,c) __insw(p,d,c) +#define insl(p,d,c) __insl(p,d,c) +#define outb(v,p) __outb(v,p) +#define outw(v,p) __outw(v,p) +#define outl(v,p) __outl(v,p) +#define outsb(p,s,c) __outsb(p,s,c) +#define outsw(p,s,c) __outsw(p,s,c) +#define outsl(p,s,c) __outsl(p,s,c) +#define mmiob() __mmiob() /* * The address passed to these functions are ioremap()ped already. diff -Nru a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h --- a/include/asm-ia64/iosapic.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-ia64/iosapic.h Sat Aug 31 15:06:00 2002 @@ -51,17 +51,24 @@ #ifndef __ASSEMBLY__ -extern void __init iosapic_init (unsigned long address, unsigned int base_irq, - int pcat_compat); -extern int iosapic_register_irq (u32 global_vector, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, - char *iosapic_address); -extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin, - unsigned long polarity, unsigned long trigger); -extern int iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, - u16 eid, u16 id, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, - char *iosapic_address); +extern void __devinit iosapic_init (unsigned long address, + unsigned int gsi_base, + int pcat_compat); +extern int gsi_to_vector (unsigned int gsi); +extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity, + unsigned long edge_triggered, + u32 gsi_base, char *iosapic_address); +extern void iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, + unsigned long polarity, + unsigned long edge_triggered); +extern int iosapic_register_platform_intr (u32 int_type, + unsigned int gsi, + int pmi_vector, + u16 eid, u16 id, + unsigned long polarity, + unsigned long edge_triggered, + unsigned int gsi_base, + char *iosapic_address); extern unsigned int iosapic_version (char *addr); extern void iosapic_pci_fixup (int); diff -Nru a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h --- a/include/asm-ia64/irq.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ia64/irq.h Sat Aug 31 15:06:06 2002 @@ -27,6 +27,6 @@ extern void disable_irq (unsigned int); extern void disable_irq_nosync (unsigned int); extern void enable_irq (unsigned int); -extern void set_irq_affinity_info (int irq, int dest, int redir); +extern void set_irq_affinity_info (unsigned int irq, int dest, int redir); #endif /* _ASM_IA64_IRQ_H */ diff -Nru a/include/asm-ia64/kmap_types.h b/include/asm-ia64/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/kmap_types.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,29 @@ +#ifndef _ASM_IA64_KMAP_TYPES_H +#define _ASM_IA64_KMAP_TYPES_H + +#include + +#if CONFIG_DEBUG_HIGHMEM +# define D(n) __KM_FENCE_##n , +#else +# define D(n) +#endif + +enum km_type { +D(0) KM_BOUNCE_READ, +D(1) KM_SKB_SUNRPC_DATA, +D(2) KM_SKB_DATA_SOFTIRQ, +D(3) KM_USER0, +D(4) KM_USER1, +D(5) KM_BIO_SRC_IRQ, +D(6) KM_BIO_DST_IRQ, +D(7) KM_PTE0, +D(8) KM_PTE1, +D(9) KM_IRQ0, +D(10) KM_IRQ1, +D(11) KM_TYPE_NR +}; + +#undef D + +#endif /* _ASM_IA64_KMAP_TYPES_H */ diff -Nru a/include/asm-ia64/mc146818rtc.h b/include/asm-ia64/mc146818rtc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/mc146818rtc.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,10 @@ +#ifndef _ASM_IA64_MC146818RTC_H +#define _ASM_IA64_MC146818RTC_H + +/* + * Machine dependent access functions for RTC registers. + */ + +/* empty include file to satisfy the include in genrtc.c */ + +#endif /* _ASM_IA64_MC146818RTC_H */ diff -Nru a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h --- a/include/asm-ia64/mmu_context.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ia64/mmu_context.h Sat Aug 31 15:05:54 2002 @@ -36,7 +36,7 @@ }; extern struct ia64_ctx ia64_ctx; -extern u8 ia64_need_tlb_flush __per_cpu_data; +DECLARE_PER_CPU(u8, ia64_need_tlb_flush); extern void wrap_mmu_context (struct mm_struct *mm); @@ -56,9 +56,9 @@ { extern void __flush_tlb_all (void); - if (unlikely(ia64_need_tlb_flush)) { + if (unlikely(__get_cpu_var(ia64_need_tlb_flush))) { __flush_tlb_all(); - ia64_need_tlb_flush = 0; + __get_cpu_var(ia64_need_tlb_flush) = 0; } } diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h --- a/include/asm-ia64/pci.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ia64/pci.h Sat Aug 31 15:06:06 2002 @@ -22,8 +22,6 @@ void pcibios_config_init(void); struct pci_bus * pcibios_scan_root(int bus); -extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); -extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); struct pci_dev; diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h --- a/include/asm-ia64/percpu.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-ia64/percpu.h Sat Aug 31 15:05:55 2002 @@ -1,6 +1,9 @@ #ifndef _ASM_IA64_PERCPU_H #define _ASM_IA64_PERCPU_H +#include +#include + /* * Copyright (C) 2002 Hewlett-Packard Co * David Mosberger-Tang @@ -8,7 +11,7 @@ #ifdef __ASSEMBLY__ -#define THIS_CPU(var) (var##__per_cpu) /* use this to mark accesses to per-CPU variables... */ +#define THIS_CPU(var) (var##__per_cpu) /* use this to mark accesses to per-CPU variables... */ #else /* !__ASSEMBLY__ */ @@ -22,8 +25,12 @@ #endif #define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu -#define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu])) #define __get_cpu_var(var) (var##__per_cpu) +#ifdef CONFIG_SMP +# define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu])) +#else +# define per_cpu(var, cpu) __get_cpu_var(var) +#endif #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h --- a/include/asm-ia64/pgalloc.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ia64/pgalloc.h Sat Aug 31 15:05:54 2002 @@ -108,7 +108,7 @@ ++pgtable_cache_size; } -#define pmd_free_tlb(tlb, pmd) pmd_free(pmd) +#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) static inline void pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, struct page *pte) @@ -154,7 +154,7 @@ free_page((unsigned long) pte); } -#define pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte)) +#define __pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte)) extern void check_pgt_cache (void); diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-ia64/processor.h Sat Aug 31 15:05:59 2002 @@ -15,9 +15,6 @@ #include -#include -#include - #include #include #include @@ -81,8 +78,10 @@ #ifndef __ASSEMBLY__ -#include #include +#include +#include +#include #include #include diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ia64/sal.h Sat Aug 31 15:06:06 2002 @@ -24,9 +24,9 @@ */ #include +#include #include -#include #include #include @@ -535,7 +535,7 @@ u64 reg_data_pairs[1]; /* array of address/data register pairs is num_mem_regs + num_io_regs elements long. Each array element consists of a u64 address followed - by a u64 data value. The oem_data array immediately follows the the + by a u64 data value. The oem_data array immediately follows the reg_data_pairs array */ u8 oem_data[1]; /* Variable length data */ } sal_log_pci_comp_err_info_t; diff -Nru a/include/asm-ia64/sn/alenlist.h b/include/asm-ia64/sn/alenlist.h --- a/include/asm-ia64/sn/alenlist.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-ia64/sn/alenlist.h Sat Aug 31 15:05:53 2002 @@ -15,7 +15,7 @@ /* * An Address/Length List is used when setting up for an I/O DMA operation. - * A driver creates an Address/Length List that describes to the the DMA + * A driver creates an Address/Length List that describes to the DMA * interface where in memory the DMA should go. The bus interface sets up * mapping registers, if required, and returns a suitable list of "physical * addresses" or "I/O address" to the driver. The driver then uses these diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h --- a/include/asm-ia64/system.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-ia64/system.h Sat Aug 31 15:05:59 2002 @@ -13,7 +13,6 @@ * Copyright (C) 1999 Don Dugger */ #include -#include #include #include @@ -26,6 +25,7 @@ #ifndef __ASSEMBLY__ +#include #include #include @@ -368,8 +368,8 @@ extern void ia64_load_extra (struct task_struct *task); #if defined(CONFIG_SMP) && defined(CONFIG_PERFMON) - extern int __per_cpu_data pfm_syst_wide; -# define PERFMON_IS_SYSWIDE() (this_cpu(pfm_syst_wide) != 0) + DECLARE_PER_CPU(int, pfm_syst_wide); +# define PERFMON_IS_SYSWIDE() (get_cpu_var(pfm_syst_wide) != 0) #else # define PERFMON_IS_SYSWIDE() (0) #endif diff -Nru a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h --- a/include/asm-ia64/tlb.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-ia64/tlb.h Sat Aug 31 15:05:59 2002 @@ -172,7 +172,7 @@ * PTE, not just those pointing to (normal) physical memory. */ static inline void -tlb_remove_tlb_entry (mmu_gather_t *tlb, pte_t *ptep, unsigned long address) +__tlb_remove_tlb_entry (mmu_gather_t *tlb, pte_t *ptep, unsigned long address) { if (tlb->start_addr == ~0UL) tlb->start_addr = address; diff -Nru a/include/asm-ia64/types.h b/include/asm-ia64/types.h --- a/include/asm-ia64/types.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-ia64/types.h Sat Aug 31 15:05:55 2002 @@ -2,14 +2,13 @@ #define _ASM_IA64_TYPES_H /* - * This file is never included by application software unless - * explicitly requested (e.g., via linux/types.h) in which case the - * application is Linux specific so (user-) name space pollution is - * not a major issue. However, for interoperability, libraries still + * This file is never included by application software unless explicitly requested (e.g., + * via linux/types.h) in which case the application is Linux specific so (user-) name + * space pollution is not a major issue. However, for interoperability, libraries still * need to be careful to avoid a name clashes. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2000, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #ifdef __ASSEMBLY__ @@ -18,9 +17,6 @@ #else # define __IA64_UL(x) ((unsigned long)(x)) # define __IA64_UL_CONST(x) x##UL -#endif - -#ifndef __ASSEMBLY__ typedef unsigned int umode_t; diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ia64/unistd.h Sat Aug 31 15:05:54 2002 @@ -223,10 +223,15 @@ #define __NR_sched_setaffinity 1231 #define __NR_sched_getaffinity 1232 #define __NR_security 1233 -#define __NR_get_large_pages 1234 -#define __NR_free_large_pages 1235 -#define __NR_share_large_pages 1236 -#define __NR_unshare_large_pages 1237 +#define __NR_alloc_hugepages 1234 +#define __NR_free_hugepages 1235 +/* 1236 currently unused */ +/* 1237 currently unused */ +#define __NR_io_setup 1238 +#define __NR_io_destroy 1239 +#define __NR_io_getevents 1240 +#define __NR_io_submit 1241 +#define __NR_io_cancel 1242 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -Nru a/include/asm-m68k/cache.h b/include/asm-m68k/cache.h --- a/include/asm-m68k/cache.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-m68k/cache.h Sat Aug 31 15:06:00 2002 @@ -8,4 +8,6 @@ #define L1_CACHE_SHIFT 4 #define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT_MAX 4 /* largest L1 which this arch supports */ + #endif diff -Nru a/include/asm-m68k/motorola_pgalloc.h b/include/asm-m68k/motorola_pgalloc.h --- a/include/asm-m68k/motorola_pgalloc.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-m68k/motorola_pgalloc.h Sat Aug 31 15:06:06 2002 @@ -55,7 +55,7 @@ __free_page(page); } -static inline void pte_free_tlb(mmu_gather_t *tlb, struct page *page) +static inline void __pte_free_tlb(mmu_gather_t *tlb, struct page *page) { cache_page(kmap(page)); kunmap(page); @@ -73,7 +73,7 @@ return free_pointer_table(pmd); } -static inline int pmd_free_tlb(mmu_gather_t *tlb, pmd_t *pmd) +static inline int __pmd_free_tlb(mmu_gather_t *tlb, pmd_t *pmd) { return free_pointer_table(pmd); } diff -Nru a/include/asm-m68k/sun3_pgalloc.h b/include/asm-m68k/sun3_pgalloc.h --- a/include/asm-m68k/sun3_pgalloc.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-m68k/sun3_pgalloc.h Sat Aug 31 15:05:59 2002 @@ -31,7 +31,7 @@ __free_page(page); } -static inline void pte_free_tlb(mmu_gather_t *tlb, struct page *page) +static inline void __pte_free_tlb(mmu_gather_t *tlb, struct page *page) { tlb_remove_page(tlb, page); } @@ -76,7 +76,7 @@ * inside the pgd, so has no extra memory associated with it. */ #define pmd_free(x) do { } while (0) -#define pmd_free_tlb(tlb, x) do { } while (0) +#define __pmd_free_tlb(tlb, x) do { } while (0) static inline void pgd_free(pgd_t * pgd) { diff -Nru a/include/asm-m68k/tlb.h b/include/asm-m68k/tlb.h --- a/include/asm-m68k/tlb.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-m68k/tlb.h Sat Aug 31 15:06:06 2002 @@ -7,7 +7,7 @@ */ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) /* * .. because we flush the whole mm when it diff -Nru a/include/asm-mips/cache.h b/include/asm-mips/cache.h --- a/include/asm-mips/cache.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-mips/cache.h Sat Aug 31 15:05:59 2002 @@ -35,5 +35,6 @@ #endif #define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #endif /* _ASM_CACHE_H */ diff -Nru a/include/asm-mips64/cache.h b/include/asm-mips64/cache.h --- a/include/asm-mips64/cache.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-mips64/cache.h Sat Aug 31 15:06:00 2002 @@ -11,5 +11,6 @@ /* bytes per L1 cache line */ #define L1_CACHE_BYTES (1 << CONFIG_L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ #endif /* _ASM_CACHE_H */ diff -Nru a/include/asm-mips64/elf.h b/include/asm-mips64/elf.h --- a/include/asm-mips64/elf.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-mips64/elf.h Sat Aug 31 15:05:54 2002 @@ -31,7 +31,7 @@ \ if (__h->e_machine != EM_MIPS) \ __res = 0; \ - if (sizeof(elf_caddr_t) == 8 && \ + if (sizeof(elf_addr_t) == 8 && \ __h->e_ident[EI_CLASS] == ELFCLASS32) \ __res = 0; \ \ diff -Nru a/include/asm-mips64/sn/sn0/hubio.h b/include/asm-mips64/sn/sn0/hubio.h --- a/include/asm-mips64/sn/sn0/hubio.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-mips64/sn/sn0/hubio.h Sat Aug 31 15:05:54 2002 @@ -68,7 +68,7 @@ /* * The following definitions use the names defined in the IO interface * document for ease of reference. When possible, software should - * generally use the the longer but clearer names defined above. + * generally use the longer but clearer names defined above. */ #define IIO_BASE 0x400000 diff -Nru a/include/asm-parisc/cache.h b/include/asm-parisc/cache.h --- a/include/asm-parisc/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-parisc/cache.h Sat Aug 31 15:05:54 2002 @@ -34,6 +34,7 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) diff -Nru a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h --- a/include/asm-ppc/cache.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ppc/cache.h Sat Aug 31 15:06:06 2002 @@ -29,6 +29,7 @@ #define L1_CACHE_BYTES L1_CACHE_LINE_SIZE #define L1_CACHE_SHIFT LG_L1_CACHE_LINE_SIZE #define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define L1_CACHE_PAGES 8 diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h --- a/include/asm-ppc/elf.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ppc/elf.h Sat Aug 31 15:05:54 2002 @@ -98,19 +98,14 @@ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. */ -#define DLINFO_ARCH_ITEMS 3 #define ARCH_DLINFO \ do { \ - sp -= DLINFO_ARCH_ITEMS * 2; \ - NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ - NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ - NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ - /* \ - * Now handle glibc compatibility. \ - */ \ - sp -= 2*2; \ - NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ + /* Now handle glibc compatibility. */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0) #endif /* __KERNEL__ */ diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h --- a/include/asm-ppc/pgalloc.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-ppc/pgalloc.h Sat Aug 31 15:05:53 2002 @@ -20,7 +20,7 @@ */ #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) -#define pmd_free_tlb(tlb,x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) #define pgd_populate(mm, pmd, pte) BUG() #define pmd_populate_kernel(mm, pmd, pte) \ @@ -33,7 +33,7 @@ extern void pte_free_kernel(pte_t *pte); extern void pte_free(struct page *pte); -#define pte_free_tlb(tlb, pte) pte_free((pte)) +#define __pte_free_tlb(tlb, pte) pte_free((pte)) #define check_pgt_cache() do { } while (0) diff -Nru a/include/asm-ppc/tlb.h b/include/asm-ppc/tlb.h --- a/include/asm-ppc/tlb.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ppc/tlb.h Sat Aug 31 15:05:54 2002 @@ -34,7 +34,7 @@ extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long address); -static inline void tlb_remove_tlb_entry(mmu_gather_t *tlb, pte_t *ptep, +static inline void __tlb_remove_tlb_entry(mmu_gather_t *tlb, pte_t *ptep, unsigned long address) { if (pte_val(*ptep) & _PAGE_HASHPTE) @@ -50,7 +50,7 @@ #define tlb_finish_arch(tlb) do { } while (0) #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) /* Get the generic bits... */ diff -Nru a/include/asm-ppc64/cache.h b/include/asm-ppc64/cache.h --- a/include/asm-ppc64/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ppc64/cache.h Sat Aug 31 15:05:54 2002 @@ -12,5 +12,6 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ #endif diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h --- a/include/asm-ppc64/elf.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-ppc64/elf.h Sat Aug 31 15:06:06 2002 @@ -31,13 +31,11 @@ typedef elf_greg_t64 elf_greg_t; typedef elf_gregset_t64 elf_gregset_t; # define elf_addr_t unsigned long -# define elf_caddr_t char * #else /* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */ typedef elf_greg_t32 elf_greg_t; typedef elf_gregset_t32 elf_gregset_t; # define elf_addr_t u32 -# define elf_caddr_t u32 #endif typedef double elf_fpreg_t; @@ -122,19 +120,14 @@ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. */ -#define DLINFO_ARCH_ITEMS 3 #define ARCH_DLINFO \ do { \ - sp -= DLINFO_ARCH_ITEMS * 2; \ - NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ - NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ - NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ - /* \ - * Now handle glibc compatibility. \ - */ \ - sp -= 2*2; \ - NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ + /* Now handle glibc compatibility. */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0) #endif /* __PPC64_ELF_H */ diff -Nru a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h --- a/include/asm-ppc64/pgalloc.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-ppc64/pgalloc.h Sat Aug 31 15:05:54 2002 @@ -53,7 +53,7 @@ free_page((unsigned long)pmd); } -#define pmd_free_tlb(tlb, pmd) pmd_free(pmd) +#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) #define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte) #define pmd_populate(mm, pmd, pte_page) \ @@ -88,7 +88,7 @@ } #define pte_free(pte_page) pte_free_kernel(page_address(pte_page)) -#define pte_free_tlb(tlb, pte) pte_free(pte) +#define __pte_free_tlb(tlb, pte) pte_free(pte) #define check_pgt_cache() do { } while (0) diff -Nru a/include/asm-ppc64/tlb.h b/include/asm-ppc64/tlb.h --- a/include/asm-ppc64/tlb.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-ppc64/tlb.h Sat Aug 31 15:05:59 2002 @@ -40,7 +40,7 @@ extern struct ppc64_tlb_batch ppc64_tlb_batch[NR_CPUS]; -static inline void tlb_remove_tlb_entry(mmu_gather_t *tlb, pte_t *ptep, +static inline void __tlb_remove_tlb_entry(mmu_gather_t *tlb, pte_t *ptep, unsigned long address) { int cpu = smp_processor_id(); diff -Nru a/include/asm-s390/cache.h b/include/asm-s390/cache.h --- a/include/asm-s390/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-s390/cache.h Sat Aug 31 15:05:54 2002 @@ -13,5 +13,6 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 +#define L1_CACHE_SHIFT_MAX 8 /* largest L1 which this arch supports */ #endif diff -Nru a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h --- a/include/asm-s390/pgalloc.h Sat Aug 31 15:06:03 2002 +++ b/include/asm-s390/pgalloc.h Sat Aug 31 15:06:03 2002 @@ -49,7 +49,7 @@ */ #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) -#define pmd_free_tlb(tlb,x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) #define pgd_populate(mm, pmd, pte) BUG() static inline void @@ -107,7 +107,7 @@ __free_page(pte); } -#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) /* * This establishes kernel virtual mappings (e.g., as a result of a diff -Nru a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h --- a/include/asm-s390/tlb.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-s390/tlb.h Sat Aug 31 15:06:06 2002 @@ -7,7 +7,7 @@ */ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) /* * .. because we flush the whole mm when it diff -Nru a/include/asm-s390x/cache.h b/include/asm-s390x/cache.h --- a/include/asm-s390x/cache.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-s390x/cache.h Sat Aug 31 15:05:54 2002 @@ -13,5 +13,6 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 +#define L1_CACHE_SHIFT_MAX 8 /* largest L1 which this arch supports */ #endif diff -Nru a/include/asm-s390x/pgalloc.h b/include/asm-s390x/pgalloc.h --- a/include/asm-s390x/pgalloc.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-s390x/pgalloc.h Sat Aug 31 15:05:54 2002 @@ -68,7 +68,7 @@ free_pages((unsigned long) pmd, 2); } -#define pmd_free_tlb(tlb,pmd) pmd_free(pmd) +#define __pmd_free_tlb(tlb,pmd) pmd_free(pmd) static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) @@ -123,7 +123,7 @@ __free_page(pte); } -#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) /* * This establishes kernel virtual mappings (e.g., as a result of a diff -Nru a/include/asm-s390x/tlb.h b/include/asm-s390x/tlb.h --- a/include/asm-s390x/tlb.h Sat Aug 31 15:05:53 2002 +++ b/include/asm-s390x/tlb.h Sat Aug 31 15:05:53 2002 @@ -7,7 +7,7 @@ */ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) /* * .. because we flush the whole mm when it diff -Nru a/include/asm-sh/cache.h b/include/asm-sh/cache.h --- a/include/asm-sh/cache.h Sat Aug 31 15:06:04 2002 +++ b/include/asm-sh/cache.h Sat Aug 31 15:06:04 2002 @@ -14,4 +14,6 @@ #define L1_CACHE_BYTES 32 #endif +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ + #endif /* __ASM_SH_CACHE_H */ diff -Nru a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h --- a/include/asm-sparc/cache.h Sat Aug 31 15:06:03 2002 +++ b/include/asm-sparc/cache.h Sat Aug 31 15:06:03 2002 @@ -13,6 +13,7 @@ #define L1_CACHE_SHIFT 5 #define L1_CACHE_BYTES 32 #define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))) +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #define SMP_CACHE_BYTES 32 diff -Nru a/include/asm-sparc/pgalloc.h b/include/asm-sparc/pgalloc.h --- a/include/asm-sparc/pgalloc.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-sparc/pgalloc.h Sat Aug 31 15:05:54 2002 @@ -47,7 +47,7 @@ #define free_pmd_fast(pmd) BTFIXUP_CALL(free_pmd_fast)(pmd) #define pmd_free(pmd) free_pmd_fast(pmd) -#define pmd_free_tlb(tlb, pmd) pmd_free(pmd) +#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *) #define pmd_populate(MM, PMD, PTE) BTFIXUP_CALL(pmd_populate)(PMD, PTE) @@ -64,6 +64,6 @@ BTFIXUPDEF_CALL(void, pte_free, struct page *) #define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) -#define pte_free_tlb(tlb, pte) pte_free(pte) +#define __pte_free_tlb(tlb, pte) pte_free(pte) #endif /* _SPARC_PGALLOC_H */ diff -Nru a/include/asm-sparc/tlb.h b/include/asm-sparc/tlb.h --- a/include/asm-sparc/tlb.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-sparc/tlb.h Sat Aug 31 15:05:59 2002 @@ -11,7 +11,7 @@ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \ } while (0) -#define tlb_remove_tlb_entry(tlb, pte, address) \ +#define __tlb_remove_tlb_entry(tlb, pte, address) \ do { } while (0) #define tlb_flush(tlb) \ diff -Nru a/include/asm-sparc64/cache.h b/include/asm-sparc64/cache.h --- a/include/asm-sparc64/cache.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-sparc64/cache.h Sat Aug 31 15:06:00 2002 @@ -9,6 +9,7 @@ #define L1_CACHE_BYTES 32 /* Two 16-byte sub-blocks per line. */ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) +#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #define SMP_CACHE_BYTES_SHIFT 6 #define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT) /* L2 cache line size. */ diff -Nru a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h --- a/include/asm-sparc64/head.h Sat Aug 31 15:05:59 2002 +++ b/include/asm-sparc64/head.h Sat Aug 31 15:05:59 2002 @@ -8,7 +8,41 @@ #define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) -#define CHEETAH_ID 0x003e0014 -#define CHEETAH_PLUS_ID 0x003e0015 +#define __CHEETAH_ID 0x003e0014 + +#define CHEETAH_MANUF 0x003e +#define CHEETAH_IMPL 0x0014 +#define CHEETAH_PLUS_IMPL 0x0015 + +#define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label) \ + rdpr %ver, %tmp1; \ + sethi %hi(__CHEETAH_ID), %tmp2; \ + srlx %tmp1, 32, %tmp1; \ + or %tmp2, %lo(__CHEETAH_ID), %tmp2;\ + cmp %tmp1, %tmp2; \ + be,pn %icc, label; \ + nop; + +#define BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(tmp1,tmp2,label) \ + rdpr %ver, %tmp1; \ + srlx %tmp1, (32 + 16), %tmp2; \ + cmp %tmp2, CHEETAH_MANUF; \ + bne,pt %xcc, 99f; \ + sllx %tmp1, 16, %tmp1; \ + srlx %tmp1, (32 + 16), %tmp2; \ + cmp %tmp2, CHEETAH_PLUS_IMPL; \ + bgeu,pt %xcc, label; \ +99: nop; + +#define BRANCH_IF_ANY_CHEETAH(tmp1,tmp2,label) \ + rdpr %ver, %tmp1; \ + srlx %tmp1, (32 + 16), %tmp2; \ + cmp %tmp2, CHEETAH_MANUF; \ + bne,pt %xcc, 99f; \ + sllx %tmp1, 16, %tmp1; \ + srlx %tmp1, (32 + 16), %tmp2; \ + cmp %tmp2, CHEETAH_IMPL; \ + bgeu,pt %xcc, label; \ +99: nop; #endif /* !(_SPARC64_HEAD_H) */ diff -Nru a/include/asm-sparc64/kmap_types.h b/include/asm-sparc64/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-sparc64/kmap_types.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,23 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +/* Dummy header just to define km_type. None of this + * is actually used on sparc64. -DaveM + */ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_TYPE_NR +}; + +#endif diff -Nru a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h --- a/include/asm-sparc64/pgalloc.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-sparc64/pgalloc.h Sat Aug 31 15:06:06 2002 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff -Nru a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h --- a/include/asm-sparc64/tlb.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-sparc64/tlb.h Sat Aug 31 15:05:55 2002 @@ -16,12 +16,12 @@ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \ } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) \ +#define __tlb_remove_tlb_entry(tlb, ptep, address) \ do { } while (0) #include -#define pmd_free_tlb(tlb, pmd) pmd_free(pmd) -#define pte_free_tlb(tlb, pte) pte_free(pte) +#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) +#define __pte_free_tlb(tlb, pte) pte_free(pte) #endif /* _SPARC64_TLB_H */ diff -Nru a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h --- a/include/asm-x86_64/cache.h Sat Aug 31 15:06:06 2002 +++ b/include/asm-x86_64/cache.h Sat Aug 31 15:06:06 2002 @@ -9,5 +9,6 @@ /* L1 cache line size */ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT_MAX 6 /* largest L1 which this arch supports */ #endif diff -Nru a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h --- a/include/asm-x86_64/pgalloc.h Sat Aug 31 15:06:00 2002 +++ b/include/asm-x86_64/pgalloc.h Sat Aug 31 15:06:00 2002 @@ -75,7 +75,7 @@ __free_page(pte); } -#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) -#define pmd_free_tlb(tlb,x) do { } while (0) +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pmd_free_tlb(tlb,x) do { } while (0) #endif /* _X86_64_PGALLOC_H */ diff -Nru a/include/asm-x86_64/tlb.h b/include/asm-x86_64/tlb.h --- a/include/asm-x86_64/tlb.h Sat Aug 31 15:05:54 2002 +++ b/include/asm-x86_64/tlb.h Sat Aug 31 15:05:54 2002 @@ -4,7 +4,7 @@ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) -#define tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) diff -Nru a/include/asm-x86_64/xor.h b/include/asm-x86_64/xor.h --- a/include/asm-x86_64/xor.h Sat Aug 31 15:05:55 2002 +++ b/include/asm-x86_64/xor.h Sat Aug 31 15:05:55 2002 @@ -37,8 +37,9 @@ /* Doesn't use gcc to save the XMM registers, because there is no easy way to tell it to do a clts before the register saving. */ -#define XMMS_SAVE \ - asm volatile ( \ +#define XMMS_SAVE do { \ + preempt_disable(); \ + asm volatile ( \ "movq %%cr0,%0 ;\n\t" \ "clts ;\n\t" \ "movups %%xmm0,(%1) ;\n\t" \ @@ -47,10 +48,11 @@ "movups %%xmm3,0x30(%1) ;\n\t" \ : "=r" (cr0) \ : "r" (xmm_save) \ - : "memory") + : "memory"); \ +} while(0) #define XMMS_RESTORE \ - asm volatile ( \ + asm volatile ( \ "sfence ;\n\t" \ "movups (%1),%%xmm0 ;\n\t" \ "movups 0x10(%1),%%xmm1 ;\n\t" \ @@ -59,7 +61,9 @@ "movq %0,%%cr0 ;\n\t" \ : \ : "r" (cr0), "r" (xmm_save) \ - : "memory") + : "memory"); \ + preempt_enable(); \ +} while(0) #define OFFS(x) "16*("#x")" #define PF_OFFS(x) "256+16*("#x")" diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h --- a/include/linux/acpi.h Sat Aug 31 15:05:53 2002 +++ b/include/linux/acpi.h Sat Aug 31 15:05:53 2002 @@ -336,12 +336,21 @@ char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); int acpi_boot_init (char *cmdline); +int acpi_numa_init (void); int acpi_table_init (char *cmdline); -int acpi_table_parse (enum acpi_table_id, acpi_table_handler); -int acpi_table_parse_madt (enum acpi_table_id, acpi_madt_entry_handler); -void acpi_table_print (struct acpi_table_header *, unsigned long); -void acpi_table_print_madt_entry (acpi_table_entry_header *); +int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); +int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); +int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); +void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); +void acpi_table_print_madt_entry (acpi_table_entry_header *madt); +void acpi_table_print_srat_entry (acpi_table_entry_header *srat); + +/* the following four functions are architecture-dependent */ +void acpi_numa_slit_init (struct acpi_table_slit *slit); +void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa); +void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma); +void acpi_numa_arch_fixup(void); extern int acpi_mp_config; diff -Nru a/include/linux/cache.h b/include/linux/cache.h --- a/include/linux/cache.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/cache.h Sat Aug 31 15:06:06 2002 @@ -44,4 +44,13 @@ #endif /* CONFIG_SMP */ #endif +#if !defined(____cacheline_maxaligned_in_smp) +#if defined(CONFIG_SMP) +#define ____cacheline_maxaligned_in_smp \ + __attribute__((__aligned__(1 << (L1_CACHE_SHIFT_MAX)))) +#else +#define ____cacheline_maxaligned_in_smp +#endif +#endif + #endif /* __LINUX_CACHE_H */ diff -Nru a/include/linux/cobalt-nvram.h b/include/linux/cobalt-nvram.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/cobalt-nvram.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,109 @@ +/* + * $Id: cobalt-nvram.h,v 1.20 2001/10/17 23:16:55 thockin Exp $ + * cobalt-nvram.h : defines for the various fields in the cobalt NVRAM + * + * Copyright 2001,2002 Sun Microsystems, Inc. + */ + +#ifndef COBALT_NVRAM_H +#define COBALT_NVRAM_H + +#include + +#define COBT_CMOS_INFO_MAX 0x7f /* top address allowed */ +#define COBT_CMOS_BIOS_DRIVE_INFO 0x12 /* drive info would go here */ + +#define COBT_CMOS_CKS_START NVRAM_OFFSET(0x0e) +#define COBT_CMOS_CKS_END NVRAM_OFFSET(0x7f) + +/* flag bytes - 16 flags for now, leave room for more */ +#define COBT_CMOS_FLAG_BYTE_0 NVRAM_OFFSET(0x10) +#define COBT_CMOS_FLAG_BYTE_1 NVRAM_OFFSET(0x11) + +/* flags in flag bytes - up to 16 */ +#define COBT_CMOS_FLAG_MIN 0x0001 +#define COBT_CMOS_CONSOLE_FLAG 0x0001 /* console on/off */ +#define COBT_CMOS_DEBUG_FLAG 0x0002 /* ROM debug messages */ +#define COBT_CMOS_AUTO_PROMPT_FLAG 0x0004 /* boot to ROM prompt? */ +#define COBT_CMOS_CLEAN_BOOT_FLAG 0x0008 /* set by a clean shutdown */ +#define COBT_CMOS_HW_NOPROBE_FLAG 0x0010 /* go easy on the probing */ +#define COBT_CMOS_SYSFAULT_FLAG 0x0020 /* system fault detected */ +#define COBT_CMOS_OOPSPANIC_FLAG 0x0040 /* panic on oops */ +#define COBT_CMOS_DELAY_CACHE_FLAG 0x0080 /* delay cache initialization */ +#define COBT_CMOS_NOLOGO_FLAG 0x0100 /* hide "C" logo @ boot */ +#define COBT_CMOS_VERSION_FLAG 0x0200 /* the version field is valid */ +#define COBT_CMOS_FLAG_MAX 0x0200 + +/* leave byte 0x12 blank - Linux looks for drive info here */ + +/* CMOS structure version, valid if COBT_CMOS_VERSION_FLAG is true */ +#define COBT_CMOS_VERSION NVRAM_OFFSET(0x13) +#define COBT_CMOS_VER_BTOCODE 1 /* min. version needed for btocode */ + +/* index of default boot method */ +#define COBT_CMOS_BOOT_METHOD NVRAM_OFFSET(0x20) +#define COBT_CMOS_BOOT_METHOD_DISK 0 +#define COBT_CMOS_BOOT_METHOD_ROM 1 +#define COBT_CMOS_BOOT_METHOD_NET 2 + +#define COBT_CMOS_BOOT_DEV_MIN NVRAM_OFFSET(0x21) +/* major #, minor # of first through fourth boot device */ +#define COBT_CMOS_BOOT_DEV0_MAJ NVRAM_OFFSET(0x21) +#define COBT_CMOS_BOOT_DEV0_MIN NVRAM_OFFSET(0x22) +#define COBT_CMOS_BOOT_DEV1_MAJ NVRAM_OFFSET(0x23) +#define COBT_CMOS_BOOT_DEV1_MIN NVRAM_OFFSET(0x24) +#define COBT_CMOS_BOOT_DEV2_MAJ NVRAM_OFFSET(0x25) +#define COBT_CMOS_BOOT_DEV2_MIN NVRAM_OFFSET(0x26) +#define COBT_CMOS_BOOT_DEV3_MAJ NVRAM_OFFSET(0x27) +#define COBT_CMOS_BOOT_DEV3_MIN NVRAM_OFFSET(0x28) +#define COBT_CMOS_BOOT_DEV_MAX NVRAM_OFFSET(0x28) + +/* checksum of bytes 0xe-0x7f */ +#define COBT_CMOS_CHECKSUM NVRAM_OFFSET(0x2e) + +/* running uptime counter, units of 5 minutes (32 bits =~ 41000 years) */ +#define COBT_CMOS_UPTIME_0 NVRAM_OFFSET(0x30) +#define COBT_CMOS_UPTIME_1 NVRAM_OFFSET(0x31) +#define COBT_CMOS_UPTIME_2 NVRAM_OFFSET(0x32) +#define COBT_CMOS_UPTIME_3 NVRAM_OFFSET(0x33) + +/* count of successful boots (32 bits) */ +#define COBT_CMOS_BOOTCOUNT_0 NVRAM_OFFSET(0x38) +#define COBT_CMOS_BOOTCOUNT_1 NVRAM_OFFSET(0x39) +#define COBT_CMOS_BOOTCOUNT_2 NVRAM_OFFSET(0x3a) +#define COBT_CMOS_BOOTCOUNT_3 NVRAM_OFFSET(0x3b) + +/* 13 bytes: system serial number, same as on the back of the system */ +#define COBT_CMOS_SYS_SERNUM_LEN 13 +#define COBT_CMOS_SYS_SERNUM_0 NVRAM_OFFSET(0x40) +#define COBT_CMOS_SYS_SERNUM_1 NVRAM_OFFSET(0x41) +#define COBT_CMOS_SYS_SERNUM_2 NVRAM_OFFSET(0x42) +#define COBT_CMOS_SYS_SERNUM_3 NVRAM_OFFSET(0x43) +#define COBT_CMOS_SYS_SERNUM_4 NVRAM_OFFSET(0x44) +#define COBT_CMOS_SYS_SERNUM_5 NVRAM_OFFSET(0x45) +#define COBT_CMOS_SYS_SERNUM_6 NVRAM_OFFSET(0x46) +#define COBT_CMOS_SYS_SERNUM_7 NVRAM_OFFSET(0x47) +#define COBT_CMOS_SYS_SERNUM_8 NVRAM_OFFSET(0x48) +#define COBT_CMOS_SYS_SERNUM_9 NVRAM_OFFSET(0x49) +#define COBT_CMOS_SYS_SERNUM_10 NVRAM_OFFSET(0x4a) +#define COBT_CMOS_SYS_SERNUM_11 NVRAM_OFFSET(0x4b) +#define COBT_CMOS_SYS_SERNUM_12 NVRAM_OFFSET(0x4c) +/* checksum for serial num - 1 byte */ +#define COBT_CMOS_SYS_SERNUM_CSUM NVRAM_OFFSET(0x4f) + +#define COBT_CMOS_ROM_REV_MAJ NVRAM_OFFSET(0x50) +#define COBT_CMOS_ROM_REV_MIN NVRAM_OFFSET(0x51) +#define COBT_CMOS_ROM_REV_REV NVRAM_OFFSET(0x52) + +#define COBT_CMOS_BTO_CODE_0 NVRAM_OFFSET(0x53) +#define COBT_CMOS_BTO_CODE_1 NVRAM_OFFSET(0x54) +#define COBT_CMOS_BTO_CODE_2 NVRAM_OFFSET(0x55) +#define COBT_CMOS_BTO_CODE_3 NVRAM_OFFSET(0x56) + +#define COBT_CMOS_BTO_IP_CSUM NVRAM_OFFSET(0x57) +#define COBT_CMOS_BTO_IP_0 NVRAM_OFFSET(0x58) +#define COBT_CMOS_BTO_IP_1 NVRAM_OFFSET(0x59) +#define COBT_CMOS_BTO_IP_2 NVRAM_OFFSET(0x5a) +#define COBT_CMOS_BTO_IP_3 NVRAM_OFFSET(0x5b) + +#endif /* COBALT_NVRAM_H */ diff -Nru a/include/linux/dcache.h b/include/linux/dcache.h --- a/include/linux/dcache.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/dcache.h Sat Aug 31 15:06:06 2002 @@ -181,8 +181,6 @@ extern void shrink_dcache_anon(struct list_head *); extern int d_invalidate(struct dentry *); -#define shrink_dcache() prune_dcache(0) -struct zone_struct; /* dcache memory management */ extern int shrink_dcache_memory(int, unsigned int); extern void prune_dcache(int); diff -Nru a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h --- a/include/linux/devfs_fs_kernel.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/devfs_fs_kernel.h Sat Aug 31 15:06:06 2002 @@ -95,7 +95,6 @@ extern devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master); extern const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen); extern int devfs_only (void); - extern void devfs_register_tape (devfs_handle_t de); extern void devfs_register_series (devfs_handle_t dir, const char *format, unsigned int num_entries, @@ -238,7 +237,6 @@ { return 0; } - static inline void devfs_register_tape (devfs_handle_t de) { return; diff -Nru a/include/linux/efi.h b/include/linux/efi.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/efi.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,284 @@ +#ifndef _LINUX_EFI_H +#define _LINUX_EFI_H + +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999, 2002 Hewlett-Packard Co. + * David Mosberger-Tang + * Stephane Eranian + */ +#include +#include +#include +#include +#include + +#include +#include + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (1L | (1L << 63)) +#define EFI_INVALID_PARAMETER (2L | (1L << 63)) +#define EFI_UNSUPPORTED (3L | (1L << 63)) +#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) +#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) +#define EFI_NOT_FOUND (14L | (1L << 63)) + +typedef unsigned long efi_status_t; +typedef u8 efi_bool_t; +typedef u16 efi_char16_t; /* UNICODE character */ + + +typedef struct { + u8 b[16]; +} efi_guid_t; + +#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ +((efi_guid_t) \ +{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) + +/* + * Generic EFI table header + */ +typedef struct { + u64 signature; + u32 revision; + u32 headersize; + u32 crc32; + u32 reserved; +} efi_table_hdr_t; + +/* + * Memory map descriptor: + */ + +/* Memory types: */ +#define EFI_RESERVED_TYPE 0 +#define EFI_LOADER_CODE 1 +#define EFI_LOADER_DATA 2 +#define EFI_BOOT_SERVICES_CODE 3 +#define EFI_BOOT_SERVICES_DATA 4 +#define EFI_RUNTIME_SERVICES_CODE 5 +#define EFI_RUNTIME_SERVICES_DATA 6 +#define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNUSABLE_MEMORY 8 +#define EFI_ACPI_RECLAIM_MEMORY 9 +#define EFI_ACPI_MEMORY_NVS 10 +#define EFI_MEMORY_MAPPED_IO 11 +#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 +#define EFI_PAL_CODE 13 +#define EFI_MAX_MEMORY_TYPE 14 + +/* Attribute values: */ +#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ +#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ +#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ +#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ +#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ +#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ +#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ +#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +#define EFI_PAGE_SHIFT 12 + +typedef struct { + u32 type; + u32 pad; + u64 phys_addr; + u64 virt_addr; + u64 num_pages; + u64 attribute; +} efi_memory_desc_t; + +typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg); + +/* + * Types and defines for Time Services + */ +#define EFI_TIME_ADJUST_DAYLIGHT 0x1 +#define EFI_TIME_IN_DAYLIGHT 0x2 +#define EFI_UNSPECIFIED_TIMEZONE 0x07ff + +typedef struct { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad1; + u32 nanosecond; + s16 timezone; + u8 daylight; + u8 pad2; +} efi_time_t; + +typedef struct { + u32 resolution; + u32 accuracy; + u8 sets_to_zero; +} efi_time_cap_t; + +/* + * Types and defines for EFI ResetSystem + */ +#define EFI_RESET_COLD 0 +#define EFI_RESET_WARM 1 + +/* + * EFI Runtime Services table + */ +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552 +#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 + +typedef struct { + efi_table_hdr_t hdr; + u64 get_time; + u64 set_time; + u64 get_wakeup_time; + u64 set_wakeup_time; + u64 set_virtual_address_map; + u64 convert_pointer; + u64 get_variable; + u64 get_next_variable; + u64 set_variable; + u64 get_next_high_mono_count; + u64 reset_system; +} efi_runtime_services_t; + +typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); +typedef efi_status_t efi_set_time_t (efi_time_t *tm); +typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, + efi_time_t *tm); +typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); +typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, void *data); +typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, + efi_guid_t *vendor); +typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr, + unsigned long data_size, void *data); +typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count); +typedef void efi_reset_system_t (int reset_type, efi_status_t status, + unsigned long data_size, efi_char16_t *data); + +/* + * EFI Configuration Table and GUID definitions + */ +#define NULL_GUID \ + EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) + +#define MPS_TABLE_GUID \ + EFI_GUID( 0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define ACPI_TABLE_GUID \ + EFI_GUID( 0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define ACPI_20_TABLE_GUID \ + EFI_GUID( 0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 ) + +#define SMBIOS_TABLE_GUID \ + EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define SAL_SYSTEM_TABLE_GUID \ + EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define HCDP_TABLE_GUID \ + EFI_GUID( 0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 ) + +typedef struct { + efi_guid_t guid; + u64 table; +} efi_config_table_t; + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) + +typedef struct { + efi_table_hdr_t hdr; + u64 fw_vendor; /* physical addr of CHAR16 vendor string */ + u32 fw_revision; + u64 con_in_handle; + u64 con_in; + u64 con_out_handle; + u64 con_out; + u64 stderr_handle; + u64 stderr; + u64 runtime; + u64 boottime; + u64 nr_tables; + u64 tables; +} efi_system_table_t; + +/* + * All runtime access to EFI goes through this structure: + */ +extern struct efi { + efi_system_table_t *systab; /* EFI system table */ + void *mps; /* MPS table */ + void *acpi; /* ACPI table (IA64 ext 0.71) */ + void *acpi20; /* ACPI table (ACPI 2.0) */ + void *smbios; /* SM BIOS table */ + void *sal_systab; /* SAL system table */ + void *boot_info; /* boot info table */ + void *hcdp; /* HCDP table */ + efi_get_time_t *get_time; + efi_set_time_t *set_time; + efi_get_wakeup_time_t *get_wakeup_time; + efi_set_wakeup_time_t *set_wakeup_time; + efi_get_variable_t *get_variable; + efi_get_next_variable_t *get_next_variable; + efi_set_variable_t *set_variable; + efi_get_next_high_mono_count_t *get_next_high_mono_count; + efi_reset_system_t *reset_system; +} efi; + +static inline int +efi_guidcmp (efi_guid_t left, efi_guid_t right) +{ + return memcmp(&left, &right, sizeof (efi_guid_t)); +} + +static inline char * +efi_guid_unparse(efi_guid_t *guid, char *out) +{ + sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->b[3], guid->b[2], guid->b[1], guid->b[0], + guid->b[5], guid->b[4], guid->b[7], guid->b[6], + guid->b[8], guid->b[9], guid->b[10], guid->b[11], + guid->b[12], guid->b[13], guid->b[14], guid->b[15]); + return out; +} + +extern void efi_init (void); +extern void efi_map_pal_code (void); +extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); +extern void efi_gettimeofday (struct timeval *tv); +extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ +extern u64 efi_get_iobase (void); +extern u32 efi_mem_type (unsigned long phys_addr); +extern u64 efi_mem_attributes (unsigned long phys_addr); + +/* + * Variable Attributes + */ +#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 + + +/* + * efi_dir is allocated in arch/ia64/kernel/efi.c. + */ +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *efi_dir; +#endif + +#endif /* _LINUX_EFI_H */ diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h --- a/include/linux/gfp.h Sat Aug 31 15:05:55 2002 +++ b/include/linux/gfp.h Sat Aug 31 15:05:55 2002 @@ -40,7 +40,7 @@ * virtual kernel addresses to the allocated page(s). */ extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order)); -extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)); +extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, struct zonelist *zonelist)); extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order); static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) diff -Nru a/include/linux/highmem.h b/include/linux/highmem.h --- a/include/linux/highmem.h Sat Aug 31 15:05:55 2002 +++ b/include/linux/highmem.h Sat Aug 31 15:05:55 2002 @@ -22,7 +22,7 @@ static inline void *kmap(struct page *page) { return page_address(page); } -#define kunmap(page) do { } while (0) +#define kunmap(page) do { (void) (page); } while (0) #define kmap_atomic(page,idx) kmap(page) #define kunmap_atomic(page,idx) kunmap(page) diff -Nru a/include/linux/ide.h b/include/linux/ide.h --- a/include/linux/ide.h Sat Aug 31 15:05:59 2002 +++ b/include/linux/ide.h Sat Aug 31 15:05:59 2002 @@ -470,7 +470,6 @@ unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ - unsigned revalidate : 1; /* request revalidation */ unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ @@ -530,6 +529,7 @@ byte acoustic; /* acoustic management */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ + struct list_head list; } ide_drive_t; /* @@ -889,6 +889,7 @@ #define IDE_SUBDRIVER_VERSION 1 typedef struct ide_driver_s { + struct module *owner; const char *name; const char *version; byte media; @@ -913,10 +914,11 @@ unsigned long (*capacity)(ide_drive_t *); ide_startstop_t (*special)(ide_drive_t *); ide_proc_entry_t *proc; - int (*init)(void); int (*reinit)(ide_drive_t *); void (*ata_prebuilder)(ide_drive_t *); void (*atapi_prebuilder)(ide_drive_t *); + struct list_head drives; + struct list_head drivers; } ide_driver_t; #define DRIVER(drive) ((drive)->driver) @@ -926,7 +928,6 @@ */ #define IDE_CHIPSET_MODULE 0 /* not supported yet */ #define IDE_PROBE_MODULE 1 -#define IDE_DRIVER_MODULE 2 typedef int (ide_module_init_proc)(void); @@ -947,7 +948,6 @@ */ #ifndef _IDE_C extern ide_hwif_t ide_hwifs[]; /* master data repository */ -extern ide_module_t *ide_modules; extern ide_module_t *ide_probe; #endif extern int noautodma; @@ -1210,37 +1210,16 @@ extern ide_proc_entry_t generic_subdriver_entries[]; #endif -int ide_reinit_drive (ide_drive_t *drive); +int ata_attach(ide_drive_t *drive); #ifdef _IDE_C #ifdef CONFIG_BLK_DEV_IDE int ideprobe_init (void); #endif /* CONFIG_BLK_DEV_IDE */ -#ifdef CONFIG_BLK_DEV_IDEDISK -int idedisk_reinit (ide_drive_t *drive); -int idedisk_init (void); -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDECD -int ide_cdrom_reinit (ide_drive_t *drive); -int ide_cdrom_init (void); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE -int idetape_reinit (ide_drive_t *drive); -int idetape_init (void); -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY -int idefloppy_reinit (ide_drive_t *drive); -int idefloppy_init (void); -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDESCSI -int idescsi_reinit (ide_drive_t *drive); -int idescsi_init (void); -#endif /* CONFIG_BLK_DEV_IDESCSI */ #endif /* _IDE_C */ -int ide_register_module (ide_module_t *module); -void ide_unregister_module (ide_module_t *module); -ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n); +int ide_register_driver(ide_driver_t *driver); +void ide_unregister_driver(ide_driver_t *driver); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_unregister_subdriver (ide_drive_t *drive); int ide_replace_subdriver(ide_drive_t *drive, const char *driver); diff -Nru a/include/linux/in.h b/include/linux/in.h --- a/include/linux/in.h Sat Aug 31 15:06:00 2002 +++ b/include/linux/in.h Sat Aug 31 15:06:00 2002 @@ -37,11 +37,12 @@ IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ - IPPROTO_PIM = 103, /* Protocol Independent Multicast */ - IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ IPPROTO_AH = 51, /* Authentication Header protocol */ + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ + IPPROTO_COMP = 108, /* Compression Header protocol */ + IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX diff -Nru a/include/linux/interrupt.h b/include/linux/interrupt.h --- a/include/linux/interrupt.h Sat Aug 31 15:05:53 2002 +++ b/include/linux/interrupt.h Sat Aug 31 15:05:53 2002 @@ -50,9 +50,9 @@ #if !CONFIG_SMP # define cli() local_irq_disable() # define sti() local_irq_enable() -# define save_flags(x) local_irq_save(x) +# define save_flags(x) local_save_flags(x) # define restore_flags(x) local_irq_restore(x) -# define save_and_cli(x) local_irq_save_off(x) +# define save_and_cli(x) local_irq_save(x) #endif diff -Nru a/include/linux/kernel.h b/include/linux/kernel.h --- a/include/linux/kernel.h Sat Aug 31 15:05:53 2002 +++ b/include/linux/kernel.h Sat Aug 31 15:05:53 2002 @@ -191,4 +191,10 @@ }; #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +/* Trap pasters of __FUNCTION__ at compile-time */ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 95 +#define __FUNCTION__ (__func__) +#endif + #endif diff -Nru a/include/linux/list.h b/include/linux/list.h --- a/include/linux/list.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/list.h Sat Aug 31 15:05:54 2002 @@ -211,6 +211,19 @@ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/mm.h Sat Aug 31 15:05:54 2002 @@ -157,7 +157,7 @@ struct address_space *mapping; /* The inode (or ...) we belong to. */ unsigned long index; /* Our offset within mapping. */ struct list_head lru; /* Pageout list, eg. active_list; - protected by pagemap_lru_lock !! */ + protected by zone->lru_lock !! */ union { struct pte_chain * chain; /* Reverse pte mapping pointer. * protected by PG_chainlock */ @@ -182,6 +182,12 @@ }; /* + * FIXME: take this include out, include page-flags.h in + * files which need it (119 of them) + */ +#include + +/* * Methods to modify the page usage count. * * What counts for a page usage: @@ -195,17 +201,23 @@ */ #define get_page(p) atomic_inc(&(p)->count) #define __put_page(p) atomic_dec(&(p)->count) -#define put_page_testzero(p) atomic_dec_and_test(&(p)->count) +#define put_page_testzero(p) \ + ({ \ + BUG_ON(page_count(page) == 0); \ + atomic_dec_and_test(&(p)->count); \ + }) #define page_count(p) atomic_read(&(p)->count) #define set_page_count(p,v) atomic_set(&(p)->count, v) + extern void FASTCALL(__page_cache_release(struct page *)); -#define put_page(p) \ - do { \ - if (!PageReserved(p) && put_page_testzero(p)) \ - __page_cache_release(p); \ - } while (0) void FASTCALL(__free_pages_ok(struct page *page, unsigned int order)); +static inline void put_page(struct page *page) +{ + if (!PageReserved(page) && put_page_testzero(page)) + __page_cache_release(page); +} + /* * Multiple processes may "see" the same page. E.g. for untouched * mappings of /dev/null, all processes see the same page full of @@ -256,22 +268,16 @@ */ /* - * FIXME: take this include out, include page-flags.h in - * files which need it (119 of them) - */ -#include - -/* * The zone field is never updated after free_area_init_core() * sets it, so none of the operations on it need to be atomic. */ #define NODE_SHIFT 4 #define ZONE_SHIFT (BITS_PER_LONG - 8) -struct zone_struct; -extern struct zone_struct *zone_table[]; +struct zone; +extern struct zone *zone_table[]; -static inline zone_t *page_zone(struct page *page) +static inline struct zone *page_zone(struct page *page) { return zone_table[page->flags >> ZONE_SHIFT]; } @@ -449,7 +455,6 @@ return 0; } -struct zone_t; /* filemap.c */ extern unsigned long page_unuse(struct page *); extern void truncate_inode_pages(struct address_space *, loff_t); diff -Nru a/include/linux/mm_inline.h b/include/linux/mm_inline.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/mm_inline.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,40 @@ + +static inline void +add_page_to_active_list(struct zone *zone, struct page *page) +{ + list_add(&page->lru, &zone->active_list); + zone->nr_active++; +} + +static inline void +add_page_to_inactive_list(struct zone *zone, struct page *page) +{ + list_add(&page->lru, &zone->inactive_list); + zone->nr_inactive++; +} + +static inline void +del_page_from_active_list(struct zone *zone, struct page *page) +{ + list_del(&page->lru); + zone->nr_active--; +} + +static inline void +del_page_from_inactive_list(struct zone *zone, struct page *page) +{ + list_del(&page->lru); + zone->nr_inactive--; +} + +static inline void +del_page_from_lru(struct zone *zone, struct page *page) +{ + list_del(&page->lru); + if (PageActive(page)) { + ClearPageActive(page); + zone->nr_active--; + } else { + zone->nr_inactive--; + } +} diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h --- a/include/linux/mmzone.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/mmzone.h Sat Aug 31 15:05:54 2002 @@ -8,6 +8,8 @@ #include #include #include +#include +#include /* * Free memory management - zoned buddy allocator. @@ -27,6 +29,21 @@ struct pglist_data; /* + * zone->lock and zone->lru_lock are two of the hottest locks in the kernel. + * So add a wild amount of padding here to ensure that they fall into separate + * cachelines. There are very few zone structures in the machine, so space + * consumption is not a concern here. + */ +#if defined(CONFIG_SMP) +struct zone_padding { + int x; +} ____cacheline_maxaligned_in_smp; +#define ZONE_PADDING(name) struct zone_padding name; +#else +#define ZONE_PADDING(name) +#endif + +/* * On machines where it is needed (eg PCs) we divide physical memory * into multiple physical zones. On a PC we have 3 zones: * @@ -34,7 +51,8 @@ * ZONE_NORMAL 16-896 MB direct mapped by the kernel * ZONE_HIGHMEM > 896 MB only page cache and user processes */ -typedef struct zone_struct { + +struct zone { /* * Commonly accessed fields: */ @@ -43,6 +61,17 @@ unsigned long pages_min, pages_low, pages_high; int need_balance; + ZONE_PADDING(_pad1_) + + spinlock_t lru_lock; + struct list_head active_list; + struct list_head inactive_list; + atomic_t refill_counter; + unsigned long nr_active; + unsigned long nr_inactive; + + ZONE_PADDING(_pad2_) + /* * free areas of different sizes */ @@ -89,7 +118,7 @@ */ char *name; unsigned long size; -} zone_t; +} ____cacheline_maxaligned_in_smp; #define ZONE_DMA 0 #define ZONE_NORMAL 1 @@ -107,16 +136,16 @@ * so despite the zonelist table being relatively big, the cache * footprint of this construct is very small. */ -typedef struct zonelist_struct { - zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited -} zonelist_t; +struct zonelist { + struct zone *zones[MAX_NR_ZONES+1]; // NULL delimited +}; #define GFP_ZONEMASK 0x0f /* * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM * (mostly NUMA machines?) to denote a higher-level memory zone than the - * zone_struct denotes. + * zone denotes. * * On NUMA machines, each NUMA node would have a pg_data_t to describe * it's memory layout. @@ -126,8 +155,8 @@ */ struct bootmem_data; typedef struct pglist_data { - zone_t node_zones[MAX_NR_ZONES]; - zonelist_t node_zonelists[GFP_ZONEMASK+1]; + struct zone node_zones[MAX_NR_ZONES]; + struct zonelist node_zonelists[GFP_ZONEMASK+1]; int nr_zones; struct page *node_mem_map; unsigned long *valid_addr_bitmap; @@ -142,7 +171,8 @@ extern int numnodes; extern pg_data_t *pgdat_list; -static inline int memclass(zone_t *pgzone, zone_t *classzone) +static inline int +memclass(struct zone *pgzone, struct zone *classzone) { if (pgzone->zone_pgdat != classzone->zone_pgdat) return 0; @@ -156,10 +186,10 @@ * prototypes for the discontig memory code. */ struct page; -extern void show_free_areas_core(pg_data_t *pgdat); -extern void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, +void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size, struct page *pmap); +void get_zone_counts(unsigned long *active, unsigned long *inactive); extern pg_data_t contig_page_data; @@ -181,7 +211,7 @@ * next_zone - helper magic for for_each_zone() * Thanks to William Lee Irwin III for this piece of ingenuity. */ -static inline zone_t * next_zone(zone_t * zone) +static inline struct zone *next_zone(struct zone *zone) { pg_data_t *pgdat = zone->zone_pgdat; @@ -198,7 +228,7 @@ /** * for_each_zone - helper macro to iterate over all memory zones - * @zone - pointer to zone_t variable + * @zone - pointer to struct zone variable * * The user only needs to declare the zone variable, for_each_zone * fills it in. This basically means for_each_zone() is an @@ -206,7 +236,7 @@ * * for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next) * for (i = 0; i < MAX_NR_ZONES; ++i) { - * zone_t * z = pgdat->node_zones + i; + * struct zone * z = pgdat->node_zones + i; * ... * } * } diff -Nru a/include/linux/net.h b/include/linux/net.h --- a/include/linux/net.h Sat Aug 31 15:05:59 2002 +++ b/include/linux/net.h Sat Aug 31 15:05:59 2002 @@ -137,6 +137,7 @@ extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags); extern int sock_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * iov, long count, long size); +extern int sock_map_fd(struct socket *sock); extern int net_ratelimit(void); extern unsigned long net_random(void); diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/netdevice.h Sat Aug 31 15:06:06 2002 @@ -365,6 +365,7 @@ #define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ +#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */ /* Called after device is detached from network. */ void (*uninit)(struct net_device *dev); diff -Nru a/include/linux/nvram.h b/include/linux/nvram.h --- a/include/linux/nvram.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/nvram.h Sat Aug 31 15:06:06 2002 @@ -4,14 +4,24 @@ #include /* /dev/nvram ioctls */ -#define NVRAM_INIT _IO('p', 0x40) /* initialize NVRAM and set checksum */ -#define NVRAM_SETCKS _IO('p', 0x41) /* recalculate checksum */ +#define NVRAM_INIT _IO('p', 0x40) /* initialize NVRAM and set checksum */ +#define NVRAM_SETCKS _IO('p', 0x41) /* recalculate checksum */ + +/* for all current systems, this is where NVRAM starts */ +#define NVRAM_FIRST_BYTE 14 +/* all these functions expect an NVRAM offset, not an absolute */ +#define NVRAM_OFFSET(x) ((x)-NVRAM_FIRST_BYTE) #ifdef __KERNEL__ -extern unsigned char nvram_read_byte( int i ); -extern void nvram_write_byte( unsigned char c, int i ); -extern int nvram_check_checksum( void ); -extern void nvram_set_checksum( void ); +/* __foo is foo without grabbing the rtc_lock - get it yourself */ +extern unsigned char __nvram_read_byte(int i); +extern unsigned char nvram_read_byte(int i); +extern void __nvram_write_byte(unsigned char c, int i); +extern void nvram_write_byte(unsigned char c, int i); +extern int __nvram_check_checksum(void); +extern int nvram_check_checksum(void); +extern void __nvram_set_checksum(void); +extern void nvram_set_checksum(void); #endif #endif /* _LINUX_NVRAM_H */ diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/page-flags.h Sat Aug 31 15:05:54 2002 @@ -28,7 +28,7 @@ * * Note that the referenced bit, the page->lru list_head and the active, * inactive_dirty and inactive_clean lists are protected by the - * pagemap_lru_lock, and *NOT* by the usual PG_locked bit! + * zone->lru_lock, and *NOT* by the usual PG_locked bit! * * PG_error is set to indicate that an I/O error occurred on this page. * @@ -76,8 +76,6 @@ unsigned long nr_dirty; unsigned long nr_writeback; unsigned long nr_pagecache; - unsigned long nr_active; /* on active_list LRU */ - unsigned long nr_inactive; /* on inactive_list LRU */ unsigned long nr_page_table_pages; unsigned long nr_reverse_maps; } ____cacheline_aligned_in_smp page_states[NR_CPUS]; @@ -163,6 +161,7 @@ #define SetPageActive(page) set_bit(PG_active, &(page)->flags) #define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) #define TestClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags) +#define TestSetPageActive(page) test_and_set_bit(PG_active, &(page)->flags) #define PageSlab(page) test_bit(PG_slab, &(page)->flags) #define SetPageSlab(page) set_bit(PG_slab, &(page)->flags) diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h --- a/include/linux/pagemap.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/pagemap.h Sat Aug 31 15:05:54 2002 @@ -22,13 +22,9 @@ #define PAGE_CACHE_MASK PAGE_MASK #define PAGE_CACHE_ALIGN(addr) (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK) -#define page_cache_get(x) get_page(x) - -static inline void page_cache_release(struct page *page) -{ - if (!PageReserved(page) && put_page_testzero(page)) - __page_cache_release(page); -} +#define page_cache_get(page) get_page(page) +#define page_cache_release(page) put_page(page) +void release_pages(struct page **pages, int nr); static inline struct page *page_cache_alloc(struct address_space *x) { diff -Nru a/include/linux/pagevec.h b/include/linux/pagevec.h --- a/include/linux/pagevec.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/pagevec.h Sat Aug 31 15:06:06 2002 @@ -18,7 +18,6 @@ void __pagevec_release_nonlru(struct pagevec *pvec); void __pagevec_free(struct pagevec *pvec); void __pagevec_lru_add(struct pagevec *pvec); -void __pagevec_lru_del(struct pagevec *pvec); void lru_add_drain(void); void pagevec_deactivate_inactive(struct pagevec *pvec); @@ -68,10 +67,4 @@ { if (pagevec_count(pvec)) __pagevec_lru_add(pvec); -} - -static inline void pagevec_lru_del(struct pagevec *pvec) -{ - if (pagevec_count(pvec)) - __pagevec_lru_del(pvec); } diff -Nru a/include/linux/pci.h b/include/linux/pci.h --- a/include/linux/pci.h Sat Aug 31 15:06:00 2002 +++ b/include/linux/pci.h Sat Aug 31 15:06:00 2002 @@ -359,6 +359,7 @@ 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */ + struct list_head pools; /* pci_pools tied to this device */ u32 current_state; /* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, @@ -456,12 +457,8 @@ /* Low-level architecture-dependent routines */ struct pci_ops { - int (*read_byte)(struct pci_dev *, int where, u8 *val); - int (*read_word)(struct pci_dev *, int where, u16 *val); - int (*read_dword)(struct pci_dev *, int where, u32 *val); - int (*write_byte)(struct pci_dev *, int where, u8 val); - int (*write_word)(struct pci_dev *, int where, u16 val); - int (*write_dword)(struct pci_dev *, int where, u32 val); + int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); + int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); }; struct pbus_set_ranges_data @@ -560,12 +557,37 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); -int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); -int pci_read_config_word(struct pci_dev *dev, int where, u16 *val); -int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val); -int pci_write_config_byte(struct pci_dev *dev, int where, u8 val); -int pci_write_config_word(struct pci_dev *dev, int where, u16 val); -int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); +int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); +int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); +int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val); +int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val); +int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val); +int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val); + +static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) +{ + return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val); +} +static int inline pci_read_config_word(struct pci_dev *dev, int where, u16 *val) +{ + return pci_bus_read_config_word (dev->bus, dev->devfn, where, val); +} +static int inline pci_read_config_dword(struct pci_dev *dev, int where, u32 *val) +{ + return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val); +} +static int inline pci_write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val); +} +static int inline pci_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + return pci_bus_write_config_word (dev->bus, dev->devfn, where, val); +} +static int inline pci_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); +} extern spinlock_t pci_lock; diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/sched.h Sat Aug 31 15:05:54 2002 @@ -405,6 +405,7 @@ #define PF_FREEZE 0x00010000 /* this task should be frozen for suspend */ #define PF_IOTHREAD 0x00020000 /* this thread is needed for doing I/O to swap */ #define PF_FROZEN 0x00040000 /* frozen for system suspend */ +#define PF_SYNC 0x00080000 /* performing fsync(), etc */ /* * Ptrace flags @@ -659,7 +660,7 @@ extern task_t *child_reaper; extern int do_execve(char *, char **, char **, struct pt_regs *); -extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); +extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int *); extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); diff -Nru a/include/linux/sctp.h b/include/linux/sctp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/sctp.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,588 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * Various protocol defined structures. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * randall@sctp.chicago.il.us + * kmorneau@cisco.com + * qxie1@email.mot.com + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#ifndef __LINUX_SCTP_H__ +#define __LINUX_SCTP_H__ + +#include /* We need in_addr. */ +#include /* We need in6_addr. */ + + +/* Section 3.1. SCTP Common Header Format */ +typedef struct sctphdr { + __u16 source; + __u16 dest; + __u32 vtag; + __u32 checksum; +} sctp_sctphdr_t __attribute__((packed)); + +/* Section 3.2. Chunk Field Descriptions. */ +typedef struct sctp_chunkhdr { + __u8 type; + __u8 flags; + __u16 length; +} sctp_chunkhdr_t __attribute__((packed)); + + +/* Section 3.2. Chunk Type Values. + * [Chunk Type] identifies the type of information contained in the Chunk + * Value field. It takes a value from 0 to 254. The value of 255 is + * reserved for future use as an extension field. + */ +typedef enum { + SCTP_CID_DATA = 0, + SCTP_CID_INIT = 1, + SCTP_CID_INIT_ACK = 2, + SCTP_CID_SACK = 3, + SCTP_CID_HEARTBEAT = 4, + SCTP_CID_HEARTBEAT_ACK = 5, + SCTP_CID_ABORT = 6, + SCTP_CID_SHUTDOWN = 7, + SCTP_CID_SHUTDOWN_ACK = 8, + SCTP_CID_ERROR = 9, + SCTP_CID_COOKIE_ECHO = 10, + SCTP_CID_COOKIE_ACK = 11, + SCTP_CID_ECN_ECNE = 12, + SCTP_CID_ECN_CWR = 13, + SCTP_CID_SHUTDOWN_COMPLETE = 14, + + /* Use hex, as defined in ADDIP sec. 3.1 */ + SCTP_CID_ASCONF = 0xC1, + SCTP_CID_ASCONF_ACK = 0x80, +} sctp_cid_t; /* enum */ + + +/* Section 3.2 + * Chunk Types are encoded such that the highest-order two bits specify + * the action that must be taken if the processing endpoint does not + * recognize the Chunk Type. + */ +typedef enum { + SCTP_CID_ACTION_DISCARD = 0x00, + SCTP_CID_ACTION_DISCARD_ERR = 0x40, + SCTP_CID_ACTION_SKIP = 0x80, + SCTP_CID_ACTION_SKIP_ERR = 0xc0, +} sctp_cid_action_t; + +enum { SCTP_CID_ACTION_MASK = 0xc0, }; + +/* This flag is used in Chunk Flags for ABORT and SHUTDOWN COMPLETE. + * + * 3.3.7 Abort Association (ABORT) (6): + * The T bit is set to 0 if the sender had a TCB that it destroyed. + * If the sender did not have a TCB it should set this bit to 1. + */ +enum { SCTP_CHUNK_FLAG_T = 0x01 }; + +/* + * Set the T bit + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 14 |Reserved |T| Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bits + * + * Reserved: 7 bits + * Set to 0 on transmit and ignored on receipt. + * + * T bit: 1 bit + * The T bit is set to 0 if the sender had a TCB that it destroyed. If + * the sender did NOT have a TCB it should set this bit to 1. + * + * Note: Special rules apply to this chunk for verification, please + * see Section 8.5.1 for details. + */ + +#define sctp_test_T_bit(c) ((c)->chunk_hdr->flags & SCTP_CHUNK_FLAG_T) + +/* RFC 2960 + * Section 3.2.1 Optional/Variable-length Parmaeter Format. + */ + +typedef struct sctp_paramhdr { + __u16 type; + __u16 length; +} sctp_paramhdr_t __attribute((packed)); + +typedef enum { + + /* RFC 2960 Section 3.3.5 */ + SCTP_PARAM_HEATBEAT_INFO = __constant_htons(1), + /* RFC 2960 Section 3.3.2.1 */ + SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), + SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), + SCTP_PARAM_STATE_COOKIE = __constant_htons(7), + SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8), + SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9), + SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11), + SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), + SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), + + /* Add-IP Extension. Section 3.2 */ + SCTP_PARAM_ADD_IP = __constant_htons(0xc001), + SCTP_PARAM_DEL_IP = __constant_htons(0xc002), + SCTP_PARAM_ERR_CAUSE = __constant_htons(0xc003), + SCTP_PARAM_SET_PRIMARY = __constant_htons(0xc004), + SCTP_PARAM_SUCCESS_REPORT = __constant_htons(0xc005), + SCTP_PARAM_ADAPTION_LAYER_IND = __constant_htons(0xc006), + +} sctp_param_t; /* enum */ + + +/* RFC 2960 Section 3.2.1 + * The Parameter Types are encoded such that the highest-order two bits + * specify the action that must be taken if the processing endpoint does + * not recognize the Parameter Type. + * + */ +typedef enum { + SCTP_PARAM_ACTION_DISCARD = __constant_htons(0x0000), + SCTP_PARAM_ACTION_DISCARD_ERR = __constant_htons(0x4000), + SCTP_PARAM_ACTION_SKIP = __constant_htons(0x8000), + SCTP_PARAM_ACTION_SKIP_ERR = __constant_htons(0xc000), +} sctp_param_action_t; + + +/* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ + +typedef struct sctp_datahdr { + __u32 tsn; + __u16 stream; + __u16 ssn; + __u32 ppid; + __u8 payload[0]; +} sctp_datahdr_t __attribute__((packed)); + +typedef struct sctp_data_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_datahdr_t data_hdr; +} sctp_data_chunk_t __attribute__((packed)); + +/* DATA Chuck Specific Flags */ +enum { + SCTP_DATA_MIDDLE_FRAG = 0x00, + SCTP_DATA_LAST_FRAG = 0x01, + SCTP_DATA_FIRST_FRAG = 0x02, + SCTP_DATA_NOT_FRAG = 0x03, + SCTP_DATA_UNORDERED = 0x04, +}; +enum { SCTP_DATA_FRAG_MASK = 0x03, }; + + +/* RFC 2960 Section 3.3.2 Initiation (INIT) (1) + * + * This chunk is used to initiate a SCTP association between two + * endpoints. + */ +typedef struct sctp_inithdr { + __u32 init_tag; + __u32 a_rwnd; + __u16 num_outbound_streams; + __u16 num_inbound_streams; + __u32 initial_tsn; + __u8 params[0]; +} sctp_inithdr_t __attribute__((packed)); + +typedef struct sctp_init_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_inithdr_t init_hdr; +} sctp_init_chunk_t __attribute__((packed)); + + +/* Section 3.3.2.1. IPv4 Address Parameter (5) */ +typedef struct sctp_ipv4addr_param { + sctp_paramhdr_t param_hdr; + struct in_addr addr; +} sctp_ipv4addr_param_t __attribute__((packed)); + +/* Section 3.3.2.1. IPv6 Address Parameter (6) */ +typedef struct sctp_ipv6addr_param { + sctp_paramhdr_t param_hdr; + struct in6_addr addr; +} sctp_ipv6addr_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Cookie Preservative (9) */ +typedef struct sctp_cookie_preserve_param { + sctp_paramhdr_t param_hdr; + uint32_t lifespan_increment; +} sctp_cookie_preserve_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Host Name Address (11) */ +typedef struct sctp_hostname_param { + sctp_paramhdr_t param_hdr; + uint8_t hostname[0]; +} sctp_hostname_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Supported Address Types (12) */ +typedef struct sctp_supported_addrs_param { + sctp_paramhdr_t param_hdr; + uint16_t types[0]; +} sctp_supported_addrs_param_t __attribute__((packed)); + +/* Appendix A. ECN Capable (32768) */ +typedef struct sctp_ecn_capable_param { + sctp_paramhdr_t param_hdr; +} sctp_ecn_capable_param_t __attribute__((packed)); + + + +/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): + * The INIT ACK chunk is used to acknowledge the initiation of an SCTP + * association. + */ +typedef sctp_init_chunk_t sctp_initack_chunk_t; + +/* Section 3.3.3.1 State Cookie (7) */ +typedef struct sctp_cookie_param { + sctp_paramhdr_t p; + __u8 body[0]; +} sctp_cookie_param_t __attribute__((packed)); + +/* Section 3.3.3.1 Unrecognized Parameters (8) */ +typedef struct sctp_unrecognized_param { + sctp_paramhdr_t param_hdr; + sctp_paramhdr_t unrecognized; +} sctp_unrecognized_param_t __attribute__((packed)); + + + +/* + * 3.3.4 Selective Acknowledgement (SACK) (3): + * + * This chunk is sent to the peer endpoint to acknowledge received DATA + * chunks and to inform the peer endpoint of gaps in the received + * subsequences of DATA chunks as represented by their TSNs. + */ + +typedef struct sctp_gap_ack_block { + __u16 start; + __u16 end; +} sctp_gap_ack_block_t __attribute__((packed)); + +typedef uint32_t sctp_dup_tsn_t; + +typedef union { + sctp_gap_ack_block_t gab; + sctp_dup_tsn_t dup; +} sctp_sack_variable_t; + +typedef struct sctp_sackhdr { + __u32 cum_tsn_ack; + __u32 a_rwnd; + __u16 num_gap_ack_blocks; + __u16 num_dup_tsns; + sctp_sack_variable_t variable[0]; +} sctp_sackhdr_t __attribute__((packed)); + +typedef struct sctp_sack_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_sackhdr_t sack_hdr; +} sctp_sack_chunk_t __attribute__((packed)); + + +/* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4): + * + * An endpoint should send this chunk to its peer endpoint to probe the + * reachability of a particular destination transport address defined in + * the present association. + */ + +typedef struct sctp_heartbeathdr { + sctp_paramhdr_t info; +} sctp_heartbeathdr_t __attribute__((packed)); + +typedef struct sctp_heartbeat_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_heartbeathdr_t hb_hdr; +} sctp_heartbeat_chunk_t __attribute__((packed)); + + +/* For the abort and shutdown ACK we must carry the init tag in the + * common header. Just the common header is all that is needed with a + * chunk descriptor. + */ +typedef struct sctp_abort_chunk { + sctp_chunkhdr_t uh; +} sctp_abort_chunkt_t __attribute__((packed)); + + +/* For the graceful shutdown we must carry the tag (in common header) + * and the highest consecutive acking value. + */ +typedef struct sctp_shutdownhdr { + __u32 cum_tsn_ack; +} sctp_shutdownhdr_t __attribute__((packed)); + +struct sctp_shutdown_chunk_t { + sctp_chunkhdr_t chunk_hdr; + sctp_shutdownhdr_t shutdown_hdr; +} __attribute__((packed)); + + + +/* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ + +typedef struct sctp_errhdr { + __u16 cause; + __u16 length; + __u8 variable[0]; +} sctp_errhdr_t __attribute__((packed)); + +typedef struct sctp_operr_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_errhdr_t err_hdr; +} sctp_operr_chunk_t __attribute__((packed)); + +/* RFC 2960 3.3.10 - Operation Error + * + * Cause Code: 16 bits (unsigned integer) + * + * Defines the type of error conditions being reported. + * Cause Code + * Value Cause Code + * --------- ---------------- + * 1 Invalid Stream Identifier + * 2 Missing Mandatory Parameter + * 3 Stale Cookie Error + * 4 Out of Resource + * 5 Unresolvable Address + * 6 Unrecognized Chunk Type + * 7 Invalid Mandatory Parameter + * 8 Unrecognized Parameters + * 9 No User Data + * 10 Cookie Received While Shutting Down + */ +typedef enum { + + SCTP_ERROR_NO_ERROR = __constant_htons(0x00), + SCTP_ERROR_INV_STRM = __constant_htons(0x01), + SCTP_ERROR_MISS_PARAM = __constant_htons(0x02), + SCTP_ERROR_STALE_COOKIE = __constant_htons(0x03), + SCTP_ERROR_NO_RESOURCE = __constant_htons(0x04), + SCTP_ERROR_DNS_FAILED = __constant_htons(0x05), + SCTP_ERROR_UNKNOWN_CHUNK = __constant_htons(0x06), + SCTP_ERROR_INV_PARAM = __constant_htons(0x07), + SCTP_ERROR_UNKNOWN_PARAM = __constant_htons(0x08), + SCTP_ERROR_NO_DATA = __constant_htons(0x09), + SCTP_ERROR_COOKIE_IN_SHUTDOWN = __constant_htons(0x0a), + + + /* SCTP Implementation Guide: + * 11 Restart of an association with new addresses + * 12 User Initiated Abort + */ + + SCTP_ERROR_RESTART = __constant_htons(0x0b), + SCTP_ERROR_USER_ABORT = __constant_htons(0x0c), + + /* ADDIP Section 3.3 New Error Causes + * + * Four new Error Causes are added to the SCTP Operational Errors, + * primarily for use in the ASCONF-ACK chunk. + * + * Value Cause Code + * --------- ---------------- + * 0x0100 Request to Delete Last Remaining IP Address. + * 0x0101 Operation Refused Due to Resource Shortage. + * 0x0102 Request to Delete Source IP Address. + * 0x0103 Association Aborted due to illegal ASCONF-ACK + */ + SCTP_ERROR_DEL_LAST_IP = __constant_htons(0x0100), + SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101), + SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102), + SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103), + +} sctp_error_t; + + + +/* RFC 2960. Appendix A. Explicit Congestion Notification. + * Explicit Congestion Notification Echo (ECNE) (12) + */ +typedef struct sctp_ecnehdr { + __u32 lowest_tsn; +} sctp_ecnehdr_t; + +typedef struct sctp_ecne_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_ecnehdr_t ence_hdr; +} sctp_ecne_chunk_t __attribute__((packed)); + +/* RFC 2960. Appendix A. Explicit Congestion Notification. + * Congestion Window Reduced (CWR) (13) + */ +typedef struct sctp_cwrhdr { + __u32 lowest_tsn; +} sctp_cwrhdr_t; + +typedef struct sctp_cwr_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_cwrhdr_t cwr_hdr; +} sctp_cwr_chunk_t __attribute__((packed)); + + +/* FIXME: Cleanup needs to continue below this line. */ + +/* + * ADDIP Section 3.1 New Chunk Types + */ + + +/* ADDIP Section 3.1.1 + * + * ASCONF-Request Correlation ID: 32 bits (unsigned integer) + * + * This is an opaque integer assigned by the sender to identify each + * request parameter. It is in host byte order and is only meaningful + * to the sender. The receiver of the ASCONF Chunk will copy this 32 + * bit value into the ASCONF Correlation ID field of the + * ASCONF-ACK. The sender of the ASCONF can use this same value in the + * ASCONF-ACK to find which request the response is for. + * + * ASCONF Parameter: TLV format + * + * Each Address configuration change is represented by a TLV parameter + * as defined in Section 3.2. One or more requests may be present in + * an ASCONF Chunk. + */ +typedef struct { + __u32 correlation; + sctp_paramhdr_t p; + __u8 payload[0]; +} sctpAsconfReq_t; + +/* ADDIP + * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * + * This chunk is used to communicate to the remote endpoint one of the + * configuration change requests that MUST be acknowledged. The + * information carried in the ASCONF Chunk uses the form of a + * Tag-Length-Value (TLV), as described in "3.2.1 + * Optional/Variable-length Parameter Format" in [RFC2960], for all + * variable parameters. + */ +typedef struct { + __u32 serial; + __u8 reserved[3]; + __u8 addr_type; + __u32 addr[4]; + sctpAsconfReq_t requests[0]; +} sctpAsconf_t; + +/* ADDIP + * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) + * + * ASCONF-Request Correlation ID: 32 bits (unsigned integer) + * + * This value is copied from the ASCONF Correlation ID received in the + * ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify + * which ASCONF parameter this response is associated with. + * + * ASCONF Parameter Response : TLV format + * + * The ASCONF Parameter Response is used in the ASCONF-ACK to report + * status of ASCONF processing. By default, if a responding endpoint + * does not include any Error Cause, a success is indicated. Thus a + * sender of an ASCONF-ACK MAY indicate complete success of all TLVs in + * an ASCONF by returning only the Chunk Type, Chunk Flags, Chunk Length + * (set to 8) and the Serial Number. + */ +typedef union { + struct { + __u32 correlation; + sctp_paramhdr_t header; /* success report */ + } success; + struct { + __u32 correlation; + sctp_paramhdr_t header; /* error cause indication */ + sctp_paramhdr_t errcause; + uint8_t request[0]; /* original request from ASCONF */ + } error; +#define __correlation success.correlation +#define __header success.header +#define __cause error.errcause +#define __request error.request +} sctpAsconfAckRsp_t; + +/* ADDIP + * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) + * + * This chunk is used by the receiver of an ASCONF Chunk to + * acknowledge the reception. It carries zero or more results for any + * ASCONF Parameters that were processed by the receiver. + */ +typedef struct { + __u32 serial; + sctpAsconfAckRsp_t responses[0]; +} sctpAsconfAck_t; + +/********************************************************************* + * Internal structures + * + * These are data structures which never go out on the wire. + *********************************************************************/ + +/* What is this data structure for? The TLV isn't one--it is just a + * value. Perhaps this data structure ought to have a type--otherwise + * it is not unambigiously parseable. --piggy + */ +typedef struct { + struct list_head hook; + int length; /* length of the TLV */ + + /* the actually TLV to be copied into ASCONF_ACK */ + sctpAsconfAckRsp_t TLV; +} sctpAsconfAckRspNode_t; + + + + +#endif /* __LINUX_SCTP_H__ */ diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h --- a/include/linux/skbuff.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/skbuff.h Sat Aug 31 15:05:54 2002 @@ -109,7 +109,8 @@ struct sk_buff; -#define MAX_SKB_FRAGS 6 +/* To allow 64K frame to be packed as single skb without frag_list */ +#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2) typedef struct skb_frag_struct skb_frag_t; @@ -125,6 +126,8 @@ struct skb_shared_info { atomic_t dataref; unsigned int nr_frags; + unsigned short tso_size; + unsigned short tso_segs; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; }; diff -Nru a/include/linux/smp.h b/include/linux/smp.h --- a/include/linux/smp.h Sat Aug 31 15:06:00 2002 +++ b/include/linux/smp.h Sat Aug 31 15:06:00 2002 @@ -87,9 +87,6 @@ #define smp_processor_id() 0 #define hard_smp_processor_id() 0 #define smp_threads_ready 1 -#ifndef CONFIG_PREEMPT -#define kernel_lock() -#endif #define smp_call_function(func,info,retry,wait) ({ 0; }) static inline void smp_send_reschedule(int cpu) { } static inline void smp_send_reschedule_all(void) { } diff -Nru a/include/linux/socket.h b/include/linux/socket.h --- a/include/linux/socket.h Sat Aug 31 15:06:06 2002 +++ b/include/linux/socket.h Sat Aug 31 15:06:06 2002 @@ -227,6 +227,7 @@ #define SOL_UDP 17 #define SOL_IPV6 41 #define SOL_ICMPV6 58 +#define SOL_SCTP 132 #define SOL_RAW 255 #define SOL_IPX 256 #define SOL_AX25 257 diff -Nru a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h --- a/include/linux/sunrpc/svcsock.h Sat Aug 31 15:05:55 2002 +++ b/include/linux/sunrpc/svcsock.h Sat Aug 31 15:05:55 2002 @@ -21,7 +21,7 @@ struct sock * sk_sk; /* INET layer */ struct svc_serv * sk_server; /* service for this socket */ - unsigned char sk_inuse; /* use count */ + unsigned int sk_inuse; /* use count */ unsigned long sk_flags; #define SK_BUSY 0 /* enqueued/receiving */ #define SK_CONN 1 /* conn pending */ diff -Nru a/include/linux/swap.h b/include/linux/swap.h --- a/include/linux/swap.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/swap.h Sat Aug 31 15:05:54 2002 @@ -139,7 +139,7 @@ struct vm_area_struct; struct sysinfo; struct address_space; -struct zone_t; +struct zone; /* linux/mm/rmap.c */ extern int FASTCALL(page_referenced(struct page *)); @@ -163,7 +163,7 @@ /* linux/mm/vmscan.c */ extern wait_queue_head_t kswapd_wait; -extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int)); +extern int try_to_free_pages(struct zone *, unsigned int, unsigned int); /* linux/mm/page_io.c */ int swap_readpage(struct file *file, struct page *page); @@ -182,6 +182,7 @@ extern int move_from_swap_cache(struct page *page, unsigned long index, struct address_space *mapping); extern void free_page_and_swap_cache(struct page *page); +extern void free_pages_and_swap_cache(struct page **pages, int nr); extern struct page * lookup_swap_cache(swp_entry_t); extern struct page * read_swap_cache_async(swp_entry_t); @@ -209,54 +210,7 @@ asmlinkage long sys_swapoff(const char *); asmlinkage long sys_swapon(const char *, int); -extern spinlock_t _pagemap_lru_lock; - extern void FASTCALL(mark_page_accessed(struct page *)); - -/* - * List add/del helper macros. These must be called - * with the pagemap_lru_lock held! - */ -#define DEBUG_LRU_PAGE(page) \ -do { \ - if (!PageLRU(page)) \ - BUG(); \ - if (PageActive(page)) \ - BUG(); \ -} while (0) - -#define __add_page_to_active_list(page) \ -do { \ - list_add(&(page)->lru, &active_list); \ - inc_page_state(nr_active); \ -} while (0) - -#define add_page_to_active_list(page) \ -do { \ - DEBUG_LRU_PAGE(page); \ - SetPageActive(page); \ - __add_page_to_active_list(page); \ -} while (0) - -#define add_page_to_inactive_list(page) \ -do { \ - DEBUG_LRU_PAGE(page); \ - list_add(&(page)->lru, &inactive_list); \ - inc_page_state(nr_inactive); \ -} while (0) - -#define del_page_from_active_list(page) \ -do { \ - list_del(&(page)->lru); \ - ClearPageActive(page); \ - dec_page_state(nr_active); \ -} while (0) - -#define del_page_from_inactive_list(page) \ -do { \ - list_del(&(page)->lru); \ - dec_page_state(nr_inactive); \ -} while (0) extern spinlock_t swaplock; diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/sysctl.h Sat Aug 31 15:05:54 2002 @@ -172,6 +172,7 @@ NET_TR=14, NET_DECNET=15, NET_ECONET=16, + NET_SCTP=17, }; /* /proc/sys/kernel/random */ @@ -514,6 +515,21 @@ NET_DECNET_CONF_DEV_FORWARDING = 5, NET_DECNET_CONF_DEV_BLKSIZE = 6, NET_DECNET_CONF_DEV_STATE = 7 +}; + +/* /proc/sys/net/sctp */ +enum { + NET_SCTP_RTO_INITIAL = 1, + NET_SCTP_RTO_MIN = 2, + NET_SCTP_RTO_MAX = 3, + NET_SCTP_RTO_ALPHA = 4, + NET_SCTP_RTO_BETA = 5, + NET_SCTP_VALID_COOKIE_LIFE = 6, + NET_SCTP_ASSOCIATION_MAX_RETRANS = 7, + NET_SCTP_PATH_MAX_RETRANS = 8, + NET_SCTP_MAX_INIT_RETRANSMITS = 9, + NET_SCTP_HB_INTERVAL = 10, + NET_SCTP_MAX_BURST = 11, }; /* CTL_PROC names: */ diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h --- a/include/linux/tcp.h Sat Aug 31 15:06:00 2002 +++ b/include/linux/tcp.h Sat Aug 31 15:06:00 2002 @@ -241,7 +241,8 @@ __u32 snd_wnd; /* The window we expect to receive */ __u32 max_window; /* Maximal window ever seen from peer */ __u32 pmtu_cookie; /* Last pmtu seen by socket */ - __u16 mss_cache; /* Cached effective mss, not including SACKS */ + __u32 mss_cache; /* Cached effective mss, not including SACKS */ + __u16 mss_cache_std; /* Like mss_cache, but without TSO */ __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ __u16 ext_header_len; /* Network protocol overhead (IP/IPv6 options) */ __u8 ca_state; /* State of fast-retransmit machine */ diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Sat Aug 31 15:05:59 2002 +++ b/include/linux/usb.h Sat Aug 31 15:05:59 2002 @@ -1036,6 +1036,14 @@ void usb_buffer_dmasync (struct urb *urb); void usb_buffer_unmap (struct urb *urb); +struct scatterlist; +int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents); +void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); +void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); + /*-------------------------------------------------------------------* * SYNCHRONOUS CALL SUPPORT * *-------------------------------------------------------------------*/ diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h --- a/include/linux/writeback.h Sat Aug 31 15:05:54 2002 +++ b/include/linux/writeback.h Sat Aug 31 15:05:54 2002 @@ -72,4 +72,13 @@ read-only. */ +/* + * Tell the writeback paths that they are being called for a "data integrity" + * operation such as fsync(). + */ +static inline int called_for_sync(void) +{ + return current->flags & PF_SYNC; +} + #endif /* WRITEBACK_H */ diff -Nru a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h --- a/include/net/bluetooth/bluetooth.h Sat Aug 31 15:05:59 2002 +++ b/include/net/bluetooth/bluetooth.h Sat Aug 31 15:05:59 2002 @@ -73,16 +73,12 @@ extern void bluez_dump(char *pref, __u8 *buf, int count); -#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95 -#define __func__ __FUNCTION__ -#endif - #define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) -#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg) -#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) +#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg) +#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg) #ifdef HCI_DATA_DUMP -#define BT_DMP(buf, len) bluez_dump(__func__, buf, len) +#define BT_DMP(buf, len) bluez_dump(__FUNCTION__, buf, len) #else #define BT_DMP(D...) #endif diff -Nru a/include/net/inet_common.h b/include/net/inet_common.h --- a/include/net/inet_common.h Sat Aug 31 15:06:06 2002 +++ b/include/net/inet_common.h Sat Aug 31 15:06:06 2002 @@ -43,6 +43,14 @@ extern void inet_sock_destruct(struct sock *sk); extern atomic_t inet_sock_nr; +extern int inet_bind(struct socket *sock, + struct sockaddr *uaddr, int addr_len); +extern int inet_getname(struct socket *sock, + struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet_ioctl(struct socket *sock, + unsigned int cmd, unsigned long arg); + #endif diff -Nru a/include/net/inetpeer.h b/include/net/inetpeer.h --- a/include/net/inetpeer.h Sat Aug 31 15:05:54 2002 +++ b/include/net/inetpeer.h Sat Aug 31 15:05:54 2002 @@ -53,12 +53,13 @@ extern spinlock_t inet_peer_idlock; /* can be called with or without local BH being disabled */ -static inline __u16 inet_getid(struct inet_peer *p) +static inline __u16 inet_getid(struct inet_peer *p, int more) { __u16 id; spin_lock_bh(&inet_peer_idlock); - id = p->ip_id_count++; + id = p->ip_id_count; + p->ip_id_count += 1 + more; spin_unlock_bh(&inet_peer_idlock); return id; } diff -Nru a/include/net/ip.h b/include/net/ip.h --- a/include/net/ip.h Sat Aug 31 15:06:04 2002 +++ b/include/net/ip.h Sat Aug 31 15:06:04 2002 @@ -187,7 +187,7 @@ !(dst->mxlock&(1<id = (sk && inet_sk(sk)->daddr) ? htons(inet_sk(sk)->id++) : 0; } else - __ip_select_ident(iph, dst); + __ip_select_ident(iph, dst, 0); +} + +static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more) +{ + if (iph->frag_off&__constant_htons(IP_DF)) { + if (sk && inet_sk(sk)->daddr) { + iph->id = htons(inet_sk(sk)->id); + inet_sk(sk)->id += 1 + more; + } else + iph->id = 0; + } else + __ip_select_ident(iph, dst, more); } /* diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h --- a/include/net/ipv6.h Sat Aug 31 15:05:55 2002 +++ b/include/net/ipv6.h Sat Aug 31 15:05:55 2002 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ + * $Id: ipv6.h,v 1.1 2002/05/20 15:13:07 jgrimm Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -335,6 +335,14 @@ extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, u16 port, u32 info, u8 *payload); extern void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info); + +extern int inet6_release(struct socket *sock); +extern int inet6_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len); +extern int inet6_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet6_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); #endif /* __KERNEL__ */ #endif /* _NET_IPV6_H */ diff -Nru a/include/net/sctp/command.h b/include/net/sctp/command.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/command.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,211 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, and IBM + * + * This file is part of the SCTP kernel reference Implementation + * + * These are the definitions needed for the command object. + * + * The SCTP reference implementation 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. + * + * the SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the + * following email addresses: + * + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#ifndef __net_sctp_command_h__ +#define __net_sctp_command_h__ + +#include +#include + + +typedef enum { + SCTP_CMD_NOP = 0, /* Do nothing. */ + SCTP_CMD_NEW_ASOC, /* Register a new association. */ + SCTP_CMD_DELETE_TCB, /* Delete the current association. */ + SCTP_CMD_NEW_STATE, /* Enter a new state. */ + SCTP_CMD_REPORT_TSN, /* Record the arrival of a TSN. */ + SCTP_CMD_GEN_SACK, /* Send a Selective ACK (maybe). */ + SCTP_CMD_PROCESS_SACK, /* Process an inbound SACK. */ + SCTP_CMD_GEN_INIT_ACK, /* Generate an INIT ACK chunk. */ + SCTP_CMD_PEER_INIT, /* Process a INIT from the peer. */ + SCTP_CMD_GEN_COOKIE_ECHO, /* Generate a COOKIE ECHO chunk. */ + SCTP_CMD_CHUNK_ULP, /* Send a chunk to the sockets layer. */ + SCTP_CMD_EVENT_ULP, /* Send a notification to the sockets layer. */ + SCTP_CMD_REPLY, /* Send a chunk to our peer. */ + SCTP_CMD_SEND_PKT, /* Send a full packet to our peer. */ + SCTP_CMD_RETRAN, /* Mark a transport for retransmission. */ + SCTP_CMD_ECN_CE, /* Do delayed CE processing. */ + SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */ + SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */ + SCTP_CMD_TIMER_START, /* Start a timer. */ + SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ + SCTP_CMD_TIMER_STOP, /* Stop a timer. */ + SCTP_CMD_COUNTER_RESET, /* Reset a counter. */ + SCTP_CMD_COUNTER_INC, /* Increment a counter. */ + SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */ + SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ + SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ + SCTP_CMD_REPORT_BIGGAP, /* Narc on a TSN (it was too high). */ + SCTP_CMD_SET_BIND_ADDR, /* Set the association bind_addr. */ + SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ + SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ + SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ + SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */ + SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */ + SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */ + SCTP_CMD_REPORT_BAD_TAG, /* Verification tags didn't match. */ + SCTP_CMD_PROCESS_CTSN, /* Sideeffect from shutdown. */ + SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ + SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */ + SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ + SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ + SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ + SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ + + SCTP_CMD_LAST +} sctp_verb_t; + +#define SCTP_CMD_MAX (SCTP_CMD_LAST - 1) +#define SCTP_CMD_NUM_VERBS (SCTP_CMD_MAX + 1) + +/* How many commands can you put in an sctp_cmd_seq_t? + * This is a rather arbitrary number, ideally derived from a careful + * analysis of the state functions, but in reality just taken from + * thin air in the hopes othat we don't trigger a kernel panic. + */ +#define SCTP_MAX_NUM_COMMANDS 14 + +typedef union { + __s32 i32; + __u32 u32; + __u16 u16; + __u8 u8; + int error; + sctp_state_t state; + sctp_event_timeout_t to; + sctp_counter_t counter; + void *ptr; + sctp_chunk_t *chunk; + sctp_association_t *asoc; + sctp_transport_t *transport; + sctp_bind_addr_t *bp; + sctp_init_chunk_t *init; + sctp_ulpevent_t *ulpevent; + sctp_packet_t *packet; + sctp_sackhdr_t *sackh; +} sctp_arg_t; + +/* We are simulating ML type constructors here. + * + * SCTP_ARG_CONSTRUCTOR(NAME, TYPE, ELT) builds a function called + * SCTP_NAME() which takes an argument of type TYPE and returns an + * sctp_arg_t. It does this by inserting the sole argument into the + * ELT union element of a local sctp_arg_t. + * + * E.g., SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) builds SCTP_I32(arg), + * which takes an __s32 and returns a sctp_arg_t containing the + * __s32. So, after foo = SCTP_I32(arg), foo.i32 == arg. + */ +static inline sctp_arg_t SCTP_NULL(void) +{ + sctp_arg_t retval; retval.ptr = NULL; return retval; +} +static inline sctp_arg_t SCTP_NOFORCE(void) +{ + sctp_arg_t retval; retval.i32 = 0; return retval; +} +static inline sctp_arg_t SCTP_FORCE(void) +{ + sctp_arg_t retval; retval.i32 = 1; return retval; +} + +#define SCTP_ARG_CONSTRUCTOR(name, type, elt) \ +static inline sctp_arg_t \ +SCTP_## name (type arg) \ +{ sctp_arg_t retval; retval.elt = arg; return retval; } + +SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) +SCTP_ARG_CONSTRUCTOR(U32, __u32, u32) +SCTP_ARG_CONSTRUCTOR(U16, __u16, u16) +SCTP_ARG_CONSTRUCTOR(U8, __u8, u8) +SCTP_ARG_CONSTRUCTOR(ERROR, int, error) +SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) +SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) +SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) +SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) +SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk) +SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) +SCTP_ARG_CONSTRUCTOR(TRANSPORT, sctp_transport_t *, transport) +SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp) +SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) +SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent) +SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet) +SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) + +typedef struct { + sctp_arg_t obj; + sctp_verb_t verb; +} sctp_cmd_t; + +typedef struct { + sctp_cmd_t cmds[SCTP_MAX_NUM_COMMANDS]; + __u8 next_free_slot; + __u8 next_cmd; +} sctp_cmd_seq_t; + + +/* Create a new sctp_command_sequence. + * Return NULL if creating a new sequence fails. + */ +sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); + +/* Initialize a block of memory as a command sequence. + * Return 0 if the initialization fails. + */ +int sctp_init_cmd_seq(sctp_cmd_seq_t *seq); + +/* Add a command to an sctp_cmd_seq_t. + * Return 0 if the command sequence is full. + * + * Use the SCTP_* constructors defined by SCTP_ARG_CONSTRUCTOR() above + * to wrap data which goes in the obj argument. + */ +int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); + +/* Rewind an sctp_cmd_seq_t to iterate from the start. + * Return 0 if the rewind fails. + */ +int sctp_rewind_sequence(sctp_cmd_seq_t *seq); + +/* Return the next command structure in an sctp_cmd_seq. + * Return NULL at the end of the sequence. + */ +sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq); + +/* Dispose of a command sequence. */ +void sctp_free_cmd_seq(sctp_cmd_seq_t *seq); + +#endif /* __net_sctp_command_h__ */ + diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/constants.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,450 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * The SCTP reference implementation 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. + * + * the SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the following email + * addresses: + * + * La Monte H.P. Yarroll + * Karl Knutson + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * Xingang Guo + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + * + * There are still LOTS of bugs in this code... I always run on the motto + * "it is a wonder any code ever works :)" + * + * + */ + +#ifndef __sctp_constants_h__ +#define __sctp_constants_h__ + +#include /* For TCP states used in sctp_sock_state_t */ +#include +#include /* For ipv6hdr. */ +#include + +/* What a hack! Jiminy Cricket! */ +enum { SCTP_MAX_STREAM = 10 }; + +/* Define the amount of space to reserve for SCTP, IP, LL. + * There is a little bit of waste that we are always allocating + * for ipv6 headers, but this seems worth the simplicity. + */ + +#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\ + + sizeof(struct ipv6hdr)\ + + MAX_HEADER)) + +/* Define the amount of space to reserve for SCTP, IP, LL. + * There is a little bit of waste that we are always allocating + * for ipv6 headers, but this seems worth the simplicity. + */ + +#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\ + + sizeof(struct ipv6hdr)\ + + MAX_HEADER)) + +/* Since CIDs are sparse, we need all four of the following + * symbols. CIDs are dense through SCTP_CID_BASE_MAX. + */ +#define SCTP_CID_BASE_MAX SCTP_CID_SHUTDOWN_COMPLETE +#define SCTP_CID_MAX SCTP_CID_ASCONF_ACK + +#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) +#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2) + + +/* These are the different flavours of event. */ +typedef enum { + + SCTP_EVENT_T_CHUNK = 1, + SCTP_EVENT_T_TIMEOUT, + SCTP_EVENT_T_OTHER, + SCTP_EVENT_T_PRIMITIVE + +} sctp_event_t; + +#define SCTP_EVENT_T_MAX SCTP_EVENT_T_PRIMITIVE +#define SCTP_EVENT_T_NUM (SCTP_EVENT_T_MAX + 1) + +/* As a convenience for the state machine, we append SCTP_EVENT_* and + * SCTP_ULP_* to the list of possible chunks. + */ + +typedef enum { + + SCTP_EVENT_TIMEOUT_NONE = 0, + SCTP_EVENT_TIMEOUT_T1_COOKIE, + SCTP_EVENT_TIMEOUT_T1_INIT, + SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, + SCTP_EVENT_TIMEOUT_T3_RTX, + SCTP_EVENT_TIMEOUT_T4_RTO, + SCTP_EVENT_TIMEOUT_HEARTBEAT, + SCTP_EVENT_TIMEOUT_SACK, + SCTP_EVENT_TIMEOUT_AUTOCLOSE, + SCTP_EVENT_TIMEOUT_PMTU_RAISE, + +} sctp_event_timeout_t; + +#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_PMTU_RAISE +#define SCTP_NUM_TIMEOUT_TYPES (SCTP_EVENT_TIMEOUT_MAX + 1) + +typedef enum { + + SCTP_EVENT_NO_PENDING_TSN = 0, + SCTP_EVENT_ICMP_UNREACHFRAG, + +} sctp_event_other_t; + +#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_ICMP_UNREACHFRAG +#define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1) + +/* These are primitive requests from the ULP. */ +typedef enum { + + SCTP_PRIMITIVE_INITIALIZE = 0, + SCTP_PRIMITIVE_ASSOCIATE, + SCTP_PRIMITIVE_SHUTDOWN, + SCTP_PRIMITIVE_ABORT, + SCTP_PRIMITIVE_SEND, + SCTP_PRIMITIVE_SETPRIMARY, + SCTP_PRIMITIVE_RECEIVE, + SCTP_PRIMITIVE_STATUS, + SCTP_PRIMITIVE_CHANGEHEARTBEAT, + SCTP_PRIMITIVE_REQUESTHEARTBEAT, + SCTP_PRIMITIVE_GETSRTTREPORT, + SCTP_PRIMITIVE_SETFAILURETHRESHOLD, + SCTP_PRIMITIVE_SETPROTOPARAMETERS, + SCTP_PRIMITIVE_RECEIVE_UNSENT, + SCTP_PRIMITIVE_RECEIVE_UNACKED, + SCTP_PRIMITIVE_DESTROY, + +} sctp_event_primitive_t; + +#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_DESTROY +#define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1) + +/* We define here a utility type for manipulating subtypes. + * The subtype constructors all work like this: + * + * sctp_subtype_t foo = SCTP_ST_CHUNK(SCTP_CID_INIT); + */ + +typedef union { + + sctp_cid_t chunk; + sctp_event_timeout_t timeout; + sctp_event_other_t other; + sctp_event_primitive_t primitive; + +} sctp_subtype_t; + +#define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \ +static inline sctp_subtype_t \ +SCTP_ST_## _name (_type _arg) \ +{ sctp_subtype_t _retval; _retval._elt = _arg; return _retval; } + +SCTP_SUBTYPE_CONSTRUCTOR(CHUNK, sctp_cid_t, chunk) +SCTP_SUBTYPE_CONSTRUCTOR(TIMEOUT, sctp_event_timeout_t, timeout) +SCTP_SUBTYPE_CONSTRUCTOR(OTHER, sctp_event_other_t, other) +SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, sctp_event_primitive_t, primitive) + + +#define sctp_chunk_is_control(a) (a->chunk_hdr->type != SCTP_CID_DATA) +#define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA) + +/* Calculate the actual data size in a data chunk */ +#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end)\ + - (unsigned long)(c->chunk_hdr)\ + - sizeof(sctp_data_chunk_t))) + +/* This is a table of printable names of sctp_param_t's. */ +extern const char *sctp_param_tbl[]; + + +#define SCTP_MAX_ERROR_CAUSE SCTP_ERROR_NONEXIST_IP +#define SCTP_NUM_ERROR_CAUSE 10 + +/* Internal error codes */ +typedef enum { + + SCTP_IERROR_NO_ERROR = 0, + SCTP_IERROR_BASE = 1000, + SCTP_IERROR_NO_COOKIE, + SCTP_IERROR_BAD_SIG, + SCTP_IERROR_STALE_COOKIE, + SCTP_IERROR_NOMEM, + SCTP_IERROR_MALFORMED, + SCTP_IERROR_BAD_TAG, + SCTP_IERROR_BIG_GAP, + SCTP_IERROR_DUP_TSN, + +} sctp_ierror_t; + + + +/* SCTP state defines for internal state machine */ +typedef enum { + + SCTP_STATE_EMPTY = 0, + SCTP_STATE_CLOSED = 1, + SCTP_STATE_COOKIE_WAIT = 2, + SCTP_STATE_COOKIE_ECHOED = 3, + SCTP_STATE_ESTABLISHED = 4, + SCTP_STATE_SHUTDOWN_PENDING = 5, + SCTP_STATE_SHUTDOWN_SENT = 6, + SCTP_STATE_SHUTDOWN_RECEIVED = 7, + SCTP_STATE_SHUTDOWN_ACK_SENT = 8, + +} sctp_state_t; + +#define SCTP_STATE_MAX SCTP_STATE_SHUTDOWN_ACK_SENT +#define SCTP_STATE_NUM_STATES (SCTP_STATE_MAX + 1) + +/* These are values for sk->state. + * For a UDP-style SCTP socket, the states are defined as follows + * (at this point of time, may change later after more discussions: FIXME) + * A socket in SCTP_SS_UNCONNECTED state indicates that it is not willing + * to accept new associations, but it can initiate the creation of new + * ones. + * A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations and can initiate the creation of new ones. + * A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off + * socket with one association. + */ +typedef enum { + SCTP_SS_CLOSED = TCP_CLOSE, + SCTP_SS_LISTENING = TCP_LISTEN, + SCTP_SS_ESTABLISHING = TCP_SYN_SENT, + SCTP_SS_ESTABLISHED = TCP_ESTABLISHED, + SCTP_SS_DISCONNECTING = TCP_CLOSING, +} sctp_sock_state_t; + +/* These functions map various type to printable names. */ +const char *sctp_cname(const sctp_subtype_t); /* chunk types */ +const char *sctp_oname(const sctp_subtype_t); /* other events */ +const char *sctp_tname(const sctp_subtype_t); /* timeouts */ +const char *sctp_pname(const sctp_subtype_t); /* primitives */ + +/* This is a table of printable names of sctp_state_t's. */ +extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; + +/* SCTP reachability state for each address */ +#define SCTP_ADDR_NOHB 4 +#define SCTP_ADDR_REACHABLE 2 +#define SCTP_ADDR_NOT_REACHABLE 1 + + + + +/* Guess at how big to make the TSN mapping array. + * We guarantee that we can handle at least this big a gap between the + * cumulative ACK and the highest TSN. In practice, we can often + * handle up to twice this value. + * + * NEVER make this more than 32767 (2^15-1). The Gap Ack Blocks in a + * SACK (see section 3.3.4) are only 16 bits, so 2*SCTP_TSN_MAP_SIZE + * must be less than 65535 (2^16 - 1), or we will have overflow + * problems creating SACK's. + */ +#define SCTP_TSN_MAP_SIZE 2048 +#define SCTP_TSN_MAX_GAP 65535 + +/* We will not record more than this many duplicate TSNs between two + * SACKs. The minimum PMTU is 576. Remove all the headers and there + * is enough room for 131 duplicate reports. Round down to the + * nearest power of 2. + */ +#define SCTP_MAX_DUP_TSNS 128 + +typedef enum { + SCTP_COUNTER_INIT_ERROR, +} sctp_counter_t; + +/* How many counters does an association need? */ +#define SCTP_NUMBER_COUNTERS 5 + + +/* Here we define the default timers. */ + +/* cookie timer def = ? seconds */ +#define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ) + +/* init timer def = 3 seconds */ +#define SCTP_DEFAULT_TIMEOUT_T1_INIT (3 * HZ) + +/* shutdown timer def = 300 ms */ +#define SCTP_DEFAULT_TIMEOUT_T2_SHUTDOWN ((300 * HZ) / 1000) + +/* 0 seconds + RTO */ +#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (10 * HZ) + +/* recv timer def = 200ms (in usec) */ +#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000) +#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000) /* 500 ms */ + +/* How long do we wait before attempting to raise the PMTU? */ +#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE (10 * 60 * HZ) /* 10 Minutes */ +#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE_MIN (10 * 60 * HZ) /* 10 Minutes */ + +/* RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 + * RTO.Beta - 1/4 + */ +#define SCTP_RTO_INITIAL (3 * HZ) +#define SCTP_RTO_MIN (1 * HZ) +#define SCTP_RTO_MAX (60 * HZ) + +#define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ +#define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ + +/* Maximum number of new data packets that can be sent in a burst. */ +#define SCTP_MAX_BURST 4 + +#define SCTP_CLOCK_GRANULARITY 1 /* 1 jiffy */ + +#define SCTP_DEF_MAX_INIT 6 +#define SCTP_DEF_MAX_SEND 10 + +#define SCTP_DEFAULT_COOKIE_LIFE_SEC 60 /* seconds */ +#define SCTP_DEFAULT_COOKIE_LIFE_USEC 0 /* microseconds */ + +#define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ +#define SCTP_DEFAULT_MAXWINDOW 32768 /* default rwnd size */ +#define SCTP_DEFAULT_MAXSEGMENT 1500 /* MTU size, this is the limit + * to which we will raise the P-MTU. + */ +#define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */ +#define SCTP_HOW_MANY_SECRETS 2 /* How many secrets I keep */ +#define SCTP_HOW_LONG_COOKIE_LIVE 3600 /* How many seconds the current + * secret will live? + */ +#define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */ + +#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ + +#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash + * functions simpler to write. + */ + +/* These return values describe the success or failure of a number of + * routines which form the lower interface to SCTP_outqueue. + */ +typedef enum { + SCTP_XMIT_OK, + SCTP_XMIT_PMTU_FULL, + SCTP_XMIT_RWND_FULL, + SCTP_XMIT_MUST_FRAG, +} sctp_xmit_t; + +/* These are the commands for manipulating transports. */ +typedef enum { + SCTP_TRANSPORT_UP, + SCTP_TRANSPORT_DOWN, +} sctp_transport_cmd_t; + +/* These are the address scopes defined mainly for IPv4 addresses + * based on draft of SCTP IPv4 scoping . + * These scopes are hopefully generic enough to be used on scoping both + * IPv4 and IPv6 addresses in SCTP. + * At this point, the IPv6 scopes will be mapped to these internal scopes + * as much as possible. + */ +typedef enum { + SCTP_SCOPE_GLOBAL, /* IPv4 global addresses */ + SCTP_SCOPE_PRIVATE, /* IPv4 private addresses */ + SCTP_SCOPE_LINK, /* IPv4 link local address */ + SCTP_SCOPE_LOOPBACK, /* IPv4 loopback address */ + SCTP_SCOPE_UNUSABLE, /* IPv4 unusable addresses */ +} sctp_scope_t; + +/* Based on IPv4 scoping , + * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, + * 192.88.99.0/24. + * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP + * addresses. + */ +#define IS_IPV4_UNUSABLE_ADDRESS(a) \ + ((INADDR_BROADCAST == *a) || \ + (MULTICAST(*a)) || \ + (((unsigned char *)(a))[0] == 0) || \ + ((((unsigned char *)(a))[0] == 198) && \ + (((unsigned char *)(a))[1] == 18) && \ + (((unsigned char *)(a))[2] == 0)) || \ + ((((unsigned char *)(a))[0] == 192) && \ + (((unsigned char *)(a))[1] == 88) && \ + (((unsigned char *)(a))[2] == 99))) + +/* IPv4 Link-local addresses: 169.254.0.0/16. */ +#define IS_IPV4_LINK_ADDRESS(a) \ + ((((unsigned char *)(a))[0] == 169) && \ + (((unsigned char *)(a))[1] == 254)) + +/* RFC 1918 "Address Allocation for Private Internets" defines the IPv4 + * private address space as the following: + * + * 10.0.0.0 - 10.255.255.255 (10/8 prefix) + * 172.16.0.0.0 - 172.31.255.255 (172.16/12 prefix) + * 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + */ +#define IS_IPV4_PRIVATE_ADDRESS(a) \ + ((((unsigned char *)(a))[0] == 10) || \ + ((((unsigned char *)(a))[0] == 172) && \ + (((unsigned char *)(a))[1] >= 16) && \ + (((unsigned char *)(a))[1] < 32)) || \ + ((((unsigned char *)(a))[0] == 192) && \ + (((unsigned char *)(a))[1] == 168))) + +/* Flags used for the bind address copy functions. */ +#define SCTP_ADDR6_ALLOWED 0x00000001 /* IPv6 address is allowed by + local sock family */ +#define SCTP_ADDR4_PEERSUPP 0x00000002 /* IPv4 address is supported by + peer */ +#define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by + peer */ + +/* Reasons to lower cwnd. */ +typedef enum { + SCTP_LOWER_CWND_T3_RTX, + SCTP_LOWER_CWND_FAST_RTX, + SCTP_LOWER_CWND_ECNE, + SCTP_LOWER_CWND_INACTIVE, +} sctp_lower_cwnd_t; + +#endif /* __sctp_constants_h__ */ + diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/sctp.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,507 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * The base lksctp header. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Xingang Guo + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __net_sctp_h__ +#define __net_sctp_h__ + +/* Header Strategy. + * Start getting some control over the header file depencies: + * includes + * constants + * structs + * prototypes + * macros, externs, and inlines + * + * Move test_frame specific items out of the kernel headers + * and into the test frame headers. This is not perfect in any sense + * and will continue to evolve. + */ + + +#include + +#ifdef TEST_FRAME +#undef CONFIG_PROC_FS +#undef CONFIG_SCTP_DBG_OBJCNT +#undef CONFIG_SYSCTL +#endif /* TEST_FRAME */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + + +/* Set SCTP_DEBUG flag via config if not already set. */ +#ifndef SCTP_DEBUG +#ifdef CONFIG_SCTP_DBG_MSG +#define SCTP_DEBUG 1 +#else +#define SCTP_DEBUG 0 +#endif /* CONFIG_SCTP_DBG */ +#endif /* SCTP_DEBUG */ + +#ifdef CONFIG_IP_SCTP_MODULE +#define SCTP_PROTOSW_FLAG 0 +#else /* static! */ +#define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT +#endif + +/* + * Function declarations. + */ + +/* + * sctp_protocol.c + */ +extern sctp_protocol_t sctp_proto; +extern struct sock *sctp_get_ctl_sock(void); +extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, + sctp_scope_t, int priority, int flags); + + +/* + * sctp_socket.c + */ +extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +extern int sctp_inet_listen(struct socket *sock, int backlog); +extern void sctp_write_space(struct sock *sk); +extern unsigned int sctp_poll(struct file *file, struct socket *sock, + poll_table *wait); + +/* + * sctp_primitive.c + */ +extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); +extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); +extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); +extern int sctp_primitive_SEND(sctp_association_t *, void *arg); + + +/* + * sctp_crc32c.c + */ +extern __u32 count_crc(__u8 *ptr, __u16 count); + +/* + * sctp_input.c + */ +extern int sctp_rcv(struct sk_buff *skb); +extern void sctp_v4_err(struct sk_buff *skb, u32 info); +extern void sctp_hash_established(sctp_association_t *); +extern void __sctp_hash_established(sctp_association_t *); +extern void sctp_unhash_established(sctp_association_t *); +extern void __sctp_unhash_established(sctp_association_t *); +extern void sctp_hash_endpoint(sctp_endpoint_t *); +extern void __sctp_hash_endpoint(sctp_endpoint_t *); +extern void sctp_unhash_endpoint(sctp_endpoint_t *); +extern void __sctp_unhash_endpoint(sctp_endpoint_t *); + +/* + * sctp_hashdriver.c + */ +extern void sctp_hash_digest(const char *secret, const int secret_len, + const char *text, const int text_len, + __u8 *digest); + +/* + * Section: Macros, externs, and inlines + */ + + +#ifdef TEST_FRAME + +#include + +#else + +/* spin lock wrappers. */ +#define sctp_spin_lock_irqsave(lock, flags) spin_lock_irqsave(lock, flags) +#define sctp_spin_unlock_irqrestore(lock, flags) \ + spin_unlock_irqrestore(lock, flags) +#define sctp_local_bh_disable() local_bh_disable() +#define sctp_local_bh_enable() local_bh_enable() +#define sctp_spin_lock(lock) spin_lock(lock) +#define sctp_spin_unlock(lock) spin_unlock(lock) +#define sctp_write_lock(lock) write_lock(lock) +#define sctp_write_unlock(lock) write_unlock(lock) +#define sctp_read_lock(lock) read_lock(lock) +#define sctp_read_unlock(lock) read_unlock(lock) + +/* sock lock wrappers. */ +#define sctp_lock_sock(sk) lock_sock(sk) +#define sctp_release_sock(sk) release_sock(sk) +#define sctp_bh_lock_sock(sk) bh_lock_sock(sk) +#define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk) +#define __sctp_sock_busy(sk) ((sk)->lock.users) +#define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk) +#define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) + + +/* Determine if this is a valid kernel address. */ +static inline int sctp_is_valid_kaddr(unsigned long addr) +{ + struct page *page; + + /* Make sure the address is not in the user address space. */ + if (addr < PAGE_OFFSET) + return 0; + + page = virt_to_page(addr); + + /* Is this page valid? */ + if (!virt_addr_valid(addr) || PageReserved(page)) + return 0; + + return 1; +} + +#endif /* !TEST_FRAME */ + + +/* Print debugging messages. */ +#if SCTP_DEBUG +extern int sctp_debug_flag; +#define SCTP_DEBUG_PRINTK(whatever...) \ + ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever))) +#define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; } +#define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; } + +#define SCTP_ASSERT(expr, str, func) \ + if (!(expr)) { \ + SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \ + str, (#expr), __FILE__, __FUNCTION__, __LINE__); \ + func; \ + } + +#else /* SCTP_DEBUG */ + +#define SCTP_DEBUG_PRINTK(whatever...) +#define SCTP_ENABLE_DEBUG +#define SCTP_DISABLE_DEBUG +#define SCTP_ASSERT(expr, str, func) + +#endif /* SCTP_DEBUG */ + + +/* + * Macros for keeping a global reference of object allocations. + */ +#ifdef CONFIG_SCTP_DBG_OBJCNT + +extern atomic_t sctp_dbg_objcnt_sock; +extern atomic_t sctp_dbg_objcnt_ep; +extern atomic_t sctp_dbg_objcnt_assoc; +extern atomic_t sctp_dbg_objcnt_transport; +extern atomic_t sctp_dbg_objcnt_chunk; +extern atomic_t sctp_dbg_objcnt_bind_addr; +extern atomic_t sctp_dbg_objcnt_addr; + +/* Macros to atomically increment/decrement objcnt counters. */ +#define SCTP_DBG_OBJCNT_INC(name) \ +atomic_inc(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT_DEC(name) \ +atomic_dec(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT(name) \ +atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) + +/* Macro to help create new entries in in the global array of + * objcnt counters. + */ +#define SCTP_DBG_OBJCNT_ENTRY(name) \ +{.label= #name, .counter= &sctp_dbg_objcnt_## name} + +extern void sctp_dbg_objcnt_init(void); +extern void sctp_dbg_objcnt_exit(void); + +#else + +#define SCTP_DBG_OBJCNT_INC(name) +#define SCTP_DBG_OBJCNT_DEC(name) + +static inline void sctp_dbg_objcnt_init(void) { return; } +static inline void sctp_dbg_objcnt_exit(void) { return; } + +#endif /* CONFIG_SCTP_DBG_OBJCOUNT */ + +#if defined CONFIG_SYSCTL +extern void sctp_sysctl_register(void); +extern void sctp_sysctl_unregister(void); +#else +static inline void sctp_sysctl_register(void) { return; } +static inline void sctp_sysctl_unregister(void) { return; } +#endif + + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +extern int sctp_v6_init(void); +extern void sctp_v6_exit(void); + +static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) +{ + return ipv6_addr_type((struct in6_addr*) addr); +} + +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16)) + +/* Note: These V6 macros are obsolescent. */ +/* Use this macro to enclose code fragments which are V6-dependent. */ +#define SCTP_V6(m...) m +#define SCTP_V6_SUPPORT 1 + +#else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ + +#define sctp_ipv6_addr_type(a) 0 +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16)) +#define SCTP_V6(m...) /* Do nothing. */ +#undef SCTP_V6_SUPPORT + +static inline int sctp_v6_init(void) { return 0; } +static inline void sctp_v6_exit(void) { return; } + +#endif /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ + + +/* Map an association to an assoc_id. */ +static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) +{ + return (sctp_assoc_t) asoc; +} + +/* Look up the association by its id. */ +static inline sctp_association_t *sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) +{ + sctp_association_t *asoc = NULL; + + /* First, verify that this is a kernel address. */ + if (sctp_is_valid_kaddr((unsigned long) id)) { + sctp_association_t *temp = (sctp_association_t *) id; + + /* Verify that this _is_ an sctp_association_t + * data structure and if so, that the socket matches. + */ + if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && + (temp->base.sk == sk)) + asoc = temp; + } + + return asoc; +} + +/* A macro to walk a list of skbs. */ +#define sctp_skb_for_each(pos, head, tmp) \ +for (pos = (head)->next;\ + tmp = (pos)->next, pos != ((struct sk_buff *)(head));\ + pos = tmp) + + +/* A helper to append an entire skb list (list) to another (head). */ +static inline void sctp_skb_list_tail(struct sk_buff_head *list, + struct sk_buff_head *head) +{ + int flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&head->lock, flags); + sctp_spin_lock(&list->lock); + + list_splice((struct list_head *)list, (struct list_head *)head->prev); + + head->qlen += list->qlen; + list->qlen = 0; + + sctp_spin_unlock(&list->lock); + sctp_spin_unlock_irqrestore(&head->lock, flags); +} + +/** + * sctp_list_dequeue - remove from the head of the queue + * @list: list to dequeue from + * + * Remove the head of the list. The head item is + * returned or %NULL if the list is empty. + */ + +static inline struct list_head *sctp_list_dequeue(struct list_head *list) +{ + struct list_head *result = NULL; + + if (list->next != list) { + result = list->next; + list->next = result->next; + list->next->prev = list; + INIT_LIST_HEAD(result); + } + return result; +} + +/* Calculate the size (in bytes) occupied by the data of an iovec. */ +static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) +{ + size_t retval = 0; + + for (; iovlen > 0; --iovlen) { + retval += iov->iov_len; + iov++; + } + + return retval; +} + + +/* Round an int up to the next multiple of 4. */ +#define WORD_ROUND(s) (((s)+3)&~3) + +/* Make a new instance of type. */ +#define t_new(type, flags) (type *)kmalloc(sizeof(type), flags) + +/* Compare two timevals. */ +#define tv_lt(s, t) \ + (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec)) + +/* Stolen from net/profile.h. Using it from there is more grief than + * it is worth. + */ +static inline void tv_add(const struct timeval *entered, struct timeval *leaved) +{ + time_t usecs = leaved->tv_usec + entered->tv_usec; + time_t secs = leaved->tv_sec + entered->tv_sec; + + if (usecs >= 1000000) { + usecs -= 1000000; + secs++; + } + leaved->tv_sec = secs; + leaved->tv_usec = usecs; +} + + +/* External references. */ + +extern struct proto sctp_prot; +extern struct proc_dir_entry *proc_net_sctp; +extern void sctp_put_port(struct sock *sk); + +/* Static inline functions. */ + +/* Return the SCTP protocol structure. */ +static inline sctp_protocol_t *sctp_get_protocol(void) +{ + return &sctp_proto; +} + +/* Warning: The following hash functions assume a power of two 'size'. */ +/* This is the hash function for the SCTP port hash table. */ +static inline int sctp_phashfn(__u16 lport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + return (lport & (sctp_proto->port_hashsize - 1)); +} + +/* This is the hash function for the endpoint hash table. */ +static inline int sctp_ep_hashfn(__u16 lport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + return (lport & (sctp_proto->ep_hashsize - 1)); +} + +/* This is the hash function for the association hash table. */ +static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + int h = (lport << 16) + rport; + h ^= h>>8; + return (h & (sctp_proto->assoc_hashsize - 1)); +} + +/* This is the hash function for the association hash table. This is + * not used yet, but could be used as a better hash function when + * we have a vtag. + */ +static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + int h = (lport << 16) + rport; + h ^= vtag; + return (h & (sctp_proto->assoc_hashsize-1)); +} + +/* WARNING: Do not change the layout of the members in sctp_sock! */ +struct sctp_sock { + struct sock sk; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct ipv6_pinfo *pinet6; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + struct inet_opt inet; + struct sctp_opt sctp; +}; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +struct sctp6_sock { + struct sock sk; + struct ipv6_pinfo *pinet6; + struct inet_opt inet; + struct sctp_opt sctp; + struct ipv6_pinfo inet6; +}; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + +#define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) + +#endif /* __net_sctp_h__ */ diff -Nru a/include/net/sctp/sla1.h b/include/net/sctp/sla1.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/sla1.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,80 @@ +/* SCTP reference Implementation + * Copyright (C) 1999 Cisco, Inc. + * Copyright (C) 1999 Motorola, Inc. + * + * This file originates from Randy Stewart's SCTP reference Implementation. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randy Stewart + * Ken Morneau + * Qiaobing Xie + */ + +#ifndef __SLA1_h__ +#define __SLA1_h__ + +struct SLA_1_Context { + unsigned int A; + unsigned int B; + unsigned int C; + unsigned int D; + unsigned int E; + unsigned int H0; + unsigned int H1; + unsigned int H2; + unsigned int H3; + unsigned int H4; + unsigned int words[80]; + unsigned int TEMP; + + /* block I am collecting to process */ + char SLAblock[64]; + + /* collected so far */ + int howManyInBlock; + unsigned int runningTotal; +}; + + +#define F1(B,C,D) (((B & C) | ((~B) & D))) /* 0 <= t <= 19 */ +#define F2(B,C,D) (B ^ C ^ D) /* 20 <= t <= 39 */ +#define F3(B,C,D) ((B & C) | (B & D) | (C & D)) /* 40 <= t <= 59 */ +#define F4(B,C,D) (B ^ C ^ D) /*600 <= t <= 79 */ +/* circular shift */ + +#define CSHIFT(A,B) ((B << A) | (B >> (32-A))) + +#define K1 0x5a827999 /* 0 <= t <= 19 */ +#define K2 0x6ed9eba1 /* 20 <= t <= 39 */ +#define K3 0x8f1bbcdc /* 40 <= t <= 59 */ +#define K4 0xca62c1d6 /* 60 <= t <= 79 */ + +#define H0INIT 0x67452301 +#define H1INIT 0xefcdab89 +#define H2INIT 0x98badcfe +#define H3INIT 0x10325476 +#define H4INIT 0xc3d2e1f0 + +extern void SLA1_Init(struct SLA_1_Context *); +extern void SLA1_Process(struct SLA_1_Context *, const unsigned char *, int); +extern void SLA1_Final(struct SLA_1_Context *, unsigned char *); + +#endif diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/sm.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,418 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * These are definitions needed by the state machine. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email addresses: + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Dajiang Zhang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __sctp_sm_h__ +#define __sctp_sm_h__ + +/* + * Possible values for the disposition are: + */ +typedef enum { + SCTP_DISPOSITION_DISCARD, /* No further processing. */ + SCTP_DISPOSITION_CONSUME, /* Process return values normally. */ + SCTP_DISPOSITION_NOMEM, /* We ran out of memory--recover. */ + SCTP_DISPOSITION_DELETE_TCB, /* Close the association. */ + SCTP_DISPOSITION_ABORT, /* Close the association NOW. */ + SCTP_DISPOSITION_VIOLATION, /* The peer is misbehaving. */ + SCTP_DISPOSITION_NOT_IMPL, /* This entry is not implemented. */ + SCTP_DISPOSITION_ERROR, /* This is plain old user error. */ + SCTP_DISPOSITION_BUG, /* This is a bug. */ +} sctp_disposition_t; + +typedef struct { + int name; + int action; +} sctp_sm_command_t; + +typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, + const sctp_association_t *, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *); +typedef void (sctp_timer_event_t) (unsigned long); +typedef struct { + sctp_state_fn_t *fn; + char *name; +} sctp_sm_table_entry_t; + +/* A naming convention of "sctp_sf_xxx" applies to all the state functions + * currently in use. + */ + +/* Prototypes for generic state functions. */ +sctp_state_fn_t sctp_sf_not_impl; +sctp_state_fn_t sctp_sf_bug; + +/* Prototypes for gener timer state functions. */ +sctp_state_fn_t sctp_sf_timer_ignore; + +/* Prototypes for chunk state functions. */ +sctp_state_fn_t sctp_sf_do_9_1_abort; +sctp_state_fn_t sctp_sf_cookie_wait_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_abort; +sctp_state_fn_t sctp_sf_do_5_1B_init; +sctp_state_fn_t sctp_sf_do_5_1C_ack; +sctp_state_fn_t sctp_sf_do_5_1D_ce; +sctp_state_fn_t sctp_sf_do_5_1E_ca; +sctp_state_fn_t sctp_sf_do_4_C; +sctp_state_fn_t sctp_sf_eat_data_6_2; +sctp_state_fn_t sctp_sf_eat_data_fast_4_4; +sctp_state_fn_t sctp_sf_eat_sack_6_2; +sctp_state_fn_t sctp_sf_tabort_8_4_8; +sctp_state_fn_t sctp_sf_operr_notify; +sctp_state_fn_t sctp_sf_t1_timer_expire; +sctp_state_fn_t sctp_sf_t2_timer_expire; +sctp_state_fn_t sctp_sf_sendbeat_8_3; +sctp_state_fn_t sctp_sf_beat_8_3; +sctp_state_fn_t sctp_sf_backbeat_8_3; +sctp_state_fn_t sctp_sf_do_9_2_final; +sctp_state_fn_t sctp_sf_do_9_2_shutdown; +sctp_state_fn_t sctp_sf_do_ecn_cwr; +sctp_state_fn_t sctp_sf_do_ecne; +sctp_state_fn_t sctp_sf_ootb; +sctp_state_fn_t sctp_sf_shut_8_4_5; +sctp_state_fn_t sctp_sf_pdiscard; +sctp_state_fn_t sctp_sf_violation; +sctp_state_fn_t sctp_sf_discard_chunk; +sctp_state_fn_t sctp_sf_do_5_2_1_siminit; +sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; +sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; + +/* Prototypes for primitive event state functions. */ +sctp_state_fn_t sctp_sf_do_prm_asoc; +sctp_state_fn_t sctp_sf_do_prm_send; +sctp_state_fn_t sctp_sf_do_9_2_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_wait_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; +sctp_state_fn_t sctp_sf_do_9_1_prm_abort; +sctp_state_fn_t sctp_sf_cookie_wait_prm_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort; +sctp_state_fn_t sctp_sf_error_closed; +sctp_state_fn_t sctp_sf_error_shutdown; +sctp_state_fn_t sctp_sf_ignore_primitive; + +/* Prototypes for other event state functions. */ +sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; +sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack; +sctp_state_fn_t sctp_sf_ignore_other; + +/* Prototypes for timeout event state functions. */ +sctp_state_fn_t sctp_sf_do_6_3_3_rtx; +sctp_state_fn_t sctp_sf_do_6_2_sack; +sctp_state_fn_t sctp_sf_autoclose_timer_expire; + + +/* These are state functions which are either obsolete or not in use yet. + * If any of these functions needs to be revived, it should be renamed with + * the "sctp_sf_xxx" prefix, and be moved to the above prototype groups. + */ + +/* Prototypes for chunk state functions. Not in use. */ +sctp_state_fn_t sctp_sf_do_5_2_6_stale; +sctp_state_fn_t sctp_sf_do_9_2_reshutack; +sctp_state_fn_t sctp_sf_do_9_2_reshut; +sctp_state_fn_t sctp_sf_do_9_2_shutack; + +sctp_state_fn_t lucky; +sctp_state_fn_t other_stupid; + +/* Prototypes for timeout event state functions. Not in use. */ +sctp_state_fn_t sctp_do_4_2_reinit; +sctp_state_fn_t sctp_do_4_3_reecho; +sctp_state_fn_t sctp_do_9_2_reshut; +sctp_state_fn_t sctp_do_9_2_reshutack; +sctp_state_fn_t sctp_do_8_3_hb_err; +sctp_state_fn_t sctp_heartoff; + +/* Prototypes for addip related state functions. Not in use. */ +sctp_state_fn_t sctp_addip_do_asconf; +sctp_state_fn_t sctp_addip_do_asconf_ack; + +/* Prototypes for utility support functions. */ +__u8 sctp_get_chunk_type(sctp_chunk_t *chunk); +sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, + sctp_state_t state, + sctp_subtype_t event_subtype); + +time_t timeval_sub(struct timeval *, struct timeval *); +sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, + sctp_chunk_t *, + const int priority); +__u32 sctp_generate_verification_tag(void); +sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *, + const int priority, int *addrs_len); + +void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); + +/* Prototypes for chunk-building functions. */ +sctp_chunk_t *sctp_make_init(const sctp_association_t *, + const sctp_bind_addr_t *, + int priority); +sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, + const sctp_chunk_t *, + const int priority); +sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, + const __u32 lowest_tsn, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const __u8 *data, + __u8 flags, __u16 ssn); +sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const __u8 flags, + __u16 ssn); +sctp_chunk_t *sctp_make_data(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const __u8 *data); +sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, + const struct sctp_sndrcvinfo *, int len); +sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, + const __u32); +sctp_chunk_t *sctp_make_sack(const sctp_association_t *); +sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); +sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, + const sctp_chunk_t *); +void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); +sctp_chunk_t *sctp_make_abort(const sctp_association_t *, + const sctp_chunk_t *, + const size_t hint); +sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, + const sctp_chunk_t *, + __u32 tsn); +sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, + const sctp_transport_t *, + const void *payload, + const size_t paylen); +sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, + const sctp_chunk_t *, + const void *payload, + const size_t paylen); +sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, + const sctp_chunk_t *chunk, + __u16 cause_code, + const void *payload, + size_t paylen); +void sctp_chunk_assign_tsn(sctp_chunk_t *); + + +/* Prototypes for statetable processing. */ + +int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *, + sctp_association_t *asoc, + void *event_arg, + int priority); + +int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *commands, + int priority); + +/* 2nd level prototypes */ +int +sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *retval, + int priority); + + +int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *); +void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap); + +void sctp_generate_t3_rtx_event(unsigned long peer); +void sctp_generate_heartbeat_event(unsigned long peer); + +sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); + +sctp_cookie_param_t * +sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, + const sctp_chunk_t *, int *cookie_len, + const __u8 *, int addrs_len); +sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, + const sctp_association_t *, + sctp_chunk_t *, int priority, int *err); +int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, + struct sockaddr_storage*, int); + +/* 3rd level prototypes */ +__u32 sctp_generate_tag(const sctp_endpoint_t *); +__u32 sctp_generate_tsn(const sctp_endpoint_t *); + +/* 4th level prototypes */ +void sctp_param2sockaddr(sockaddr_storage_t *addr, const sctpParam_t param, + __u16 port); +int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); +int sockaddr2sctp_addr(const sockaddr_storage_t *, sctpParam_t); + +/* Extern declarations for major data structures. */ +sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); +extern sctp_sm_table_entry_t +primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_sm_table_entry_t +other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_sm_table_entry_t +timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; + +/* These are some handy utility macros... */ + + +/* Get the size of a DATA chunk payload. */ +static inline __u16 sctp_data_size(sctp_chunk_t *chunk) +{ + __u16 size; + + size = ntohs(chunk->chunk_hdr->length); + size -= sizeof(sctp_data_chunk_t); + + return size; +} + +/* Compare two TSNs */ + +/* RFC 1982 - Serial Number Arithmetic + * + * 2. Comparison + * Then, s1 is said to be equal to s2 if and only if i1 is equal to i2, + * in all other cases, s1 is not equal to s2. + * + * s1 is said to be less than s2 if, and only if, s1 is not equal to s2, + * and + * + * (i1 < i2 and i2 - i1 < 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 > 2^(SERIAL_BITS - 1)) + * + * s1 is said to be greater than s2 if, and only if, s1 is not equal to + * s2, and + * + * (i1 < i2 and i2 - i1 > 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1)) + */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on TSNs in this document SHOULD use Serial + * Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32. + */ + +enum { + TSN_SIGN_BIT = (1<<31) +}; + +static inline int TSN_lt(__u32 s, __u32 t) +{ + return (((s) - (t)) & TSN_SIGN_BIT); +} + +static inline int TSN_lte(__u32 s, __u32 t) +{ + return (((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT)); +} + +/* Compare two SSNs */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on Stream Sequence Numbers in this document + * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where + * SERIAL_BITS = 16. + */ +enum { + SSN_SIGN_BIT = (1<<15) +}; + +static inline int SSN_lt(__u16 s, __u16 t) +{ + return (((s) - (t)) & SSN_SIGN_BIT); +} + +static inline int SSN_lte(__u16 s, __u16 t) +{ + return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); +} + +/* Run sctp_add_cmd() generating a BUG() if there is a failure. */ +static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +{ + if (unlikely(!sctp_add_cmd(seq, verb, obj))) + BUG(); +} + +#endif /* __sctp_sm_h__ */ diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/structs.h Sat Aug 31 15:06:07 2002 @@ -0,0 +1,1541 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email addresses: + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Daisy Chang + * Dajiang Zhang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_structs_h__ +#define __sctp_structs_h__ + +#include /* We get struct timespec. */ +#include /* linux/in.h needs this!! */ +#include /* We get struct sockaddr_in. */ +#include /* We get struct in6_addr */ +#include /* We get MAXHOSTNAMELEN. */ +#include /* This gets us atomic counters. */ +#include /* We need sk_buff_head. */ +#include /* We need tq_struct. */ +#include /* We need sctp* header structs. */ + +/* + * This is (almost) a direct quote from RFC 2553. + */ + +/* + * Desired design of maximum size and alignment + */ +#define _SS_MAXSIZE 128 /* Implementation specific max size */ +#define _SS_ALIGNSIZE (sizeof (__s64)) + /* Implementation specific desired alignment */ +/* + * Definitions used for sockaddr_storage structure paddings design. + */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t)+ \ + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + +struct sockaddr_storage { + sa_family_t __ss_family; /* address family */ + /* Following fields are implementation specific */ + char __ss_pad1[_SS_PAD1SIZE]; + /* 6 byte pad, to make implementation */ + /* specific pad up to alignment field that */ + /* follows explicit in the data structure */ + __s64 __ss_align; /* field to force desired structure */ + /* storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; + /* 112 byte pad to achieve desired size, */ + /* _SS_MAXSIZE value minus size of ss_family */ + /* __ss_pad1, __ss_align fields is 112 */ +}; + +/* A convenience structure for handling sockaddr structures. + * We should wean ourselves off this. + */ +typedef union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + struct sockaddr sa; +} sockaddr_storage_t; + + +/* Forward declarations for data structures. */ +struct SCTP_protocol; +struct SCTP_endpoint; +struct SCTP_association; +struct SCTP_transport; +struct SCTP_packet; +struct SCTP_chunk; +struct SCTP_inqueue; +struct SCTP_outqueue; +struct SCTP_bind_addr; +struct sctp_opt; +struct sctp_endpoint_common; + + +typedef struct SCTP_protocol sctp_protocol_t; +typedef struct SCTP_endpoint sctp_endpoint_t; +typedef struct SCTP_association sctp_association_t; +typedef struct SCTP_transport sctp_transport_t; +typedef struct SCTP_packet sctp_packet_t; +typedef struct SCTP_chunk sctp_chunk_t; +typedef struct SCTP_inqueue sctp_inqueue_t; +typedef struct SCTP_outqueue sctp_outqueue_t; +typedef struct SCTP_bind_addr sctp_bind_addr_t; +typedef struct sctp_opt sctp_opt_t; +typedef struct sctp_endpoint_common sctp_endpoint_common_t; + +#include +#include +#include + + +/* Structures useful for managing bind/connect. */ + +typedef struct sctp_bind_bucket { + unsigned short port; + unsigned short fastreuse; + struct sctp_bind_bucket *next; + struct sctp_bind_bucket **pprev; + struct sock *sk; +} sctp_bind_bucket_t; + +typedef struct sctp_bind_hashbucket { + spinlock_t lock; + struct sctp_bind_bucket *chain; +} sctp_bind_hashbucket_t; + +/* Used for hashing all associations. */ +typedef struct sctp_hashbucket { + rwlock_t lock; + sctp_endpoint_common_t *chain; +} sctp_hashbucket_t __attribute__((__aligned__(8))); + + +/* The SCTP protocol structure. */ +struct SCTP_protocol { + /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values + * + * The following protocol parameters are RECOMMENDED: + * + * RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 (3 when converted to right shifts.) + * RTO.Beta - 1/4 (2 when converted to right shifts.) + */ + __u32 rto_initial; + __u32 rto_min; + __u32 rto_max; + + /* Note: rto_alpha and rto_beta are really defined as inverse + * powers of two to facilitate integer operations. + */ + int rto_alpha; + int rto_beta; + + /* Max.Burst - 4 */ + int max_burst; + + /* Valid.Cookie.Life - 60 seconds */ + int valid_cookie_life; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + int max_retrans_association; + int max_retrans_path; + int max_retrans_init; + + /* HB.interval - 30 seconds */ + int hb_interval; + + /* The following variables are implementation specific. */ + + /* Default initialization values to be applied to new associations. */ + __u16 max_instreams; + __u16 max_outstreams; + + /* This is a list of groups of functions for each address + * family that we support. + */ + list_t address_families; + + /* This is the hash of all endpoints. */ + int ep_hashsize; + sctp_hashbucket_t *ep_hashbucket; + + /* This is the hash of all associations. */ + int assoc_hashsize; + sctp_hashbucket_t *assoc_hashbucket; + + /* This is the sctp port control hash. */ + int port_hashsize; + int port_rover; + spinlock_t port_alloc_lock; /* Protects port_rover. */ + sctp_bind_hashbucket_t *port_hashtable; + + /* This is the global local address list. + * We actively maintain this complete list of interfaces on + * the system by catching routing events. + * + * It is a list of struct sockaddr_storage_list. + */ + list_t local_addr_list; + spinlock_t local_addr_lock; +}; + + +/* + * Pointers to address related SCTP functions. + * (i.e. things that depend on the address family.) + */ +typedef struct sctp_func { + int (*queue_xmit) (struct sk_buff *skb); + int (*setsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int optlen); + int (*getsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int *optlen); + int (*get_dst_mtu) (const sockaddr_storage_t *address); + __u16 net_header_len; + int sockaddr_len; + sa_family_t sa_family; + list_t list; +} sctp_func_t; + +sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); + +/* SCTP Socket type: UDP or TCP style. */ +typedef enum { + SCTP_SOCKET_UDP = 0, + SCTP_SOCKET_UDP_HIGH_BANDWIDTH, + SCTP_SOCKET_TCP +} sctp_socket_type_t; + +/* Per socket SCTP information. */ +struct sctp_opt { + /* What kind of a socket is this? */ + sctp_socket_type_t type; + + /* What is our base endpointer? */ + sctp_endpoint_t *ep; + + /* Various Socket Options. */ + __u16 default_stream; + __u32 default_ppid; + struct sctp_initmsg initmsg; + struct sctp_rtoinfo rtoinfo; + struct sctp_paddrparams paddrparam; + struct sctp_event_subscribe subscribe; + __u32 autoclose; + __u8 nodelay; + __u8 disable_fragments; +}; + + + +/* This is our APPLICATION-SPECIFIC state cookie. + * THIS IS NOT DICTATED BY THE SPECIFICATION. + */ +/* These are the parts of an association which we send in the cookie. + * Most of these are straight out of: + * RFC2960 12.2 Parameters necessary per association (i.e. the TCB) + * + */ + +typedef struct sctp_cookie { + + /* My : Tag expected in every inbound packet and sent + * Verification: in the INIT or INIT ACK chunk. + * Tag : + */ + __u32 my_vtag; + + /* Peer's : Tag expected in every outbound packet except + * Verification: in the INIT chunk. + * Tag : + */ + __u32 peer_vtag; + + /* The rest of these are not from the spec, but really need to + * be in the cookie. + */ + + /* My Tie Tag : Assist in discovering a restarting association. */ + __u32 my_ttag; + + /* Peer's Tie Tag: Assist in discovering a restarting association. */ + __u32 peer_ttag; + + /* When does this cookie expire? */ + struct timeval expiration; + + /* Number of inbound/outbound streams which are set + * and negotiated during the INIT process. */ + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + + /* This is the first sequence number I used. */ + __u32 initial_tsn; + + /* This holds the originating address of the INIT packet. */ + sockaddr_storage_t peer_addr; + + /* 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 + * raw_addr_list_len field, which will be used at the time when + * the association TCB is re-constructed from the cookie. + */ + __u32 raw_addr_list_len; + sctp_init_chunk_t peer_init[0]; +} sctp_cookie_t; + + +/* The format of our cookie that we send to our peer. */ +typedef struct sctp_signed_cookie { + __u8 signature[SCTP_SECRET_SIZE]; + sctp_cookie_t c; +} sctp_signed_cookie_t; + + +/* This convenience type allows us to avoid casting when walking + * through a parameter list. + */ +typedef union { + __u8 *v; + sctp_paramhdr_t *p; + + sctp_cookie_preserve_param_t *bht; + sctp_hostname_param_t *dns; + sctp_cookie_param_t *cookie; + sctp_supported_addrs_param_t *sat; + sctp_ipv4addr_param_t *v4; + sctp_ipv6addr_param_t *v6; +} sctpParam_t; + +/* This is another convenience type to allocate memory for address + * params for the maximum size and pass such structures around + * internally. + */ +typedef union { + sctp_ipv4addr_param_t v4; + sctp_ipv6addr_param_t v6; +} sctpIpAddress_t; + +/* RFC 2960. Section 3.3.5 Heartbeat. + * Heartbeat Information: variable length + * The Sender-specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent (see Section 8.3). + */ +typedef struct sctp_sender_hb_info { + sctp_paramhdr_t param_hdr; + sockaddr_storage_t daddr; + unsigned long sent_at; +} sctp_sender_hb_info_t __attribute__((packed)); + +/* RFC2960 1.4 Key Terms + * + * o Chunk: A unit of information within an SCTP packet, consisting of + * a chunk header and chunk-specific content. + * + * As a matter of convenience, we remember the SCTP common header for + * each chunk as well as a few other header pointers... + */ +struct SCTP_chunk { + /* These first three elements MUST PRECISELY match the first + * three elements of struct sk_buff. This allows us to reuse + * all the skb_* queue management functions. + */ + sctp_chunk_t *next; + sctp_chunk_t *prev; + struct sk_buff_head *list; + + /* This is our link to the per-transport transmitted list. */ + struct list_head transmitted_list; + + /* This field is used by chunks that hold fragmented data. + * For the first fragment this is the list that holds the rest of + * fragments. For the remaining fragments, this is the link to the + * frag_list maintained in the first fragment. + */ + struct list_head frag_list; + + /* This points to the sk_buff containing the actual data. */ + struct sk_buff *skb; + + /* These are the SCTP headers by reverse order in a packet. + * Note that some of these may happen more than once. In that + * case, we point at the "current" one, whatever that means + * for that level of header. + */ + + /* We point this at the FIRST TLV parameter to chunk_hdr. */ + sctpParam_t param_hdr; + union { + __u8 *v; + sctp_datahdr_t *data_hdr; + sctp_inithdr_t *init_hdr; + sctp_sackhdr_t *sack_hdr; + sctp_heartbeathdr_t *hb_hdr; + sctp_sender_hb_info_t *hbs_hdr; + sctp_shutdownhdr_t *shutdown_hdr; + sctp_signed_cookie_t *cookie_hdr; + sctp_ecnehdr_t *ecne_hdr; + sctp_cwrhdr_t *ecn_cwr_hdr; + sctp_errhdr_t *err_hdr; + } subh; + + __u8 *chunk_end; + + sctp_chunkhdr_t *chunk_hdr; + + sctp_sctphdr_t *sctp_hdr; + + /* This needs to be recoverable for SCTP_SEND_FAILED events. */ + struct sctp_sndrcvinfo sinfo; + + /* Which association does this belong to? */ + sctp_association_t *asoc; + + /* What endpoint received this chunk? */ + sctp_endpoint_common_t *rcvr; + + /* We fill this in if we are calculating RTT. */ + unsigned long sent_at; + + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ + __u8 num_times_sent; /* How man times did we send this? */ + __u8 has_tsn; /* Does this chunk have a TSN yet? */ + __u8 singleton; /* Was this the only chunk in the packet? */ + __u8 end_of_packet; /* Was this the last chunk in the packet? */ + __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ + __u8 pdiscard; /* Discard the whole packet now? */ + __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __u8 tsn_missing_report; /* Data chunk missing counter. */ + + /* What is the origin IP address for this chunk? */ + sockaddr_storage_t source; + + /* For an inbound chunk, this tells us where it came from. + * For an outbound chunk, it tells us where we'd like it to + * go. It is NULL if we have no preference. + */ + sctp_transport_t *transport; +}; + +sctp_chunk_t *sctp_make_chunk(const sctp_association_t *, __u8 type, + __u8 flags, int size); +void sctp_free_chunk(sctp_chunk_t *); +sctp_chunk_t *sctp_copy_chunk(sctp_chunk_t *, int flags); +void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); +int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); +sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, + struct sock *); +void sctp_init_source(sctp_chunk_t *chunk); +const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); + +/* This is a structure for holding either an IPv6 or an IPv4 address. */ +/* sin_family -- AF_INET or AF_INET6 + * sin_port -- ordinary port number + * sin_addr -- cast to either (struct in_addr) or (struct in6_addr) + */ +struct sockaddr_storage_list { + list_t list; + sockaddr_storage_t a; +}; + +typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); + +/* This structure holds lists of chunks as we are assembling for + * transmission. + */ +struct SCTP_packet { + /* These are the SCTP header values (host order) for the packet. */ + __u16 source_port; + __u16 destination_port; + __u32 vtag; + + /* This contains the payload chunks. */ + struct sk_buff_head chunks; + /* This is the total size of all chunks INCLUDING padding. */ + size_t size; + + /* The packet is destined for this transport address. + * The function we finally use to pass down to the next lower + * layer lives in the transport structure. + */ + sctp_transport_t *transport; + + /* Allow a callback for getting a high priority chunk + * bundled early into the packet (This is used for ECNE). + */ + sctp_packet_phandler_t *get_prepend_chunk; + + /* This packet should advertise ECN capability to the network + * via the ECT bit. + */ + int ecn_capable; + + /* This packet contains a COOKIE-ECHO chunk. */ + int has_cookie_echo; + + int malloced; +}; + +typedef int (sctp_outqueue_thandler_t)(sctp_outqueue_t *, void *); +typedef int (sctp_outqueue_ehandler_t)(sctp_outqueue_t *); +typedef sctp_packet_t *(sctp_outqueue_ohandler_init_t) + (sctp_packet_t *, + sctp_transport_t *, + __u16 sport, + __u16 dport); +typedef sctp_packet_t *(sctp_outqueue_ohandler_config_t) + (sctp_packet_t *, + __u32 vtag, + int ecn_capable, + sctp_packet_phandler_t *get_prepend_chunk); +typedef sctp_xmit_t (sctp_outqueue_ohandler_t)(sctp_packet_t *, + sctp_chunk_t *); +typedef int (sctp_outqueue_ohandler_force_t)(sctp_packet_t *); + +sctp_outqueue_ohandler_init_t sctp_packet_init; +sctp_outqueue_ohandler_config_t sctp_packet_config; +sctp_outqueue_ohandler_t sctp_packet_append_chunk; +sctp_outqueue_ohandler_t sctp_packet_transmit_chunk; +sctp_outqueue_ohandler_force_t sctp_packet_transmit; +void sctp_packet_free(sctp_packet_t *); + + +/* This represents a remote transport address. + * For local transport addresses, we just use sockaddr_storage_t. + * + * RFC2960 Section 1.4 Key Terms + * + * o Transport address: A Transport Address is traditionally defined + * by Network Layer address, Transport Layer protocol and Transport + * Layer port number. In the case of SCTP running over IP, a + * transport address is defined by the combination of an IP address + * and an SCTP port number (where SCTP is the Transport protocol). + * + * RFC2960 Section 7.1 SCTP Differences from TCP Congestion control + * + * o The sender keeps a separate congestion control parameter set for + * each of the destination addresses it can send to (not each + * source-destination pair but for each destination). The parameters + * should decay if the address is not used for a long enough time + * period. + * + */ +struct SCTP_transport { + /* A list of transports. */ + list_t transports; + + /* Reference counting. */ + atomic_t refcnt; + int dead; + + /* This is the peer's IP address and port. */ + sockaddr_storage_t ipaddr; + + /* These are the functions we call to handle LLP stuff. */ + sctp_func_t *af_specific; + + /* Which association do we belong to? */ + sctp_association_t *asoc; + + /* RFC2960 + * + * 12.3 Per Transport Address Data + * + * For each destination transport address in the peer's + * address list derived from the INIT or INIT ACK chunk, a + * number of data elements needs to be maintained including: + */ + __u32 rtt; /* This is the most recent RTT. */ + + /* RTO : The current retransmission timeout value. */ + __u32 rto; + + /* RTTVAR : The current RTT variation. */ + __u32 rttvar; + + /* SRTT : The current smoothed round trip time. */ + __u32 srtt; + + /* RTO-Pending : A flag used to track if one of the DATA + * chunks sent to this address is currently being + * used to compute a RTT. If this flag is 0, + * the next DATA chunk sent to this destination + * should be used to compute a RTT and this flag + * should be set. Every time the RTT + * calculation completes (i.e. the DATA chunk + * is SACK'd) clear this flag. + */ + int rto_pending; + + + /* + * These are the congestion stats. + */ + /* cwnd : The current congestion window. */ + __u32 cwnd; /* This is the actual cwnd. */ + + /* ssthresh : The current slow start threshold value. */ + __u32 ssthresh; + + /* partial : The tracking method for increase of cwnd when in + * bytes acked : congestion avoidance mode (see Section 6.2.2) + */ + __u32 partial_bytes_acked; + + /* Data that has been sent, but not acknowledged. */ + __u32 flight_size; + + /* PMTU : The current known path MTU. */ + __u32 pmtu; + + /* When was the last time(in jiffies) that a data packet was sent on + * this transport? This is used to adjust the cwnd when the transport + * becomes inactive. + */ + unsigned long last_time_used; + + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to + * the destination address every heartbeat interval. + */ + int hb_interval; + + /* When was the last time (in jiffies) that we heard from this + * transport? We use this to pick new active and retran paths. + */ + unsigned long last_time_heard; + + /* Last time(in jiffies) when cwnd is reduced due to the congestion + * indication based on ECNE chunk. + */ + unsigned long last_time_ecne_reduced; + + /* state : The current state of this destination, + * : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. + */ + struct { + int active; + int hb_allowed; + } state; + + /* These are the error stats for this destination. */ + + /* Error count : The current error count for this destination. */ + unsigned short error_count; + + /* Error : Current error threshold for this destination + * Threshold : i.e. what value marks the destination down if + * : errorCount reaches this value. + */ + unsigned short error_threshold; + + /* This is the max_retrans value for the transport and will + * be initialized to proto.max_retrans.path. This can be changed + * using SCTP_SET_PEER_ADDR_PARAMS socket option. + */ + int max_retrans; + + /* We use this name for debugging output... */ + char *debug_name; + + /* Per : A timer used by each destination. + * Destination : + * Timer : + * + * [Everywhere else in the text this is called T3-rtx. -ed] + */ + struct timer_list T3_rtx_timer; + + /* Heartbeat timer is per destination. */ + struct timer_list hb_timer; + + /* Since we're using per-destination retransmission timers + * (see above), we're also using per-destination "transmitted" + * queues. This probably ought to be a private struct + * accessible only within the outqueue, but it's not, yet. + */ + struct list_head transmitted; + + /* We build bundle-able packets for this transport here. */ + sctp_packet_t packet; + + /* This is the list of transports that have chunks to send. */ + struct list_head send_ready; + + int malloced; /* Is this structure kfree()able? */ +}; + +extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); +extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, + const sockaddr_storage_t *, int); +extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); +extern void sctp_transport_free(sctp_transport_t *); +extern void sctp_transport_destroy(sctp_transport_t *); +extern void sctp_transport_reset_timers(sctp_transport_t *); +extern void sctp_transport_hold(sctp_transport_t *); +extern void sctp_transport_put(sctp_transport_t *); +extern void sctp_transport_update_rto(sctp_transport_t *, __u32); +extern void sctp_transport_raise_cwnd(sctp_transport_t *, __u32, __u32); +extern void sctp_transport_lower_cwnd(sctp_transport_t *, sctp_lower_cwnd_t); + +/* This is the structure we use to queue packets as they come into + * SCTP. We write packets to it and read chunks from it. It handles + * fragment reassembly and chunk unbundling. + */ +struct SCTP_inqueue { + /* This is actually a queue of sctp_chunk_t each + * containing a partially decoded packet. + */ + struct sk_buff_head in; + /* This is the packet which is currently off the in queue and is + * being worked on through the inbound chunk processing. + */ + sctp_chunk_t *in_progress; + + /* This is the delayed task to finish delivering inbound + * messages. + */ + struct tq_struct immediate; + + int malloced; /* Is this structure kfree()able? */ +}; + +sctp_inqueue_t *sctp_inqueue_new(void); +void sctp_inqueue_init(sctp_inqueue_t *); +void sctp_inqueue_free(sctp_inqueue_t *); +void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet); +sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *); +void sctp_inqueue_set_th_handler(sctp_inqueue_t *, + void (*)(void *), void *); + +/* This is the structure we use to hold outbound chunks. You push + * chunks in and they automatically pop out the other end as bundled + * packets (it calls (*output_handler)()). + * + * This structure covers sections 6.3, 6.4, 6.7, 6.8, 6.10, 7., 8.1, + * and 8.2 of the v13 draft. + * + * It handles retransmissions. The connection to the timeout portion + * of the state machine is through sctp_..._timeout() and timeout_handler. + * + * If you feed it SACKs, it will eat them. + * + * If you give it big chunks, it will fragment them. + * + * It assigns TSN's to data chunks. This happens at the last possible + * instant before transmission. + * + * When free()'d, it empties itself out via output_handler(). + */ +struct SCTP_outqueue { + sctp_association_t *asoc; + + /* BUG: This really should be an array of streams. + * This really holds a list of chunks (one stream). + * FIXME: If true, why so? + */ + struct sk_buff_head out; + + /* These are control chunks we want to send. */ + struct sk_buff_head control; + + /* These are chunks that have been sacked but are above the + * CTSN, or cumulative tsn ack point. + */ + struct list_head sacked; + + /* Put chunks on this list to schedule them for + * retransmission. + */ + struct list_head retransmit; + + /* Call these functions to send chunks down to the next lower + * layer. This is always SCTP_packet, but we separate the two + * structures to make testing simpler. + */ + sctp_outqueue_ohandler_init_t *init_output; + sctp_outqueue_ohandler_config_t *config_output; + sctp_outqueue_ohandler_t *append_output; + sctp_outqueue_ohandler_t *build_output; + sctp_outqueue_ohandler_force_t *force_output; + + /* How many unackd bytes do we have in-flight? */ + __u32 outstanding_bytes; + + /* Is this structure empty? */ + int empty; + + /* Are we kfree()able? */ + int malloced; +}; + +sctp_outqueue_t *sctp_outqueue_new(sctp_association_t *); +void sctp_outqueue_init(sctp_association_t *, sctp_outqueue_t *); +void sctp_outqueue_teardown(sctp_outqueue_t *); +void sctp_outqueue_free(sctp_outqueue_t*); +void sctp_force_outqueue(sctp_outqueue_t *); +int sctp_push_outqueue(sctp_outqueue_t *, sctp_chunk_t *chunk); +int sctp_flush_outqueue(sctp_outqueue_t *, int); +int sctp_sack_outqueue(sctp_outqueue_t *, sctp_sackhdr_t *); +int sctp_outqueue_is_empty(const sctp_outqueue_t *); +int sctp_outqueue_set_output_handlers(sctp_outqueue_t *, + sctp_outqueue_ohandler_init_t init, + sctp_outqueue_ohandler_config_t config, + sctp_outqueue_ohandler_t append, + sctp_outqueue_ohandler_t build, + sctp_outqueue_ohandler_force_t force); +void sctp_outqueue_restart(sctp_outqueue_t *); +void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8); + + +/* These bind address data fields common between endpoints and associations */ +struct SCTP_bind_addr { + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * SCTP Port: The local SCTP port number the endpoint is + * bound to. + */ + __u16 port; + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * Address List: The list of IP addresses that this instance + * has bound. This information is passed to one's + * peer(s) in INIT and INIT ACK chunks. + */ + list_t address_list; + + int malloced; /* Are we kfree()able? */ +}; + +sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); +void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); +void sctp_bind_addr_free(sctp_bind_addr_t *); +int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, + sctp_scope_t scope, int priority,int flags); +int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, + int priority); +int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); +int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); +sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, + int *addrs_len, + int priority); +int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, + __u8 *raw_addr_list, + int addrs_len, + unsigned short port, + int priority); + +sctp_scope_t sctp_scope(const sockaddr_storage_t *); +int sctp_in_scope(const sockaddr_storage_t *addr, const sctp_scope_t scope); +int sctp_is_any(const sockaddr_storage_t *addr); +int sctp_addr_is_valid(const sockaddr_storage_t *addr); + + +/* What type of sctp_endpoint_common? */ +typedef enum { + SCTP_EP_TYPE_SOCKET, + SCTP_EP_TYPE_ASSOCIATION, +} sctp_endpoint_type_t; + +/* + * A common base class to bridge the implmentation view of a + * socket (usually listening) endpoint versus an association's + * local endpoint. + * This common structure is useful for several purposes: + * 1) Common interface for lookup routines. + * a) Subfunctions work for either endpoint or association + * b) Single interface to lookup allows hiding the lookup lock rather + * than acquiring it externally. + * 2) Common interface for the inbound chunk handling/state machine. + * 3) Common object handling routines for reference counting, etc. + * 4) Disentangle association lookup from endpoint lookup, where we + * do not have to find our endpoint to find our association. + * + */ + +struct sctp_endpoint_common { + /* Fields to help us manage our entries in the hash tables. */ + sctp_endpoint_common_t *next; + sctp_endpoint_common_t **pprev; + int hashent; + + /* Runtime type information. What kind of endpoint is this? */ + sctp_endpoint_type_t type; + + /* Some fields to help us manage this object. + * refcnt - Reference count access to this object. + * dead - Do not attempt to use this object. + * malloced - Do we need to kfree this object? + */ + atomic_t refcnt; + char dead; + char malloced; + + /* What socket does this endpoint belong to? */ + struct sock *sk; + + /* This is where we receive inbound chunks. */ + sctp_inqueue_t inqueue; + + /* This substructure includes the defining parameters of the + * endpoint: + * bind_addr.port is our shared port number. + * bind_addr.address_list is our set of local IP addresses. + */ + sctp_bind_addr_t bind_addr; + + /* Protection during address list comparisons. */ + rwlock_t addr_lock; +}; + + +/* RFC Section 1.4 Key Terms + * + * o SCTP endpoint: The logical sender/receiver of SCTP packets. On a + * multi-homed host, an SCTP endpoint is represented to its peers as a + * combination of a set of eligible destination transport addresses to + * which SCTP packets can be sent and a set of eligible source + * transport addresses from which SCTP packets can be received. + * All transport addresses used by an SCTP endpoint must use the + * same port number, but can use multiple IP addresses. A transport + * address used by an SCTP endpoint must not be used by another + * SCTP endpoint. In other words, a transport address is unique + * to an SCTP endpoint. + * + * From an implementation perspective, each socket has one of these. + * A TCP-style socket will have exactly one association on one of + * these. An UDP-style socket will have multiple associations hanging + * off one of these. + */ + +struct SCTP_endpoint { + /* Common substructure for endpoint and association. */ + sctp_endpoint_common_t base; + + /* These are the system-wide defaults and other stuff which is + * endpoint-independent. + */ + sctp_protocol_t *proto; + + /* Associations: A list of current associations and mappings + * to the data consumers for each association. This + * may be in the form of a hash table or other + * implementation dependent structure. The data + * consumers may be process identification + * information such as file descriptors, named pipe + * pointer, or table pointers dependent on how SCTP + * is implemented. + */ + /* This is really a list of sctp_association_t entries. */ + list_t asocs; + + /* Secret Key: A secret key used by this endpoint to compute + * the MAC. This SHOULD be a cryptographic quality + * random number with a sufficient length. + * Discussion in [RFC1750] can be helpful in + * selection of the key. + */ + __u8 secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; + int current_key; + int last_key; + int key_changed_at; + + /* Default timeouts. */ + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + + /* Various thresholds. */ + + /* Name for debugging output... */ + char *debug_name; +}; + +/* Recover the outter endpoint structure. */ +static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) +{ + sctp_endpoint_t *ep; + + /* We are not really a list, but the list_entry() macro is + * really quite generic to find the address of an outter struct. + */ + ep = list_entry(base, sctp_endpoint_t, base); + return ep; +} + +/* These are function signatures for manipulating endpoints. */ +sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *, struct sock *, int); +sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *, sctp_protocol_t *, + struct sock *, int priority); +void sctp_endpoint_free(sctp_endpoint_t *); +void sctp_endpoint_put(sctp_endpoint_t *); +void sctp_endpoint_hold(sctp_endpoint_t *); +void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); +sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, + const sockaddr_storage_t *paddr, + sctp_transport_t **); +sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, + const sockaddr_storage_t *); + +void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, + const sockaddr_storage_t *peer_addr, + sctp_init_chunk_t *peer_init, int priority); +int sctp_process_param(sctp_association_t *asoc, + sctpParam_t param, + const sockaddr_storage_t *peer_addr, + sctp_cid_t cid, int priority); +__u32 sctp_generate_tag(const sctp_endpoint_t *ep); +__u32 sctp_generate_tsn(const sctp_endpoint_t *ep); + + +/* RFC2960 + * + * 12. Recommended Transmission Control Block (TCB) Parameters + * + * This section details a recommended set of parameters that should + * be contained within the TCB for an implementation. This section is + * for illustrative purposes and should not be deemed as requirements + * on an implementation or as an exhaustive list of all parameters + * inside an SCTP TCB. Each implementation may need its own additional + * parameters for optimization. + */ + + +/* Here we have information about each individual association. */ +struct SCTP_association { + + /* A base structure common to endpoint and association. + * In this context, it represents the associations's view + * of the local endpoint of the association. + */ + sctp_endpoint_common_t base; + + /* Associations on the same socket. */ + list_t asocs; + + /* This is a signature that lets us know that this is a + * sctp_association_t data structure. Used for mapping an + * association id to an association. + */ + __u32 eyecatcher; + + /* This is our parent endpoint. */ + sctp_endpoint_t *ep; + + /* These are those association elements needed in the cookie. */ + sctp_cookie_t c; + + /* This is all information about our peer. */ + struct { + /* rwnd + * + * Peer Rwnd : Current calculated value of the peer's rwnd. + */ + __u32 rwnd; + + /* transport_addr_list + * + * Peer : A list of SCTP transport addresses that the + * Transport : peer is bound to. This information is derived + * Address : from the INIT or INIT ACK and is used to + * List : associate an inbound packet with a given + * : association. Normally this information is + * : hashed or keyed for quick lookup and access + * : of the TCB. + * + * It is a list of SCTP_transport's. + */ + list_t transport_addr_list; + + /* port + * The transport layer port number. + */ + __u16 port; + + /* primary_path + * + * Primary : This is the current primary destination + * Path : transport address of the peer endpoint. It + * : may also specify a source transport address + * : on this endpoint. + * + * All of these paths live on transport_addr_list. + * + * At the bakeoffs, we discovered that the intent of + * primaryPath is that it only changes when the ULP + * asks to have it changed. We add the activePath to + * designate the connection we are currently using to + * transmit new data and most control chunks. + */ + sctp_transport_t *primary_path; + + /* active_path + * The path that we are currently using to + * transmit new data and most control chunks. + */ + sctp_transport_t *active_path; + + /* retran_path + * + * RFC2960 6.4 Multi-homed SCTP Endpoints + * ... + * Furthermore, when its peer is multi-homed, an + * endpoint SHOULD try to retransmit a chunk to an + * active destination transport address that is + * different from the last destination address to + * which the DATA chunk was sent. + */ + sctp_transport_t *retran_path; + + /* Pointer to last transport I have sent on. */ + sctp_transport_t *last_sent_to; + + /* This is the last transport I have recieved DATA on. */ + sctp_transport_t *last_data_from; + + /* + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + * + * Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. This value is hidden + * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). + */ + sctp_tsnmap_t tsn_map; + __u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; + + /* We record duplicate TSNs here. We clear this after + * every SACK. + * FIXME: We should move this into the tsnmap? --jgrimm + */ + sctp_dup_tsn_t dup_tsns[SCTP_MAX_DUP_TSNS]; + int next_dup_tsn; + + /* Do we need to sack the peer? */ + int sack_needed; + + /* These are capabilities which our peer advertised. */ + __u8 ecn_capable; /* Can peer do ECN? */ + __u8 ipv4_address; /* Peer understands IPv4 addresses? */ + __u8 ipv6_address; /* Peer understands IPv6 addresses? */ + __u8 hostname_address;/* Peer understands DNS addresses? */ + sctp_inithdr_t i; + int cookie_len; + void *cookie; + + /* ADDIP Extention (ADDIP) --xguo */ + /* minus 1 (ADDIP sec. 4.2 C1) */ + __u32 addip_serial; + } peer; + + /* State : A state variable indicating what state the + * : association is in, i.e. COOKIE-WAIT, + * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, + * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. + * + * Note: No "CLOSED" state is illustrated since if a + * association is "CLOSED" its TCB SHOULD be removed. + * + * In this implementation we DO have a CLOSED + * state which is used during initiation and shutdown. + * + * State takes values from SCTP_STATE_*. + */ + sctp_state_t state; + + /* When did we enter this state? */ + int state_timestamp; + + /* The cookie life I award for any cookie. */ + struct timeval cookie_life; + __u32 cookie_preserve; + + /* Overall : The overall association error count. + * Error Count : [Clear this any time I get something.] + */ + int overall_error_count; + + /* Overall : The threshold for this association that if + * Error : the Overall Error Count reaches will cause + * Threshold : this association to be torn down. + */ + int overall_error_threshold; + + /* These are the association's initial, max, and min RTO values. + * These values will be initialized by system defaults, but can + * be modified via the SCTP_RTOINFO socket option. + */ + __u32 rto_initial; + __u32 rto_max; + __u32 rto_min; + + /* Maximum number of new data packets that can be sent in a burst. */ + int max_burst; + + /* This is the max_retrans value for the association. This value will + * be initialized initialized from system defaults, but can be + * modified by the SCTP_ASSOCINFO socket option. + */ + int max_retrans; + + /* Maximum number of times the endpoint will retransmit INIT */ + __u16 max_init_attempts; + + /* How many times have we resent an INIT? */ + __u16 init_retries; + + /* The largest timeout or RTO value to use in attempting an INIT */ + __u16 max_init_timeo; + + + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; + + /* Transport to which SHUTDOWN chunk was last sent. */ + sctp_transport_t *shutdown_last_sent_to; + + /* Next TSN : The next TSN number to be assigned to a new + * : DATA chunk. This is sent in the INIT or INIT + * : ACK chunk to the peer and incremented each + * : time a DATA chunk is assigned a TSN + * : (normally just prior to transmit or during + * : fragmentation). + */ + __u32 next_tsn; + + /* + * Last Rcvd : This is the last TSN received in sequence. This value + * TSN : is set initially by taking the peer's Initial TSN, + * : received in the INIT or INIT ACK chunk, and + * : subtracting one from it. + * + * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. + */ + + __u32 ctsn_ack_point; + + /* The number of unacknowledged data chunks. Reported through + * the SCTP_STATUS sockopt. + */ + __u16 unack_data; + + /* This is the association's receive buffer space. This value is used + * to set a_rwnd field in an INIT or a SACK chunk. + */ + __u32 rwnd; + + /* Number of bytes by which the rwnd has slopped. The rwnd is allowed + * to slop over a maximum of the association's frag_point. + */ + __u32 rwnd_over; + + /* This is the sndbuf size in use for the association. + * This corresponds to the sndbuf size for the association, + * as specified in the sk->sndbuf. + */ + int sndbuf_used; + + /* This is the wait queue head for send requests waiting on + * the association sndbuf space. + */ + wait_queue_head_t wait; + + /* Association : The smallest PMTU discovered for all of the + * PMTU : peer's transport addresses. + */ + __u32 pmtu; + + /* The message size at which SCTP fragmentation will occur. */ + __u32 frag_point; + + /* Ack State : This flag indicates if the next received + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). + */ + /* Do we need to send an ack? + * When counters[SctpCounterAckState] is above 1 we do! + */ + int counters[SCTP_NUMBER_COUNTERS]; + + struct { + __u16 stream; + __u32 ppid; + } defaults; + + /* This tracks outbound ssn for a given stream. */ + __u16 ssn[SCTP_MAX_STREAM]; + + /* All outbound chunks go through this structure. */ + sctp_outqueue_t outqueue; + + /* A smart pipe that will handle reordering and fragmentation, + * as well as handle passing events up to the ULP. + * In the future, we should make this at least dynamic, if + * not also some sparse structure. + */ + sctp_ulpqueue_t ulpq; + __u8 _ssnmap[sctp_ulpqueue_storage_size(SCTP_MAX_STREAM)]; + + /* Need to send an ECNE Chunk? */ + int need_ecne; + + /* Last TSN that caused an ECNE Chunk to be sent. */ + __u32 last_ecne_tsn; + + /* Last TSN that caused a CWR Chunk to be sent. */ + __u32 last_cwr_tsn; + + /* How many duplicated TSNs have we seen? */ + int numduptsns; + + /* Number of seconds of idle time before an association is closed. */ + __u32 autoclose; + + /* Name for debugging output... */ + char *debug_name; + + /* These are to support + * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses + * and Enforcement of Flow and Message Limits" + * + * or "ADDIP" for short. + */ + + /* Is the ADDIP extension enabled for this association? */ + int addip_enable; + + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * [This is our one-and-only-one ASCONF in flight. If we do + * not have an ASCONF in flight, this is NULL.] + */ + sctp_chunk_t *addip_last_asconf; + + /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. + * + * IMPLEMENTATION NOTE: As an optimization a receiver may wish + * to save the last ASCONF-ACK for some predetermined period + * of time and instead of re-processing the ASCONF (with the + * same serial number) it may just re-transmit the + * ASCONF-ACK. It may wish to use the arrival of a new serial + * number to discard the previously saved ASCONF-ACK or any + * other means it may choose to expire the saved ASCONF-ACK. + * + * [This is our saved ASCONF-ACK. We invalidate it when a new + * ASCONF serial number arrives.] + */ + sctp_chunk_t *addip_last_asconf_ack; + + /* These ASCONF chunks are waiting to be sent. + * + * These chunaks can't be pushed to outqueue until receiving + * ASCONF_ACK for the previous ASCONF indicated by + * addip_last_asconf, so as to guarantee that only one ASCONF + * is in flight at any time. + * + * ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * In defining the ASCONF Chunk transfer procedures, it is + * essential that these transfers MUST NOT cause congestion + * within the network. To achieve this, we place these + * restrictions on the transfer of ASCONF Chunks: + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * + * [I really think this is EXACTLY the sort of intelligence + * which already resides in SCTP_outqueue. Please move this + * queue and its supporting logic down there. --piggy] + */ + struct sk_buff_head addip_chunks; + + /* ADDIP Section 4.1 ASCONF Chunk Procedures + * + * A2) A serial number should be assigned to the Chunk. The + * serial number should be a monotonically increasing + * number. All serial numbers are defined to be initialized at + * the start of the association to the same value as the + * Initial TSN. + * + * [and] + * + * ADDIP + * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * + * Serial Number : 32 bits (unsigned integer) + * + * This value represents a Serial Number for the ASCONF + * Chunk. The valid range of Serial Number is from 0 to + * 4294967295 (2**32 - 1). Serial Numbers wrap back to 0 + * after reaching 4294967295. + */ + __u32 addip_serial; +}; + + +/* An eyecatcher for determining if we are really looking at an + * association data structure. + */ +enum { + SCTP_ASSOC_EYECATCHER = 0xa550c123, +}; + +/* Recover the outter association structure. */ +static inline sctp_association_t *sctp_assoc(sctp_endpoint_common_t *base) +{ + sctp_association_t *asoc; + + /* We are not really a list, but the list_entry() macro is + * really quite generic find the address of an outter struct. + */ + asoc = list_entry(base, sctp_association_t, base); + return asoc; +} + +/* These are function signatures for manipulating associations. */ + + +sctp_association_t * +sctp_association_new(const sctp_endpoint_t *, const struct sock *, + sctp_scope_t scope, int priority); +sctp_association_t * +sctp_association_init(sctp_association_t *, const sctp_endpoint_t *, + const struct sock *, sctp_scope_t scope, + int priority); +void sctp_association_free(sctp_association_t *); +void sctp_association_put(sctp_association_t *); +void sctp_association_hold(sctp_association_t *); + +sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *); +sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, + const sockaddr_storage_t *); +sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, + const sockaddr_storage_t *address, + const int priority); +void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *, + sctp_transport_cmd_t, sctp_sn_error_t); +sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, __u32); +sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, + const sockaddr_storage_t *, + const sockaddr_storage_t *); +void sctp_assoc_migrate(sctp_association_t *, struct sock *); +void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); + +__u32 __sctp_association_get_next_tsn(sctp_association_t *); +__u32 __sctp_association_get_tsn_block(sctp_association_t *, int); +__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); + +int sctp_cmp_addr(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2); +int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2); +sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc); +sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc); + + +/* A convenience structure to parse out SCTP specific CMSGs. */ +typedef struct sctp_cmsgs { + struct sctp_initmsg *init; + struct sctp_sndrcvinfo *info; +} sctp_cmsgs_t; + +/* Structure for tracking memory objects */ +typedef struct { + char *label; + atomic_t *counter; +} sctp_dbg_objcnt_entry_t; + +#endif /* __sctp_structs_h__ */ diff -Nru a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/tsnmap.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,159 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, Intel, and International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These are the definitions needed for the tsnmap type. The tsnmap is used + * to track out of order TSNs received. + * + * The SCTP reference implementation 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. + * + * the SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#include + +#ifndef __sctp_tsnmap_h__ +#define __sctp_tsnmap_h__ + + + +/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB) + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + */ +typedef struct sctp_tsnmap { + + + /* This array counts the number of chunks with each TSN. + * It points at one of the two buffers with which we will + * ping-pong between. + */ + __u8 *tsn_map; + + /* This marks the tsn which overflows the tsn_map, when the + * cumulative ack point reaches this point we know we can switch + * maps (tsn_map and overflow_map swap). + */ + __u32 overflow_tsn; + + /* This is the overflow array for tsn_map. + * It points at one of the other ping-pong buffers. + */ + __u8 *overflow_map; + + /* This is the TSN at tsn_map[0]. */ + __u32 base_tsn; + + /* Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. + */ + __u32 cumulative_tsn_ack_point; + + /* This is the minimum number of TSNs we can track. This corresponds + * to the size of tsn_map. Note: the overflow_map allows us to + * potentially track more than this quantity. + */ + __u16 len; + + /* This is the highest TSN we've marked. */ + __u32 max_tsn_seen; + + /* No. of data chunks pending receipt. used by SCTP_STATUS sockopt */ + __u16 pending_data; + + int malloced; + + __u8 raw_map[0]; +} sctp_tsnmap_t; + +typedef struct sctp_tsnmap_iter { + __u32 start; +} sctp_tsnmap_iter_t; + + +/* Create a new tsnmap. */ +sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, + int priority); + +/* Dispose of a tsnmap. */ +void sctp_tsnmap_free(sctp_tsnmap_t *map); + +/* This macro assists in creation of external storage for variable length + * internal buffers. We double allocate so the overflow map works. + */ +#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2) + +/* Initialize a block of memory as a tsnmap. */ +sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn); + + + +/* Test the tracking state of this TSN. + * Returns: + * 0 if the TSN has not yet been seen + * >0 if the TSN has been seen (duplicate) + * <0 if the TSN is invalid (too large to track) + */ +int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn); + +/* Mark this TSN as seen. */ +void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn); + +/* Retrieve the Cumulative TSN ACK Point. */ +__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map); + +/* Retrieve the highest TSN we've seen. */ +__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map); + +/* Is there a gap in the TSN map? */ +int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map); + +/* Initialize a gap ack block interator from user-provided memory. */ +void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter); + +/* Get the next gap ack blocks. We return 0 if there are no more + * gap ack blocks. + */ +int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + __u16 *start, __u16 *end); + + +#endif /* __sctp_tsnmap_h__ */ + + + diff -Nru a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/ulpevent.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,135 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * These are the definitions needed for the sctp_ulpevent type. The + * sctp_ulpevent type is used to carry information from the state machine + * upwards to the ULP. + * + * The SCTP reference implementation 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. + * + * the SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#ifndef __sctp_ulpevent_h__ +#define __sctp_ulpevent_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +/* Warning: This sits inside an skb.cb[] area. Be very careful of + * growing this structure as it is at the maximum limit now. + */ +typedef struct sctp_ulpevent { + int malloced; + sctp_association_t *asoc; + struct sk_buff *parent; + struct sctp_sndrcvinfo sndrcvinfo; + int chunk_flags; /* Temp. until we get a new chunk_t */ + int msg_flags; +} sctp_ulpevent_t; + + +sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority); + +sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags); + +void sctp_ulpevent_free(sctp_ulpevent_t *event); + +int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event); + +sctp_ulpevent_t *sctp_ulpevent_make_assoc_change( + const struct SCTP_association *asoc, + __u16 flags, + __u16 state, + __u16 error, + __u16 outbound, + __u16 inbound, + int priority); + +sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( + const struct SCTP_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority); + +sctp_ulpevent_t *sctp_ulpevent_make_remote_error( + const struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + __u16 flags, + int priority); +sctp_ulpevent_t *sctp_ulpevent_make_send_failed( + const struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + __u16 flags, + __u32 error, + int priority); + +sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( + const struct SCTP_association *asoc, + __u16 flags, + int priority); + +sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + int priority); + +void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr); + +__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event); + + + +/* Given an event subscription, is this event enabled? */ +static inline int sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event, + const struct sctp_event_subscribe *mask) +{ + const char *amask = (const char *) mask; + __u16 sn_type; + int enabled = 1; + + if (sctp_ulpevent_is_notification(event)) { + sn_type = sctp_ulpevent_get_notification_type(event); + enabled = amask[sn_type - SCTP_SN_TYPE_BASE]; + } + return enabled; +} + + +#endif /* __sctp_ulpevent_h__ */ + + + + + + + diff -Nru a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/ulpqueue.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,93 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * These are the definitions needed for the sctp_ulpqueue type. The + * sctp_ulpqueue is the interface between the Upper Layer Protocol, or ULP, + * and the core SCTP state machine. This is the component which handles + * reassembly and ordering. + * + * The SCTP reference implementation 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. + * + * the SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_ulpqueue_h__ +#define __sctp_ulpqueue_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +typedef struct sctp_ulpqueue { + int malloced; + spinlock_t lock; + sctp_association_t *asoc; + struct sk_buff_head reasm; + struct sk_buff_head lobby; + __u16 ssn[0]; +} sctp_ulpqueue_t; + +/* This macro assists in creation of external storage for variable length + * internal buffers. + */ +#define sctp_ulpqueue_storage_size(inbound) (sizeof(__u16) * (inbound)) + +sctp_ulpqueue_t *sctp_ulpqueue_new(sctp_association_t *asoc, + __u16 inbound, + int priority); + +sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, + sctp_association_t *asoc, + __u16 inbound); + +void sctp_ulpqueue_free(sctp_ulpqueue_t *); + + +/* Add a new DATA chunk for processing. */ +int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, + sctp_chunk_t *chunk, + int priority); + + +/* Add a new event for propogation to the ULP. */ +int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *, + sctp_ulpevent_t *event); + + +/* Is the ulpqueue empty. */ +int sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); + +int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); + +#endif /* __sctp_ulpqueue_h__ */ + + + + + + + diff -Nru a/include/net/sctp/user.h b/include/net/sctp/user.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/sctp/user.h Sat Aug 31 15:06:06 2002 @@ -0,0 +1,607 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This header represents the structures and constants needed to support + * the SCTP Extension to the Sockets API. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * R. Stewart + * K. Morneau + * Q. Xie + * Karl Knutson + * Jon Grimm + * Daisy Chang + * + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#include +#include + +#ifndef __net_sctp_user_h__ +#define __net_sctp_user_h__ + + +typedef void * sctp_assoc_t; + +/* The following symbols come from the Sockets API Extensions for + * SCTP . + */ +enum sctp_optname { + SCTP_RTOINFO, +#define SCTP_RTOINFO SCTP_RTOINFO + SCTP_ASSOCRTXINFO, +#define SCTP_ASSOCRTXINFO SCTP_ASSOCRTXINFO + SCTP_INITMSG, +#define SCTP_INITMSG SCTP_INITMSG + SCTP_AUTO_CLOSE, +#define SCTP_AUTO_CLOSE SCTP_AUTO_CLOSE + SCTP_SET_PRIMARY_ADDR, +#define SCTP_SET_PRIMARY_ADDR SCTP_SET_PRIMARY_ADDR + SCTP_SET_PEER_PRIMARY_ADDR, +#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR + SCTP_SET_ADAPTATION_LAYER, +#define SCTP_SET_ADAPTATION_LAYER SCTP_SET_ADAPTATION_LAYER + SCTP_SET_STREAM_TIMEOUTS, +#define SCTP_SET_STREAM_TIMEOUTS SCTP_SET_STREAM_TIMEOUTS + SCTP_DISABLE_FRAGMENTS, +#define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS + SCTP_SET_PEER_ADDR_PARAMS, +#define SCTP_SET_PEER_ADDR_PARAMS SCTP_SET_PEER_ADDR_PARAMS + SCTP_GET_PEER_ADDR_PARAMS, +#define SCTP_GET_PEER_ADDR_PARAMS SCTP_GET_PEER_ADDR_PARAMS + SCTP_STATUS, +#define SCTP_STATUS SCTP_STATUS + SCTP_GET_PEER_ADDR_INFO, +#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO + SCTP_SET_EVENTS, +#define SCTP_SET_EVENTS SCTP_SET_EVENTS + SCTP_AUTOCLOSE, +#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE + SCTP_SET_DEFAULT_SEND_PARAM, +#define SCTP_SET_DEFAULT_SEND_PARAM SCTP_SET_DEFAULT_SEND_PARAM + + SCTP_SOCKOPT_DEBUG_NAME = 42, /* FIXME */ +#define SCTP_SOCKOPT_DEBUG_NAME SCTP_SOCKOPT_DEBUG_NAME + + SCTP_SOCKOPT_BINDX_ADD, /* BINDX requests for adding addresses. */ +#define SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_ADD + SCTP_SOCKOPT_BINDX_REM, /* BINDX requests for removing addresses. */ +#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM + SCTP_SOCKOPT_PEELOFF, /* peel off association. */ +#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF +}; + + +/* + * 5.2 SCTP msg_control Structures + * + * A key element of all SCTP-specific socket extensions is the use of + * ancillary data to specify and access SCTP-specific data via the + * struct msghdr's msg_control member used in sendmsg() and recvmsg(). + * Fine-grained control over initialization and sending parameters are + * handled with ancillary data. + * + * Each ancillary data item is preceeded by a struct cmsghdr (see + * Section 5.1), which defines the function and purpose of the data + * contained in in the cmsg_data[] member. + */ + +/* + * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for initializing new + * SCTP associations with sendmsg(). The SCTP_INITMSG socket option + * uses this same data structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + * + */ +struct sctp_initmsg { + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + __u16 sinit_max_attempts; + __u16 sinit_max_init_timeo; +}; + + +/* + * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for sendmsg() and + * describes SCTP header information about a received message through + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + * + */ +struct sctp_sndrcvinfo { + __u16 sinfo_stream; + __u16 sinfo_ssn; + __u16 sinfo_flags; + __u32 sinfo_ppid; + __u32 sinfo_context; + __u32 sinfo_timetolive; + __u32 sinfo_tsn; + sctp_assoc_t sinfo_assoc_id; +}; + +/* + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + */ + +enum sctp_sinfo_flags { + MSG_UNORDERED = 1, /* Send/recieve message unordered. */ + MSG_ADDR_OVER = 2, /* Override the primary destination. */ + MSG_ABORT=4, /* Send an ABORT message to the peer. */ + /* MSG_EOF is already defined per socket.h */ +}; + + +typedef union { + __u8 raw; + struct sctp_initmsg init; + struct sctp_sndrcvinfo sndrcv; +} sctp_cmsg_data_t; + +/* These are cmsg_types. */ +typedef enum sctp_cmsg_type { + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ +} sctp_cmsg_t; + + +/* + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notificaion. The notification information has the + * following format: + * + */ + +struct sctp_assoc_change { + __u16 sac_type; + __u16 sac_flags; + __u32 sac_length; + __u16 sac_state; + __u16 sac_error; + __u16 sac_outbound_streams; + __u16 sac_inbound_streams; + sctp_assoc_t sac_assoc_id; +}; + +/* + * sac_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the association. They include: + * + * Note: The following state names deviate from the API draft as + * the names clash too easily with other kernel symbols. + */ +enum sctp_sac_state { + SCTP_COMM_UP, + SCTP_COMM_LOST, + SCTP_RESTART, + SCTP_SHUTDOWN_COMP, + SCTP_CANT_STR_ASSOC, +}; + +/* + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. The information has the + * following structure: + */ +struct sctp_paddr_change { + __u16 spc_type; + __u16 spc_flags; + __u32 spc_length; + struct sockaddr_storage spc_aaddr; + int spc_state; + int spc_error; + sctp_assoc_t spc_assoc_id; +}; + +/* + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. They include: + */ +enum sctp_spc_state { + ADDRESS_AVAILABLE, + ADDRESS_UNREACHABLE, + ADDRESS_REMOVED, + ADDRESS_ADDED, + ADDRESS_MADE_PRIM, +}; + + +/* + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. SCTP error TLVs have the format: + */ +struct sctp_remote_error { + __u16 sre_type; + __u16 sre_flags; + __u32 sre_length; + __u16 sre_error; + __u16 sre_len; + sctp_assoc_t sre_assoc_id; + __u8 sre_data[0]; +}; + + +/* + * 5.3.1.4 SCTP_SEND_FAILED + * + * If SCTP cannot deliver a message it may return the message as a + * notification. + */ +struct sctp_send_failed { + __u16 ssf_type; + __u16 ssf_flags; + __u32 ssf_length; + __u32 ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + __u8 ssf_data[0]; +}; + +/* + * ssf_flags: 16 bits (unsigned integer) + * + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ + +enum sctp_ssf_flags { + SCTP_DATA_UNSENT, + SCTP_DATA_SENT, +}; + +/* + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ + +struct sctp_shutdown_event { + __u16 sse_type; + __u16 sse_flags; + __u32 sse_length; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.6 SCTP_ADAPTION_INDICATION + * + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application + * that of the peers requested adaption layer. + */ +struct sctp_adaption_event { + __u16 sai_type; + __u16 sai_flags; + __u32 sai_length; + __u32 sai_adaptation_bits; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT + * + * When a reciever is engaged in a partial delivery of a + * message this notification will be used to inidicate + * various events. + */ + +struct sctp_rcv_pdapi_event { + __u16 pdapi_type; + __u16 pdapi_flags; + __u32 pdapi_length; + __u32 pdapi_indication; + sctp_assoc_t pdapi_assoc_id; +}; + + +/* + * Described in Section 7.3 + * Ancillary Data and Notification Interest Options + */ +struct sctp_event_subscribe { + __u8 sctp_data_io_event; + __u8 sctp_association_event; + __u8 sctp_address_event; + __u8 sctp_send_failure_event; + __u8 sctp_peer_error_event; + __u8 sctp_shutdown_event; + __u8 sctp_partial_delivery_event; + __u8 sctp_adaption_layer_event; +}; + +/* + * 5.3.1 SCTP Notification Structure + * + * The notification structure is defined as the union of all + * notification types. + * + */ +union sctp_notification { + struct { + __u16 sn_type; /* Notification type. */ + __u16 sn_flags; + __u32 sn_length; + } h; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_padr_change; + struct sctp_remote_error sn_remote_error; + struct sctp_send_failed sn_send_failed; + struct sctp_shutdown_event sn_shutdown_event; + struct sctp_adaption_event sn_adaption_event; + struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; +}; + +/* Section 5.3.1 + * All standard values for sn_type flags are greater than 2^15. + * Values from 2^15 and down are reserved. + */ + +enum sctp_sn_type { + SCTP_SN_TYPE_BASE = (1<<15), + SCTP_ASSOC_CHANGE, + SCTP_PEER_ADDR_CHANGE, + SCTP_REMOTE_ERROR, + SCTP_SEND_FAILED, + SCTP_SHUTDOWN_EVENT, + SCTP_PARTIAL_DELIVERY_EVENT, + SCTP_ADAPTION_INDICATION, +}; + +/* Notification error codes used to fill up the error fields in some + * notifications. + * SCTP_PEER_ADDRESS_CHAGE : spc_error + * SCTP_ASSOC_CHANGE : sac_error + * These names should be potentially included in the draft 04 of the SCTP + * sockets API specification. + */ +typedef enum sctp_sn_error { + SCTP_FAILED_THRESHOLD, + SCTP_RECEIVED_SACK, + SCTP_HEARTBEAT_SUCCESS, + SCTP_RESPONSE_TO_USER_REQ, + SCTP_INTERNAL_ERROR, + SCTP_SHUTDOWN_GUARD_EXPIRES, + SCTP_PEER_FAULTY, +} sctp_sn_error_t; + +/* + * + * 7.1.14 Peer Address Parameters + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ + +struct sctp_paddrparams { + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; + sctp_assoc_t spp_assoc_id; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ + +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +}; + + +/* + * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. See [SCTP] for more information on how + * these parameters are used in RTO calculation. The peer address + * parameter is ignored for TCP style socket. + */ + +struct sctp_rtoinfo { + __u32 srto_initial; + __u32 srto_max; + __u32 srto_min; + sctp_assoc_t srto_assoc_id; +}; + +/* + * 7.1.2 Association Retransmission Parameter (SCTP_ASSOCRTXINFO) + * + * The protocol parameter used to set the number of retransmissions + * sent before an association is considered unreachable. + * See [SCTP] for more information on how this parameter is used. The + * peer address parameter is ignored for TCP style socket. + */ + +struct sctp_assocparams { + __u16 sasoc_asocmaxrxt; + sctp_assoc_t sasoc_assoc_id; +}; + + +/* + * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ + +struct sctp_setprim { + struct sockaddr_storage ssp_addr; + sctp_assoc_t ssp_assoc_id; +}; + +/* + * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the local SCTP stack use the enclosed peer address as + * the association primary. The enclosed address must be one of the + * association peer's addresses. The following structure is used to + * make a set peer primary request: + */ + +struct sctp_setpeerprim { + struct sockaddr_storage sspp_addr; + sctp_assoc_t sspp_assoc_id; +}; + +/* + * 7.2.1 Association Status (SCTP_STATUS) + * + * Applications can retrieve current status information about an + * association, including association state, peer receiver window size, + * number of unacked data chunks, and number of data chunks pending + * receipt. This information is read-only. The following structure is + * used to access this information: + */ +struct sctp_status { + sctp_assoc_t sstat_assoc_id; + __s32 sstat_state; + __u32 sstat_rwnd; + __u16 sstat_unackdata; + __u16 sstat_penddata; + __u16 sstat_instrms; + __u16 sstat_outstrms; + __u32 sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; +}; + + +/* + * 7.1.12 Set Adaption Layer Indicator + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future + * INIT and INIT-ACK exchanges. + */ + +struct sctp_setadaption { + __u32 ssb_adaption_ind; +}; + +/* + * 7.1.12 Set default message time outs (SCTP_SET_STREAM_TIMEOUTS) + * + * This option requests that the requested stream apply a + * default time-out for messages in queue. + */ +struct sctp_setstrm_timeout { + sctp_assoc_t ssto_assoc_id; + __u32 ssto_timeout; + __u16 ssto_streamid_start; + __u16 ssto_streamid_end; +}; + + +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; + +/* + * 8.1 sctp_bindx() + * + * The flags parameter is formed from the bitwise OR of zero or more of the + * following currently defined flags: + */ +#define BINDX_ADD_ADDR 0x01 +#define BINDX_REM_ADDR 0x02 + +/* This is the structure that is passed as an argument(optval) to + * getsockopt(SCTP_SOCKOPT_PEELOFF). + */ +typedef struct { + sctp_assoc_t associd; + int sd; +} sctp_peeloff_arg_t; + +#endif /* __net_sctp_user_h__ */ + + + diff -Nru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h Sat Aug 31 15:06:06 2002 +++ b/include/net/sock.h Sat Aug 31 15:06:06 2002 @@ -130,7 +130,7 @@ bsdism; unsigned char debug; unsigned char rcvtstamp; - /* Hole of 1 byte. Try to pack. */ + unsigned char no_largesend; int route_caps; int proc; unsigned long lingertime; diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Sat Aug 31 15:05:54 2002 +++ b/include/net/tcp.h Sat Aug 31 15:05:54 2002 @@ -905,16 +905,21 @@ /* Compute the current effective MSS, taking SACKs and IP options, * and even PMTU discovery events into account. + * + * LARGESEND note: !urg_mode is overkill, only frames up to snd_up + * cannot be large. However, taking into account rare use of URG, this + * is not a big flaw. */ -static __inline__ unsigned int tcp_current_mss(struct sock *sk) +static __inline__ unsigned int tcp_current_mss(struct sock *sk, int large) { struct tcp_opt *tp = tcp_sk(sk); struct dst_entry *dst = __sk_dst_get(sk); - int mss_now = tp->mss_cache; + int mss_now = large && (sk->route_caps&NETIF_F_TSO) && !tp->urg_mode ? + tp->mss_cache : tp->mss_cache_std; if (dst && dst->pmtu != tp->pmtu_cookie) - mss_now = tcp_sync_mss(sk, dst->pmtu); + mss_now = tcp_sync_mss(sk, dst->pmtu); if (tp->eff_sacks) mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + @@ -933,7 +938,7 @@ static inline void tcp_initialize_rcv_mss(struct sock *sk) { struct tcp_opt *tp = tcp_sk(sk); - unsigned int hint = min(tp->advmss, tp->mss_cache); + unsigned int hint = min(tp->advmss, tp->mss_cache_std); hint = min(hint, tp->rcv_wnd/2); hint = min(hint, TCP_MIN_RCVMSS); @@ -1269,7 +1274,7 @@ static __inline__ void tcp_push_pending_frames(struct sock *sk, struct tcp_opt *tp) { - __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk), tp->nonagle); + __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1), tp->nonagle); } static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_opt *tp) @@ -1277,7 +1282,7 @@ struct sk_buff *skb = tp->send_head; return (skb && - tcp_snd_test(tp, skb, tcp_current_mss(sk), + tcp_snd_test(tp, skb, tcp_current_mss(sk, 1), tcp_skb_is_last(sk, skb) ? 1 : tp->nonagle)); } @@ -1837,6 +1842,15 @@ if (rst && xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_MSL) return 0; return 1; +} + +static inline void tcp_v4_setup_caps(struct sock *sk, struct dst_entry *dst) +{ + sk->route_caps = dst->dev->features; + if (sk->route_caps & NETIF_F_TSO) { + if (sk->no_largesend) + sk->route_caps &= ~NETIF_F_TSO; + } } #define TCP_CHECK_TIMER(sk) do { } while (0) diff -Nru a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h --- a/include/net/tcp_ecn.h Sat Aug 31 15:05:55 2002 +++ b/include/net/tcp_ecn.h Sat Aug 31 15:05:55 2002 @@ -28,12 +28,13 @@ } static __inline__ void -TCP_ECN_send_syn(struct tcp_opt *tp, struct sk_buff *skb) +TCP_ECN_send_syn(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { tp->ecn_flags = 0; - if (sysctl_tcp_ecn) { + if (sysctl_tcp_ecn && !(sk->route_caps&NETIF_F_TSO)) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; tp->ecn_flags = TCP_ECN_OK; + sk->no_largesend = 1; } } diff -Nru a/include/video/sbusfb.h b/include/video/sbusfb.h --- a/include/video/sbusfb.h Sat Aug 31 15:06:06 2002 +++ b/include/video/sbusfb.h Sat Aug 31 15:06:06 2002 @@ -85,8 +85,6 @@ struct fb_info_sbusfb { struct fb_info info; - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; struct display disp; struct display_switch dispsw; struct fbtype type; diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Sat Aug 31 15:05:55 2002 +++ b/init/main.c Sat Aug 31 15:05:55 2002 @@ -387,7 +387,6 @@ asmlinkage void __init start_kernel(void) { char * command_line; - unsigned long mempages; extern char saved_command_line[]; /* * Interrupts are still disabled. Do necessary setups, then @@ -439,13 +438,11 @@ kmem_cache_sizes_init(); pgtable_cache_init(); pte_chain_init(); - mempages = num_physpages; - - fork_init(mempages); + fork_init(num_physpages); proc_caches_init(); security_scaffolding_startup(); buffer_init(); - vfs_caches_init(mempages); + vfs_caches_init(num_physpages); radix_tree_init(); signals_init(); #ifdef CONFIG_PROC_FS diff -Nru a/kernel/dma.c b/kernel/dma.c --- a/kernel/dma.c Sat Aug 31 15:05:55 2002 +++ b/kernel/dma.c Sat Aug 31 15:05:55 2002 @@ -150,10 +150,10 @@ } static struct file_operations proc_dma_operations = { - open: proc_dma_open, - read: seq_read, - llseek: seq_lseek, - release: single_release, + .open = proc_dma_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static int __init proc_dma_init(void) diff -Nru a/kernel/exit.c b/kernel/exit.c --- a/kernel/exit.c Sat Aug 31 15:05:59 2002 +++ b/kernel/exit.c Sat Aug 31 15:05:59 2002 @@ -712,15 +712,19 @@ if (retval) goto end_wait4; retval = p->pid; - if (p->real_parent != p->parent || p->ptrace) { + if (p->real_parent != p->parent) { write_lock_irq(&tasklist_lock); - remove_parent(p); - p->parent = p->real_parent; - add_parent(p, p->parent); + ptrace_unlink(p); do_notify_parent(p, SIGCHLD); write_unlock_irq(&tasklist_lock); - } else + } else { + if (p->ptrace) { + write_lock_irq(&tasklist_lock); + ptrace_unlink(p); + write_unlock_irq(&tasklist_lock); + } release_task(p); + } goto end_wait4; default: continue; diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Sat Aug 31 15:05:54 2002 +++ b/kernel/fork.c Sat Aug 31 15:05:54 2002 @@ -649,7 +649,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, - unsigned long stack_size) + unsigned long stack_size, + int *user_tid) { int retval; struct task_struct *p = NULL; @@ -760,7 +761,20 @@ retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_namespace; - + /* + * Notify the child of the TID? + */ + retval = -EFAULT; + if (clone_flags & CLONE_SETTID) + if (put_user(p->pid, user_tid)) + goto bad_fork_cleanup_namespace; + + /* + * Does the userspace VM want the TID cleared on mm_release()? + */ + if (clone_flags & CLONE_CLEARTID) + p->user_tid = user_tid; + /* Our parent execution domain becomes current domain These must match for thread signalling to apply */ @@ -876,11 +890,12 @@ struct task_struct *do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, - unsigned long stack_size) + unsigned long stack_size, + int *user_tid) { struct task_struct *p; - p = copy_process(clone_flags, stack_start, regs, stack_size); + p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid); if (!IS_ERR(p)) { struct completion vfork; diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Sat Aug 31 15:05:54 2002 +++ b/kernel/ksyms.c Sat Aug 31 15:05:54 2002 @@ -496,8 +496,6 @@ #endif EXPORT_SYMBOL(kstat); -EXPORT_SYMBOL(nr_running); -EXPORT_SYMBOL(nr_context_switches); /* misc */ EXPORT_SYMBOL(panic); diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Sat Aug 31 15:05:55 2002 +++ b/kernel/sched.c Sat Aug 31 15:05:55 2002 @@ -1039,6 +1039,7 @@ printk("bad: schedule() with irqs disabled!\n"); show_stack(NULL); preempt_enable_no_resched(); + return; } need_resched: @@ -1900,7 +1901,7 @@ typedef struct { list_t list; task_t *task; - struct semaphore sem; + struct completion done; } migration_req_t; /* @@ -1944,13 +1945,13 @@ task_rq_unlock(rq, &flags); goto out; } - init_MUTEX_LOCKED(&req.sem); + init_completion(&req.done); req.task = p; list_add(&req.list, &rq->migration_queue); task_rq_unlock(rq, &flags); wake_up_process(rq->migration_thread); - down(&req.sem); + wait_for_completion(&req.done); out: preempt_enable(); } @@ -2031,7 +2032,7 @@ double_rq_unlock(rq_src, rq_dest); local_irq_restore(flags); - up(&req->sem); + complete(&req->done); } } diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Sat Aug 31 15:05:59 2002 +++ b/mm/filemap.c Sat Aug 31 15:05:59 2002 @@ -61,7 +61,6 @@ * ->inode_lock (__mark_inode_dirty) * ->sb_lock (fs/fs-writeback.c) */ -spinlock_t _pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* * Remove a page from the page cache and free it. Caller has to make @@ -117,10 +116,10 @@ struct list_head *head, *curr; struct page * page; struct address_space *mapping = inode->i_mapping; - struct pagevec lru_pvec; + struct pagevec pvec; head = &mapping->clean_pages; - pagevec_init(&lru_pvec); + pagevec_init(&pvec); write_lock(&mapping->page_lock); curr = head->next; @@ -144,8 +143,8 @@ __remove_from_page_cache(page); unlock_page(page); - if (!pagevec_add(&lru_pvec, page)) - __pagevec_lru_del(&lru_pvec); + if (!pagevec_add(&pvec, page)) + __pagevec_release(&pvec); continue; unlock: unlock_page(page); @@ -153,7 +152,7 @@ } write_unlock(&mapping->page_lock); - pagevec_lru_del(&lru_pvec); + pagevec_release(&pvec); } static int do_invalidatepage(struct page *page, unsigned long offset) @@ -465,31 +464,38 @@ SetPageReferenced(page); } - /* Set the page dirty again, unlock */ - set_page_dirty(page); unlock_page(page); - return 0; + return -EAGAIN; /* It will be set dirty again */ } EXPORT_SYMBOL(fail_writepage); /** - * filemap_fdatawrite - walk the list of dirty pages of the given address space - * and writepage() all of them. - * - * @mapping: address space structure to write + * filemap_fdatawrite - start writeback against all of a mapping's dirty pages + * @mapping: address space structure to write * + * This is a "data integrity" operation, as opposed to a regular memory + * cleansing writeback. The difference between these two operations is that + * if a dirty page/buffer is encountered, it must be waited upon, and not just + * skipped over. + * + * The PF_SYNC flag is set across this operation and the various functions + * which care about this distinction must use called_for_sync() to find out + * which behaviour they should implement. */ int filemap_fdatawrite(struct address_space *mapping) { - return do_writepages(mapping, NULL); + int ret; + + current->flags |= PF_SYNC; + ret = do_writepages(mapping, NULL); + current->flags &= ~PF_SYNC; + return ret; } /** - * filemap_fdatawait - walk the list of locked pages of the given address space - * and wait for all of them. - * - * @mapping: address space structure to wait for - * + * filemap_fdatawait - walk the list of locked pages of the given address + * space and wait for all of them. + * @mapping: address space structure to wait for */ int filemap_fdatawait(struct address_space * mapping) { @@ -498,8 +504,9 @@ write_lock(&mapping->page_lock); while (!list_empty(&mapping->locked_pages)) { - struct page *page = list_entry(mapping->locked_pages.next, struct page, list); + struct page *page; + page = list_entry(mapping->locked_pages.next,struct page,list); list_del(&page->list); if (PageDirty(page)) list_add(&page->list, &mapping->dirty_pages); @@ -611,7 +618,7 @@ */ static inline wait_queue_head_t *page_waitqueue(struct page *page) { - const zone_t *zone = page_zone(page); + const struct zone *zone = page_zone(page); return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; } @@ -1151,14 +1158,15 @@ { struct address_space *mapping = file->f_dentry->d_inode->i_mapping; unsigned long max; - struct page_state ps; + unsigned long active; + unsigned long inactive; if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) return -EINVAL; /* Limit it to a sane percentage of the inactive list.. */ - get_page_state(&ps); - max = ps.nr_inactive / 2; + get_zone_counts(&active, &inactive); + max = inactive / 2; if (nr > max) nr = max; diff -Nru a/mm/msync.c b/mm/msync.c --- a/mm/msync.c Sat Aug 31 15:05:59 2002 +++ b/mm/msync.c Sat Aug 31 15:05:59 2002 @@ -145,10 +145,7 @@ int err; down(&inode->i_sem); - ret = filemap_fdatawait(inode->i_mapping); - err = filemap_fdatawrite(inode->i_mapping); - if (!ret) - ret = err; + ret = filemap_fdatawrite(inode->i_mapping); if (flags & MS_SYNC) { if (file->f_op && file->f_op->fsync) { err = file->f_op->fsync(file, file->f_dentry, 1); diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c --- a/mm/page-writeback.c Sat Aug 31 15:05:54 2002 +++ b/mm/page-writeback.c Sat Aug 31 15:05:54 2002 @@ -350,10 +350,15 @@ #if 0 if (!PageWriteback(page) && PageDirty(page)) { lock_page(page); - if (!PageWriteback(page) && TestClearPageDirty(page)) - page->mapping->a_ops->writepage(page); - else + if (!PageWriteback(page) && TestClearPageDirty(page)) { + int ret; + + ret = page->mapping->a_ops->writepage(page); + if (ret == -EAGAIN) + __set_page_dirty_nobuffers(page); + } else { unlock_page(page); + } } #endif } @@ -395,6 +400,10 @@ page_cache_get(page); write_unlock(&mapping->page_lock); ret = mapping->a_ops->writepage(page); + if (ret == -EAGAIN) { + __set_page_dirty_nobuffers(page); + ret = 0; + } if (ret == 0 && wait) { wait_on_page_writeback(page); if (PageError(page)) diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Sat Aug 31 15:05:54 2002 +++ b/mm/page_alloc.c Sat Aug 31 15:05:54 2002 @@ -27,15 +27,13 @@ unsigned long totalram_pages; unsigned long totalhigh_pages; int nr_swap_pages; -LIST_HEAD(active_list); -LIST_HEAD(inactive_list); pg_data_t *pgdat_list; /* * Used by page_zone() to look up the address of the struct zone whose * id is encoded in the upper bits of page->flags */ -zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES]; +struct zone *zone_table[MAX_NR_ZONES*MAX_NR_NODES]; EXPORT_SYMBOL(zone_table); static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; @@ -46,7 +44,7 @@ /* * Temporary debugging check for pages not lying within a given zone. */ -static inline int bad_range(zone_t *zone, struct page *page) +static inline int bad_range(struct zone *zone, struct page *page) { if (page - mem_map >= zone->zone_start_mapnr + zone->size) return 1; @@ -85,7 +83,7 @@ unsigned long index, page_idx, mask, flags; free_area_t *area; struct page *base; - zone_t *zone; + struct zone *zone; KERNEL_STAT_ADD(pgfree, 1<mapping != NULL); BUG_ON(PageLocked(page)); - BUG_ON(PageLRU(page)); BUG_ON(PageActive(page)); BUG_ON(PageWriteback(page)); BUG_ON(page->pte.chain != NULL); @@ -155,7 +152,8 @@ #define MARK_USED(index, order, area) \ __change_bit((index) >> (1+(order)), (area)->map) -static inline struct page * expand (zone_t *zone, struct page *page, +static inline struct page * +expand(struct zone *zone, struct page *page, unsigned long index, int low, int high, free_area_t * area) { unsigned long size = 1 << high; @@ -186,14 +184,14 @@ BUG_ON(PageActive(page)); BUG_ON(PageDirty(page)); BUG_ON(PageWriteback(page)); + BUG_ON(page->pte.chain != NULL); page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked); set_page_count(page, 1); } -static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order)); -static struct page * rmqueue(zone_t *zone, unsigned int order) +static struct page *rmqueue(struct zone *zone, unsigned int order) { free_area_t * area = zone->free_area + order; unsigned int curr_order = order; @@ -236,7 +234,7 @@ #ifdef CONFIG_SOFTWARE_SUSPEND int is_head_of_free_region(struct page *page) { - zone_t *zone = page_zone(page); + struct zone *zone = page_zone(page); unsigned long flags; int order; list_t *curr; @@ -266,7 +264,7 @@ #endif static /* inline */ struct page * -balance_classzone(zone_t * classzone, unsigned int gfp_mask, +balance_classzone(struct zone* classzone, unsigned int gfp_mask, unsigned int order, int * freed) { struct page * page = NULL; @@ -321,10 +319,12 @@ /* * 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 * +__alloc_pages(unsigned int gfp_mask, unsigned int order, + struct zonelist *zonelist) { unsigned long min; - zone_t **zones, *classzone; + struct zone **zones, *classzone; struct page * page; int freed, i; @@ -338,11 +338,11 @@ /* Go through the zonelist once, looking for a zone with enough free */ min = 1UL << order; for (i = 0; zones[i] != NULL; i++) { - zone_t *z = zones[i]; + struct zone *z = zones[i]; /* the incremental min is allegedly to discourage fallback */ min += z->pages_low; - if (z->free_pages > min) { + if (z->free_pages > min || z->free_pages >= z->pages_high) { page = rmqueue(z, order); if (page) return page; @@ -359,13 +359,13 @@ min = 1UL << order; for (i = 0; zones[i] != NULL; i++) { unsigned long local_min; - zone_t *z = zones[i]; + struct zone *z = zones[i]; local_min = z->pages_min; if (gfp_mask & __GFP_HIGH) local_min >>= 2; min += local_min; - if (z->free_pages > min) { + if (z->free_pages > min || z->free_pages >= z->pages_high) { page = rmqueue(z, order); if (page) return page; @@ -378,7 +378,7 @@ if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) { /* go through the zonelist yet again, ignoring mins */ for (i = 0; zones[i] != NULL; i++) { - zone_t *z = zones[i]; + struct zone *z = zones[i]; page = rmqueue(z, order); if (page) @@ -405,10 +405,10 @@ /* go through the zonelist yet one more time */ min = 1UL << order; for (i = 0; zones[i] != NULL; i++) { - zone_t *z = zones[i]; + struct zone *z = zones[i]; min += z->pages_min; - if (z->free_pages > min) { + if (z->free_pages > min || z->free_pages >= z->pages_high) { page = rmqueue(z, order); if (page) return page; @@ -478,7 +478,7 @@ unsigned int nr_free_pages(void) { unsigned int sum = 0; - zone_t *zone; + struct zone *zone; for_each_zone(zone) sum += zone->free_pages; @@ -492,9 +492,9 @@ unsigned int sum = 0; for_each_pgdat(pgdat) { - zonelist_t *zonelist = pgdat->node_zonelists + offset; - zone_t **zonep = zonelist->zones; - zone_t *zone; + struct zonelist *zonelist = pgdat->node_zonelists + offset; + struct zone **zonep = zonelist->zones; + struct zone *zone; for (zone = *zonep++; zone; zone = *zonep++) { unsigned long size = zone->size; @@ -559,13 +559,23 @@ ret->nr_dirty += ps->nr_dirty; ret->nr_writeback += ps->nr_writeback; ret->nr_pagecache += ps->nr_pagecache; - ret->nr_active += ps->nr_active; - ret->nr_inactive += ps->nr_inactive; ret->nr_page_table_pages += ps->nr_page_table_pages; ret->nr_reverse_maps += ps->nr_reverse_maps; } } +void get_zone_counts(unsigned long *active, unsigned long *inactive) +{ + struct zone *zone; + + *active = 0; + *inactive = 0; + for_each_zone(zone) { + *active += zone->nr_active; + *inactive += zone->nr_inactive; + } +} + unsigned long get_page_cache_size(void) { struct page_state ps; @@ -602,8 +612,11 @@ pg_data_t *pgdat; struct page_state ps; int type; + unsigned long active; + unsigned long inactive; get_page_state(&ps); + get_zone_counts(&active, &inactive); printk("Free pages: %6dkB (%6dkB HighMem)\n", K(nr_free_pages()), @@ -611,22 +624,28 @@ for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next) for (type = 0; type < MAX_NR_ZONES; ++type) { - zone_t *zone = &pgdat->node_zones[type]; - printk("Zone:%s " - "freepages:%6lukB " - "min:%6lukB " - "low:%6lukB " - "high:%6lukB\n", + struct zone *zone = &pgdat->node_zones[type]; + printk("Zone:%s" + " freepages:%6lukB" + " min:%6lukB" + " low:%6lukB" + " high:%6lukB" + " active:%6lukB" + " inactive:%6lukB" + "\n", zone->name, K(zone->free_pages), K(zone->pages_min), K(zone->pages_low), - K(zone->pages_high)); + K(zone->pages_high), + K(zone->nr_active), + K(zone->nr_inactive) + ); } printk("( Active:%lu inactive:%lu dirty:%lu writeback:%lu free:%u )\n", - ps.nr_active, - ps.nr_inactive, + active, + inactive, ps.nr_dirty, ps.nr_writeback, nr_free_pages()); @@ -634,7 +653,7 @@ for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next) for (type = 0; type < MAX_NR_ZONES; type++) { list_t *elem; - zone_t *zone = &pgdat->node_zones[type]; + struct zone *zone = &pgdat->node_zones[type]; unsigned long nr, flags, order, total = 0; if (!zone->size) @@ -663,8 +682,8 @@ int i, j, k; for (i = 0; i <= GFP_ZONEMASK; i++) { - zonelist_t *zonelist; - zone_t *zone; + struct zonelist *zonelist; + struct zone *zone; zonelist = pgdat->node_zonelists + i; memset(zonelist, 0, sizeof(*zonelist)); @@ -797,7 +816,7 @@ offset = lmem_map - mem_map; for (j = 0; j < MAX_NR_ZONES; j++) { - zone_t *zone = pgdat->node_zones + j; + struct zone *zone = pgdat->node_zones + j; unsigned long mask; unsigned long size, realsize; @@ -809,10 +828,16 @@ printk("zone(%lu): %lu pages.\n", j, size); zone->size = size; zone->name = zone_names[j]; - zone->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&zone->lock); + spin_lock_init(&zone->lru_lock); zone->zone_pgdat = pgdat; zone->free_pages = 0; zone->need_balance = 0; + INIT_LIST_HEAD(&zone->active_list); + INIT_LIST_HEAD(&zone->inactive_list); + atomic_set(&zone->refill_counter, 0); + zone->nr_active = 0; + zone->nr_inactive = 0; if (!size) continue; diff -Nru a/mm/rmap.c b/mm/rmap.c --- a/mm/rmap.c Sat Aug 31 15:06:06 2002 +++ b/mm/rmap.c Sat Aug 31 15:06:06 2002 @@ -14,7 +14,7 @@ /* * Locking: * - the page->pte.chain is protected by the PG_chainlock bit, - * which nests within the pagemap_lru_lock, then the + * which nests within the zone->lru_lock, then the * mm->page_table_lock, and then the page lock. * - because swapout locking is opposite to the locking order * in the page fault path, the swapout path uses trylocks @@ -260,7 +260,7 @@ * table entry mapping a page. Because locking order here is opposite * to the locking order used by the page fault path, we use trylocks. * Locking: - * pagemap_lru_lock page_launder() + * zone->lru_lock page_launder() * page lock page_launder(), trylock * pte_chain_lock page_launder() * mm->page_table_lock try_to_unmap_one(), trylock @@ -328,7 +328,7 @@ * @page: the page to get unmapped * * Tries to remove all the page table entries which are mapping this - * page, used in the pageout path. Caller must hold pagemap_lru_lock + * page, used in the pageout path. Caller must hold zone->lru_lock * and the page lock. Return values are: * * SWAP_SUCCESS - we succeeded in removing all mappings diff -Nru a/mm/swap.c b/mm/swap.c --- a/mm/swap.c Sat Aug 31 15:05:59 2002 +++ b/mm/swap.c Sat Aug 31 15:05:59 2002 @@ -19,31 +19,27 @@ #include #include #include +#include #include /* How many pages do we try to swap or page in/out together? */ int page_cluster; /* - * Move an inactive page to the active list. + * FIXME: speed this up? */ -static inline void activate_page_nolock(struct page * page) +void activate_page(struct page *page) { + struct zone *zone = page_zone(page); + + spin_lock_irq(&zone->lru_lock); if (PageLRU(page) && !PageActive(page)) { - del_page_from_inactive_list(page); - add_page_to_active_list(page); + del_page_from_inactive_list(zone, page); + SetPageActive(page); + add_page_to_active_list(zone, page); KERNEL_STAT_INC(pgactivate); } -} - -/* - * FIXME: speed this up? - */ -void activate_page(struct page * page) -{ - spin_lock_irq(&_pagemap_lru_lock); - activate_page_nolock(page); - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); } /** @@ -77,66 +73,71 @@ void __page_cache_release(struct page *page) { unsigned long flags; + struct zone *zone = page_zone(page); - spin_lock_irqsave(&_pagemap_lru_lock, flags); - if (TestClearPageLRU(page)) { - if (PageActive(page)) - del_page_from_active_list(page); - else - del_page_from_inactive_list(page); - } + spin_lock_irqsave(&zone->lru_lock, flags); + if (TestClearPageLRU(page)) + del_page_from_lru(zone, page); if (page_count(page) != 0) page = NULL; - spin_unlock_irqrestore(&_pagemap_lru_lock, flags); + spin_unlock_irqrestore(&zone->lru_lock, flags); if (page) __free_pages_ok(page, 0); } /* * Batched page_cache_release(). Decrement the reference count on all the - * pagevec's pages. If it fell to zero then remove the page from the LRU and + * passed pages. If it fell to zero then remove the page from the LRU and * free it. * - * Avoid taking pagemap_lru_lock if possible, but if it is taken, retain it + * Avoid taking zone->lru_lock if possible, but if it is taken, retain it * for the remainder of the operation. * * The locking in this function is against shrink_cache(): we recheck the * page count inside the lock to see whether shrink_cache grabbed the page * via the LRU. If it did, give up: shrink_cache will free it. - * - * This function reinitialises the caller's pagevec. */ -void __pagevec_release(struct pagevec *pvec) +void release_pages(struct page **pages, int nr) { int i; - int lock_held = 0; struct pagevec pages_to_free; + struct zone *zone = NULL; pagevec_init(&pages_to_free); - for (i = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; + for (i = 0; i < nr; i++) { + struct page *page = pages[i]; + struct zone *pagezone; if (PageReserved(page) || !put_page_testzero(page)) continue; - if (!lock_held) { - spin_lock_irq(&_pagemap_lru_lock); - lock_held = 1; + pagezone = page_zone(page); + if (pagezone != zone) { + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); } - - if (TestClearPageLRU(page)) { - if (PageActive(page)) - del_page_from_active_list(page); - else - del_page_from_inactive_list(page); + if (TestClearPageLRU(page)) + del_page_from_lru(zone, page); + if (page_count(page) == 0) { + if (!pagevec_add(&pages_to_free, page)) { + spin_unlock_irq(&zone->lru_lock); + pagevec_free(&pages_to_free); + pagevec_init(&pages_to_free); + spin_lock_irq(&zone->lru_lock); + } } - if (page_count(page) == 0) - pagevec_add(&pages_to_free, page); } - if (lock_held) - spin_unlock_irq(&_pagemap_lru_lock); + if (zone) + spin_unlock_irq(&zone->lru_lock); pagevec_free(&pages_to_free); +} + +void __pagevec_release(struct pagevec *pvec) +{ + release_pages(pvec->pages, pagevec_count(pvec)); pagevec_init(pvec); } @@ -169,24 +170,27 @@ void pagevec_deactivate_inactive(struct pagevec *pvec) { int i; - int lock_held = 0; + struct zone *zone = NULL; if (pagevec_count(pvec) == 0) return; for (i = 0; i < pagevec_count(pvec); i++) { struct page *page = pvec->pages[i]; + struct zone *pagezone = page_zone(page); - if (!lock_held) { + if (pagezone != zone) { if (PageActive(page) || !PageLRU(page)) continue; - spin_lock_irq(&_pagemap_lru_lock); - lock_held = 1; + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); } if (!PageActive(page) && PageLRU(page)) - list_move(&page->lru, &inactive_list); + list_move(&page->lru, &pagezone->inactive_list); } - if (lock_held) - spin_unlock_irq(&_pagemap_lru_lock); + if (zone) + spin_unlock_irq(&zone->lru_lock); __pagevec_release(pvec); } @@ -197,39 +201,24 @@ void __pagevec_lru_add(struct pagevec *pvec) { int i; + struct zone *zone = NULL; - spin_lock_irq(&_pagemap_lru_lock); for (i = 0; i < pagevec_count(pvec); i++) { struct page *page = pvec->pages[i]; + struct zone *pagezone = page_zone(page); + if (pagezone != zone) { + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); + } if (TestSetPageLRU(page)) BUG(); - add_page_to_inactive_list(page); - } - spin_unlock_irq(&_pagemap_lru_lock); - pagevec_release(pvec); -} - -/* - * Remove the passed pages from the LRU, then drop the caller's refcount on - * them. Reinitialises the caller's pagevec. - */ -void __pagevec_lru_del(struct pagevec *pvec) -{ - int i; - - spin_lock_irq(&_pagemap_lru_lock); - for (i = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; - - if (!TestClearPageLRU(page)) - BUG(); - if (PageActive(page)) - del_page_from_active_list(page); - else - del_page_from_inactive_list(page); + add_page_to_inactive_list(zone, page); } - spin_unlock_irq(&_pagemap_lru_lock); + if (zone) + spin_unlock_irq(&zone->lru_lock); pagevec_release(pvec); } diff -Nru a/mm/swap_state.c b/mm/swap_state.c --- a/mm/swap_state.c Sat Aug 31 15:05:59 2002 +++ b/mm/swap_state.c Sat Aug 31 15:05:59 2002 @@ -292,26 +292,53 @@ return err; } + /* - * Perform a free_page(), also freeing any swap cache associated with - * this page if it is the last user of the page. Can not do a lock_page, - * as we are holding the page_table_lock spinlock. + * If we are the only user, then try to free up the swap cache. + * + * Its ok to check for PageSwapCache without the page lock + * here because we are going to recheck again inside + * exclusive_swap_page() _with_ the lock. + * - Marcelo */ -void free_page_and_swap_cache(struct page *page) +static inline void free_swap_cache(struct page *page) { - /* - * If we are the only user, then try to free up the swap cache. - * - * Its ok to check for PageSwapCache without the page lock - * here because we are going to recheck again inside - * exclusive_swap_page() _with_ the lock. - * - Marcelo - */ if (PageSwapCache(page) && !TestSetPageLocked(page)) { remove_exclusive_swap_page(page); unlock_page(page); } +} + +/* + * Perform a free_page(), also freeing any swap cache associated with + * this page if it is the last user of the page. Can not do a lock_page, + * as we are holding the page_table_lock spinlock. + */ +void free_page_and_swap_cache(struct page *page) +{ + free_swap_cache(page); page_cache_release(page); +} + +/* + * Passed an array of pages, drop them all from swapcache and then release + * them. They are removed from the LRU and freed if this is their last use. + */ +void free_pages_and_swap_cache(struct page **pages, int nr) +{ + const int chunk = 16; + struct page **pagep = pages; + + while (nr) { + int todo = min(chunk, nr); + int i; + + for (i = 0; i < todo; i++) + free_swap_cache(pagep[i]); + release_pages(pagep, todo); + pagep += todo; + nr -= todo; + } } /* diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Sat Aug 31 15:05:54 2002 +++ b/mm/vmscan.c Sat Aug 31 15:05:54 2002 @@ -23,6 +23,7 @@ #include #include #include /* for try_to_release_page() */ +#include #include #include @@ -93,7 +94,7 @@ } static /* inline */ int -shrink_list(struct list_head *page_list, int nr_pages, zone_t *classzone, +shrink_list(struct list_head *page_list, int nr_pages, unsigned int gfp_mask, int priority, int *max_scan) { struct address_space *mapping; @@ -109,8 +110,6 @@ page = list_entry(page_list->prev, struct page, lru); list_del(&page->lru); - if (!memclass(page_zone(page), classzone)) - goto keep; if (TestSetPageLocked(page)) goto keep; @@ -264,7 +263,7 @@ } /* - * pagemap_lru_lock is heavily contented. We relieve it by quickly privatising + * zone->lru_lock is heavily contented. We relieve it by quickly privatising * a batch of pages and working on them outside the lock. Any pages which were * not freed will be added back to the LRU. * @@ -275,7 +274,7 @@ * in the kernel (apart from the copy_*_user functions). */ static /* inline */ int -shrink_cache(int nr_pages, zone_t *classzone, +shrink_cache(int nr_pages, struct zone *zone, unsigned int gfp_mask, int priority, int max_scan) { LIST_HEAD(page_list); @@ -292,15 +291,17 @@ pagevec_init(&pvec); lru_add_drain(); - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); while (max_scan > 0 && nr_pages > 0) { struct page *page; int n = 0; - while (n < nr_to_process && !list_empty(&inactive_list)) { - page = list_entry(inactive_list.prev, struct page, lru); + while (n < nr_to_process && !list_empty(&zone->inactive_list)) { + page = list_entry(zone->inactive_list.prev, + struct page, lru); - prefetchw_prev_lru_page(page, &inactive_list, flags); + prefetchw_prev_lru_page(page, + &zone->inactive_list, flags); if (!TestClearPageLRU(page)) BUG(); @@ -308,28 +309,28 @@ if (page_count(page) == 0) { /* It is currently in pagevec_release() */ SetPageLRU(page); - list_add(&page->lru, &inactive_list); + list_add(&page->lru, &zone->inactive_list); continue; } list_add(&page->lru, &page_list); page_cache_get(page); n++; } - spin_unlock_irq(&_pagemap_lru_lock); + zone->nr_inactive -= n; + spin_unlock_irq(&zone->lru_lock); if (list_empty(&page_list)) goto done; max_scan -= n; - mod_page_state(nr_inactive, -n); KERNEL_STAT_ADD(pgscan, n); - nr_pages = shrink_list(&page_list, nr_pages, classzone, + nr_pages = shrink_list(&page_list, nr_pages, gfp_mask, priority, &max_scan); if (nr_pages <= 0 && list_empty(&page_list)) goto done; - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); /* * Put back any unfreeable pages. */ @@ -339,17 +340,17 @@ BUG(); list_del(&page->lru); if (PageActive(page)) - __add_page_to_active_list(page); + add_page_to_active_list(zone, page); else - add_page_to_inactive_list(page); + add_page_to_inactive_list(zone, page); if (!pagevec_add(&pvec, page)) { - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); __pagevec_release(&pvec); - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); } } } - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); done: pagevec_release(&pvec); return nr_pages; @@ -362,9 +363,9 @@ * processes, from rmap. * * If the pages are mostly unmapped, the processing is fast and it is - * appropriate to hold pagemap_lru_lock across the whole operation. But if + * appropriate to hold zone->lru_lock across the whole operation. But if * the pages are mapped, the processing is slow (page_referenced()) so we - * should drop pagemap_lru_lock around each page. It's impossible to balance + * should drop zone->lru_lock around each page. It's impossible to balance * this, so instead we remove the pages from the LRU while processing them. * It is safe to rely on PG_active against the non-LRU pages in here because * nobody will play with that bit on a non-LRU page. @@ -372,7 +373,8 @@ * The downside is that we have to touch page->count against each page. * But we had to alter page->flags anyway. */ -static /* inline */ void refill_inactive(const int nr_pages_in) +static /* inline */ void +refill_inactive_zone(struct zone *zone, const int nr_pages_in) { int pgdeactivate = 0; int nr_pages = nr_pages_in; @@ -383,24 +385,24 @@ struct pagevec pvec; lru_add_drain(); - spin_lock_irq(&_pagemap_lru_lock); - while (nr_pages && !list_empty(&active_list)) { - page = list_entry(active_list.prev, struct page, lru); - prefetchw_prev_lru_page(page, &active_list, flags); + spin_lock_irq(&zone->lru_lock); + while (nr_pages && !list_empty(&zone->active_list)) { + page = list_entry(zone->active_list.prev, struct page, lru); + prefetchw_prev_lru_page(page, &zone->active_list, flags); if (!TestClearPageLRU(page)) BUG(); list_del(&page->lru); if (page_count(page) == 0) { /* It is currently in pagevec_release() */ SetPageLRU(page); - list_add(&page->lru, &active_list); + list_add(&page->lru, &zone->active_list); continue; } page_cache_get(page); list_add(&page->lru, &l_hold); nr_pages--; } - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); while (!list_empty(&l_hold)) { page = list_entry(l_hold.prev, struct page, lru); @@ -419,7 +421,7 @@ } pagevec_init(&pvec); - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); while (!list_empty(&l_inactive)) { page = list_entry(l_inactive.prev, struct page, lru); prefetchw_prev_lru_page(page, &l_inactive, flags); @@ -427,11 +429,11 @@ BUG(); if (!TestClearPageActive(page)) BUG(); - list_move(&page->lru, &inactive_list); + list_move(&page->lru, &zone->inactive_list); if (!pagevec_add(&pvec, page)) { - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); __pagevec_release(&pvec); - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); } } while (!list_empty(&l_active)) { @@ -440,31 +442,30 @@ if (TestSetPageLRU(page)) BUG(); BUG_ON(!PageActive(page)); - list_move(&page->lru, &active_list); + list_move(&page->lru, &zone->active_list); if (!pagevec_add(&pvec, page)) { - spin_unlock_irq(&_pagemap_lru_lock); + spin_unlock_irq(&zone->lru_lock); __pagevec_release(&pvec); - spin_lock_irq(&_pagemap_lru_lock); + spin_lock_irq(&zone->lru_lock); } } - spin_unlock_irq(&_pagemap_lru_lock); + zone->nr_active -= pgdeactivate; + zone->nr_inactive += pgdeactivate; + spin_unlock_irq(&zone->lru_lock); pagevec_release(&pvec); - mod_page_state(nr_active, -pgdeactivate); - mod_page_state(nr_inactive, pgdeactivate); KERNEL_STAT_ADD(pgscan, nr_pages_in - nr_pages); KERNEL_STAT_ADD(pgdeactivate, pgdeactivate); } static /* inline */ int -shrink_caches(zone_t *classzone, int priority, - unsigned int gfp_mask, int nr_pages) +shrink_zone(struct zone *zone, int priority, + unsigned int gfp_mask, int nr_pages) { unsigned long ratio; - struct page_state ps; int max_scan; - static atomic_t nr_to_refill = ATOMIC_INIT(0); + /* This is bogus for ZONE_HIGHMEM? */ if (kmem_cache_reap(gfp_mask) >= nr_pages) return 0; @@ -478,17 +479,16 @@ * just to make sure that the kernel will slowly sift through the * active list. */ - get_page_state(&ps); - ratio = (unsigned long)nr_pages * ps.nr_active / - ((ps.nr_inactive | 1) * 2); - atomic_add(ratio+1, &nr_to_refill); - if (atomic_read(&nr_to_refill) > SWAP_CLUSTER_MAX) { - atomic_sub(SWAP_CLUSTER_MAX, &nr_to_refill); - refill_inactive(SWAP_CLUSTER_MAX); + ratio = (unsigned long)nr_pages * zone->nr_active / + ((zone->nr_inactive | 1) * 2); + atomic_add(ratio+1, &zone->refill_counter); + if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) { + atomic_sub(SWAP_CLUSTER_MAX, &zone->refill_counter); + refill_inactive_zone(zone, SWAP_CLUSTER_MAX); } - max_scan = ps.nr_inactive / priority; - nr_pages = shrink_cache(nr_pages, classzone, + max_scan = zone->nr_inactive / priority; + nr_pages = shrink_cache(nr_pages, zone, gfp_mask, priority, max_scan); if (nr_pages <= 0) @@ -507,7 +507,31 @@ return nr_pages; } -int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order) +static int +shrink_caches(struct zone *classzone, int priority, + int gfp_mask, int nr_pages) +{ + struct zone *first_classzone; + struct zone *zone; + + first_classzone = classzone->zone_pgdat->node_zones; + zone = classzone; + while (zone >= first_classzone) { + if (zone->free_pages <= zone->pages_high) { + nr_pages = shrink_zone(zone, priority, + gfp_mask, nr_pages); + } + zone--; + } + return nr_pages; +} + +/* + * This is the main entry point to page reclaim. + */ +int +try_to_free_pages(struct zone *classzone, + unsigned int gfp_mask, unsigned int order) { int priority = DEF_PRIORITY; int nr_pages = SWAP_CLUSTER_MAX; @@ -515,24 +539,20 @@ KERNEL_STAT_INC(pageoutrun); do { - nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); + nr_pages = shrink_caches(classzone, priority, + gfp_mask, nr_pages); if (nr_pages <= 0) return 1; } while (--priority); - - /* - * Hmm.. Cache shrink failed - time to kill something? - * Mhwahahhaha! This is the part I really like. Giggle. - */ out_of_memory(); return 0; } DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); -static int check_classzone_need_balance(zone_t * classzone) +static int check_classzone_need_balance(struct zone *classzone) { - zone_t * first_classzone; + struct zone *first_classzone; first_classzone = classzone->zone_pgdat->node_zones; while (classzone >= first_classzone) { @@ -546,7 +566,7 @@ static int kswapd_balance_pgdat(pg_data_t * pgdat) { int need_more_balance = 0, i; - zone_t * zone; + struct zone *zone; for (i = pgdat->nr_zones-1; i >= 0; i--) { zone = pgdat->node_zones + i; @@ -584,7 +604,7 @@ static int kswapd_can_sleep_pgdat(pg_data_t * pgdat) { - zone_t * zone; + struct zone *zone; int i; for (i = pgdat->nr_zones-1; i >= 0; i--) { diff -Nru a/net/Config.in b/net/Config.in --- a/net/Config.in Sat Aug 31 15:05:55 2002 +++ b/net/Config.in Sat Aug 31 15:05:55 2002 @@ -26,6 +26,9 @@ source net/ipv6/Config.in fi fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + source net/sctp/Config.in + fi fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM diff -Nru a/net/Makefile b/net/Makefile --- a/net/Makefile Sat Aug 31 15:05:59 2002 +++ b/net/Makefile Sat Aug 31 15:05:59 2002 @@ -35,6 +35,7 @@ obj-$(CONFIG_ECONET) += econet/ obj-$(CONFIG_VLAN_8021Q) += 8021q/ obj-$(CONFIG_LLC) += llc/ +obj-$(CONFIG_IP_SCTP) += sctp/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_MODULES) += netsyms.o diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Sat Aug 31 15:06:00 2002 +++ b/net/core/dev.c Sat Aug 31 15:06:00 2002 @@ -1229,19 +1229,20 @@ int netif_rx(struct sk_buff *skb) { - int this_cpu = smp_processor_id(); + int this_cpu; struct softnet_data *queue; unsigned long flags; if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); - /* The code is rearranged so that the path is the most - short when CPU is congested, but is still operating. + /* + * The code is rearranged so that the path is the most + * short when CPU is congested, but is still operating. */ - queue = &softnet_data[this_cpu]; - local_irq_save(flags); + this_cpu = smp_processor_id(); + queue = &softnet_data[this_cpu]; netdev_rx_stat[this_cpu].total++; if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { @@ -1252,10 +1253,10 @@ enqueue: dev_hold(skb->dev); __skb_queue_tail(&queue->input_pkt_queue, skb); - local_irq_restore(flags); #ifndef OFFLINE_SAMPLE get_sample_stats(this_cpu); #endif + local_irq_restore(flags); return queue->cng_level; } diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c --- a/net/core/skbuff.c Sat Aug 31 15:05:55 2002 +++ b/net/core/skbuff.c Sat Aug 31 15:05:55 2002 @@ -209,6 +209,8 @@ atomic_set(&skb->users, 1); atomic_set(&(skb_shinfo(skb)->dataref), 1); skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->tso_segs = 0; skb_shinfo(skb)->frag_list = NULL; out: return skb; @@ -490,6 +492,7 @@ unsigned int size; u8 *data; long offset; + struct skb_shared_info *ninfo; int headerlen = skb->data - skb->head; int expand = (skb->tail + skb->data_len) - skb->end; @@ -509,6 +512,14 @@ if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) BUG(); + /* Set up shinfo */ + ninfo = (struct skb_shared_info*)(data + size); + atomic_set(&ninfo->dataref, 1); + ninfo->tso_size = skb_shinfo(skb)->tso_size; + ninfo->tso_segs = skb_shinfo(skb)->tso_segs; + ninfo->nr_frags = 0; + ninfo->frag_list = NULL; + /* Offset between the two in bytes */ offset = data - skb->head; @@ -525,11 +536,6 @@ skb->tail += offset; skb->data += offset; - /* Set up shinfo */ - atomic_set(&(skb_shinfo(skb)->dataref), 1); - skb_shinfo(skb)->nr_frags = 0; - skb_shinfo(skb)->frag_list = NULL; - /* We are no longer a clone, even if we were. */ skb->cloned = 0; @@ -583,6 +589,8 @@ } skb_shinfo(n)->nr_frags = i; } + skb_shinfo(n)->tso_size = skb_shinfo(skb)->tso_size; + skb_shinfo(n)->tso_segs = skb_shinfo(skb)->tso_segs; if (skb_shinfo(skb)->frag_list) { skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; @@ -694,6 +702,9 @@ * * You must pass %GFP_ATOMIC as the allocation priority if this function * is called from an interrupt. + * + * BUG ALERT: ip_summed is not copied. Why does this work? Is it used + * only by netfilter in the cases when checksum is recalculated? --ANK */ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, int gfp_mask) @@ -716,6 +727,8 @@ BUG(); copy_skb_header(n, skb); + skb_shinfo(n)->tso_size = skb_shinfo(skb)->tso_size; + skb_shinfo(n)->tso_segs = skb_shinfo(skb)->tso_segs; return n; } diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c Sat Aug 31 15:05:54 2002 +++ b/net/ipv4/af_inet.c Sat Aug 31 15:05:54 2002 @@ -493,7 +493,7 @@ /* It is off by default, see below. */ int sysctl_ip_nonlocal_bind; -static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; struct sock *sk = sock->sk; @@ -729,7 +729,7 @@ /* * This does both peername and sockname. */ -static int inet_getname(struct socket *sock, struct sockaddr *uaddr, +int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sock *sk = sock->sk; @@ -846,7 +846,7 @@ * There's a good 20K of config code hanging around the kernel. */ -static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c --- a/net/ipv4/ip_output.c Sat Aug 31 15:06:06 2002 +++ b/net/ipv4/ip_output.c Sat Aug 31 15:06:06 2002 @@ -306,10 +306,20 @@ iph = skb->nh.iph; } - if (skb->len > rt->u.dst.pmtu) - goto fragment; + if (skb->len > rt->u.dst.pmtu) { + unsigned int hlen; + if (!(sk->route_caps&NETIF_F_TSO)) + goto fragment; + + /* Hack zone: all this must be done by TCP. */ + hlen = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + skb_shinfo(skb)->tso_size = rt->u.dst.pmtu - hlen; + skb_shinfo(skb)->tso_segs = + (skb->len - hlen + skb_shinfo(skb)->tso_size - 1)/ + skb_shinfo(skb)->tso_size - 1; + } - ip_select_ident(iph, &rt->u.dst, sk); + ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs); /* Add an IP checksum. */ ip_send_check(iph); @@ -371,7 +381,7 @@ sk->bound_dev_if)) goto no_route; __sk_dst_set(sk, &rt->u.dst); - sk->route_caps = rt->u.dst.dev->features; + tcp_v4_setup_caps(sk, &rt->u.dst); } skb->dst = dst_clone(&rt->u.dst); @@ -577,7 +587,7 @@ * for packets without DF or having * been fragmented. */ - __ip_select_ident(iph, &rt->u.dst); + __ip_select_ident(iph, &rt->u.dst, 0); id = iph->id; } diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c --- a/net/ipv4/netfilter/ip_nat_core.c Sat Aug 31 15:05:54 2002 +++ b/net/ipv4/netfilter/ip_nat_core.c Sat Aug 31 15:05:54 2002 @@ -894,7 +894,7 @@ /* Note: May not be from a NAT'd host, but probably safest to do translation always as if it came from the host itself (even though a "host unreachable" coming from the host - itself is a bit wierd). + itself is a bit weird). More explanation: some people use NAT for anonymizing. Also, CERT recommends dropping all packets from private IP diff -Nru a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c --- a/net/ipv4/netfilter/ip_tables.c Sat Aug 31 15:05:55 2002 +++ b/net/ipv4/netfilter/ip_tables.c Sat Aug 31 15:05:55 2002 @@ -68,13 +68,12 @@ #define inline #endif -/* Locking is simple: we assume at worst case there will be one packet - in user context and one from bottom halves (or soft irq if Alexey's - softnet patch was applied). - +/* We keep a set of rules for each CPU, so we can avoid write-locking - them; doing a readlock_bh() stops packets coming through if we're - in user context. + them in the softirq when updating the counters and therefore + only need to read-lock in the softirq; doing a write_lock_bh() in user + context stops packets coming through and allows user context to read + the counters or update the rules. To be cache friendly on SMP, we arrange them like so: [ n-entries ] diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Sat Aug 31 15:06:06 2002 +++ b/net/ipv4/route.c Sat Aug 31 15:06:06 2002 @@ -729,7 +729,7 @@ spin_unlock_bh(&ip_fb_id_lock); } -void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst) +void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) { struct rtable *rt = (struct rtable *) dst; @@ -741,7 +741,7 @@ so that we need not to grab a lock to dereference it. */ if (rt->peer) { - iph->id = htons(inet_getid(rt->peer)); + iph->id = htons(inet_getid(rt->peer, more)); return; } } else diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Sat Aug 31 15:05:55 2002 +++ b/net/ipv4/tcp.c Sat Aug 31 15:05:55 2002 @@ -846,7 +846,7 @@ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); copied = 0; err = -EPIPE; @@ -921,7 +921,7 @@ if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) goto do_error; - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); } out: @@ -1001,7 +1001,7 @@ static inline int select_size(struct sock *sk, struct tcp_opt *tp) { - int tmp = tp->mss_cache; + int tmp = tp->mss_cache_std; if (sk->route_caps & NETIF_F_SG) { int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); @@ -1037,7 +1037,7 @@ /* This should be in poll */ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); /* Ok commence sending. */ iovlen = msg->msg_iovlen; @@ -1192,7 +1192,7 @@ if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) goto do_error; - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); } } @@ -2444,7 +2444,7 @@ switch (optname) { case TCP_MAXSEG: - val = tp->mss_cache; + val = tp->mss_cache_std; if (!val && ((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN))) val = tp->user_mss; break; @@ -2507,7 +2507,7 @@ info.tcpi_rto = (1000000 * tp->rto) / HZ; info.tcpi_ato = (1000000 * tp->ack.ato) / HZ; - info.tcpi_snd_mss = tp->mss_cache; + info.tcpi_snd_mss = tp->mss_cache_std; info.tcpi_rcv_mss = tp->ack.rcv_mss; info.tcpi_unacked = tp->packets_out; diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c Sat Aug 31 15:05:55 2002 +++ b/net/ipv4/tcp_input.c Sat Aug 31 15:05:55 2002 @@ -772,6 +772,14 @@ int flag = 0; int i; + /* So, SACKs for already sent large segments will be lost. + * Not good, but alternative is to resegment the queue. */ + if (sk->route_caps&NETIF_F_TSO) { + sk->route_caps &= ~NETIF_F_TSO; + sk->no_largesend = 1; + tp->mss_cache = tp->mss_cache_std; + } + if (!tp->sacked_out) tp->fackets_out = 0; prior_fackets = tp->fackets_out; @@ -2963,6 +2971,8 @@ /* When incoming ACK allowed to free some skb from write_queue, * we remember this event in flag tp->queue_shrunk and wake up socket * on the exit from tcp input handler. + * + * PROBLEM: sndbuf expansion does not work well with largesend. */ static void tcp_new_space(struct sock *sk) { @@ -2972,8 +2982,8 @@ !(sk->userlocks&SOCK_SNDBUF_LOCK) && !tcp_memory_pressure && atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { - int sndmem = tp->mss_clamp + MAX_TCP_HEADER + 16 + - sizeof(struct sk_buff), + int sndmem = max_t(u32, tp->mss_clamp, tp->mss_cache) + + MAX_TCP_HEADER + 16 + sizeof(struct sk_buff), demanded = max_t(unsigned int, tp->snd_cwnd, tp->reordering + 1); sndmem *= 2*demanded; @@ -3502,6 +3512,8 @@ */ TCP_ECN_rcv_synack(tp, th); + if (tp->ecn_flags&TCP_ECN_OK) + sk->no_largesend = 1; tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tcp_ack(sk, skb, FLAG_SLOWPATH); @@ -3627,10 +3639,13 @@ tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tp->max_window = tp->snd_wnd; + TCP_ECN_rcv_syn(tp, th); + if (tp->ecn_flags&TCP_ECN_OK) + sk->no_largesend = 1; + tcp_sync_mss(sk, tp->pmtu_cookie); tcp_initialize_rcv_mss(sk); - TCP_ECN_rcv_syn(tp, th); tcp_send_synack(sk); #if 0 diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Sat Aug 31 15:05:59 2002 +++ b/net/ipv4/tcp_ipv4.c Sat Aug 31 15:05:59 2002 @@ -780,7 +780,7 @@ } __sk_dst_set(sk, &rt->u.dst); - sk->route_caps = rt->u.dst.dev->features; + tcp_v4_setup_caps(sk, &rt->u.dst); if (!inet->opt || !inet->opt->srr) daddr = rt->rt_dst; @@ -1559,7 +1559,7 @@ goto exit; newsk->dst_cache = dst; - newsk->route_caps = dst->dev->features; + tcp_v4_setup_caps(newsk, dst); newtp = tcp_sk(newsk); newinet = inet_sk(newsk); @@ -1865,7 +1865,7 @@ return err; __sk_dst_set(sk, &rt->u.dst); - sk->route_caps = rt->u.dst.dev->features; + tcp_v4_setup_caps(sk, &rt->u.dst); new_saddr = rt->rt_src; @@ -1913,7 +1913,7 @@ RT_CONN_FLAGS(sk), sk->bound_dev_if); if (!err) { __sk_dst_set(sk, &rt->u.dst); - sk->route_caps = rt->u.dst.dev->features; + tcp_v4_setup_caps(sk, &rt->u.dst); return 0; } diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Sat Aug 31 15:05:55 2002 +++ b/net/ipv4/tcp_minisocks.c Sat Aug 31 15:05:55 2002 @@ -786,6 +786,8 @@ newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len; newtp->mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); + if (newtp->ecn_flags&TCP_ECN_OK) + newsk->no_largesend = 1; TCP_INC_STATS_BH(TcpPassiveOpens); } diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c Sat Aug 31 15:06:04 2002 +++ b/net/ipv4/tcp_output.c Sat Aug 31 15:06:04 2002 @@ -531,7 +531,21 @@ /* And store cached results */ tp->pmtu_cookie = pmtu; - tp->mss_cache = mss_now; + tp->mss_cache = tp->mss_cache_std = mss_now; + + if (sk->route_caps&NETIF_F_TSO) { + int large_mss; + + large_mss = 65535 - tp->af_specific->net_header_len - + tp->ext_header_len - tp->tcp_header_len; + + if (tp->max_window && large_mss > (tp->max_window>>1)) + large_mss = max((tp->max_window>>1), 68U - tp->tcp_header_len); + + /* Always keep large mss multiple of real mss. */ + tp->mss_cache = mss_now*(large_mss/mss_now); + } + return mss_now; } @@ -561,7 +575,7 @@ * We also handle things correctly when the user adds some * IP options mid-stream. Silly to do, but cover it. */ - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, 1); while((skb = tp->send_head) && tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : 1)) { @@ -767,7 +781,7 @@ { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; - unsigned int mss = tcp_current_mss(sk); + unsigned int mss = tcp_current_mss(sk, 0); int lost = 0; for_retrans_queue(skb, sk, tp) { @@ -812,7 +826,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = tcp_sk(sk); - unsigned int cur_mss = tcp_current_mss(sk); + unsigned int cur_mss = tcp_current_mss(sk, 0); int err; /* Do not sent more than we queued. 1/4 is reserved for possible @@ -821,6 +835,27 @@ if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf)) return -EAGAIN; + if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { + struct sk_buff *skb2; + + if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) + BUG(); + + if (sk->route_caps&NETIF_F_TSO) { + sk->route_caps &= ~NETIF_F_TSO; + sk->no_largesend = 1; + tp->mss_cache = tp->mss_cache_std; + } + + if(tcp_fragment(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) + return -ENOMEM; + + skb2 = skb->next; + __skb_unlink(skb, skb->list); + tcp_free_skb(sk, skb); + skb = skb2; + } + /* If receiver has shrunk his window, and skb is out of * new window, do not retransmit it. The exception is the * case, when window is shrunk to zero. In this case @@ -998,7 +1033,7 @@ * unsent frames. But be careful about outgoing SACKS * and IP options. */ - mss_now = tcp_current_mss(sk); + mss_now = tcp_current_mss(sk, 1); if(tp->send_head != NULL) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN; @@ -1121,6 +1156,8 @@ memset(th, 0, sizeof(struct tcphdr)); th->syn = 1; th->ack = 1; + if (dst->dev->features&NETIF_F_TSO) + req->ecn_ok = 0; TCP_ECN_make_synack(req, th); th->source = inet_sk(sk)->sport; th->dest = req->rmt_port; @@ -1224,7 +1261,7 @@ skb_reserve(buff, MAX_TCP_HEADER); TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; - TCP_ECN_send_syn(tp, buff); + TCP_ECN_send_syn(sk, tp, buff); TCP_SKB_CB(buff)->sacked = 0; buff->csum = 0; TCP_SKB_CB(buff)->seq = tp->write_seq++; @@ -1379,7 +1416,7 @@ if ((skb = tp->send_head) != NULL && before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) { int err; - int mss = tcp_current_mss(sk); + int mss = tcp_current_mss(sk, 0); int seg_size = tp->snd_una+tp->snd_wnd-TCP_SKB_CB(skb)->seq; if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) @@ -1395,6 +1432,13 @@ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; if (tcp_fragment(sk, skb, seg_size)) return -1; + /* SWS override triggered forced fragmentation. + * Disable TSO, the connection is too sick. */ + if (sk->route_caps&NETIF_F_TSO) { + sk->no_largesend = 1; + sk->route_caps &= ~NETIF_F_TSO; + tp->mss_cache = tp->mss_cache_std; + } } TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->when = tcp_time_stamp; diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c Sat Aug 31 15:06:00 2002 +++ b/net/ipv6/af_inet6.c Sat Aug 31 15:06:00 2002 @@ -274,7 +274,7 @@ /* bind for INET6 API */ -static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr; struct sock *sk = sock->sk; @@ -370,7 +370,7 @@ return 0; } -static int inet6_release(struct socket *sock) +int inet6_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -415,7 +415,7 @@ * This does both peername and sockname. */ -static int inet6_getname(struct socket *sock, struct sockaddr *uaddr, +int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr; @@ -451,7 +451,7 @@ return(0); } -static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = -EINVAL; @@ -547,7 +547,7 @@ .sendpage = sock_no_sendpage, }; -static struct net_proto_family inet6_family_ops = { +struct net_proto_family inet6_family_ops = { .family =PF_INET6, .create =inet6_create, }; diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c --- a/net/ipv6/ipv6_syms.c Sat Aug 31 15:06:06 2002 +++ b/net/ipv6/ipv6_syms.c Sat Aug 31 15:06:06 2002 @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -10,3 +11,16 @@ EXPORT_SYMBOL(register_inet6addr_notifier); EXPORT_SYMBOL(unregister_inet6addr_notifier); EXPORT_SYMBOL(ip6_route_output); +EXPORT_SYMBOL(addrconf_lock); +EXPORT_SYMBOL(ipv6_setsockopt); +EXPORT_SYMBOL(ipv6_getsockopt); +EXPORT_SYMBOL(inet6_register_protosw); +EXPORT_SYMBOL(inet6_unregister_protosw); +EXPORT_SYMBOL(inet6_add_protocol); +EXPORT_SYMBOL(inet6_del_protocol); +EXPORT_SYMBOL(ip6_xmit); +EXPORT_SYMBOL(inet6_release); +EXPORT_SYMBOL(inet6_bind); +EXPORT_SYMBOL(inet6_getname); +EXPORT_SYMBOL(inet6_ioctl); +EXPORT_SYMBOL(ipv6_get_saddr); diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Sat Aug 31 15:06:00 2002 +++ b/net/ipv6/tcp_ipv6.c Sat Aug 31 15:06:00 2002 @@ -659,7 +659,7 @@ } ip6_dst_store(sk, dst, NULL); - sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; + sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); if (saddr == NULL) { err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf); @@ -1333,7 +1333,7 @@ MOD_INC_USE_COUNT; ip6_dst_store(newsk, dst, NULL); - sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; + sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); newtcp6sk = (struct tcp6_sock *)newsk; newtcp6sk->pinet6 = &newtcp6sk->inet6; @@ -1721,7 +1721,7 @@ } ip6_dst_store(sk, dst, NULL); - sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; + sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); } return 0; diff -Nru a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c --- a/net/irda/irlmp_event.c Sat Aug 31 15:05:55 2002 +++ b/net/irda/irlmp_event.c Sat Aug 31 15:05:55 2002 @@ -416,7 +416,7 @@ /* We don't want to change state just yet, because * we want to reflect accurately the real state of - * the LAP, not the the state we whish it was in, + * the LAP, not the state we wish it was in, * so that we don't loose LM_LAP_CONNECT_REQUEST. * In some cases, IrLAP won't close the LAP * immediately. For example, it might still be diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Sat Aug 31 15:05:59 2002 +++ b/net/netsyms.c Sat Aug 31 15:05:59 2002 @@ -56,7 +56,8 @@ extern struct net_proto_family inet_family_ops; -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) \ + || defined (CONFIG_IP_SCTP_MODULE) #include #include #include @@ -159,6 +160,7 @@ EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(sock_kmalloc); EXPORT_SYMBOL(sock_kfree_s); +EXPORT_SYMBOL(sock_map_fd); #ifdef CONFIG_FILTER EXPORT_SYMBOL(sk_run_filter); @@ -286,7 +288,7 @@ #endif -#if defined (CONFIG_IPV6_MODULE) +#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) /* inet functions common to v4 and v6 */ EXPORT_SYMBOL(inet_release); EXPORT_SYMBOL(inet_stream_connect); @@ -396,6 +398,14 @@ #endif EXPORT_SYMBOL(tcp_read_sock); + +#ifdef CONFIG_IP_SCTP_MODULE +EXPORT_SYMBOL(ip_setsockopt); +EXPORT_SYMBOL(ip_getsockopt); +EXPORT_SYMBOL(inet_ioctl); +EXPORT_SYMBOL(inet_bind); +EXPORT_SYMBOL(inet_getname); +#endif /* CONFIG_IP_SCTP_MODULE */ EXPORT_SYMBOL(netlink_set_err); EXPORT_SYMBOL(netlink_broadcast); diff -Nru a/net/sctp/Config.help b/net/sctp/Config.help --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/Config.help Sat Aug 31 15:06:07 2002 @@ -0,0 +1,49 @@ +CONFIG_IP_SCTP + Stream Control Transmission Protocol + + From RFC 2960 (http://www.ietf.org/rfc/rfc2960.txt) + + "SCTP is a reliable transport protocol operating on top of a + connectionless packet network such as IP. It offers the following + services to its users: + + -- acknowledged error-free non-duplicated transfer of user data, + -- data fragmentation to conform to discovered path MTU size, + -- sequenced delivery of user messages within multiple streams, + with an option for order-of-arrival delivery of individual user + messages, + -- optional bundling of multiple user messages into a single SCTP + packet, and + -- network-level fault tolerance through supporting of multi- + homing at either or both ends of an association." + + This protocol support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module will be called sctp.o. If you want to compile it + as a module, say M here and read . + + If in doubt, say N. + +CONFIG_SCTP_ADLER32 + RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. + This has been deprecated and replaced by an algorithm now referred + to as crc32c. + + If you say Y, this will use the Adler-32 algorithm, this might be useful + for interoperation with downlevel peers. + + If unsure, say N. + +CONFIG_SCTP_DBG_MSG + If you say Y, this will enable verbose debugging messages. + + If unsure, say N. However, if you are running into problems, use this + option to gather detailed trace information + +CONFIG_SCTP_DBG_OBJCNT + If you say Y, this will enable debugging support for counting the types + of objects that are currently allocated. This is useful for identifying + memory leaks. If the /proc filesystem is enabled this debug information + can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' + + If unsure, say N diff -Nru a/net/sctp/Config.in b/net/sctp/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/Config.in Sat Aug 31 15:06:07 2002 @@ -0,0 +1,20 @@ +# +# SCTP configuration +# +mainmenu_option next_comment +comment ' SCTP Configuration (EXPERIMENTAL)' + +if [ "$CONFIG_IPV6" != "n" ]; then + define_bool CONFIG_IPV6_SCTP__ $CONFIG_IPV6 +else + define_bool CONFIG_IPV6_SCTP__ y +fi + +dep_tristate ' The SCTP Protocol (EXPERIMENTAL)' CONFIG_IP_SCTP $CONFIG_IPV6_SCTP__ +if [ "$CONFIG_IP_SCTP" != "n" ]; then + bool ' SCTP: Use old checksum (Adler-32)' CONFIG_SCTP_ADLER32 + bool ' SCTP: Debug messages' CONFIG_SCTP_DBG_MSG + bool ' SCTP: Debug object counts' CONFIG_SCTP_DBG_OBJCNT +fi + +endmenu diff -Nru a/net/sctp/Makefile b/net/sctp/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/Makefile Sat Aug 31 15:06:07 2002 @@ -0,0 +1,28 @@ +# +# Makefile for SCTP support code. +# + +obj-$(CONFIG_IP_SCTP) += sctp.o + +sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ + protocol.o endpointola.o associola.o \ + transport.o sm_make_chunk.o ulpevent.o \ + inqueue.o outqueue.o ulpqueue.o command.o \ + tsnmap.o bind_addr.o socket.o primitive.o \ + output.o input.o hashdriver.o sla1.o \ + debug.o + +ifeq ($(CONFIG_SCTP_ADLER32), y) +sctp-y += adler32.o +else +sctp-y += crc32c.o +endif + +sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o +sctp-$(CONFIG_SYSCTL) += sysctl.o + +sctp-$(subst m,y,$(CONFIG_IPV6)) += ipv6.o + +sctp-objs := $(sctp-y) + +include $(TOPDIR)/Rules.make diff -Nru a/net/sctp/adler32.c b/net/sctp/adler32.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/adler32.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,148 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file has direct heritage from the SCTP user-level reference + * implementation by R. Stewart, et al. These functions implement the + * Adler-32 algorithm as specified by RFC 2960. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +/* This is an entry point for external calls + * Define this function in the header file. This is + * direct from rfc1950, ... + * + * The following C code computes the Adler-32 checksum of a data buffer. + * It is written for clarity, not for speed. The sample code is in the + * ANSI C programming language. Non C users may find it easier to read + * with these hints: + * + * & Bitwise AND operator. + * >> Bitwise right shift operator. When applied to an + * unsigned quantity, as here, right shift inserts zero bit(s) + * at the left. + * << Bitwise left shift operator. Left shift inserts zero + * bit(s) at the right. + * ++ "n++" increments the variable n. + * % modulo operator: a % b is the remainder of a divided by b. + * + * Well, the above is a bit of a lie, I have optimized this a small + * tad, but I have commented the original lines below + */ + +#include +#include + +#define BASE 65521 /* largest prime smaller than 65536 */ + + +/* Performance work as shown this pig to be the + * worst CPU wise guy. I have done what I could think + * of on my flight to Austrialia but I am sure some + * clever assembly could speed this up, but of + * course this would require the dreaded #ifdef's for + * architecture. If you can speed this up more, pass + * it back and we will incorporate it :-) + */ + +unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) +{ + __u32 s1 = adler & 0xffff; + __u32 s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++,buf++) { + /* s1 = (s1 + buf[n]) % BASE */ + /* first we add */ + s1 = (s1 + *buf); + + /* Now if we need to, we do a mod by + * subtracting. It seems a bit faster + * since I really will only ever do + * one subtract at the MOST, since buf[n] + * is a max of 255. + */ + if(s1 >= BASE) + s1 -= BASE; + + /* s2 = (s2 + s1) % BASE */ + /* first we add */ + s2 = (s2 + s1); + + /* again, it is more efficent (it seems) to + * subtract since the most s2 will ever be + * is (BASE-1 + BASE-1) in the worse case. + * This would then be (2 * BASE) - 2, which + * will still only do one subtract. On Intel + * this is much better to do this way and + * avoid the divide. Have not -pg'd on + * sparc. + */ + if (s2 >= BASE) { + /* s2 %= BASE;*/ + s2 -= BASE; + } + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + return (s2 << 16) + s1; +} + +__u32 count_crc(__u8 *ptr, __u16 count) +{ + /* + * Update a running Adler-32 checksum with the bytes + * buf[0..len-1] and return the updated checksum. The Adler-32 + * checksum should be initialized to 1. + */ + __u32 adler = 1L; + __u32 zero = 0L; + + /* Calculate the CRC up to the checksum field. */ + adler = update_adler32(adler, ptr, + sizeof(struct sctphdr) - sizeof(__u32)); + /* Skip over the checksum field. */ + adler = update_adler32(adler, (unsigned char *) &zero, + sizeof(__u32)); + ptr += sizeof(struct sctphdr); + count -= sizeof(struct sctphdr); + + /* Calculate the rest of the Adler-32. */ + adler = update_adler32(adler, ptr, count); + + return adler; +} diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/associola.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,1033 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * This module provides the abstraction for an SCTP association. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Forward declarations for internal functions. */ +static void sctp_assoc_bh_rcv(sctp_association_t *asoc); + + +/* 1st Level Abstractions. */ + +/* Allocate and initialize a new association */ +sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, + const struct sock *sk, + sctp_scope_t scope, int priority) +{ + sctp_association_t *asoc; + + asoc = t_new(sctp_association_t, priority); + if (!asoc) + goto fail; + + if (!sctp_association_init(asoc, ep, sk, scope, priority)) + goto fail_init; + + asoc->base.malloced = 1; + SCTP_DBG_OBJCNT_INC(assoc); + + return asoc; + +fail_init: + kfree(asoc); +fail: + return NULL; +} + +/* Intialize a new association from provided memory. */ +sctp_association_t *sctp_association_init(sctp_association_t *asoc, + const sctp_endpoint_t *ep, + const struct sock *sk, + sctp_scope_t scope, + int priority) +{ + sctp_opt_t *sp; + int i; + + /* Retrieve the SCTP per socket area. */ + sp = sctp_sk((struct sock *)sk); + + /* Init all variables to a known value. */ + memset(asoc, 0, sizeof(sctp_association_t)); + + /* Discarding const is appropriate here. */ + asoc->ep = (sctp_endpoint_t *)ep; + sctp_endpoint_hold(asoc->ep); + + /* Hold the sock. */ + asoc->base.sk = (struct sock *)sk; + sock_hold(asoc->base.sk); + + /* Initialize the common base substructure. */ + asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; + + /* Initialize the object handling fields. */ + atomic_set(&asoc->base.refcnt, 1); + asoc->base.dead = 0; + asoc->base.malloced = 0; + + /* Initialize the bind addr area. */ + sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); + asoc->base.addr_lock = RW_LOCK_UNLOCKED; + + asoc->state = SCTP_STATE_CLOSED; + asoc->state_timestamp = jiffies; + + /* Set things that have constant value. */ + asoc->cookie_life.tv_sec = SCTP_DEFAULT_COOKIE_LIFE_SEC; + asoc->cookie_life.tv_usec = SCTP_DEFAULT_COOKIE_LIFE_USEC; + + asoc->pmtu = 0; + asoc->frag_point = 0; + + /* Initialize the default association max_retrans and RTO values. */ + asoc->max_retrans = ep->proto->max_retrans_association; + asoc->rto_initial = ep->proto->rto_initial; + asoc->rto_max = ep->proto->rto_max; + asoc->rto_min = ep->proto->rto_min; + + asoc->overall_error_threshold = 0; + asoc->overall_error_count = 0; + + /* Initialize the maximum mumber of new data packets that can be sent + * in a burst. + */ + asoc->max_burst = ep->proto->max_burst; + + /* Copy things from the endpoint. */ + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + asoc->timeouts[i] = ep->timeouts[i]; + init_timer(&asoc->timers[i]); + asoc->timers[i].function = sctp_timer_events[i]; + asoc->timers[i].data = (unsigned long) asoc; + } + + /* Pull default initialization values from the sock options. + * Note: This assumes that the values have already been + * validated in the sock. + */ + asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; + asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; + asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; + asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ; + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * The stream sequence number in all the streams shall start + * from 0 when the association is established. Also, when the + * stream sequence number reaches the value 65535 the next + * stream sequence number shall be set to 0. + */ + for (i = 0; i < SCTP_MAX_STREAM; i++) + asoc->ssn[i] = 0; + + /* Set the local window size for receive. + * This is also the rcvbuf space per association. + * RFC 6 - A SCTP receiver MUST be able to receive a minimum of + * 1500 bytes in one SCTP packet. + */ + if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) + asoc->rwnd = SCTP_DEFAULT_MINWINDOW; + else + asoc->rwnd = sk->rcvbuf; + + asoc->rwnd_over = 0; + + /* Use my own max window until I learn something better. */ + asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; + + /* Set the sndbuf size for transmit. */ + asoc->sndbuf_used = 0; + + init_waitqueue_head(&asoc->wait); + + asoc->c.my_vtag = sctp_generate_tag(ep); + asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ + asoc->c.peer_vtag = 0; + asoc->c.my_ttag = 0; + asoc->c.peer_ttag = 0; + + asoc->c.initial_tsn = sctp_generate_tsn(ep); + + asoc->next_tsn = asoc->c.initial_tsn; + + asoc->ctsn_ack_point = asoc->next_tsn - 1; + + asoc->unack_data = 0; + + SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", + asoc->ep->debug_name, + asoc->ctsn_ack_point); + + /* ADDIP Section 4.1 Asconf Chunk Procedures + * + * When an endpoint has an ASCONF signaled change to be sent to the + * remote endpoint it should do the following: + * ... + * A2) a serial number should be assigned to the chunk. The serial + * number should be a monotonically increasing number. All serial + * numbers are defined to be initialized at the start of the + * association to the same value as the initial TSN. + */ + asoc->addip_serial = asoc->c.initial_tsn; + + /* Make an empty list of remote transport addresses. */ + INIT_LIST_HEAD(&asoc->peer.transport_addr_list); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * After the reception of the first data chunk in an + * association the endpoint must immediately respond with a + * sack to acknowledge the data chunk. Subsequent + * acknowledgements should be done as described in Section + * 6.2. + * + * [We implement this by telling a new association that it + * already received one packet.] + */ + asoc->peer.sack_needed = 1; + + /* Create an input queue. */ + sctp_inqueue_init(&asoc->base.inqueue); + sctp_inqueue_set_th_handler(&asoc->base.inqueue, + (void (*)(void *))sctp_assoc_bh_rcv, + asoc); + + /* Create an output queue. */ + sctp_outqueue_init(asoc, &asoc->outqueue); + sctp_outqueue_set_output_handlers(&asoc->outqueue, + sctp_packet_init, + sctp_packet_config, + sctp_packet_append_chunk, + sctp_packet_transmit_chunk, + sctp_packet_transmit); + + if (NULL == sctp_ulpqueue_init(&asoc->ulpq, asoc, SCTP_MAX_STREAM)) + goto fail_init; + + /* Set up the tsn tracking. */ + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); + asoc->peer.next_dup_tsn = 0; + + skb_queue_head_init(&asoc->addip_chunks); + + asoc->need_ecne = 0; + + asoc->debug_name = "unnamedasoc"; + asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; + + /* Assume that peer would support both address types unless we are + * told otherwise. + */ + asoc->peer.ipv4_address = 1; + asoc->peer.ipv6_address = 1; + INIT_LIST_HEAD(&asoc->asocs); + + asoc->autoclose = sp->autoclose; + + return asoc; + +fail_init: + sctp_endpoint_put(asoc->ep); + sock_put(asoc->base.sk); + return NULL; +} + + +/* Free this association if possible. There may still be users, so + * the actual deallocation may be delayed. + */ +void sctp_association_free(sctp_association_t *asoc) +{ + sctp_transport_t *transport; + sctp_endpoint_t *ep; + list_t *pos, *temp; + int i; + + ep = asoc->ep; + list_del(&asoc->asocs); + + /* Mark as dead, so other users can know this structure is + * going away. + */ + asoc->base.dead = 1; + + /* Dispose of any data lying around in the outqueue. */ + sctp_outqueue_free(&asoc->outqueue); + + /* Dispose of any pending messages for the upper layer. */ + sctp_ulpqueue_free(&asoc->ulpq); + + /* Dispose of any pending chunks on the inqueue. */ + sctp_inqueue_free(&asoc->base.inqueue); + + /* Clean up the bound address list. */ + sctp_bind_addr_free(&asoc->base.bind_addr); + + /* Do we need to go through all of our timers and + * delete them? To be safe we will try to delete all, but we + * should be able to go through and make a guess based + * on our state. + */ + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + if (timer_pending(&asoc->timers[i]) && + del_timer(&asoc->timers[i])) + sctp_association_put(asoc); + } + + /* Release the transport structures. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + list_del(pos); + sctp_transport_free(transport); + } + + asoc->eyecatcher = 0; + + sctp_association_put(asoc); +} + + +/* Cleanup and free up an association. */ +static void sctp_association_destroy(sctp_association_t *asoc) +{ + SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); + + sctp_endpoint_put(asoc->ep); + sock_put(asoc->base.sk); + + if (asoc->base.malloced) { + kfree(asoc); + SCTP_DBG_OBJCNT_DEC(assoc); + } +} + + +/* Add a transport address to an association. */ +sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, + const sockaddr_storage_t *addr, + int priority) +{ + sctp_transport_t *peer; + sctp_opt_t *sp; + const __u16 *port; + + switch (addr->sa.sa_family) { + case AF_INET: + port = &addr->v4.sin_port; + break; + + case AF_INET6: + SCTP_V6( + port = &addr->v6.sin6_port; + break; + ); + + default: + return NULL; + }; + + /* Set the port if it has not been set yet. */ + if (0 == asoc->peer.port) { + asoc->peer.port = *port; + } + + SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", + return NULL); + + /* Check to see if this is a duplicate. */ + peer = sctp_assoc_lookup_paddr(asoc, addr); + if (peer) + return peer; + + peer = sctp_transport_new(addr, priority); + if (NULL == peer) + return NULL; + + sctp_transport_set_owner(peer, asoc); + + /* If this is the first transport addr on this association, + * initialize the association PMTU to the peer's PMTU. + * If not and the current association PMTU is higher than the new + * peer's PMTU, reset the association PMTU to the new peer's PMTU. + */ + if (asoc->pmtu) { + asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu); + } else { + asoc->pmtu = peer->pmtu; + } + + SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " + "%d\n", asoc, asoc->pmtu); + + asoc->frag_point = asoc->pmtu - + (SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t)); + + /* The asoc->peer.port might not be meaningful as of now, but + * initialize the packet structure anyway. + */ + (asoc->outqueue.init_output)(&peer->packet, + peer, + asoc->base.bind_addr.port, + asoc->peer.port); + + /* 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 value of ssthresh MAY be arbitrarily high + * (for example, implementations MAY use the size of the + * receiver advertised window). + */ + peer->cwnd = asoc->pmtu * 2; + + /* At this point, we may not have the receiver's advertised window, + * so initialize ssthresh to the default value and it will be set + * later when we process the INIT. + */ + peer->ssthresh = SCTP_DEFAULT_MAXWINDOW; + + peer->partial_bytes_acked = 0; + peer->flight_size = 0; + + peer->error_threshold = peer->max_retrans; + + /* Update the overall error threshold value of the association + * taking the new peer's error threshold into account. + */ + asoc->overall_error_threshold = + min(asoc->overall_error_threshold + peer->error_threshold, + asoc->max_retrans); + + /* Initialize the peer's heartbeat interval based on the + * sock configured value. + */ + sp = sctp_sk(asoc->base.sk); + peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; + + /* Attach the remote transport to our asoc. */ + list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); + + /* If we do not yet have a primary path, set one. */ + if (NULL == asoc->peer.primary_path) { + asoc->peer.primary_path = peer; + asoc->peer.active_path = peer; + asoc->peer.retran_path = peer; + } + + if (asoc->peer.active_path == asoc->peer.retran_path) + asoc->peer.retran_path = peer; + + return peer; +} + +/* Lookup a transport by address. */ +sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, + const sockaddr_storage_t *address) +{ + sctp_transport_t *t; + list_t *pos; + + /* Cycle through all transports searching for a peer address. */ + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + if (sctp_cmp_addr_exact(address, &t->ipaddr)) + return t; + } + + return NULL; +} + +/* Engage in transport control operations. + * Mark the transport up or down and send a notification to the user. + * Select and update the new active and retran paths. + */ +void sctp_assoc_control_transport(sctp_association_t *asoc, + sctp_transport_t *transport, + sctp_transport_cmd_t command, + sctp_sn_error_t error) +{ + sctp_transport_t *t = NULL; + sctp_transport_t *first; + sctp_transport_t *second; + sctp_ulpevent_t *event; + list_t *pos; + int spc_state = 0; + + /* Record the transition on the transport. */ + switch (command) { + case SCTP_TRANSPORT_UP: + transport->state.active = 1; + spc_state = ADDRESS_AVAILABLE; + break; + + case SCTP_TRANSPORT_DOWN: + transport->state.active = 0; + spc_state = ADDRESS_UNREACHABLE; + break; + + default: + BUG(); + }; + + /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the + * user. + */ + event = sctp_ulpevent_make_peer_addr_change(asoc, + (struct sockaddr_storage *) &transport->ipaddr, + 0, spc_state, error, GFP_ATOMIC); + if (event) + sctp_ulpqueue_tail_event(&asoc->ulpq, event); + + /* Select new active and retran paths. */ + + /* Look for the two most recently used active transports. + * + * This code produces the wrong ordering whenever jiffies + * rolls over, but we still get usable transports, so we don't + * worry about it. + */ + first = NULL; second = NULL; + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + + if (!t->state.active) + continue; + if (!first || t->last_time_heard > first->last_time_heard) { + second = first; + first = t; + } + if (!second || t->last_time_heard > second->last_time_heard) + second = t; + } + + /* RFC 2960 6.4 Multi-Homed SCTP Endpoints + * + * By default, an endpoint should always transmit to the + * primary path, unless the SCTP user explicitly specifies the + * destination transport address (and possibly source + * transport address) to use. + * + * [If the primary is active but not most recent, bump the most + * recently used transport.] + */ + if (asoc->peer.primary_path->state.active && + first != asoc->peer.primary_path) { + second = first; + first = asoc->peer.primary_path; + } + + /* If we failed to find a usable transport, just camp on the + * primary, even if it is inactive. + */ + if (NULL == first) { + first = asoc->peer.primary_path; + second = asoc->peer.primary_path; + } + + /* Set the active and retran transports. */ + asoc->peer.active_path = first; + asoc->peer.retran_path = second; +} + +/* Hold a reference to an association. */ +void sctp_association_hold(sctp_association_t *asoc) +{ + atomic_inc(&asoc->base.refcnt); +} + +/* Release a reference to an association and cleanup + * if there are no more references. + */ +void sctp_association_put(sctp_association_t *asoc) +{ + if (atomic_dec_and_test(&asoc->base.refcnt)) + sctp_association_destroy(asoc); +} + +/* Allocate the next TSN, Transmission Sequence Number, for the given + * association. + */ +__u32 __sctp_association_get_next_tsn(sctp_association_t *asoc) +{ + /* From Section 1.6 Serial Number Arithmetic: + * Transmission Sequence Numbers wrap around when they reach + * 2**32 - 1. That is, the next TSN a DATA chunk MUST use + * after transmitting TSN = 2*32 - 1 is TSN = 0. + */ + __u32 retval = asoc->next_tsn; + asoc->next_tsn++; + asoc->unack_data++; + + return retval; +} + +/* Allocate 'num' TSNs by incrementing the association's TSN by num. */ +__u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num) +{ + __u32 retval = asoc->next_tsn; + + asoc->next_tsn += num; + asoc->unack_data += num; + + return retval; +} + +/* Fetch the next Stream Sequence Number for stream number 'sid'. */ +__u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) +{ + return asoc->ssn[sid]++; +} + +/* Compare two addresses to see if they match. Wildcard addresses + * always match within their address family. + * + * FIXME: We do not match address scopes correctly. + */ +int sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2) +{ + int len; + const void *base1; + const void *base2; + + if (ss1->sa.sa_family != ss2->sa.sa_family) + return 0; + if (ss1->v4.sin_port != ss2->v4.sin_port) + return 0; + + switch (ss1->sa.sa_family) { + case AF_INET: + if (INADDR_ANY == ss1->v4.sin_addr.s_addr || + INADDR_ANY == ss2->v4.sin_addr.s_addr) + goto match; + + len = sizeof(struct in_addr); + base1 = &ss1->v4.sin_addr; + base2 = &ss2->v4.sin_addr; + break; + + case AF_INET6: + SCTP_V6( + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss1->v6.sin6_addr)) + goto match; + + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss2->v6.sin6_addr)) + goto match; + + len = sizeof(struct in6_addr); + base1 = &ss1->v6.sin6_addr; + base2 = &ss2->v6.sin6_addr; + break; + ) + + default: + printk(KERN_WARNING + "WARNING, bogus socket address family %d\n", + ss1->sa.sa_family); + return 0; + }; + + return (0 == memcmp(base1, base2, len)); + +match: + return 1; +} + +/* Compare two addresses to see if they match. Wildcard addresses + * only match themselves. + * + * FIXME: We do not match address scopes correctly. + */ +int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2) +{ + int len; + const void *base1; + const void *base2; + + if (ss1->sa.sa_family != ss2->sa.sa_family) + return 0; + if (ss1->v4.sin_port != ss2->v4.sin_port) + return 0; + + switch (ss1->sa.sa_family) { + case AF_INET: + len = sizeof(struct in_addr); + base1 = &ss1->v4.sin_addr; + base2 = &ss2->v4.sin_addr; + break; + + case AF_INET6: + SCTP_V6( + len = sizeof(struct in6_addr); + base1 = &ss1->v6.sin6_addr; + base2 = &ss2->v6.sin6_addr; + break; + ) + + default: + printk(KERN_WARNING + "WARNING, bogus socket address family %d\n", + ss1->sa.sa_family); + return 0; + }; + + return (0 == memcmp(base1, base2, len)); +} + +/* Return an ecne chunk to get prepended to a packet. + * Note: We are sly and return a shared, prealloced chunk. + */ +sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc) +{ + sctp_chunk_t *chunk; + int need_ecne; + __u32 lowest_tsn; + + /* Can be called from task or bh. Both need_ecne and + * last_ecne_tsn are written during bh. + */ + need_ecne = asoc->need_ecne; + lowest_tsn = asoc->last_ecne_tsn; + + if (need_ecne) { + chunk = sctp_make_ecne(asoc, lowest_tsn); + + /* ECNE is not mandatory to the flow. Being unable to + * alloc mem is not deadly. We are just unable to help + * out the network. If we run out of memory, just return + * NULL. + */ + } else { + chunk = NULL; + } + + return chunk; +} + +/* Use this function for the packet prepend callback when no ECNE + * packet is desired (e.g. some packets don't like to be bundled). + */ +sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) +{ + return NULL; +} + +/* + * Find which transport this TSN was sent on. + */ +sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) +{ + sctp_transport_t *active; + sctp_transport_t *match; + list_t *entry, *pos; + sctp_transport_t *transport; + sctp_chunk_t *chunk; + __u32 key = htonl(tsn); + + match = NULL; + + /* + * FIXME: In general, find a more efficient data structure for + * searching. + */ + + /* + * The general strategy is to search each transport's transmitted + * list. Return which transport this TSN lives on. + * + * Let's be hopeful and check the active_path first. + * Another optimization would be to know if there is only one + * outbound path and not have to look for the TSN at all. + * + */ + + active = asoc->peer.active_path; + + list_for_each(entry, &active->transmitted) { + chunk = list_entry(entry, sctp_chunk_t, transmitted_list); + + if (key == chunk->subh.data_hdr->tsn) { + match = active; + goto out; + } + } + + /* If not found, go search all the other transports. */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + + if (transport == active) + break; + list_for_each(entry, &transport->transmitted) { + chunk = list_entry(entry, sctp_chunk_t, + transmitted_list); + if (key == chunk->subh.data_hdr->tsn) { + match = transport; + goto out; + } + } + } +out: + return match; +} + +/* Is this the association we are looking for? */ +sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, + const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr) +{ + sctp_transport_t *transport; + + sctp_read_lock(&asoc->base.addr_lock); + + if ((asoc->base.bind_addr.port == laddr->v4.sin_port) && + (asoc->peer.port == paddr->v4.sin_port)) { + transport = sctp_assoc_lookup_paddr(asoc, paddr); + if (!transport) + goto out; + + if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) + goto out; + } + transport = NULL; + +out: + sctp_read_unlock(&asoc->base.addr_lock); + return transport; +} + +/* Do delayed input processing. This is scheduled by sctp_rcv(). */ +static void sctp_assoc_bh_rcv(sctp_association_t *asoc) +{ + sctp_endpoint_t *ep; + sctp_chunk_t *chunk; + struct sock *sk; + sctp_inqueue_t *inqueue; + int state, subtype; + sctp_assoc_t associd = sctp_assoc2id(asoc); + int error = 0; + + /* The association should be held so we should be safe. */ + ep = asoc->ep; + sk = asoc->base.sk; + + inqueue = &asoc->base.inqueue; + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + state = asoc->state; + subtype = chunk->chunk_hdr->type; + + /* Remember where the last DATA chunk came from so we + * know where to send the SACK. + */ + if (sctp_chunk_is_data(chunk)) + asoc->peer.last_data_from = chunk->transport; + + if (chunk->transport) + chunk->transport->last_time_heard = jiffies; + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), + state, ep, asoc, chunk, GFP_ATOMIC); + + /* Check to see if the association is freed in response to + * the incoming chunk. If so, get out of the while loop. + */ + if (!sctp_id2assoc(sk, associd)) + goto out; + + if (error != 0) + goto err_out; + } + +err_out: + /* Is this the right way to pass errors up to the ULP? */ + if (error) + sk->err = -error; +out: +} + +/* This routine moves an association from its old sk to a new sk. */ +void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) +{ + sctp_opt_t *newsp = sctp_sk(newsk); + + /* Delete the association from the old endpoint's list of + * associations. + */ + list_del(&assoc->asocs); + + /* Release references to the old endpoint and the sock. */ + sctp_endpoint_put(assoc->ep); + sock_put(assoc->base.sk); + + /* Get a reference to the new endpoint. */ + assoc->ep = newsp->ep; + sctp_endpoint_hold(assoc->ep); + + /* Get a reference to the new sock. */ + assoc->base.sk = newsk; + sock_hold(assoc->base.sk); + + /* Add the association to the new endpoint's list of associations. */ + sctp_endpoint_add_asoc(newsp->ep, assoc); +} + +/* Update an association (possibly from unexpected COOKIE-ECHO processing). */ +void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) +{ + int i; + + /* Copy in new parameters of peer. */ + asoc->c = new->c; + asoc->peer.rwnd = new->peer.rwnd; + asoc->peer.next_dup_tsn = new->peer.next_dup_tsn; + asoc->peer.sack_needed = new->peer.sack_needed; + asoc->peer.i = new->peer.i; + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, + asoc->peer.i.initial_tsn); + + /* FIXME: + * Do we need to copy primary_path etc? + * + * More explicitly, addresses may have been removed and + * this needs accounting for. + */ + + /* If the case is A (association restart), use + * initial_tsn as next_tsn. If the case is B, use + * current next_tsn in case there is data sent to peer + * has been discarded and needs retransmission. + */ + if (SCTP_STATE_ESTABLISHED == asoc->state) { + asoc->next_tsn = new->next_tsn; + asoc->ctsn_ack_point = new->ctsn_ack_point; + + /* Reinitialize SSN for both local streams + * and peer's streams. + */ + for (i = 0; i < SCTP_MAX_STREAM; i++) { + asoc->ssn[i] = 0; + asoc->ulpq.ssn[i] = 0; + } + } else { + asoc->ctsn_ack_point = asoc->next_tsn - 1; + } +} + +/* Choose the transport for sending a shutdown packet. + * Round-robin through the active transports, else round-robin + * through the inactive transports as this is the next best thing + * we can try. + */ +sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +{ + sctp_transport_t *t, *next; + list_t *head = &asoc->peer.transport_addr_list; + list_t *pos; + + /* If this is the first time SHUTDOWN is sent, use the active + * path. + */ + if (!asoc->shutdown_last_sent_to) + return asoc->peer.active_path; + + /* Otherwise, find the next transport in a round-robin fashion. */ + + t = asoc->shutdown_last_sent_to; + pos = &t->transports; + next = NULL; + + while (1) { + /* Skip the head. */ + if (pos->next == head) + pos = head->next; + else + pos = pos->next; + + t = list_entry(pos, sctp_transport_t, transports); + + /* Try to find an active transport. */ + + if (t->state.active) { + break; + } else { + /* Keep track of the next transport in case + * we don't find any active transport. + */ + if (!next) + next = t; + } + + /* We have exhausted the list, but didn't find any + * other active transports. If so, use the next + * transport. + */ + if (t == asoc->shutdown_last_sent_to) { + t = next; + break; + } + } + + return t; +} diff -Nru a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/bind_addr.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,529 @@ +/* SCTP kernel reference Implementation + * Copyright (c) Cisco 1999,2000 + * Copyright (c) Motorola 1999,2000,2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) La Monte H.P. Yarroll 2001 + * + * This file is part of the SCTP kernel reference implementation. + * + * A collection class to handle the storage of transport addresses. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, + sctp_scope_t scope, int priority, int flags); +static void sctp_bind_addr_clean(sctp_bind_addr_t *); + +/* First Level Abstractions. */ + +/* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses + * in 'src' which have a broader scope than 'scope'. + */ +int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, + sctp_scope_t scope, int priority, int flags) +{ + struct sockaddr_storage_list *addr; + list_t *pos; + int error = 0; + + /* All addresses share the same port. */ + dest->port = src->port; + + /* Extract the addresses which are relevant for this scope. */ + list_for_each(pos, &src->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + error = sctp_copy_one_addr(dest, &addr->a, scope, + priority, flags); + if (error < 0) + goto out; + } + +out: + if (error) + sctp_bind_addr_clean(dest); + + return error; +} + +/* Create a new SCTP_bind_addr from nothing. */ +sctp_bind_addr_t *sctp_bind_addr_new(int priority) +{ + sctp_bind_addr_t *retval; + + retval = t_new(sctp_bind_addr_t, priority); + if (!retval) + goto nomem; + + sctp_bind_addr_init(retval, 0); + retval->malloced = 1; + SCTP_DBG_OBJCNT_INC(bind_addr); + +nomem: + return retval; +} + +/* Initialize the SCTP_bind_addr structure for either an endpoint or + * an association. + */ +void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) +{ + bp->malloced = 0; + + INIT_LIST_HEAD(&bp->address_list); + bp->port = port; +} + +/* Dispose of the address list. */ +static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) +{ + struct sockaddr_storage_list *addr; + list_t *pos, *temp; + + /* Empty the bind address list. */ + list_for_each_safe(pos, temp, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + list_del(pos); + kfree(addr); + SCTP_DBG_OBJCNT_DEC(addr); + } +} + +/* Dispose of an SCTP_bind_addr structure */ +void sctp_bind_addr_free(sctp_bind_addr_t *bp) +{ + /* Empty the bind address list. */ + sctp_bind_addr_clean(bp); + + if (bp->malloced) { + kfree(bp); + SCTP_DBG_OBJCNT_DEC(bind_addr); + } +} + +/* Add an address to the bind address list in the SCTP_bind_addr structure. */ +int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, + int priority) +{ + struct sockaddr_storage_list *addr; + + /* Add the address to the bind address list. */ + addr = t_new(struct sockaddr_storage_list, priority); + if (!addr) + return -ENOMEM; + + addr->a = *new; + + /* Fix up the port if it has not yet been set. + * Both v4 and v6 have the port at the same offset. + */ + if (!addr->a.v4.sin_port) + addr->a.v4.sin_port = bp->port; + + INIT_LIST_HEAD(&addr->list); + list_add_tail(&addr->list, &bp->address_list); + SCTP_DBG_OBJCNT_INC(addr); + + return 0; +} + +/* Delete an address from the bind address list in the SCTP_bind_addr + * structure. + */ +int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) +{ + list_t *pos, *temp; + struct sockaddr_storage_list *addr; + + list_for_each_safe(pos, temp, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_cmp_addr_exact(&addr->a, del_addr)) { + /* Found the exact match. */ + list_del(pos); + kfree(addr); + SCTP_DBG_OBJCNT_DEC(addr); + + return 0; + } + } + + return -EINVAL; +} + +/* Create a network byte-order representation of all the addresses + * formated as SCTP parameters. + * + * The second argument is the return value for the length. + */ +sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, + int priority) +{ + sctpParam_t rawaddr; + sctpParam_t addrparms; + sctpParam_t retval; + int addrparms_len; + sctpIpAddress_t rawaddr_space; + int len; + struct sockaddr_storage_list *addr; + list_t *pos; + + retval.v = NULL; + addrparms_len = 0; + len = 0; + + /* Allocate enough memory at once. */ + list_for_each(pos, &bp->address_list) { + len += sizeof(sctp_ipv6addr_param_t); + } + + addrparms.v = kmalloc(len, priority); + if (!addrparms.v) + goto end_raw; + + retval = addrparms; + rawaddr.v4 = &rawaddr_space.v4; + + list_for_each(pos, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + len = sockaddr2sctp_addr(&addr->a, rawaddr); + memcpy(addrparms.v, rawaddr.v, len); + addrparms.v += len; + addrparms_len += len; + } + +end_raw: + *addrs_len = addrparms_len; + return retval; +} + +/* + * Create an address list out of the raw address list format (IPv4 and IPv6 + * address parameters). + */ +int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, + int addrs_len, __u16 port, int priority) +{ + sctpParam_t rawaddr; + sockaddr_storage_t addr; + int retval = 0; + int len; + + /* Convert the raw address to standard address format */ + while (addrs_len) { + rawaddr.v = raw_addr_list; + if (SCTP_PARAM_IPV4_ADDRESS==rawaddr.p->type + || SCTP_PARAM_IPV6_ADDRESS==rawaddr.p->type) { + sctp_param2sockaddr(&addr, rawaddr, port); + retval = sctp_add_bind_addr(bp, &addr, priority); + if (retval) { + /* Can't finish building the list, clean up. */ + sctp_bind_addr_clean(bp); + break; + } + + len = ntohs(rawaddr.p->length); + addrs_len -= len; + raw_addr_list += len; + } else { + /* Corrupted raw addr list! */ + retval = -EINVAL; + sctp_bind_addr_clean(bp); + break; + } + } + + return retval; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Does this contain a specified address? */ +int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) +{ + struct sockaddr_storage_list *laddr; + list_t *pos; + + list_for_each(pos, &bp->address_list) { + laddr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_cmp_addr(&laddr->a, addr)) + return 1; + } + + return 0; +} + +/* Copy out addresses from the global local address list. */ +static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, + sctp_scope_t scope, int priority, int flags) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + int error = 0; + + if (sctp_is_any(addr)) { + error = sctp_copy_local_addr_list(proto, dest, scope, + priority, flags); + } else if (sctp_in_scope(addr, scope)) { + /* Now that the address is in scope, check to see if + * the address type is supported by local sock as + * well as the remote peer. + */ + if ((((AF_INET == addr->sa.sa_family) && + (flags & SCTP_ADDR4_PEERSUPP))) || + (((AF_INET6 == addr->sa.sa_family) && + (flags & SCTP_ADDR6_ALLOWED) && + (flags & SCTP_ADDR6_PEERSUPP)))) + error = sctp_add_bind_addr(dest, addr, priority); + } + + return error; +} + +/* Is addr one of the wildcards? */ +int sctp_is_any(const sockaddr_storage_t *addr) +{ + int retval = 0; + + switch (addr->sa.sa_family) { + case AF_INET: + if (INADDR_ANY == addr->v4.sin_addr.s_addr) + retval = 1; + break; + + case AF_INET6: + SCTP_V6( + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&addr->v6.sin6_addr)) + retval = 1; + ); + break; + + default: + break; + }; + + return retval; +} + +/* Is 'addr' valid for 'scope'? */ +int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) +{ + sctp_scope_t addr_scope = sctp_scope(addr); + + switch (addr->sa.sa_family) { + case AF_INET: + /* According to the SCTP IPv4 address scoping document - + * , the scope has + * a heirarchy of 5 levels: + * Level 0 - unusable SCTP addresses + * Level 1 - loopback address + * Level 2 - link-local addresses + * Level 3 - private addresses. + * Level 4 - global addresses + * For INIT and INIT-ACK address list, let L be the level of + * of requested destination address, sender and receiver + * SHOULD include all of its addresses with level greater + * than or equal to L. + */ + /* The unusable SCTP addresses will not be considered with + * any defined scopes. + */ + if (SCTP_SCOPE_UNUSABLE == addr_scope) + return 0; + + /* Note that we are assuming that the scoping are the same + * for both IPv4 addresses and IPv6 addresses, i.e., if the + * scope is link local, both IPv4 link local addresses and + * IPv6 link local addresses would be treated as in the + * scope. There is no filtering for IPv4 vs. IPv6 addresses + * based on scoping alone. + */ + if (addr_scope <= scope) + return 1; + break; + + case AF_INET6: + /* FIXME: + * This is almost certainly wrong since scopes have an + * heirarchy. I don't know what RFC to look at. + * There may be some guidance in the SCTP implementors + * guide (an Internet Draft as of October 2001). + * + * Further verification on the correctness of the IPv6 + * scoping is needed. According to the IPv6 scoping draft, + * the link local and site local address may require + * further scoping. + * + * Is the heirachy of the IPv6 scoping the same as what's + * defined for IPv4? + * If the same heirarchy indeed applies to both famiies, + * this function can be simplified with one set of code. + * (see the comments for IPv4 above) + */ + if (addr_scope <= scope) + return 1; + break; + + default: + return 0; + }; + + return 0; +} + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + +/* What is the scope of 'addr'? */ +sctp_scope_t sctp_scope(const sockaddr_storage_t *addr) +{ + sctp_scope_t retval = SCTP_SCOPE_GLOBAL; + + switch (addr->sa.sa_family) { + case AF_INET: + /* We are checking the loopback, private and other address + * scopes as defined in RFC 1918. + * The IPv4 scoping is based on the draft for SCTP IPv4 + * scoping . + * The set of SCTP address scope hopefully can cover both + * types of addresses. + */ + + /* Should IPv4 scoping be a sysctl configurable option + * so users can turn it off (default on) for certain + * unconventional networking environments? + */ + + /* Check for unusable SCTP addresses. */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_UNUSABLE; + } else if (LOOPBACK(addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LOOPBACK; + } else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LINK; + } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_PRIVATE; + } else { + retval = SCTP_SCOPE_GLOBAL; + } + break; + + case AF_INET6: + { + SCTP_V6( + int v6scope; + v6scope = ipv6_addr_scope((struct in6_addr *) + &addr->v6.sin6_addr); + /* The IPv6 scope is really a set of bit + * fields. See IFA_* in . + * Mapping them to the generic SCTP scope + * set is an attempt to have code + * consistencies with the IPv4 scoping. + */ + switch (v6scope) { + case IFA_HOST: + retval = SCTP_SCOPE_LOOPBACK; + break; + + case IFA_LINK: + retval = SCTP_SCOPE_LINK; + break; + + case IFA_SITE: + retval = SCTP_SCOPE_PRIVATE; + break; + + default: + retval = SCTP_SCOPE_GLOBAL; + break; + }; + ); + break; + } + + default: + retval = SCTP_SCOPE_GLOBAL; + break; + }; + + return retval; +} + +/* This function checks if the address is a valid address to be used for + * SCTP. + * + * Output: + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +int sctp_addr_is_valid(const sockaddr_storage_t *addr) +{ + unsigned short sa_family = addr->sa.sa_family; + + switch (sa_family) { + case AF_INET: + /* Is this a non-unicast address or a unusable SCTP address? */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) + return 0; + break; + + case AF_INET6: + SCTP_V6( + { + int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + + /* Is this a non-unicast address */ + if (!(ret & IPV6_ADDR_UNICAST)) + return 0; + break; + }); + + default: + return 0; + }; + + return 1; +} diff -Nru a/net/sctp/command.c b/net/sctp/command.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/command.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,104 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, and IBM + * Copyright 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions manipulate sctp command sequences. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include + +/* Create a new sctp_command_sequence. */ +sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) +{ + sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority); + + /* XXX Check for NULL? -DaveM */ + sctp_init_cmd_seq(retval); + + return retval; +} + +/* Initialize a block of memory as a command sequence. */ +int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) +{ + memset(seq, 0, sizeof(sctp_cmd_seq_t)); + return 1; /* We always succeed. */ +} + +/* Add a command to a sctp_cmd_seq_t. + * Return 0 if the command sequence is full. + */ +int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +{ + if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS) + goto fail; + + seq->cmds[seq->next_free_slot].verb = verb; + seq->cmds[seq->next_free_slot++].obj = obj; + + return 1; + +fail: + return 0; +} + +/* Rewind an sctp_cmd_seq_t to iterate from the start. */ +int sctp_rewind_sequence(sctp_cmd_seq_t *seq) +{ + seq->next_cmd = 0; + return 1; /* We always succeed. */ +} + +/* Return the next command structure in a sctp_cmd_seq. + * Returns NULL at the end of the sequence. + */ +sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) +{ + sctp_cmd_t *retval = NULL; + + if (seq->next_cmd < seq->next_free_slot) + retval = &seq->cmds[seq->next_cmd++]; + + return retval; +} + +/* Dispose of a command sequence. */ +void sctp_free_cmd_seq(sctp_cmd_seq_t *seq) +{ + kfree(seq); +} diff -Nru a/net/sctp/crc32c.c b/net/sctp/crc32c.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/crc32c.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,187 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * SCTP Checksum functions + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Dinakaran Joseph + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +/* The following code has been taken directly from + * draft-ietf-tsvwg-sctpcsum-03.txt + * + * The code has now been modified specifically for SCTP knowledge. + */ + +#include +#include + +#define CRC32C_POLY 0x1EDC6F41 +#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Copyright 2001, D. Otis. Use this program, code or tables */ +/* extracted from it, as desired without restriction. */ +/* */ +/* 32 Bit Reflected CRC table generation for SCTP. */ +/* To accommodate serial byte data being shifted out least */ +/* significant bit first, the table's 32 bit words are reflected */ +/* which flips both byte and bit MS and LS positions. The CRC */ +/* is calculated MS bits first from the perspective of the serial*/ +/* stream. The x^32 term is implied and the x^0 term may also */ +/* be shown as +1. The polynomial code used is 0x1EDC6F41. */ +/* Castagnoli93 */ +/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ +/* x^11+x^10+x^9+x^8+x^6+x^0 */ +/* Guy Castagnoli Stefan Braeuer and Martin Herrman */ +/* "Optimization of Cyclic Redundancy-Check Codes */ +/* with 24 and 32 Parity Bits", */ +/* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +__u32 crc_c[256] = { + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, + 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, + 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, + 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, + 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, + 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, + 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, + 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, + 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, + 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, + 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, + 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, + 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, + 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, + 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, + 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, + 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, + 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, + 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, + 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, + 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, + 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, + 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, + 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, + 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, + 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, + 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, + 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, + 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, + 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, + 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, + 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, + 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, +}; + +__u32 count_crc(__u8 *buffer, __u16 length) +{ + __u32 crc32 = ~(__u32) 0; + __u32 i, result; + __u8 byte0, byte1, byte2, byte3; + + /* Optimize this routine to be SCTP specific, knowing how + * to skip the checksum field of the SCTP header. + */ + + /* Calculate CRC up to the checksum. */ + for (i = 0; i < (sizeof(struct sctphdr) - sizeof(__u32)); i++) + CRC32C(crc32, buffer[i]); + + /* Skip checksum field of the header. */ + for (i = 0; i < sizeof(__u32); i++) + CRC32C(crc32, 0); + + /* Calculate the rest of the CRC. */ + for (i = sizeof(struct sctphdr); i < length ; i++) + CRC32C(crc32, buffer[i]); + + result = ~crc32; + + /* result now holds the negated polynomial remainder; + * since the table and algorithm is "reflected" [williams95]. + * That is, result has the same value as if we mapped the message + * to a polyomial, computed the host-bit-order polynomial + * remainder, performed final negation, then did an end-for-end + * bit-reversal. + * Note that a 32-bit bit-reversal is identical to four inplace + * 8-bit reversals followed by an end-for-end byteswap. + * In other words, the bytes of each bit are in the right order, + * but the bytes have been byteswapped. So we now do an explicit + * byteswap. On a little-endian machine, this byteswap and + * the final ntohl cancel out and could be elided. + */ + byte0 = result & 0xff; + byte1 = (result>>8) & 0xff; + byte2 = (result>>16) & 0xff; + byte3 = (result>>24) & 0xff; + + crc32 = ((byte0 << 24) | + (byte1 << 16) | + (byte2 << 8) | + byte3); + return crc32; +} + + diff -Nru a/net/sctp/debug.c b/net/sctp/debug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/debug.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,215 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * This file converts numerical ID value to alphabetical names for SCTP + * terms such as chunk type, parameter time, event type, etc. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include + +#if SCTP_DEBUG +int sctp_debug_flag = 1; /* Initially enable DEBUG */ +#endif /* SCTP_DEBUG */ + +/* These are printable forms of Chunk ID's from section 3.1. */ +static const char *sctp_cid_tbl[SCTP_NUM_BASE_CHUNK_TYPES] = { + "DATA", + "INIT", + "INIT_ACK", + "SACK", + "HEARTBEAT", + "HEARTBEAT_ACK", + "ABORT", + "SHUTDOWN", + "SHUTDOWN_ACK", + "ERROR", + "COOKIE_ECHO", + "COOKIE_ACK", + "ECN_ECNE", + "ECN_CWR", + "SHUTDOWN_COMPLETE", +}; + +/* Lookup "chunk type" debug name. */ +const char *sctp_cname(const sctp_subtype_t cid) +{ + if (cid.chunk < 0) + return "illegal chunk id"; + if (cid.chunk <= SCTP_CID_BASE_MAX) + return sctp_cid_tbl[cid.chunk]; + + switch (cid.chunk) { + case SCTP_CID_ASCONF: + return "ASCONF"; + + case SCTP_CID_ASCONF_ACK: + return "ASCONF_ACK"; + + default: + return "unknown chunk"; + }; + return "unknown chunk"; +} + +/* These are printable form of variable-length parameters. */ +const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = { + "", + "PARAM_HEATBEAT_INFO", + "", + "", + "", + "PARAM_IPV4_ADDRESS", + "PARAM_IPV6_ADDRESS", + "PARAM_STATE_COOKIE", + "PARAM_UNRECOGNIZED_PARAMETERS", + "PARAM_COOKIE_PRESERVATIVE", + "", + "PARAM_HOST_NAME_ADDRESS", + "PARAM_SUPPORTED_ADDRESS_TYPES", +}; + +/* These are printable forms of the states. */ +const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = { + "STATE_EMPTY", + "STATE_CLOSED", + "STATE_COOKIE_WAIT", + "STATE_COOKIE_ECHOED", + "STATE_ESTABLISHED", + "STATE_SHUTDOWN_PENDING", + "STATE_SHUTDOWN_SENT", + "STATE_SHUTDOWN_RECEIVED", + "STATE_SHUTDOWN_ACK_SENT", +}; + +/* Events that could change the state of an association. */ +const char *sctp_evttype_tbl[] = { + "EVENT_T_unknown", + "EVENT_T_CHUNK", + "EVENT_T_TIMEOUT", + "EVENT_T_OTHER", + "EVENT_T_PRIMITIVE" +}; + +/* Return value of a state function */ +const char *sctp_status_tbl[] = { + "DISPOSITION_DISCARD", + "DISPOSITION_CONSUME", + "DISPOSITION_NOMEM", + "DISPOSITION_DELETE_TCB", + "DISPOSITION_ABORT", + "DISPOSITION_VIOLATION", + "DISPOSITION_NOT_IMPL", + "DISPOSITION_ERROR", + "DISPOSITION_BUG" +}; + +/* Printable forms of primitives */ +static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = { + "PRIMITIVE_INITIALIZE", + "PRIMITIVE_ASSOCIATE", + "PRIMITIVE_SHUTDOWN", + "PRIMITIVE_ABORT", + "PRIMITIVE_SEND", + "PRIMITIVE_SETPRIMARY", + "PRIMITIVE_RECEIVE", + "PRIMITIVE_STATUS", + "PRIMITIVE_CHANGEHEARTBEAT", + "PRIMITIVE_REQUESTHEARTBEAT", + "PRIMITIVE_GETSRTTREPORT", + "PRIMITIVE_SETFAILURETHRESHOLD", + "PRIMITIVE_SETPROTOPARAMETERS", + "PRIMITIVE_RECEIVE_UNSENT", + "PRIMITIVE_RECEIVE_UNACKED", + "PRIMITIVE_DESTROY" +}; + +/* Lookup primitive debug name. */ +const char *sctp_pname(const sctp_subtype_t id) +{ + if (id.primitive < 0) + return "illegal primitive"; + if (id.primitive <= SCTP_EVENT_PRIMITIVE_MAX) + return sctp_primitive_tbl[id.primitive]; + return "unknown_primitive"; +} + +static const char *sctp_other_tbl[] = { + "NO_PENDING_TSN", + "ICMP_UNREACHFRAG" +}; + +/* Lookup "other" debug name. */ +const char *sctp_oname(const sctp_subtype_t id) +{ + if (id.other < 0) + return "illegal 'other' event"; + if (id.other < SCTP_EVENT_OTHER_MAX) + return sctp_other_tbl[id.other]; + return "unknown 'other' event"; +} + +static const char *sctp_timer_tbl[] = { + "TIMEOUT_NONE", + "TIMEOUT_T1_COOKIE", + "TIMEOUT_T1_INIT", + "TIMEOUT_T2_SHUTDOWN", + "TIMEOUT_T3_RTX", + "TIMEOUT_T4_RTO", + "TIMEOUT_HEARTBEAT", + "TIMEOUT_SACK", + "TIMEOUT_AUTOCLOSE", + "TIMEOUT_PMTU_RAISE", +}; + +/* Lookup timer debug name. */ +const char *sctp_tname(const sctp_subtype_t id) +{ + if (id.timeout < 0) + return "illegal 'timer' event"; + if (id.timeout <= SCTP_EVENT_TIMEOUT_MAX) + return sctp_timer_tbl[id.timeout]; + return "unknown_timer"; +} diff -Nru a/net/sctp/endpointola.c b/net/sctp/endpointola.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/endpointola.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,369 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * This abstraction represents an SCTP endpoint. + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Daisy Chang + * Dajiang Zhang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include /* get_random_bytes() */ +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); + +/* Create a sctp_endpoint_t with all that boring stuff initialized. + * Returns NULL if there isn't enough memory. + */ +sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, + struct sock *sk, int priority) +{ + sctp_endpoint_t *ep; + + /* Build a local endpoint. */ + ep = t_new(sctp_endpoint_t, priority); + if (!ep) + goto fail; + if (!sctp_endpoint_init(ep, proto, sk, priority)) + goto fail_init; + ep->base.malloced = 1; + SCTP_DBG_OBJCNT_INC(ep); + return ep; + +fail_init: + kfree(ep); +fail: + return NULL; +} + +/* + * Initialize the base fields of the endpoint structure. + */ +sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, + struct sock *sk, int priority) +{ + memset(ep, 0, sizeof(sctp_endpoint_t)); + + /* Initialize the base structure. */ + /* What type of endpoint are we? */ + ep->base.type = SCTP_EP_TYPE_SOCKET; + + /* Initialize the basic object fields. */ + atomic_set(&ep->base.refcnt, 1); + ep->base.dead = 0; + ep->base.malloced = 1; + + /* Create an input queue. */ + sctp_inqueue_init(&ep->base.inqueue); + + /* Set its top-half handler */ + sctp_inqueue_set_th_handler(&ep->base.inqueue, + (void (*)(void *))sctp_endpoint_bh_rcv, + ep); + + /* Initialize the bind addr area */ + sctp_bind_addr_init(&ep->base.bind_addr, 0); + ep->base.addr_lock = RW_LOCK_UNLOCKED; + + /* Remember who we are attached to. */ + ep->base.sk = sk; + sock_hold(ep->base.sk); + + /* This pointer is useful to access the default protocol parameter + * values. + */ + ep->proto = proto; + + /* Create the lists of associations. */ + INIT_LIST_HEAD(&ep->asocs); + + /* Set up the base timeout information. */ + ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] + = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] + = SCTP_DEFAULT_TIMEOUT_T1_INIT; + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] + = sctp_sk(sk)->rtoinfo.srto_initial; + ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] + = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] + = SCTP_DEFAULT_TIMEOUT_SACK; + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] + = sctp_sk(sk)->autoclose * HZ; + ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] + = SCTP_DEFAULT_TIMEOUT_PMTU_RAISE; + + /* Set up the default send/receive buffer space. */ + + /* FIXME - Should the min and max window size be configurable + * sysctl parameters as opposed to be constants? + */ + sk->rcvbuf = SCTP_DEFAULT_MAXWINDOW; + sk->sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; + + /* Use SCTP specific send buffer space queues. */ + sk->write_space = sctp_write_space; + sk->use_write_queue = 1; + + /* Initialize the secret key used with cookie. */ + get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); + ep->last_key = ep->current_key = 0; + ep->key_changed_at = jiffies; + + ep->debug_name = "unnamedEndpoint"; + return ep; +} + +/* Add an association to an endpoint. */ +void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +{ + /* Now just add it to our list of asocs */ + list_add_tail(&asoc->asocs, &ep->asocs); +} + +/* Free the endpoint structure. Delay cleanup until + * all users have released their reference count on this structure. + */ +void sctp_endpoint_free(sctp_endpoint_t *ep) +{ + ep->base.dead = 1; + sctp_endpoint_put(ep); +} + +/* Final destructor for endpoint. */ +void sctp_endpoint_destroy(sctp_endpoint_t *ep) +{ + SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); + + /* Unlink this endpoint, so we can't find it again! */ + sctp_unhash_endpoint(ep); + + /* Cleanup the inqueue. */ + sctp_inqueue_free(&ep->base.inqueue); + + sctp_bind_addr_free(&ep->base.bind_addr); + + /* Remove and free the port */ + if (ep->base.sk->prev != NULL) + sctp_put_port(ep->base.sk); + + /* Give up our hold on the sock. */ + if (ep->base.sk) + sock_put(ep->base.sk); + + /* Finally, free up our memory. */ + if (ep->base.malloced) { + kfree(ep); + SCTP_DBG_OBJCNT_DEC(ep); + } +} + +/* Hold a reference to an endpoint. */ +void sctp_endpoint_hold(sctp_endpoint_t *ep) +{ + atomic_inc(&ep->base.refcnt); +} + +/* Release a reference to an endpoint and clean up if there are + * no more references. + */ +void sctp_endpoint_put(sctp_endpoint_t *ep) +{ + if (atomic_dec_and_test(&ep->base.refcnt)) + sctp_endpoint_destroy(ep); +} + +/* Is this the endpoint we are looking for? */ +sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, + const sockaddr_storage_t *laddr) +{ + sctp_endpoint_t *retval; + + sctp_read_lock(&ep->base.addr_lock); + if (ep->base.bind_addr.port == laddr->v4.sin_port) { + if (sctp_bind_addr_has_addr(&ep->base.bind_addr, laddr)) { + retval = ep; + goto out; + } + } + + retval = NULL; + +out: + sctp_read_unlock(&ep->base.addr_lock); + return retval; +} + +/* Find the association that goes with this chunk. + * We do a linear search of the associations for this endpoint. + * We return the matching transport address too. + */ +sctp_association_t *__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) +{ + int rport; + sctp_association_t *asoc; + list_t *pos; + + rport = paddr->v4.sin_port; + + list_for_each(pos, &endpoint->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + if (rport == asoc->peer.port) { + sctp_read_lock(&asoc->base.addr_lock); + *transport = sctp_assoc_lookup_paddr(asoc, paddr); + sctp_read_unlock(&asoc->base.addr_lock); + + if (*transport) + return asoc; + } + } + + *transport = NULL; + return NULL; +} + +/* Lookup association on an endpoint based on a peer address. BH-safe. */ +sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) +{ + sctp_association_t *asoc; + + sctp_local_bh_disable(); + asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); + sctp_local_bh_enable(); + + return asoc; +} + +/* Do delayed input processing. This is scheduled by sctp_rcv(). + * This may be called on BH or task time. + */ +static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +{ + sctp_association_t *asoc; + struct sock *sk; + sctp_transport_t *transport; + sctp_chunk_t *chunk; + sctp_inqueue_t *inqueue; + sctp_subtype_t subtype; + sctp_state_t state; + int error = 0; + + if (ep->base.dead) + goto out; + + asoc = NULL; + inqueue = &ep->base.inqueue; + sk = ep->base.sk; + + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + subtype.chunk = chunk->chunk_hdr->type; + + /* We might have grown an association since last we + * looked, so try again. + * + * This happens when we've just processed our + * COOKIE-ECHO chunk. + */ + if (NULL == chunk->asoc) { + asoc = sctp_endpoint_lookup_assoc(ep, + sctp_source(chunk), + &transport); + chunk->asoc = asoc; + chunk->transport = transport; + } + + state = asoc ? asoc->state : SCTP_STATE_CLOSED; + + /* Remember where the last DATA chunk came from so we + * know where to send the SACK. + */ + if (asoc && sctp_chunk_is_data(chunk)) + asoc->peer.last_data_from = chunk->transport; + + if (chunk->transport) + chunk->transport->last_time_heard = jiffies; + + /* FIX ME We really would rather NOT have to use + * GFP_ATOMIC. + */ + error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state, + ep, asoc, chunk, GFP_ATOMIC); + + if (error != 0) + goto err_out; + + /* Check to see if the endpoint is freed in response to + * the incoming chunk. If so, get out of the while loop. + */ + if (!sctp_sk(sk)->ep) + goto out; + } + +err_out: + /* Is this the right way to pass errors up to the ULP? */ + if (error) + ep->base.sk->err = -error; + +out: +} + + + + diff -Nru a/net/sctp/hashdriver.c b/net/sctp/hashdriver.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/hashdriver.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,128 @@ +/* SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola + * + * This file origiantes from Randy Stewart's SCTP reference Implementation. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randy Stewart rstewar1@email.mot.com + * Ken Morneau kmorneau@cisco.com + * Qiaobing Xie qxie1@email.mot.com + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorperated into the next SCTP release. + * + * There are still LOTS of bugs in this code... I always run on the motto + * "it is a wonder any code ever works :)" + */ + +#include +#include +#include +#include + +/* SCTP Main driver. + * passing a two pointers and two lengths, + * returning a digest pointer filled. The md5 code + * was taken directly from the RFC (2104) so to understand it + * you may want to go look at the RFC referenced in the + * SCTP spec. We did modify this code to either user OUR + * implementation of SLA1 or the MD5 that comes from its + * RFC. SLA1 may have IPR issues so you need to check in + * to this if you wish to use it... Or at least that is + * what the FIP-180.1 web page says. + */ + +void sctp_hash_digest(const char *key, const int in_key_len, + const char *text, const int text_len, + __u8 *digest) +{ + int key_len = in_key_len; + struct SLA_1_Context context; + + __u8 k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + __u8 k_opad[65]; /* outer padding - + * key XORd with opad + */ + __u8 tk[20]; + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + struct SLA_1_Context tctx; + + SLA1_Init(&tctx); + SLA1_Process(&tctx, key, key_len); + SLA1_Final(&tctx,tk); + key = tk; + key_len = 20; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof k_ipad); + memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner hash */ + SLA1_Init(&context); /* init context for 1st + * pass + */ + SLA1_Process(&context, k_ipad, 64); /* start with inner pad */ + SLA1_Process(&context, text, text_len); /* then text of datagram */ + SLA1_Final(&context,digest); /* finish up 1st pass */ + + /* + * perform outer hash + */ + SLA1_Init(&context); /* init context for 2nd + * pass + */ + SLA1_Process(&context, k_opad, 64); /* start with outer pad */ + SLA1_Process(&context, digest, 20); /* then results of 1st + * hash + */ + SLA1_Final(&context, digest); /* finish up 2nd pass */ +} + diff -Nru a/net/sctp/input.c b/net/sctp/input.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/input.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,662 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions handle all input from the IP layer into SCTP. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Hui Huang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include /* For struct list_head */ +#include +#include +#include /* For struct timeval */ +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static int sctp_rcv_ootb(struct sk_buff *); +sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, + const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp); +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); + +/* Initialize a sockaddr_storage from in incoming skb. + * FIXME: This belongs with AF specific sctp_func_t. --jgrimm + */ +static sockaddr_storage_t *sctp_sockaddr_storage_init(sockaddr_storage_t *addr, + const struct sk_buff *skb, + int is_saddr) +{ + sockaddr_storage_t *ret = NULL; + void *to, *saddr, *daddr; + __u16 *port; + size_t len; + struct sctphdr *sh; + + switch (skb->nh.iph->version) { + case 4: + to = &addr->v4.sin_addr.s_addr; + port = &addr->v4.sin_port; + saddr = &skb->nh.iph->saddr; + daddr = &skb->nh.iph->daddr; + len = sizeof(struct in_addr); + addr->v4.sin_family = AF_INET; + break; + + case 6: + SCTP_V6( + to = &addr->v6.sin6_addr; + port = &addr->v6.sin6_port; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + len = sizeof(struct in6_addr); + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; /* FIXME */ + addr->v6.sin6_scope_id = 0; /* FIXME */ + break; + ) + + default: + goto out; + }; + + sh = (struct sctphdr *) skb->h.raw; + if (is_saddr) { + *port = ntohs(sh->source); + memcpy(to, saddr, len); + } else { + *port = ntohs(sh->dest); + memcpy(to, daddr, len); + } + + ret = addr; +out: + return ret; +} + +/* Calculate the SCTP checksum of an SCTP packet. */ +static inline int sctp_rcv_checksum(struct sk_buff *skb) +{ + struct sctphdr *sh; + __u32 cmp, val; + + sh = (struct sctphdr *) skb->h.raw; + cmp = ntohl(sh->checksum); + val = count_crc((__u8 *)sh, skb->len); + if (val != cmp) { + /* CRC failure, dump it. */ + return -1; + } + return 0; +} + +/* + * This is the routine which IP calls when receiving an SCTP packet. + */ +int sctp_rcv(struct sk_buff *skb) +{ + struct sock *sk; + sctp_association_t *asoc; + sctp_endpoint_t *ep = NULL; + sctp_endpoint_common_t *rcvr; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk; + struct sctphdr *sh; + sockaddr_storage_t src; + sockaddr_storage_t dest; + int ret = 0; + + if (skb->pkt_type!=PACKET_HOST) + goto discard_it; + + sh = (struct sctphdr *) skb->h.raw; + + /* Pull up the IP and SCTP headers. */ + __skb_pull(skb, skb->h.raw - skb->data); + if (skb->len < sizeof(struct sctphdr)) + goto bad_packet; + if (sctp_rcv_checksum(skb) < 0) + goto bad_packet; + + skb_pull(skb, sizeof(struct sctphdr)); + + sctp_sockaddr_storage_init(&src, skb, 1); + sctp_sockaddr_storage_init(&dest, skb, 0); + + /* If the packet is to or from a non-unicast address, + * silently discard the packet. + * + * This is not clearly defined in the RFC except in section + * 8.4 - OOTB handling. However, based on the book "Stream Control + * Transmission Protocol" 2.1, "It is important to note that the + * IP address of an SCTP transport address must be a routable + * unicast address. In other words, IP multicast addresses and + * IP broadcast addresses cannot be used in an SCTP transport + * address." + */ + if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) + goto discard_it; + + asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); + + /* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets. + * An SCTP packet is called an "out of the blue" (OOTB) + * packet if it is correctly formed, i.e., passed the + * receiver's checksum check, but the receiver is not + * able to identify the association to which this + * packet belongs. + */ + if (!asoc) { + ep = __sctp_rcv_lookup_endpoint(&dest); + if (sctp_rcv_ootb(skb)) + goto discard_release; + } + + /* Retrieve the common input handling substructure. */ + rcvr = asoc ? &asoc->base : &ep->base; + sk = rcvr->sk; + + if (!ipsec_sk_policy(sk, skb)) + goto discard_release; + + /* Create an SCTP packet structure. */ + chunk = sctp_chunkify(skb, asoc, sk); + if (!chunk) { + ret = -ENOMEM; + goto discard_release; + } + + /* Remember what endpoint is to handle this packet. */ + chunk->rcvr = rcvr; + + /* Remember the SCTP header. */ + chunk->sctp_hdr = sh; + + /* Set the source address. */ + sctp_init_source(chunk); + + /* Remember where we came from. */ + chunk->transport = transport; + + /* Acquire access to the sock lock. Note: We are safe from other + * bottom halves on this lock, but a user may be in the lock too, + * so check if it is busy. + */ + sctp_bh_lock_sock(sk); + + if (__sctp_sock_busy(sk)) { + sk_add_backlog(sk, (struct sk_buff *) chunk); + } else { + sctp_backlog_rcv(sk, (struct sk_buff *) chunk); + } + + /* Release the sock and any reference counts we took in the + * lookup calls. + */ + sctp_bh_unlock_sock(sk); + if (asoc) { + sctp_association_put(asoc); + } else { + sctp_endpoint_put(ep); + } + sock_put(sk); + return ret; + +bad_packet: +#if 0 /* FIXME */ + SCTP_INC_STATS(SctpInErrs); +#endif /* FIXME*/ + +discard_it: + kfree_skb(skb); + return ret; + +discard_release: + /* Release any structures we may be holding. */ + if (asoc) { + sock_put(asoc->base.sk); + sctp_association_put(asoc); + } else { + sock_put(ep->base.sk); + sctp_endpoint_put(ep); + } + + goto discard_it; +} + +/* Handle second half of inbound skb processing. If the sock was busy, + * we may have need to delay processing until later when the sock is + * released (on the backlog). If not busy, we call this routine + * directly from the bottom half. + */ +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) +{ + sctp_chunk_t *chunk; + sctp_inqueue_t *inqueue; + + /* One day chunk will live inside the skb, but for + * now this works. + */ + chunk = (sctp_chunk_t *) skb; + inqueue = &chunk->rcvr->inqueue; + + sctp_push_inqueue(inqueue, chunk); + return 0; +} + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. If err < 0 then the socket should + * be closed and the error returned to the user. If err > 0 + * it's just the icmp type << 8 | icmp code. After adjustment + * header points to the first 8 bytes of the sctp header. We need + * to find the appropriate port. + * + * The locking strategy used here is very "optimistic". When + * someone else accesses the socket the ICMP is just dropped + * and for some paths there is no check at all. + * A more general error queue to queue errors for later handling + * is probably better. + * + */ +void sctp_v4_err(struct sk_buff *skb, u32 info) +{ + /* This should probably involve a call to SCTPhandleICMP(). */ +} + +/* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets. + * + * This function scans all the chunks in the OOTB packet to determine if + * the packet should be discarded right away. If a response might be needed + * for this packet, or, if further processing is possible, the packet will + * be queued to a proper inqueue for the next phase of handling. + * + * Output: + * Return 0 - If further processing is needed. + * Return 1 - If the packet can be discarded right away. + */ +int sctp_rcv_ootb(struct sk_buff *skb) +{ + sctp_chunkhdr_t *ch; + __u8 *ch_end; + + ch = (sctp_chunkhdr_t *) skb->data; + + /* Scan through all the chunks in the packet. */ + do { + ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); + + /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the + * receiver MUST silently discard the OOTB packet and take no + * further action. + */ + if (SCTP_CID_ABORT == ch->type) + goto discard; + + /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE + * chunk, the receiver should silently discard the packet + * and take no further action. + */ + if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE) + goto discard; + + /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR + * or a COOKIE ACK the SCTP Packet should be silently + * discarded. + */ + if (ch->type == SCTP_CID_COOKIE_ACK) + goto discard; + + if (ch->type == SCTP_CID_ERROR) { + /* FIXME - Need to check the "Stale cookie" ERROR. */ + goto discard; + } + + ch = (sctp_chunkhdr_t *) ch_end; + } while (ch_end < skb->tail); + + return 0; + +discard: + return 1; +} + +/* Insert endpoint into the hash table. */ +void __sctp_hash_endpoint(sctp_endpoint_t *ep) +{ + sctp_endpoint_common_t **epp; + sctp_endpoint_common_t *epb; + sctp_hashbucket_t *head; + + epb = &ep->base; + + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); + head = &sctp_proto.ep_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + epp = &head->chain; + epb->next = *epp; + if (epb->next) + (*epp)->pprev = &epb->next; + *epp = epb; + epb->pprev = epp; + sctp_write_unlock(&head->lock); +} + +/* Add an endpoint to the hash. Local BH-safe. */ +void sctp_hash_endpoint(sctp_endpoint_t *ep) +{ + sctp_local_bh_disable(); + __sctp_hash_endpoint(ep); + sctp_local_bh_enable(); +} + +/* Remove endpoint from the hash table. */ +void __sctp_unhash_endpoint(sctp_endpoint_t *ep) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + + epb = &ep->base; + + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); + + head = &sctp_proto.ep_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + + if (epb->pprev) { + if (epb->next) + epb->next->pprev = epb->pprev; + *epb->pprev = epb->next; + epb->pprev = NULL; + } + + sctp_write_unlock(&head->lock); +} + +/* Remove endpoint from the hash. Local BH-safe. */ +void sctp_unhash_endpoint(sctp_endpoint_t *ep) +{ + sctp_local_bh_disable(); + __sctp_unhash_endpoint(ep); + sctp_local_bh_enable(); +} + +/* Look up an endpoint. */ +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + sctp_endpoint_t *ep; + int hash; + + hash = sctp_ep_hashfn(laddr->v4.sin_port); + head = &sctp_proto.ep_hashbucket[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + ep = sctp_ep(epb); + if (sctp_endpoint_is_match(ep, laddr)) + goto hit; + } + + ep = sctp_sk((sctp_get_ctl_sock()))->ep; + epb = &ep->base; + +hit: + sctp_endpoint_hold(ep); + sock_hold(epb->sk); + read_unlock(&head->lock); + return ep; +} + +/* Add an association to the hash. Local BH-safe. */ +void sctp_hash_established(sctp_association_t *asoc) +{ + sctp_local_bh_disable(); + __sctp_hash_established(asoc); + sctp_local_bh_enable(); +} + +/* Insert association into the hash table. */ +void __sctp_hash_established(sctp_association_t *asoc) +{ + sctp_endpoint_common_t **epp; + sctp_endpoint_common_t *epb; + sctp_hashbucket_t *head; + + epb = &asoc->base; + + /* Calculate which chain this entry will belong to. */ + epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); + + head = &sctp_proto.assoc_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + epp = &head->chain; + epb->next = *epp; + if (epb->next) + (*epp)->pprev = &epb->next; + *epp = epb; + epb->pprev = epp; + sctp_write_unlock(&head->lock); +} + +/* Remove association from the hash table. Local BH-safe. */ +void sctp_unhash_established(sctp_association_t *asoc) +{ + sctp_local_bh_disable(); + __sctp_unhash_established(asoc); + sctp_local_bh_enable(); +} + +/* Remove association from the hash table. */ +void __sctp_unhash_established(sctp_association_t *asoc) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + + epb = &asoc->base; + + epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, + asoc->peer.port); + + head = &sctp_proto.assoc_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + + if (epb->pprev) { + if (epb->next) + epb->next->pprev = epb->pprev; + *epb->pprev = epb->next; + epb->pprev = NULL; + } + + sctp_write_unlock(&head->lock); +} + +/* Look up an association. */ +sctp_association_t *__sctp_rcv_lookup_association(const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + sctp_association_t *asoc; + sctp_transport_t *transport; + int hash; + + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ + hash = sctp_assoc_hashfn(laddr->v4.sin_port, paddr->v4.sin_port); + head = &sctp_proto.assoc_hashbucket[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + asoc = sctp_assoc(epb); + transport = sctp_assoc_is_match(asoc, laddr, paddr); + if (transport) + goto hit; + } + + read_unlock(&head->lock); + + return NULL; + +hit: + *transportp = transport; + sctp_association_hold(asoc); + sock_hold(epb->sk); + read_unlock(&head->lock); + return asoc; +} + +/* + * SCTP Implementors Guide, 2.18 Handling of address + * parameters within the INIT or INIT-ACK. + * + * D) When searching for a matching TCB upon reception of an INIT + * or INIT-ACK chunk the receiver SHOULD use not only the + * source address of the packet (containing the INIT or + * INIT-ACK) but the receiver SHOULD also use all valid + * address parameters contained within the chunk. + * + * 2.18.3 Solution description + * + * This new text clearly specifies to an implementor the need + * to look within the INIT or INIT-ACK. Any implementation that + * does not do this, may not be able to establish associations + * in certain circumstances. + * + */ +static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, + const sockaddr_storage_t *laddr, sctp_transport_t **transportp) +{ + sctp_association_t *asoc; + sockaddr_storage_t addr; + sockaddr_storage_t *paddr = &addr; + struct sctphdr *sh = (struct sctphdr *) skb->h.raw; + sctp_chunkhdr_t *ch; + __u8 *ch_end, *data; + sctpParam_t parm; + + ch = (sctp_chunkhdr_t *) skb->data; + + ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); + + if (SCTP_CID_INIT_ACK != ch->type) + return NULL; + + /* + * This code will NOT touch anything inside the chunk--it is + * strictly READ-ONLY. + * + * RFC 2960 3 SCTP packet Format + * + * Multiple chunks can be bundled into one SCTP packet up to + * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN + * COMPLETE chunks. These chunks MUST NOT be bundled with any + * other chunk in a packet. See Section 6.10 for more details + * on chunk bundling. + */ + + /* Find the start of the TLVs and the end of the chunk. This is + * the region we search for address parameters. + */ + + data = skb->data + sizeof(sctp_init_chunk_t); + + /* See sctp_process_init() for how to go thru TLVs. */ + while (data < ch_end) { + parm.v = data; + + if (!parm.p->length) + break; + + data += WORD_ROUND(ntohs(parm.p->length)); + + /* Note: Ignoring hostname addresses. */ + if ((SCTP_PARAM_IPV4_ADDRESS != parm.p->type) && + (SCTP_PARAM_IPV6_ADDRESS != parm.p->type)) + continue; + + sctp_param2sockaddr(paddr, parm, ntohs(sh->source)); + + asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); + if (asoc) + return asoc; + } + + return NULL; +} + +/* Lookup an association for an inbound skb. */ +sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, + const sockaddr_storage_t *paddr, + const sockaddr_storage_t *laddr, + sctp_transport_t **transportp) +{ + sctp_association_t *asoc; + + asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); + + /* Further lookup for INIT-ACK packet. + * SCTP Implementors Guide, 2.18 Handling of address + * parameters within the INIT or INIT-ACK. + */ + if (!asoc) + asoc = __sctp_rcv_initack_lookup(skb, laddr, transportp); + + return asoc; +} + + + + + diff -Nru a/net/sctp/inqueue.c b/net/sctp/inqueue.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/inqueue.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,199 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2002 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions are the methods for accessing the SCTP inqueue. + * + * An SCTP inqueue is a queue into which you push SCTP packets + * (which might be bundles or fragments of chunks) and out of which you + * pop SCTP whole chunks. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include + +/* Initialize an SCTP_inqueue. */ +void sctp_inqueue_init(sctp_inqueue_t *queue) +{ + skb_queue_head_init(&queue->in); + queue->in_progress = NULL; + + /* Create a task for delivering data. */ + INIT_LIST_HEAD(&queue->immediate.list); + queue->immediate.sync = 0; + queue->immediate.routine = NULL; + queue->immediate.data = NULL; + + queue->malloced = 0; +} + +/* Create an initialized SCTP_inqueue. */ +sctp_inqueue_t *sctp_inqueue_new(void) +{ + sctp_inqueue_t *retval; + + retval = t_new(sctp_inqueue_t, GFP_ATOMIC); + if (retval) { + sctp_inqueue_init(retval); + retval->malloced = 1; + } + return retval; +} + +/* Release the memory associated with an SCTP inqueue. */ +void sctp_inqueue_free(sctp_inqueue_t *queue) +{ + sctp_chunk_t *chunk; + + /* Empty the queue. */ + while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL) + sctp_free_chunk(chunk); + + /* If there is a packet which is currently being worked on, + * free it as well. + */ + if (queue->in_progress) + sctp_free_chunk(queue->in_progress); + + if (queue->malloced) { + /* Dump the master memory segment. */ + kfree(queue); + } +} + +/* Put a new packet in an SCTP inqueue. + * We assume that packet->sctp_hdr is set and in host byte order. + */ +void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) +{ + /* Directly call the packet handling routine. */ + + /* We are now calling this either from the soft interrupt + * or from the backlog processing. + * Eventually, we should clean up inqueue to not rely + * on the BH related data structures. + */ + skb_queue_tail(&(q->in), (struct sk_buff *) packet); + q->immediate.routine(q->immediate.data); +} + +/* Extract a chunk from an SCTP inqueue. + * + * WARNING: If you need to put the chunk on another queue, you need to + * make a shallow copy (clone) of it. + */ +sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue) +{ + sctp_chunk_t *chunk; + sctp_chunkhdr_t *ch = NULL; + + /* The assumption is that we are safe to process the chunks + * at this time. + */ + + if ((chunk = queue->in_progress) != NULL) { + /* There is a packet that we have been working on. + * Any post processing work to do before we move on? + */ + if (chunk->singleton || + chunk->end_of_packet || + chunk->pdiscard) { + sctp_free_chunk(chunk); + chunk = queue->in_progress = NULL; + } else { + /* Nothing to do. Next chunk in the packet, please. */ + ch = (sctp_chunkhdr_t *) chunk->chunk_end; + + /* Force chunk->skb->data to chunk->chunk_end. */ + skb_pull(chunk->skb, + chunk->chunk_end - chunk->skb->data); + } + } + + /* Do we need to take the next packet out of the queue to process? */ + if (!chunk) { + /* Is the queue empty? */ + if (skb_queue_empty(&queue->in)) + return NULL; + + chunk = queue->in_progress = + (sctp_chunk_t *) skb_dequeue(&queue->in); + + /* This is the first chunk in the packet. */ + chunk->singleton = 1; + ch = (sctp_chunkhdr_t *) chunk->skb->data; + } + + chunk->chunk_hdr = ch; + chunk->chunk_end = ((__u8 *) ch) + + WORD_ROUND(ntohs(ch->length)); + skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + chunk->subh.v = NULL; /* Subheader is no longer valid. */ + + if (chunk->chunk_end < chunk->skb->tail) { + /* This is not a singleton */ + chunk->singleton = 0; + } else { + /* We are at the end of the packet, so mark the chunk + * in case we need to send a SACK. + */ + chunk->end_of_packet = 1; + } + + SCTP_DEBUG_PRINTK("+++sctp_pop_inqueue+++ chunk %p[%s]," + " length %d, skb->len %d\n",chunk, + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), + ntohs(chunk->chunk_hdr->length), chunk->skb->len); + return chunk; +} + +/* Set a top-half handler. + * + * Originally, we the top-half handler was scheduled as a BH. We now + * call the handler directly in sctp_push_inqueue() at a time that + * we know we are lock safe. + * The intent is that this routine will pull stuff out of the + * inqueue and process it. + */ +void sctp_inqueue_set_th_handler(sctp_inqueue_t *q, + void (*callback)(void *), void *arg) +{ + q->immediate.routine = callback; + q->immediate.data = arg; +} + diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/ipv6.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,263 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * Copyright (c) 2002 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * SCTP over IPv6. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Le Yanqun + * Hui Huang + * La Monte H.P. Yarroll + * Sridhar Samudrala + * Jon Grimm + * + * Based on: + * linux/net/ipv6/tcp_ipv6.c + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* FIXME: Cleanup so we don't need TEST_FRAME here. */ +#ifndef TEST_FRAME +/* FIXME: Comments. */ +static inline void sctp_v6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + /* BUG. WRITE ME. */ +} + +/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ +static inline int sctp_v6_xmit(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + struct ipv6_pinfo *np = inet6_sk(sk); + struct flowi fl; + struct dst_entry *dst; + struct in6_addr saddr; + int err = 0; + + fl.proto = sk->protocol; + fl.fl6_dst = &np->daddr; + fl.fl6_src = NULL; + + fl.fl6_flowlabel = np->flow_label; + IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); + fl.oif = sk->bound_dev_if; + fl.uli_u.ports.sport = inet_sk(sk)->sport; + fl.uli_u.ports.dport = inet_sk(sk)->dport; + + if (np->opt && np->opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; + fl.nl_u.ip6_u.daddr = rt0->addr; + } + + dst = __sk_dst_check(sk, np->dst_cookie); + + if (dst == NULL) { + dst = ip6_route_output(sk, &fl); + + if (dst->error) { + sk->err_soft = -dst->error; + dst_release(dst); + return -sk->err_soft; + } + ip6_dst_store(sk, dst, NULL); + } + + skb->dst = dst_clone(dst); + + /* FIXME: This is all temporary until real source address + * selection is done. + */ + if (ipv6_addr_any(&np->saddr)) { + err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); + + if (err) + printk(KERN_ERR "sctp_v6_xmit: no saddr available\n"); + + /* FIXME: This is a workaround until we get + * real source address selection done. This is here + * to disallow loopback when the scoping rules have + * not bound loopback to the endpoint. + */ + if (sctp_ipv6_addr_type(&saddr) & IPV6_ADDR_LOOPBACK) { + if (!(sctp_ipv6_addr_type(&np->daddr) & + IPV6_ADDR_LOOPBACK)) { + ipv6_addr_copy(&saddr, &np->daddr); + } + } + fl.fl6_src = &saddr; + } else { + fl.fl6_src = &np->saddr; + } + + /* Restore final destination back after routing done */ + fl.nl_u.ip6_u.daddr = &np->daddr; + + return ip6_xmit(sk, skb, &fl, np->opt); +} +#endif /* TEST_FRAME */ + +/* Returns the mtu for the given v6 destination address. */ +int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) +{ + struct dst_entry *dst; + struct flowi fl; + int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; + + fl.proto = 0; + fl.fl6_dst = (struct in6_addr *)&address->v6.sin6_addr; + fl.fl6_src = NULL; + fl.fl6_flowlabel = 0; + fl.oif = 0; + fl.uli_u.ports.sport = 0; + fl.uli_u.ports.dport = 0; + + dst = ip6_route_output(NULL, &fl); + if (dst) { + dst_mtu = dst->pmtu; + SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " + "ip6_route_output: dev:%s pmtu:%d\n", + dst->dev->name, dst_mtu); + dst_release(dst); + } else { + SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " + "ip6_route_output failed, returning " + "%d as dst_mtu\n", dst_mtu); + } + + return dst_mtu; +} + +static struct proto_ops inet6_seqpacket_ops = { + .family = PF_INET6, + .release = inet6_release, + .bind = inet6_bind, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = inet_accept, + .getname = inet6_getname, + .poll = sctp_poll, + .ioctl = inet6_ioctl, + .listen = sctp_inet_listen, + .shutdown = inet_shutdown, + .setsockopt = inet_setsockopt, + .getsockopt = inet_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, + .mmap = sock_no_mmap, +}; + +static struct inet_protosw sctpv6_protosw = { + .type = SOCK_SEQPACKET, + .protocol = IPPROTO_SCTP, + .prot = &sctp_prot, + .ops = &inet6_seqpacket_ops, + .capability = -1, + .no_check = 0, + .flags = SCTP_PROTOSW_FLAG +}; + +static struct inet6_protocol sctpv6_protocol = { + .handler = sctp_rcv, + .err_handler = sctp_v6_err, + .next = NULL, + .protocol = IPPROTO_SCTP, + .copy = 0, + .data = NULL, + .name = "SCTPv6" +}; + +static sctp_func_t sctp_ipv6_specific = { + .queue_xmit = sctp_v6_xmit, + .setsockopt = ipv6_setsockopt, + .getsockopt = ipv6_getsockopt, + .get_dst_mtu = sctp_v6_get_dst_mtu, + .net_header_len = sizeof(struct ipv6hdr), + .sockaddr_len = sizeof(struct sockaddr_in6), + .sa_family = AF_INET6, +}; + +/* Initialize IPv6 support and register with inet6 stack. */ +int sctp_v6_init(void) +{ + /* Add SCTPv6 to inetsw6 linked list. */ + inet6_register_protosw(&sctpv6_protosw); + + /* Register inet6 protocol. */ + inet6_add_protocol(&sctpv6_protocol); + + /* Fill in address family info. */ + INIT_LIST_HEAD(&sctp_ipv6_specific.list); + list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); + + return 0; +} + +/* IPv6 specific exit support. */ +void sctp_v6_exit(void) +{ + list_del(&sctp_ipv6_specific.list); + inet6_del_protocol(&sctpv6_protocol); + inet6_unregister_protosw(&sctpv6_protosw); +} diff -Nru a/net/sctp/objcnt.c b/net/sctp/objcnt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/objcnt.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,133 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * Support for memory object debugging. This allows one to monitor the + * object allocations/deallocations for types instrumented for this + * via the proc fs. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include + +/* + * Global counters to count raw object allocation counts. + * To add new counters, choose a unique suffix for the variable + * name as the helper macros key off this suffix to make + * life easier for the programmer. + */ + +SCTP_DBG_OBJCNT(sock); +SCTP_DBG_OBJCNT(ep); +SCTP_DBG_OBJCNT(transport); +SCTP_DBG_OBJCNT(assoc); +SCTP_DBG_OBJCNT(bind_addr); +SCTP_DBG_OBJCNT(chunk); +SCTP_DBG_OBJCNT(addr); + +/* An array to make it easy to pretty print the debug information + * to the proc fs. + */ +sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { + SCTP_DBG_OBJCNT_ENTRY(sock), + SCTP_DBG_OBJCNT_ENTRY(ep), + SCTP_DBG_OBJCNT_ENTRY(assoc), + SCTP_DBG_OBJCNT_ENTRY(transport), + SCTP_DBG_OBJCNT_ENTRY(chunk), + SCTP_DBG_OBJCNT_ENTRY(bind_addr), + SCTP_DBG_OBJCNT_ENTRY(addr), +}; + +/* Callback from procfs to read out objcount information. + * Walk through the entries in the sctp_dbg_objcnt array, dumping + * the raw object counts for each monitored type. + * + * This code was modified from similar code in route.c + */ +static int sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + int len = 0; + off_t pos = 0; + int entries; + int i; + char temp[128]; + + /* How many entries? */ + entries = sizeof(sctp_dbg_objcnt)/sizeof(sctp_dbg_objcnt[0]); + + /* Walk the entries and print out the debug information + * for proc fs. + */ + for (i = 0; i < entries; i++) { + pos += 128; + + /* Skip ahead. */ + if (pos <= offset) { + len = 0; + continue; + } + /* Print out each entry. */ + sprintf(temp, "%s: %d", + sctp_dbg_objcnt[i].label, + atomic_read(sctp_dbg_objcnt[i].counter)); + + sprintf(buffer + len, "%-127s\n", temp); + len += 128; + if (pos >= offset+length) + goto done; + } + +done: + *start = buffer + len - (pos - offset); + len = pos - offset; + if (len > length) + len = length; + + return len; +} + +/* Initialize the objcount in the proc filesystem. */ +void sctp_dbg_objcnt_init(void) +{ + create_proc_read_entry("sctp_dbg_objcnt", 0, proc_net_sctp, + sctp_dbg_objcnt_read, NULL); +} + +/* Cleanup the objcount entry in the proc filesystem. */ +void sctp_dbg_objcnt_exit(void) +{ + remove_proc_entry("sctp_dbg_objcount", proc_net_sctp); +} + + diff -Nru a/net/sctp/output.c b/net/sctp/output.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/output.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,558 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions handle output processing. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TEST_FRAME +#include +#endif /* TEST_FRAME (not defined) */ + +#include /* for sa_family_t */ +#include /* For NULL, etc... */ +#include + +#include +#include + +/* Forward declarations for private helpers. */ +__u32 count_crc(__u8 *ptr, __u16 count); +static void sctp_packet_reset(sctp_packet_t *packet); +static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, + sctp_chunk_t *chunk); + +/* Config a packet. + * This appears to be a followup set of initializations.) + */ +sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, + __u32 vtag, + int ecn_capable, + sctp_packet_phandler_t *prepend_handler) +{ + int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + + packet->vtag = vtag; + packet->ecn_capable = ecn_capable; + packet->get_prepend_chunk = prepend_handler; + packet->has_cookie_echo = 0; + + /* We might need to call the prepend_handler right away. */ + if (packet_empty) + sctp_packet_reset(packet); + return packet; +} + +/* Initialize the packet structure. */ +sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, + sctp_transport_t *transport, + __u16 sport, + __u16 dport) +{ + packet->transport = transport; + packet->source_port = sport; + packet->destination_port = dport; + skb_queue_head_init(&packet->chunks); + packet->vtag = 0; + packet->ecn_capable = 0; + packet->get_prepend_chunk = NULL; + packet->has_cookie_echo = 0; + packet->malloced = 0; + sctp_packet_reset(packet); + return packet; +} + +/* Free a packet. */ +void sctp_packet_free(sctp_packet_t *packet) +{ + sctp_chunk_t *chunk; + + while (NULL != + (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) { + sctp_free_chunk(chunk); + } + + if (packet->malloced) + kfree(packet); +} + +/* This routine tries to append the chunk to the offered packet. If adding + * the chunk causes the packet to exceed the path MTU and COOKIE_ECHO chunk + * is not present in the packet, it transmits the input packet. + * Data can be bundled with a packet containing a COOKIE_ECHO chunk as long + * as it can fit in the packet, but any more data that does not fit in this + * packet can be sent only after receiving the COOKIE_ACK. + */ +sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval; + int error = 0; + + switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { + case SCTP_XMIT_PMTU_FULL: + if (!packet->has_cookie_echo) { + error = sctp_packet_transmit(packet); + if (error < 0) + chunk->skb->sk->err = -error; + + /* If we have an empty packet, then we can NOT ever + * return PMTU_FULL. + */ + retval = sctp_packet_append_chunk(packet, chunk); + } + break; + + case SCTP_XMIT_MUST_FRAG: + case SCTP_XMIT_RWND_FULL: + case SCTP_XMIT_OK: + break; + }; + + return retval; +} + +/* Append a chunk to the offered packet reporting back any inability to do + * so. + */ +sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval = SCTP_XMIT_OK; + __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); + size_t psize = packet->size; + size_t pmtu; + int too_big; + + pmtu = ((packet->transport->asoc) ? + (packet->transport->asoc->pmtu) : + (packet->transport->pmtu)); + + too_big = (psize + chunk_len > pmtu); + + /* Decide if we need to fragment or resubmit later. */ + if (too_big) { + int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + + /* Both control chunks and data chunks with TSNs are + * non-fragmentable. + */ + int fragmentable = sctp_chunk_is_data(chunk) + && (!chunk->has_tsn); + if (packet_empty) { + if (fragmentable) { + retval = SCTP_XMIT_MUST_FRAG; + goto finish; + } else { + /* The packet is too big but we can + * not fragment it--we have to just + * transmit and rely on IP + * fragmentation. + */ + goto append; + } + } else { /* !packet_empty */ + retval = SCTP_XMIT_PMTU_FULL; + goto finish; + } + } else { + /* The chunk fits in the packet. */ + goto append; + } + +append: + /* We believe that this chunk is OK to add to the packet (as + * long as we have the cwnd for it). + */ + + /* DATA is a special case since we must examine both rwnd and cwnd + * before we send DATA. + */ + if (sctp_chunk_is_data(chunk)) { + retval = sctp_packet_append_data(packet, chunk); + if (SCTP_XMIT_OK != retval) + goto finish; + } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) { + packet->has_cookie_echo = 1; + } + + /* It is OK to send this chunk. */ + skb_queue_tail(&packet->chunks, + (struct sk_buff *)chunk); + packet->size += chunk_len; + +finish: + return retval; +} + +/* All packets are sent to the network through this function from + * sctp_push_outqueue(). + * + * The return value is a normal kernel error return value. + */ +int sctp_packet_transmit(sctp_packet_t *packet) +{ + sctp_transport_t *transport = packet->transport; + sctp_association_t *asoc = transport->asoc; + struct sctphdr *sh; + __u32 crc32; + struct sk_buff *nskb; + sctp_chunk_t *chunk; + struct sock *sk; + int err = 0; + int padding; /* How much padding do we need? */ + __u8 packet_has_data = 0; + + /* Do NOT generate a chunkless packet... */ + if (skb_queue_empty(&packet->chunks)) + return err; + + /* Set up convenience variables... */ + chunk = (sctp_chunk_t *) (packet->chunks.next); + sk = chunk->skb->sk; + + /* Allocate the new skb. */ + nskb = dev_alloc_skb(packet->size); + if (!nskb) { + err = -ENOMEM; + goto out; + } + + /* Make sure the outbound skb has enough header room reserved. */ + skb_reserve(nskb, SCTP_IP_OVERHEAD); + + /* Set the owning socket so that we know where to get the + * destination IP address. + */ + skb_set_owner_w(nskb, sk); + + /** + * 6.10 Bundling + * + * An endpoint bundles chunks by simply including multiple + * chunks in one outbound SCTP packet. ... + */ + + /** + * 3.2 Chunk Field Descriptions + * + * The total length of a chunk (including Type, Length and + * Value fields) MUST be a multiple of 4 bytes. If the length + * of the chunk is not a multiple of 4 bytes, the sender MUST + * pad the chunk with all zero bytes and this padding is not + * included in the chunk length field. The sender should + * never pad with more than 3 bytes. + * + * [This whole comment explains WORD_ROUND() below.] + */ + SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); + while (NULL != (chunk = (sctp_chunk_t *) + skb_dequeue(&packet->chunks))) { + chunk->num_times_sent++; + chunk->sent_at = jiffies; + if (sctp_chunk_is_data(chunk)) { + sctp_chunk_assign_tsn(chunk); + + /* 6.3.1 C4) When data is in flight and when allowed + * by rule C5, a new RTT measurement MUST be made each + * round trip. Furthermore, new RTT measurements + * SHOULD be made no more than once per round-trip + * for a given destination transport address. + */ + if ((1 == chunk->num_times_sent) && + (!transport->rto_pending)) { + chunk->rtt_in_progress = 1; + transport->rto_pending = 1; + } + packet_has_data = 1; + } + memcpy(skb_put(nskb, chunk->skb->len), + chunk->skb->data, chunk->skb->len); + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; + memset(skb_put(nskb, padding), 0, padding); + SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " + "%s %d\n", + "*** Chunk", chunk, + sctp_cname(SCTP_ST_CHUNK( + chunk->chunk_hdr->type)), + chunk->has_tsn ? "TSN" : "No TSN", + chunk->has_tsn ? + ntohl(chunk->subh.data_hdr->tsn) : 0, + "length", ntohs(chunk->chunk_hdr->length), + "chunk->skb->len", chunk->skb->len, + "num_times_sent", chunk->num_times_sent, + "rtt_in_progress", chunk->rtt_in_progress); + + /* + * If this is a control chunk, this is our last + * reference. Free data chunks after they've been + * acknowledged or have failed. + */ + if (!sctp_chunk_is_data(chunk)) + sctp_free_chunk(chunk); + } + + /* Build the SCTP header. */ + sh = (struct sctphdr *) skb_push(nskb, sizeof(struct sctphdr)); + sh->source = htons(packet->source_port); + sh->dest = htons(packet->destination_port); + + /* From 6.8 Adler-32 Checksum Calculation: + * After the packet is constructed (containing the SCTP common + * header and one or more control or DATA chunks), the + * transmitter shall: + * + * 1) Fill in the proper Verification Tag in the SCTP common + * header and initialize the checksum field to 0's. + */ + sh->vtag = htonl(packet->vtag); + sh->checksum = 0; + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * + * Note: Adler-32 is no longer applicable, as has been replaced + * by CRC32-C as described in . + */ + crc32 = count_crc((__u8 *)sh, nskb->len); + + /* 3) Put the resultant value into the checksum field in the + * common header, and leave the rest of the bits unchanged. + */ + sh->checksum = htonl(crc32); + + switch (transport->ipaddr.sa.sa_family) { + case AF_INET: + inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr; + break; + + case AF_INET6: + SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) + break; + + default: + /* This is bogus address type, just bail. */ + break; + }; + + /* IP layer ECN support + * From RFC 2481 + * "The ECN-Capable Transport (ECT) bit would be set by the + * data sender to indicate that the end-points of the + * transport protocol are ECN-capable." + * + * If ECN capable && negotiated && it makes sense for + * this packet to support it (e.g. post ECN negotiation) + * then lets set the ECT bit + * + * FIXME: Need to do something else for IPv6 + */ + if (packet->ecn_capable) { + INET_ECN_xmit(nskb->sk); + } else { + INET_ECN_dontxmit(nskb->sk); + } + + /* Set up the IP options. */ + /* BUG: not implemented + * For v4 this all lives somewhere in sk->opt... + */ + + /* Dump that on IP! */ + if (asoc && asoc->peer.last_sent_to != transport) { + /* Considering the multiple CPU scenario, this is a + * "correcter" place for last_sent_to. --xguo + */ + asoc->peer.last_sent_to = transport; + } + + /* Hey, before Linux changes, here's what we have to + * do to force IP routing to recognize the change of + * dest addr. --xguo + */ + if (sk->dst_cache) + sk->dst_cache->obsolete = 1; + + if (packet_has_data) { + struct timer_list *timer; + unsigned long timeout; + + transport->last_time_used = jiffies; + + /* Restart the AUTOCLOSE timer when sending data. */ + if ((SCTP_STATE_ESTABLISHED == asoc->state) && + (asoc->autoclose)) { + timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; + timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; + + if (!mod_timer(timer, jiffies + timeout)) + sctp_association_hold(asoc); + } + } + + SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", + nskb->len); + (*transport->af_specific->queue_xmit)(nskb); +out: + packet->size = SCTP_IP_OVERHEAD; + return err; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* + * This private function resets the packet to a fresh state. + */ +static void sctp_packet_reset(sctp_packet_t *packet) +{ + sctp_chunk_t *chunk = NULL; + + packet->size = SCTP_IP_OVERHEAD; + + if (packet->get_prepend_chunk) + chunk = packet->get_prepend_chunk(packet->transport->asoc); + + /* If there a is a prepend chunk stick it on the list before + * any other chunks get appended. + */ + if (chunk) + sctp_packet_append_chunk(packet, chunk); +} + +/* This private function handles the specifics of appending DATA chunks. */ +static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval = SCTP_XMIT_OK; + size_t datasize, rwnd, inflight; + sctp_transport_t *transport = packet->transport; + __u32 max_burst_bytes; + + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * A) At any given time, the data sender MUST NOT transmit new data to + * any destination transport address if its peer's rwnd indicates + * that the peer has no buffer space (i.e. rwnd is 0, see Section + * 6.2.1). However, regardless of the value of rwnd (including if it + * is 0), the data sender can always have one DATA chunk in flight to + * the receiver if allowed by cwnd (see rule B below). This rule + * allows the sender to probe for a change in rwnd that the sender + * missed due to the SACK having been lost in transit from the data + * receiver to the data sender. + */ + + rwnd = transport->asoc->peer.rwnd; + inflight = transport->asoc->outqueue.outstanding_bytes; + + datasize = sctp_data_size(chunk); + + if (datasize > rwnd) { + if (inflight > 0) { + /* We have (at least) one data chunk in flight, + * so we can't fall back to rule 6.1 B). + */ + retval = SCTP_XMIT_RWND_FULL; + goto finish; + } + } + + /* sctpimpguide-05 2.14.2 D) When the time comes for the sender to + * transmit new DATA chunks, the protocol parameter Max.Burst MUST + * first be applied to limit how many new DATA chunks may be sent. + * The limit is applied by adjusting cwnd as follows: + * if((flightsize + Max.Burst*MTU) < cwnd) + * cwnd = flightsize + Max.Burst*MTU + */ + max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu; + if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { + transport->cwnd = transport->flight_size + max_burst_bytes; + SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " + "transport: %p, cwnd: %d, " + "ssthresh: %d, flight_size: %d, " + "pba: %d\n", + __FUNCTION__, transport, + transport->cwnd, + transport->ssthresh, + transport->flight_size, + transport->partial_bytes_acked); + } + + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * B) At any given time, the sender MUST NOT transmit new data + * to a given transport address if it has cwnd or more bytes + * of data outstanding to that transport address. + */ + if (transport->flight_size >= transport->cwnd) { + retval = SCTP_XMIT_RWND_FULL; + goto finish; + } + + /* Keep track of how many bytes are in flight over this transport. */ + transport->flight_size += datasize; + + /* Keep track of how many bytes are in flight to the receiver. */ + transport->asoc->outqueue.outstanding_bytes += datasize; + + /* Update our view of the receiver's rwnd. */ + if (datasize < rwnd) { + rwnd -= datasize; + } else { + rwnd = 0; + } + + transport->asoc->peer.rwnd = rwnd; + +finish: + return retval; +} + + + + diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/outqueue.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,1442 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions implement the outqueue class. The outqueue handles + * bundling and queueing of outgoing SCTP chunks. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Perry Melange + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include /* For struct list_head */ +#include +#include +#include /* For skb_set_owner_w */ + +#include + +/* Declare internal functions here. */ +static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); +static void sctp_check_transmitted(sctp_outqueue_t *q, + struct list_head *transmitted_queue, + sctp_transport_t *transport, + sctp_sackhdr_t *sack); + +/* Generate a new outqueue. */ +sctp_outqueue_t *sctp_outqueue_new(sctp_association_t *asoc) +{ + sctp_outqueue_t *q; + + q = t_new(sctp_outqueue_t, GFP_KERNEL); + if (q) { + sctp_outqueue_init(asoc, q); + q->malloced = 1; + } + return q; +} + +/* Initialize an existing SCTP_outqueue. This does the boring stuff. + * You still need to define handlers if you really want to DO + * something with this structure... + */ +void sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q) +{ + q->asoc = asoc; + skb_queue_head_init(&q->out); + skb_queue_head_init(&q->control); + INIT_LIST_HEAD(&q->retransmit); + INIT_LIST_HEAD(&q->sacked); + + q->init_output = NULL; + q->config_output = NULL; + q->append_output = NULL; + q->build_output = NULL; + q->force_output = NULL; + + q->outstanding_bytes = 0; + q->empty = 1; + + q->malloced = 0; +} + +/* Free the outqueue structure and any related pending chunks. + * FIXME: Add SEND_FAILED support. + */ +void sctp_outqueue_teardown(sctp_outqueue_t *q) +{ + sctp_transport_t *transport; + list_t *lchunk, *pos; + sctp_chunk_t *chunk; + + /* Throw away unacknowledged chunks. */ + list_for_each(pos, &q->asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { + chunk = list_entry(lchunk, sctp_chunk_t, + transmitted_list); + sctp_free_chunk(chunk); + } + } + + /* Throw away any leftover chunks. */ + while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out))) + sctp_free_chunk(chunk); +} + +/* Free the outqueue structure and any related pending chunks. */ +void sctp_outqueue_free(sctp_outqueue_t *q) +{ + /* Throw away leftover chunks. */ + sctp_outqueue_teardown(q); + + /* If we were kmalloc()'d, free the memory. */ + if (q->malloced) + kfree(q); +} + +/* Transmit any pending partial chunks. */ +void sctp_force_outqueue(sctp_outqueue_t *q) +{ + /* Do we really need this? */ + /* BUG */ +} + +/* Put a new chunk in an SCTP_outqueue. */ +int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) +{ + int error = 0; + + SCTP_DEBUG_PRINTK("sctp_push_outqueue(%p, %p[%s])\n", + q, chunk, chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + /* If it is data, queue it up, otherwise, send it + * immediately. + */ + if (SCTP_CID_DATA == chunk->chunk_hdr->type) { + /* Is it OK to queue data chunks? */ + /* From 9. Termination of Association + * + * When either endpoint performs a shutdown, the + * association on each peer will stop accepting new + * data from its user and only deliver data in queue + * at the time of sending or receiving the SHUTDOWN + * chunk. + */ + switch (q->asoc->state) { + case SCTP_STATE_EMPTY: + case SCTP_STATE_CLOSED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_SENT: + case SCTP_STATE_SHUTDOWN_RECEIVED: + case SCTP_STATE_SHUTDOWN_ACK_SENT: + /* Cannot send after transport endpoint shutdown */ + error = -ESHUTDOWN; + break; + + default: + SCTP_DEBUG_PRINTK("outqueueing (%p, %p[%s])\n", + q, chunk, + chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + skb_queue_tail(&q->out, (struct sk_buff *) chunk); + q->empty = 0; + break; + }; + } else { + skb_queue_tail(&q->control, (struct sk_buff *) chunk); + } + if (error < 0) + return error; + + error = sctp_flush_outqueue(q, 0); + + return error; +} + +/* Mark all the eligible packets on a transport for retransmission and force + * one packet out. + */ +void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, + __u8 fast_retransmit) +{ + struct list_head *lchunk; + sctp_chunk_t *chunk; + int error = 0; + struct list_head tlist; + + if (fast_retransmit) { + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); + } else { + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); + } + + INIT_LIST_HEAD(&tlist); + + while (!list_empty(&transport->transmitted)) { + lchunk = sctp_list_dequeue(&transport->transmitted); + chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + + /* If we are doing retransmission due to a fast retransmit, + * only the chunk's that are marked for fast retransmit + * should be added to the retransmit queue. If we are doing + * retransmission due to a timeout, only the chunks that are + * not yet acked should be added to the retransmit queue. + */ + if ((fast_retransmit && !chunk->fast_retransmit) || + (!fast_retransmit && chunk->tsn_gap_acked)) { + list_add_tail(lchunk, &tlist); + } else { + /* RFC 2960 6.2.1 Processing a Received SACK + * + * C) Any time a DATA chunk is marked for + * retransmission (via either T3-rtx timer expiration + * (Section 6.3.3) or via fast retransmit + * (Section 7.2.4)), add the data size of those + * chunks to the rwnd. + */ + q->asoc->peer.rwnd += sctp_data_size(chunk); + q->outstanding_bytes -= sctp_data_size(chunk); + transport->flight_size -= sctp_data_size(chunk); + + /* sctpimpguide-05 Section 2.8.2 + * M5) If a T3-rtx timer expires, the + * 'TSN.Missing.Report' of all affected TSNs is set + * to 0. + */ + chunk->tsn_missing_report = 0; + + /* If a chunk that is being used for RTT measurement + * has to be retransmitted, we cannot use this chunk + * anymore for RTT measurements. Reset rto_pending so + * that a new RTT measurement is started when a new + * data chunk is sent. + */ + if (chunk->rtt_in_progress) { + chunk->rtt_in_progress = 0; + transport->rto_pending = 0; + } + list_add_tail(lchunk, &q->retransmit); + } + } + + /* Reconstruct the transmitted queue with chunks that are not + * eligible for retransmission. + */ + while (NULL != (lchunk = sctp_list_dequeue(&tlist))) + list_add_tail(lchunk, &transport->transmitted); + + SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, " + "cwnd: %d, ssthresh: %d, flight_size: %d, " + "pba: %d\n", __FUNCTION__, + transport, fast_retransmit, + transport->cwnd, transport->ssthresh, + transport->flight_size, + transport->partial_bytes_acked); + + error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); + if (error) + q->asoc->base.sk->err = -error; +} + +/* + * Transmit DATA chunks on the retransmit queue. Upon return from + * sctp_flush_retran_queue() the packet 'pkt' may contain chunks which + * need to be transmitted by the caller. + * We assume that pkt->transport has already been set. + * + * The return value is a normal kernel error return value. + */ +static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, + int rtx_timeout, int *start_timer) +{ + struct list_head *lqueue; + struct list_head *lchunk; + sctp_transport_t *transport = pkt->transport; + sctp_xmit_t status; + sctp_chunk_t *chunk; + sctp_association_t *asoc; + int error = 0; + + asoc = q->asoc; + lqueue = &q->retransmit; + + /* RFC 2960 6.3.3 Handle T3-rtx Expiration + * + * E3) Determine how many of the earliest (i.e., lowest TSN) + * outstanding DATA chunks for the address for which the + * T3-rtx has expired will fit into a single packet, subject + * to the MTU constraint for the path corresponding to the + * destination transport address to which the retransmission + * is being sent (this may be different from the address for + * which the timer expires [see Section 6.4]). Call this value + * K. Bundle and retransmit those K DATA chunks in a single + * packet to the destination endpoint. + * + * [Just to be painfully clear, if we are retransmitting + * because a timeout just happened, we should send only ONE + * packet of retransmitted data.] + */ + lchunk = sctp_list_dequeue(lqueue); + + while (lchunk) { + chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); +#if 0 + /* If a chunk has been tried for more than SCTP_DEF_MAX_SEND + * times, discard it, and check the empty flag of the outqueue. + * + * --xguo + */ + if (chunk->snd_count > SCTP_DEF_MAX_SEND) { + sctp_free_chunk(chunk); + continue; + } +#endif + /* Attempt to append this chunk to the packet. */ + status = (*q->append_output)(pkt, chunk); + + switch (status) { + case SCTP_XMIT_PMTU_FULL: + /* Send this packet. */ + if ((error = (*q->force_output)(pkt)) == 0) + *start_timer = 1; + + /* If we are retransmitting, we should only + * send a single packet. + */ + if (rtx_timeout) { + list_add(lchunk, lqueue); + lchunk = NULL; + } + + /* Bundle lchunk in the next round. */ + break; + + case SCTP_XMIT_RWND_FULL: + /* Send this packet. */ + if ((error = (*q->force_output)(pkt)) == 0) + *start_timer = 1; + + /* Stop sending DATA as there is no more room + * at the reciever. + */ + list_add(lchunk, lqueue); + lchunk = NULL; + break; + + default: + /* The append was successful, so add this chunk to + * the transmitted list. + */ + list_add_tail(lchunk, + &transport->transmitted); + *start_timer = 1; + q->empty = 0; + + /* Retrieve a new chunk to bundle. */ + lchunk = sctp_list_dequeue(lqueue); + break; + }; + } + + return error; +} + +/* This routine either transmits the fragment or puts it on the output + * queue. 'pos' points to the next chunk in the output queue after the + * chunk that is currently in the process of fragmentation. + */ +void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, + sctp_packet_t *packet, + sctp_chunk_t *frag, __u32 tsn) +{ + sctp_transport_t *transport = packet->transport; + struct sk_buff_head *queue = &q->out; + sctp_xmit_t status; + int error; + + frag->subh.data_hdr->tsn = htonl(tsn); + frag->has_tsn = 1; + + /* An inner fragment may be smaller than the earlier one and may get + * in if we call q->build_output. This ensures that all the fragments + * are sent in order. + */ + if (!skb_queue_empty(queue)) { + SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " + "adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *) frag); + } else { + skb_queue_tail(queue, (struct sk_buff *) frag); + } + return; + } + + /* Add the chunk fragment to the packet. */ + status = (*q->build_output)(packet, frag); + switch (status) { + case SCTP_XMIT_RWND_FULL: + /* RWND is full, so put the chunk in the output queue. */ + SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " + "adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *) frag); + } else { + skb_queue_tail(queue, (struct sk_buff *) frag); + } + break; + + case SCTP_XMIT_OK: + error = (*q->force_output)(packet); + if (error < 0) { + /* Packet could not be transmitted, put the chunk in + * the output queue + */ + SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " + "failed. adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *) frag); + } else { + skb_queue_tail(queue, (struct sk_buff *) frag); + } + } else { + SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " + "success. 0x%x sent\n", + ntohl(frag->subh.data_hdr->tsn)); + list_add_tail(&frag->transmitted_list, + &transport->transmitted); + + sctp_transport_reset_timers(transport); + } + break; + + default: + BUG(); + }; +} + +/* This routine calls sctp_xmit_frag() for all the fragments of a message. + * The argument 'frag' point to the first fragment and it holds the list + * of all the other fragments in the 'frag_list' field. + */ +void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, + sctp_chunk_t *frag) +{ + sctp_association_t *asoc = frag->asoc; + struct list_head *lfrag, *frag_list; + __u32 tsn; + int nfrags = 1; + struct sk_buff *pos; + + /* Count the number of fragments. */ + frag_list = &frag->frag_list; + list_for_each(lfrag, frag_list) { + nfrags++; + } + + /* Get a TSN block of nfrags TSNs. */ + tsn = __sctp_association_get_tsn_block(asoc, nfrags); + + pos = skb_peek(&q->out); + /* Transmit the first fragment. */ + sctp_xmit_frag(q, pos, packet, frag, tsn++); + + /* Transmit the rest of fragments. */ + frag_list = &frag->frag_list; + list_for_each(lfrag, frag_list) { + frag = list_entry(lfrag, sctp_chunk_t, frag_list); + sctp_xmit_frag(q, pos, packet, frag, tsn++); + } +} + +/* This routine breaks the given chunk into 'max_frag_data_len' size + * fragments. It returns the first fragment with the frag_list field holding + * the remaining fragments. + */ +sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) +{ + sctp_association_t *asoc = chunk->asoc; + void *data_ptr = chunk->subh.data_hdr; + struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; + __u16 chunk_data_len = sctp_data_size(chunk); + __u16 ssn = ntohs(chunk->subh.data_hdr->ssn); + sctp_chunk_t *first_frag, *frag; + struct list_head *frag_list; + int nfrags; + + /* nfrags = no. of max size fragments + any smaller last fragment. */ + nfrags = ((chunk_data_len / max_frag_data_len) + + ((chunk_data_len % max_frag_data_len) ? 1 : 0)); + + /* Start of the data in the chunk. */ + data_ptr += sizeof(sctp_datahdr_t); + + /* Make the first fragment. */ + first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + data_ptr, SCTP_DATA_FIRST_FRAG, ssn); + + if (!first_frag) + goto err; + + /* All the fragments are added to the frag_list of the first chunk. */ + frag_list = &first_frag->frag_list; + + chunk_data_len -= max_frag_data_len; + data_ptr += max_frag_data_len; + + /* Make the middle fragments. */ + while (chunk_data_len > max_frag_data_len) { + frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); + if (!frag) + goto err; + + /* Add the middle fragment to the first fragment's frag_list. */ + list_add_tail(&frag->frag_list, frag_list); + + chunk_data_len -= max_frag_data_len; + data_ptr += max_frag_data_len; + } + + /* Make the last fragment. */ + frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, + SCTP_DATA_LAST_FRAG, ssn); + if (!frag) + goto err; + + /* Add the last fragment to the first fragment's frag_list. */ + list_add_tail(&frag->frag_list, frag_list); + + /* Free the original chunk. */ + sctp_free_chunk(chunk); + + return first_frag; + +err: + /* Free any fragments that are created before the failure. */ + if (first_frag) { + struct list_head *flist, *lfrag; + + /* Free all the fragments off the first one. */ + flist = &first_frag->frag_list; + while (NULL != (lfrag = sctp_list_dequeue(flist))) { + frag = list_entry(lfrag, sctp_chunk_t, frag_list); + sctp_free_chunk(frag); + } + + /* Free the first fragment. */ + sctp_free_chunk(first_frag); + } + + return NULL; +} + +/* + * sctp_flush_outqueue - Try to flush an outqueue. + * + * Description: Send everything in q which we legally can, subject to + * congestion limitations. + * + * Note: This function can be called from multiple contexts so appropriate + * locking concerns must be made. Today we use the sock lock to protect + * this function. + */ +int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) +{ + sctp_packet_t *packet; + sctp_packet_t singleton; + sctp_association_t *asoc = q->asoc; + int ecn_capable = asoc->peer.ecn_capable; + __u16 sport = asoc->base.bind_addr.port; + __u16 dport = asoc->peer.port; + __u32 vtag = asoc->peer.i.init_tag; + /* This is the ECNE handler for singleton packets. */ + sctp_packet_phandler_t *s_ecne_handler = NULL; + sctp_packet_phandler_t *ecne_handler = NULL; + struct sk_buff_head *queue; + sctp_transport_t *transport = NULL; + sctp_transport_t *new_transport; + sctp_chunk_t *chunk; + sctp_xmit_t status; + int error = 0; + int start_timer = 0; + sctp_ulpevent_t *event; + + /* These transports have chunks to send. */ + struct list_head transport_list; + struct list_head *ltransport; + + INIT_LIST_HEAD(&transport_list); + packet = NULL; + + /* + * 6.10 Bundling + * ... + * When bundling control chunks with DATA chunks, an + * endpoint MUST place control chunks first in the outbound + * SCTP packet. The transmitter MUST transmit DATA chunks + * within a SCTP packet in increasing order of TSN. + * ... + */ + if (ecn_capable) { + s_ecne_handler = &sctp_get_no_prepend; + ecne_handler = &sctp_get_ecne_prepend; + } + + queue = &q->control; + while (NULL != (chunk = (sctp_chunk_t *)skb_dequeue(queue))) { + /* Pick the right transport to use. */ + new_transport = chunk->transport; + + if (!new_transport) { + new_transport = asoc->peer.active_path; + } else if (!new_transport->state.active) { + /* If the chunk is Heartbeat, send it to + * chunk->transport, even it's inactive. + */ + if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) + new_transport = asoc->peer.active_path; + } + + /* Are we switching transports? + * Take care of transport locks. + */ + if (new_transport != transport) { + transport = new_transport; + if (list_empty(&transport->send_ready)) { + list_add_tail(&transport->send_ready, + &transport_list); + } + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + } + + switch (chunk->chunk_hdr->type) { + /* + * 6.10 Bundling + * ... + * An endpoint MUST NOT bundle INIT, INIT ACK or SHUTDOWN + * COMPLETE with any other chunks. [Send them immediately.] + */ + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + (*q->init_output)(&singleton, transport, sport, dport); + (*q->config_output)(&singleton, vtag, ecn_capable, + s_ecne_handler); + (void) (*q->build_output)(&singleton, chunk); + error = (*q->force_output)(&singleton); + if (error < 0) + return(error); + break; + + case SCTP_CID_ABORT: + case SCTP_CID_SACK: + case SCTP_CID_HEARTBEAT: + case SCTP_CID_HEARTBEAT_ACK: + case SCTP_CID_SHUTDOWN: + case SCTP_CID_SHUTDOWN_ACK: + case SCTP_CID_ERROR: + case SCTP_CID_COOKIE_ECHO: + case SCTP_CID_COOKIE_ACK: + case SCTP_CID_ECN_ECNE: + case SCTP_CID_ECN_CWR: + (void) (*q->build_output)(packet, chunk); + break; + + case SCTP_CID_ASCONF: + case SCTP_CID_ASCONF_ACK: + (void) (*q->build_output)(packet, chunk); + break; + + default: + /* We built a chunk with an illegal type! */ + BUG(); + }; + } + + /* Is it OK to send data chunks? */ + switch (asoc->state) { + case SCTP_STATE_COOKIE_ECHOED: + /* Only allow bundling, if this packet has a COOKIE-ECHO + * chunk. + */ + if (packet && !packet->has_cookie_echo) + break; + + /* fallthru */ + case SCTP_STATE_ESTABLISHED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_RECEIVED: + /* + * RFC 2960 6.1 Transmission of DATA Chunks + * + * C) When the time comes for the sender to transmit, + * before sending new DATA chunks, the sender MUST + * first transmit any outstanding DATA chunks which + * are marked for retransmission (limited by the + * current cwnd). + */ + if (!list_empty(&q->retransmit)) { + if (transport == asoc->peer.retran_path) + goto retran; + + /* Switch transports & prepare the packet. */ + + transport = asoc->peer.retran_path; + + if (list_empty(&transport->send_ready)) { + list_add_tail(&transport->send_ready, + &transport_list); + } + + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + retran: + error = sctp_flush_retran_queue(q, + packet, + rtx_timeout, + &start_timer); + + if (start_timer) + sctp_transport_reset_timers(transport); + } + + /* Finally, transmit new packets. */ + start_timer = 0; + queue = &q->out; + while (NULL != (chunk = (sctp_chunk_t *) skb_dequeue(queue))) { + /* RFC 2960 6.5 Every DATA chunk MUST carry a valid + * stream identifier. + */ + if (chunk->sinfo.sinfo_stream >= + asoc->c.sinit_num_ostreams) { + /* Generate a SEND FAILED event. */ + event = sctp_ulpevent_make_send_failed(asoc, + chunk, SCTP_DATA_UNSENT, + SCTP_ERROR_INV_STRM, + GFP_ATOMIC); + if (event) { + sctp_ulpqueue_tail_event(&asoc->ulpq, + event); + } + + /* Free the chunk. This chunk is not on any + * list yet, just free it. + */ + sctp_free_chunk(chunk); + continue; + } + + /* If there is a specified transport, use it. + * Otherwise, we want to use the active path. + */ + new_transport = chunk->transport; + if (new_transport == NULL || + !new_transport->state.active) + new_transport = asoc->peer.active_path; + + /* Change packets if necessary. */ + if (new_transport != transport) { + transport = new_transport; + + /* Schedule to have this transport's + * packet flushed. + */ + if (list_empty(&transport->send_ready)) { + list_add_tail(&transport->send_ready, + &transport_list); + } + + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + } + + SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ", + q, chunk, + chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK( + chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + 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 ? + atomic_read(&chunk->skb->users) : + -1); + + /* Add the chunk to the packet. */ + status = (*q->build_output)(packet, chunk); + + switch (status) { + case SCTP_XMIT_PMTU_FULL: + case SCTP_XMIT_RWND_FULL: + /* We could not append this chunk, so put + * the chunk back on the output queue. + */ + SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could" + "not transmit TSN: 0x%x, status: %d\n", + ntohl(chunk->subh.data_hdr->tsn), status); + skb_queue_head(queue, (struct sk_buff *)chunk); + goto sctp_flush_out; + break; + + case SCTP_XMIT_MUST_FRAG: { + sctp_chunk_t *frag; + + frag = sctp_fragment_chunk(chunk, + packet->transport->asoc->frag_point); + if (!frag) { + /* We could not fragment due to out of + * memory condition. Free the original + * chunk and return ENOMEM. + */ + sctp_free_chunk(chunk); + error = -ENOMEM; + return error; + } + + sctp_xmit_fragmented_chunks(q, packet, frag); + goto sctp_flush_out; + break; + } + + case SCTP_XMIT_OK: + break; + + default: + BUG(); + }; + + /* BUG: We assume that the (*q->force_output()) + * call below will succeed all the time and add the + * chunk to the transmitted list and restart the + * timers. + * It is possible that the call can fail under OOM + * conditions. + * + * Is this really a problem? Won't this behave + * like a lost TSN? + */ + list_add_tail(&chunk->transmitted_list, + &transport->transmitted); + + sctp_transport_reset_timers(transport); + + q->empty = 0; + } + break; + + default: + /* Do nothing. */ + break; + }; + +sctp_flush_out: + /* Before returning, examine all the transports touched in + * this call. Right now, we bluntly force clear all the + * transports. Things might change after we implement Nagle. + * But such an examination is still required. + * + * --xguo + */ + while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { + sctp_transport_t *t = list_entry(ltransport, + sctp_transport_t, send_ready); + if (t != transport) + transport = t; + + packet = &transport->packet; + if (packet->size != SCTP_IP_OVERHEAD) + error = (*q->force_output)(packet); + } + + return error; +} + +/* Set the various output handling callbacks. */ +int sctp_outqueue_set_output_handlers(sctp_outqueue_t *q, + sctp_outqueue_ohandler_init_t init, + sctp_outqueue_ohandler_config_t config, + sctp_outqueue_ohandler_t append, + sctp_outqueue_ohandler_t build, + sctp_outqueue_ohandler_force_t force) +{ + q->init_output = init; + q->config_output = config; + q->append_output = append; + q->build_output = build; + q->force_output = force; + return 0; +} + +/* Update unack_data based on the incoming SACK chunk */ +static void sctp_sack_update_unack_data(sctp_association_t *assoc, + sctp_sackhdr_t *sack) +{ + sctp_sack_variable_t *frags; + __u16 unack_data; + int i; + + unack_data = assoc->next_tsn - assoc->ctsn_ack_point - 1; + + frags = sack->variable; + for (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) { + unack_data -= ((ntohs(frags[i].gab.end) - + ntohs(frags[i].gab.start) + 1)); + } + + assoc->unack_data = unack_data; +} + +/* This is where we REALLY process a SACK. + * + * Process the sack against the outqueue. Mostly, this just frees + * things off the transmitted queue. + */ +int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) +{ + sctp_chunk_t *tchunk; + list_t *lchunk, *transport_list, *pos; + __u32 tsn; + __u32 sack_ctsn; + __u32 ctsn; + sctp_transport_t *transport; + int outstanding; + __u32 sack_a_rwnd; + + /* Grab the association's destination address list. */ + transport_list = &q->asoc->peer.transport_addr_list; + + /* Run through the retransmit queue. Credit bytes received + * and free those chunks that we can. + */ + sctp_check_transmitted(q, &q->retransmit, NULL, sack); + + /* Run through the transmitted queue. + * Credit bytes received and free those chunks which we can. + * + * This is a MASSIVE candidate for optimization. + */ + list_for_each(pos, transport_list) { + transport = list_entry(pos, sctp_transport_t, transports); + sctp_check_transmitted(q, &transport->transmitted, + transport, sack); + } + + /* Move the Cumulative TSN Ack Point if appropriate. */ + sack_ctsn = ntohl(sack->cum_tsn_ack); + if (TSN_lt(q->asoc->ctsn_ack_point, sack_ctsn)) + q->asoc->ctsn_ack_point = sack_ctsn; + + /* Update unack_data field in the assoc. */ + sctp_sack_update_unack_data(q->asoc, sack); + + ctsn = q->asoc->ctsn_ack_point; + + SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", + __FUNCTION__, + sack_ctsn); + SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association " + "%p is 0x%x.\n", __FUNCTION__, q->asoc, ctsn); + + /* Throw away stuff rotting on the sack queue. */ + list_for_each(lchunk, &q->sacked) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + if (TSN_lte(tsn, ctsn)) { + lchunk = lchunk->prev; + sctp_free_chunk(tchunk); + } + } + + /* ii) Set rwnd equal to the newly received a_rwnd minus the + * number of bytes still outstanding after processing the + * Cumulative TSN Ack and the Gap Ack Blocks. + */ + + sack_a_rwnd = ntohl(sack->a_rwnd); + outstanding = q->outstanding_bytes; + + if (outstanding < sack_a_rwnd) { + sack_a_rwnd -= outstanding; + } else { + sack_a_rwnd = 0; + } + + q->asoc->peer.rwnd = sack_a_rwnd; + + /* See if all chunks are acked. + * Make sure the empty queue handler will get run later. + */ + q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit); + if (!q->empty) + goto finish; + + list_for_each(pos, transport_list) { + transport = list_entry(pos, sctp_transport_t, transports); + q->empty = q->empty && list_empty(&transport->transmitted); + if (!q->empty) + goto finish; + } + + SCTP_DEBUG_PRINTK("sack queue is empty.\n"); +finish: + return q->empty; +} + +/* Is the outqueue empty? */ +int sctp_outqueue_is_empty(const sctp_outqueue_t *q) +{ + return q->empty; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Go through a transport's transmitted list or the assocication's retransmit + * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. + * The retransmit list will not have an associated transport. In case of a + * transmitted list with a transport, the transport's congestion, rto and fast + * retransmit parameters are also updated and if needed a fast retransmit + * process is started. + * + * I added coherent debug information output. --xguo + * + * Instead of printing 'sacked' or 'kept' for each TSN on the + * transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5. + * KEPT TSN6-TSN7, etc. + */ +static void sctp_check_transmitted(sctp_outqueue_t *q, + struct list_head *transmitted_queue, + sctp_transport_t *transport, + sctp_sackhdr_t *sack) +{ + struct list_head *lchunk; + sctp_chunk_t *tchunk; + struct list_head tlist; + __u32 tsn; + __u32 sack_ctsn; + __u32 rtt; + __u32 highest_new_tsn_in_sack; + __u8 restart_timer = 0; + __u8 do_fast_retransmit = 0; + int bytes_acked = 0; + + /* These state variables are for coherent debug output. --xguo */ + +#if SCTP_DEBUG + __u32 dbg_ack_tsn = 0; /* An ACKed TSN range starts here... */ + __u32 dbg_last_ack_tsn = 0; /* ...and finishes here. */ + __u32 dbg_kept_tsn = 0; /* An un-ACKed range starts here... */ + __u32 dbg_last_kept_tsn = 0; /* ...and finishes here. */ + + /* 0 : The last TSN was ACKed. + * 1 : The last TSN was NOT ACKed (i.e. KEPT). + * -1: We need to initialize. + */ + int dbg_prt_state = -1; +#endif /* SCTP_DEBUG */ + + sack_ctsn = ntohl(sack->cum_tsn_ack); + highest_new_tsn_in_sack = sack_ctsn; + + INIT_LIST_HEAD(&tlist); + + /* The while loop will skip empty transmitted queues. */ + while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + + tsn = ntohl(tchunk->subh.data_hdr->tsn); + if (sctp_acked(sack, tsn)) { + /* If this queue is the retransmit queue, the + * retransmit timer has already reclaimed + * the outstanding bytes for this chunk, so only + * count bytes associated with a transport. + */ + if (transport) { + /* If this chunk is being used for RTT + * measurement, calculate the RTT and update + * the RTO using this value. + * + * 6.3.1 C5) Karn's algorithm: RTT measurements + * MUST NOT be made using packets that were + * retransmitted (and thus for which it is + * ambiguous whether the reply was for the first + * instance of the packet or a later instance). + */ + if ((!tchunk->tsn_gap_acked) && + (1 == tchunk->num_times_sent) && + (tchunk->rtt_in_progress)) { + rtt = jiffies - tchunk->sent_at; + sctp_transport_update_rto(transport, + rtt); + } + } + if (TSN_lte(tsn, sack_ctsn)) { + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R3) Whenever a SACK is received + * that acknowledges the DATA chunk + * with the earliest outstanding TSN + * for that address, restart T3-rtx + * timer for that address with its + * current RTO. + */ + restart_timer = 1; + + if (!tchunk->tsn_gap_acked) { + tchunk->tsn_gap_acked = 1; + bytes_acked += sctp_data_size(tchunk); + } + + list_add_tail(&tchunk->transmitted_list, + &q->sacked); + } else { + /* RFC2960 7.2.4, sctpimpguide-05 2.8.2 + * M2) Each time a SACK arrives reporting + * 'Stray DATA chunk(s)' record the highest TSN + * reported as newly acknowledged, call this + * value 'HighestTSNinSack'. A newly + * acknowledged DATA chunk is one not previously + * acknowledged in a SACK. + * + * When the SCTP sender of data receives a SACK + * chunk that acknowledges, for the first time, + * the receipt of a DATA chunk, all the still + * unacknowledged DATA chunks whose TSN is older + * than that newly acknowledged DATA chunk, are + * qualified as 'Stray DATA chunks'. + */ + if (!tchunk->tsn_gap_acked) { + tchunk->tsn_gap_acked = 1; + bytes_acked += sctp_data_size(tchunk); + if (TSN_lt(highest_new_tsn_in_sack, + tsn)) { + highest_new_tsn_in_sack = tsn; + } + } + list_add_tail(lchunk, &tlist); + } + +#if SCTP_DEBUG + switch (dbg_prt_state) { + case 0: /* last TSN was ACKed */ + if (dbg_last_ack_tsn + 1 == tsn) { + /* This TSN belongs to the + * current ACK range. + */ + break; + } + + if (dbg_last_ack_tsn != dbg_ack_tsn) { + /* Display the end of the + * current range. + */ + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_ack_tsn); + } + + /* Start a new range. */ + SCTP_DEBUG_PRINTK(",%08x", tsn); + dbg_ack_tsn = tsn; + break; + + case 1: /* The last TSN was NOT ACKed. */ + if (dbg_last_kept_tsn != dbg_kept_tsn) { + /* Display the end of current range. */ + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_kept_tsn); + } + + SCTP_DEBUG_PRINTK("\n"); + + /* FALL THROUGH... */ + default: + /* This is the first-ever TSN we examined. */ + /* Start a new range of ACK-ed TSNs. */ + SCTP_DEBUG_PRINTK("ACKed: %08x", tsn); + dbg_prt_state = 0; + dbg_ack_tsn = tsn; + }; + + dbg_last_ack_tsn = tsn; +#endif /* SCTP_DEBUG */ + + } else { + if (tchunk->tsn_gap_acked) { + SCTP_DEBUG_PRINTK("%s: Receiver reneged on data " + "TSN: 0x%x\n", + __FUNCTION__, + tsn); + tchunk->tsn_gap_acked = 0; + + bytes_acked -= sctp_data_size(tchunk); + + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R4) Whenever a SACK is received missing a TSN + * that was previously acknowledged via a Gap Ack + * Block, start T3-rtx for the destination + * address to which the DATA chunk was originally + * transmitted if it is not already running. + */ + restart_timer = 1; + } + + list_add_tail(lchunk, &tlist); + +#if SCTP_DEBUG + /* See the above comments on ACK-ed TSNs. */ + switch (dbg_prt_state) { + case 1: + if (dbg_last_kept_tsn + 1 == tsn) + break; + + if (dbg_last_kept_tsn != dbg_kept_tsn) + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_kept_tsn); + + SCTP_DEBUG_PRINTK(",%08x", tsn); + dbg_kept_tsn = tsn; + break; + + case 0: + if (dbg_last_ack_tsn != dbg_ack_tsn) + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_ack_tsn); + SCTP_DEBUG_PRINTK("\n"); + + /* FALL THROUGH... */ + default: + SCTP_DEBUG_PRINTK("KEPT: %08x",tsn); + dbg_prt_state = 1; + dbg_kept_tsn = tsn; + }; + + dbg_last_kept_tsn = tsn; +#endif /* SCTP_DEBUG */ + } + } + +#if SCTP_DEBUG + /* Finish off the last range, displaying its ending TSN. */ + switch (dbg_prt_state) { + case 0: + if (dbg_last_ack_tsn != dbg_ack_tsn) { + SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_ack_tsn); + } else { + SCTP_DEBUG_PRINTK("\n"); + } + break; + + case 1: + if (dbg_last_kept_tsn != dbg_kept_tsn) { + SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_kept_tsn); + } else { + SCTP_DEBUG_PRINTK("\n"); + } + }; +#endif /* SCTP_DEBUG */ + if (transport) { + if (bytes_acked) { + /* 8.2. When an outstanding TSN is acknowledged, + * the endpoint shall clear the error counter of + * the destination transport address to which the + * DATA chunk was last sent. + * The association's overall error counter is + * also cleared. + */ + transport->error_count = 0; + transport->asoc->overall_error_count = 0; + + /* Mark the destination transport address as + * active if it is not so marked. + */ + if (!transport->state.active) { + sctp_assoc_control_transport(transport->asoc, + transport, + SCTP_TRANSPORT_UP, + SCTP_RECEIVED_SACK); + } + + sctp_transport_raise_cwnd(transport, sack_ctsn, + bytes_acked); + + transport->flight_size -= bytes_acked; + q->outstanding_bytes -= bytes_acked; + } else { + /* RFC 2960 6.1, sctpimpguide-06 2.15.2 + * When a sender is doing zero window probing, it + * should not timeout the association if it continues + * to receive new packets from the receiver. The + * reason is that the receiver MAY keep its window + * closed for an indefinite time. + * A sender is doing zero window probing when the + * receiver's advertised window is zero, and there is + * only one data chunk in flight to the receiver. + */ + if ((0 == q->asoc->peer.rwnd) && + (!list_empty(&tlist)) && + (sack_ctsn+2 == q->asoc->next_tsn)) { + SCTP_DEBUG_PRINTK("%s: SACK received for zero " + "window probe: %u\n", + __FUNCTION__, sack_ctsn); + q->asoc->overall_error_count = 0; + transport->error_count = 0; + } + } + + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R2) Whenever all outstanding data sent to an address have + * been acknowledged, turn off the T3-rtx timer of that + * address. + */ + if (!transport->flight_size) { + if (timer_pending(&transport->T3_rtx_timer) && + del_timer(&transport->T3_rtx_timer)) { + sctp_transport_put(transport); + } + } else if (restart_timer) { + if (!mod_timer(&transport->T3_rtx_timer, + jiffies + transport->rto)) + sctp_transport_hold(transport); + } + } + + /* Reconstruct the transmitted list with chunks that are not yet + * acked by the Cumulative TSN Ack. + */ + while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + + /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all + * 'Unacknowledged TSN's', if the TSN number of an + * 'Unacknowledged TSN' is smaller than the 'HighestTSNinSack' + * value, increment the 'TSN.Missing.Report' count on that + * chunk if it has NOT been fast retransmitted or marked for + * fast retransmit already. + * + * M4) If any DATA chunk is found to have a + * 'TSN.Missing.Report' + * value larger than or equal to 4, mark that chunk for + * retransmission and start the fast retransmit procedure. + */ + if ((!tchunk->fast_retransmit) && + (!tchunk->tsn_gap_acked) && + (TSN_lt(tsn, highest_new_tsn_in_sack))) { + tchunk->tsn_missing_report++; + SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", + __FUNCTION__, tsn, + tchunk->tsn_missing_report); + } + if (tchunk->tsn_missing_report >= 4) { + tchunk->fast_retransmit = 1; + do_fast_retransmit = 1; + } + + list_add_tail(lchunk, transmitted_queue); + } + + if (transport) { + if (do_fast_retransmit) + sctp_retransmit(q, transport, do_fast_retransmit); + + SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " + "ssthresh: %d, flight_size: %d, pba: %d\n", + __FUNCTION__, + transport, transport->cwnd, + transport->ssthresh, transport->flight_size, + transport->partial_bytes_acked); + } +} + +/* Is the given TSN acked by this packet? */ +static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) +{ + int i; + sctp_sack_variable_t *frags; + __u16 gap; + __u32 ctsn = ntohl(sack->cum_tsn_ack); + + if (TSN_lte(tsn, ctsn)) + goto pass; + + /* 3.3.4 Selective Acknowledgement (SACK) (3): + * + * Gap Ack Blocks: + * These fields contain the Gap Ack Blocks. They are repeated + * for each Gap Ack Block up to the number of Gap Ack Blocks + * defined in the Number of Gap Ack Blocks field. All DATA + * chunks with TSNs greater than or equal to (Cumulative TSN + * Ack + Gap Ack Block Start) and less than or equal to + * (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack + * Block are assumed to have been received correctly. + */ + + frags = sack->variable; + gap = tsn - ctsn; + for (i = 0; i < ntohs(sack->num_gap_ack_blocks); ++i) { + if (TSN_lte(ntohs(frags[i].gab.start), gap) && + TSN_lte(gap, ntohs(frags[i].gab.end))) + goto pass; + } + + return 0; +pass: + return 1; +} diff -Nru a/net/sctp/primitive.c b/net/sctp/primitive.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/primitive.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,202 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions implement the SCTP primitive functions from Section 10. + * + * Note that the descriptions from the specification are USER level + * functions--this file is the functions which populate the struct proto + * for SCTP which is the BOTTOM of the sockets interface. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Narasimha Budihal + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include /* For struct list_head */ +#include +#include +#include /* For struct timeval */ +#include +#include +#include + +#define DECLARE_PRIMITIVE(name) \ +/* This is called in the code as sctp_primitive_ ## name. */ \ +int sctp_primitive_ ## name(sctp_association_t *asoc, \ + void *arg) { \ + int error = 0; \ + sctp_event_t event_type; sctp_subtype_t subtype; \ + sctp_state_t state; \ + sctp_endpoint_t *ep; \ + \ + event_type = SCTP_EVENT_T_PRIMITIVE; \ + subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ + state = asoc ? asoc->state : SCTP_STATE_CLOSED; \ + ep = asoc ? asoc->ep : NULL; \ + \ + error = sctp_do_sm(event_type, subtype, state, ep, asoc, \ + arg, GFP_KERNEL); \ + return error; \ +} + +/* 10.1 ULP-to-SCTP + * B) Associate + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) + * -> association id [,destination transport addr list] [,outbound stream + * count] + * + * This primitive allows the upper layer to initiate an association to a + * specific peer endpoint. + * + * This version assumes that asoc is fully populated with the initial + * parameters. We then return a traditional kernel indicator of + * success or failure. + */ + +/* This is called in the code as sctp_primitive_ASSOCIATE. */ + +DECLARE_PRIMITIVE(ASSOCIATE) + +/* 10.1 ULP-to-SCTP + * C) Shutdown + * + * Format: SHUTDOWN(association id) + * -> result + * + * Gracefully closes an association. Any locally queued user data + * will be delivered to the peer. The association will be terminated only + * after the peer acknowledges all the SCTP packets sent. A success code + * will be returned on successful termination of the association. If + * attempting to terminate the association results in a failure, an error + * code shall be returned. + */ + +DECLARE_PRIMITIVE(SHUTDOWN); + +/* 10.1 ULP-to-SCTP + * C) Abort + * + * Format: Abort(association id [, cause code]) + * -> result + * + * Ungracefully closes an association. Any locally queued user data + * will be discarded and an ABORT chunk is sent to the peer. A success + * code will be returned on successful abortion of the association. If + * attempting to abort the association results in a failure, an error + * code shall be returned. + */ + +DECLARE_PRIMITIVE(ABORT); + +/* 10.1 ULP-to-SCTP + * E) Send + * + * Format: SEND(association id, buffer address, byte count [,context] + * [,stream id] [,life time] [,destination transport address] + * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) + * -> result + * + * This is the main method to send user data via SCTP. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o buffer address - the location where the user message to be + * transmitted is stored; + * + * o byte count - The size of the user data in number of bytes; + * + * Optional attributes: + * + * o context - an optional 32 bit integer that will be carried in the + * sending failure notification to the ULP if the transportation of + * this User Message fails. + * + * o stream id - to indicate which stream to send the data on. If not + * specified, stream 0 will be used. + * + * o life time - specifies the life time of the user data. The user data + * will not be sent by SCTP after the life time expires. This + * parameter can be used to avoid efforts to transmit stale + * user messages. SCTP notifies the ULP if the data cannot be + * initiated to transport (i.e. sent to the destination via SCTP's + * send primitive) within the life time variable. However, the + * user data will be transmitted if SCTP has attempted to transmit a + * chunk before the life time expired. + * + * o destination transport address - specified as one of the destination + * transport addresses of the peer endpoint to which this packet + * should be sent. Whenever possible, SCTP should use this destination + * transport address for sending the packets, instead of the current + * primary path. + * + * o unorder flag - this flag, if present, indicates that the user + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * message). + * + * o no-bundle flag - instructs SCTP not to bundle this user data with + * other outbound DATA chunks. SCTP MAY still bundle even when + * this flag is present, when faced with network congestion. + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data + * being transmitted. This value is passed as opaque data by SCTP. + */ + +DECLARE_PRIMITIVE(SEND); + +/* COMMENT BUG. Find out where this is mentioned in the spec. */ +int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) +{ + int error = 0; + sctp_event_t event_type; + sctp_subtype_t subtype; + sctp_state_t state; + sctp_endpoint_t *ep; + + event_type = SCTP_EVENT_T_OTHER; + subtype = SCTP_ST_OTHER(SCTP_EVENT_ICMP_UNREACHFRAG); + state = asoc ? asoc->state : SCTP_STATE_CLOSED; + ep = asoc ? asoc->ep : NULL; + + error = sctp_do_sm(event_type, subtype, state, ep, + asoc, arg, GFP_ATOMIC); + + return error; +} diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/protocol.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,591 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * Initialization/cleanup for SCTP protocol support. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global data structures. */ +sctp_protocol_t sctp_proto; +struct proc_dir_entry *proc_net_sctp; + +/* This is the global socket data structure used for responding to + * the Out-of-the-blue (OOTB) packets. A control sock will be created + * for this socket at the initialization time. + */ +static struct socket *sctp_ctl_socket; + +extern struct net_proto_family inet_family_ops; + +/* Return the address of the control sock. */ +struct sock *sctp_get_ctl_sock(void) +{ + return sctp_ctl_socket->sk; +} + +/* Set up the proc fs entry for the SCTP protocol. */ +void sctp_proc_init(void) +{ + if (!proc_net_sctp) { + struct proc_dir_entry *ent; + ent = proc_mkdir("net/sctp", 0); + if (ent) { + ent->owner = THIS_MODULE; + proc_net_sctp = ent; + } + } +} + +/* Clean up the proc fs entry for the SCTP protocol. */ +void sctp_proc_exit(void) +{ + if (proc_net_sctp) { + proc_net_sctp= NULL; + remove_proc_entry("net/sctp", 0); + } +} + +/* Private helper to extract ipv4 address and stash them in + * the protocol structure. + */ +static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, + struct net_device *dev) +{ + struct in_device *in_dev; + struct in_ifaddr *ifa; + struct sockaddr_storage_list *addr; + + read_lock(&inetdev_lock); + if ((in_dev = __in_dev_get(dev)) == NULL) { + read_unlock(&inetdev_lock); + return; + } + + read_lock(&in_dev->lock); + + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + /* Add the address to the local list. */ + /* XXX BUG: sleeping allocation with lock held -DaveM */ + addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); + if (addr) { + INIT_LIST_HEAD(&addr->list); + addr->a.v4.sin_family = AF_INET; + addr->a.v4.sin_port = 0; + addr->a.v4.sin_addr.s_addr = ifa->ifa_local; + list_add_tail(&addr->list, &proto->local_addr_list); + } + } + + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); +} + +/* Private helper to extract ipv6 address and stash them in + * the protocol structure. + * FIXME: Make this an address family function. + */ +static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) +{ +#ifdef SCTP_V6_SUPPORT + /* FIXME: The testframe doesn't support this function. */ +#ifndef TEST_FRAME + struct inet6_dev *in6_dev; + struct inet6_ifaddr *ifp; + struct sockaddr_storage_list *addr; + + read_lock(&addrconf_lock); + if ((in6_dev = __in6_dev_get(dev)) == NULL) { + read_unlock(&addrconf_lock); + return; + } + + read_lock_bh(&in6_dev->lock); + for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { + /* Add the address to the local list. */ + /* XXX BUG: sleeping allocation with lock held -DaveM */ + addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); + if (addr) { + addr->a.v6.sin6_family = AF_INET6; + addr->a.v6.sin6_port = 0; + addr->a.v6.sin6_addr = ifp->addr; + INIT_LIST_HEAD(&addr->list); + list_add_tail(&addr->list, &proto->local_addr_list); + } + } + + read_unlock_bh(&in6_dev->lock); + read_unlock(&addrconf_lock); +#endif /* TEST_FRAME */ +#endif /* SCTP_V6_SUPPORT */ +} + +/* Extract our IP addresses from the system and stash them in the + * protocol structure. + */ +static void __sctp_get_local_addr_list(sctp_protocol_t *proto) +{ + struct net_device *dev; + + read_lock(&dev_base_lock); + for (dev = dev_base; dev; dev = dev->next) { + sctp_v4_get_local_addr_list(proto, dev); + sctp_v6_get_local_addr_list(proto, dev); + } + read_unlock(&dev_base_lock); +} + +static void sctp_get_local_addr_list(sctp_protocol_t *proto) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); + __sctp_get_local_addr_list(&sctp_proto); + sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); +} + +/* Free the existing local addresses. */ +static void __sctp_free_local_addr_list(sctp_protocol_t *proto) +{ + struct sockaddr_storage_list *addr; + list_t *pos, *temp; + + list_for_each_safe(pos, temp, &proto->local_addr_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + list_del(pos); + kfree(addr); + } +} + +/* Free the existing local addresses. */ +static void sctp_free_local_addr_list(sctp_protocol_t *proto) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); + __sctp_free_local_addr_list(proto); + sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); +} + +/* Copy the local addresses which are valid for 'scope' into 'bp'. */ +int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, + sctp_scope_t scope, int priority, int copy_flags) +{ + struct sockaddr_storage_list *addr; + int error = 0; + list_t *pos; + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); + list_for_each(pos, &proto->local_addr_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_in_scope(&addr->a, scope)) { + /* Now that the address is in scope, check to see if + * the address type is really supported by the local + * sock as well as the remote peer. + */ + if ((((AF_INET == addr->a.sa.sa_family) && + (copy_flags & SCTP_ADDR4_PEERSUPP))) || + (((AF_INET6 == addr->a.sa.sa_family) && + (copy_flags & SCTP_ADDR6_ALLOWED) && + (copy_flags & SCTP_ADDR6_PEERSUPP)))) { + error = sctp_add_bind_addr(bp, + &addr->a, + priority); + if (error) + goto end_copy; + } + } + } + +end_copy: + sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); + + return error; +} + +/* Returns the mtu for the given v4 destination address. */ +int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) +{ + int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; + struct rtable *rt; + struct rt_key key = { + .dst = address->v4.sin_addr.s_addr, + .src = 0, + .iif = 0, + .oif = 0, + .tos = 0, + .scope = 0 + }; + + if (ip_route_output_key(&rt, &key)) { + SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key" + " failed, returning %d as dst_mtu\n", + dst_mtu); + } else { + dst_mtu = rt->u.dst.pmtu; + SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: " + "ip_route_output_key: dev:%s pmtu:%d\n", + rt->u.dst.dev->name, dst_mtu); + ip_rt_put(rt); + } + + return dst_mtu; +} + +/* Event handler for inet device events. + * Basically, whenever there is an event, we re-build our local address list. + */ +static int sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); + __sctp_free_local_addr_list(&sctp_proto); + __sctp_get_local_addr_list(&sctp_proto); + sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); + + return NOTIFY_DONE; +} + +/* + * Initialize the control inode/socket with a control endpoint data + * structure. This endpoint is reserved exclusively for the OOTB processing. + */ +int sctp_ctl_sock_init(void) +{ + int err = 0; + int family = PF_INET; + + SCTP_V6(family = PF_INET6;) + + err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, + &sctp_ctl_socket); + if (err < 0) { + printk(KERN_ERR + "SCTP: Failed to create the SCTP control socket.\n"); + return err; + } + sctp_ctl_socket->sk->allocation = GFP_ATOMIC; + inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL; + + return 0; +} + +/* Get the table of functions for manipulating a particular address + * family. + */ +sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) +{ + list_t *pos; + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *retval, *af; + + retval = NULL; + + /* Cycle through all AF specific functions looking for a + * match. + */ + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + if (address->sa.sa_family == af->sa_family) { + retval = af; + break; + } + } + + return retval; +} + +/* Registration for netdev events. */ +struct notifier_block sctp_netdev_notifier = { + .notifier_call = sctp_netdev_event, +}; + +/* Socket operations. */ +struct proto_ops inet_seqpacket_ops = { + .family = PF_INET, + .release = inet_release, /* Needs to be wrapped... */ + .bind = inet_bind, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = inet_accept, + .getname = inet_getname, /* Semantics are different. */ + .poll = sctp_poll, + .ioctl = inet_ioctl, + .listen = sctp_inet_listen, + .shutdown = inet_shutdown, /* Looks harmless. */ + .setsockopt = inet_setsockopt, /* IP_SOL IP_OPTION is a problem. */ + .getsockopt = inet_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +/* Registration with AF_INET family. */ +struct inet_protosw sctp_protosw = { + .type = SOCK_SEQPACKET, + .protocol = IPPROTO_SCTP, + .prot = &sctp_prot, + .ops = &inet_seqpacket_ops, + .capability = -1, + .no_check = 0, + .flags = SCTP_PROTOSW_FLAG +}; + +/* Register with IP layer. */ +static struct inet_protocol sctp_protocol = { + .handler = sctp_rcv, /* SCTP input handler. */ + .err_handler = sctp_v4_err, /* SCTP error control */ + .protocol = IPPROTO_SCTP, /* protocol ID */ + .name = "SCTP" /* name */ +}; + +/* IPv4 address related functions. */ +sctp_func_t sctp_ipv4_specific = { + .queue_xmit = ip_queue_xmit, + .setsockopt = ip_setsockopt, + .getsockopt = ip_getsockopt, + .get_dst_mtu = sctp_v4_get_dst_mtu, + .net_header_len = sizeof(struct iphdr), + .sockaddr_len = sizeof(struct sockaddr_in), + .sa_family = AF_INET, +}; + +/* Initialize the universe into something sensible. */ +int sctp_init(void) +{ + int i; + int status = 0; + + /* Add SCTP to inetsw linked list. */ + inet_register_protosw(&sctp_protosw); + + /* Add SCTP to inet_protos hash table. */ + inet_add_protocol(&sctp_protocol); + + /* Initialize proc fs directory. */ + sctp_proc_init(); + + /* Initialize object count debugging. */ + sctp_dbg_objcnt_init(); + + /* + * 14. Suggested SCTP Protocol Parameter Values + */ + /* The following protocol parameters are RECOMMENDED: */ + /* RTO.Initial - 3 seconds */ + sctp_proto.rto_initial = SCTP_RTO_INITIAL; + /* RTO.Min - 1 second */ + sctp_proto.rto_min = SCTP_RTO_MIN; + /* RTO.Max - 60 seconds */ + sctp_proto.rto_max = SCTP_RTO_MAX; + /* RTO.Alpha - 1/8 */ + sctp_proto.rto_alpha = SCTP_RTO_ALPHA; + /* RTO.Beta - 1/4 */ + sctp_proto.rto_beta = SCTP_RTO_BETA; + + /* Valid.Cookie.Life - 60 seconds */ + sctp_proto.valid_cookie_life = 60 * HZ; + + /* Max.Burst - 4 */ + sctp_proto.max_burst = SCTP_MAX_BURST; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + sctp_proto.max_retrans_association = 10; + sctp_proto.max_retrans_path = 5; + sctp_proto.max_retrans_init = 8; + + /* HB.interval - 30 seconds */ + sctp_proto.hb_interval = 30 * HZ; + + /* Implementation specific variables. */ + + /* Initialize default stream count setup information. + * Note: today the stream accounting data structures are very + * fixed size, so one really does need to make sure that these have + * upper/lower limits when changing. + */ + sctp_proto.max_instreams = SCTP_MAX_STREAM; + sctp_proto.max_outstreams = SCTP_MAX_STREAM; + + /* Allocate and initialize the association hash table. */ + sctp_proto.assoc_hashsize = 4096; + sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) + kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.assoc_hashbucket) { + printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); + status = -ENOMEM; + goto err_ahash_alloc; + } + for (i = 0; i < sctp_proto.assoc_hashsize; i++) { + sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED; + sctp_proto.assoc_hashbucket[i].chain = NULL; + } + + /* Allocate and initialize the endpoint hash table. */ + sctp_proto.ep_hashsize = 64; + sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) + kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.ep_hashbucket) { + printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); + status = -ENOMEM; + goto err_ehash_alloc; + } + + for (i = 0; i < sctp_proto.ep_hashsize; i++) { + sctp_proto.ep_hashbucket[i].lock = RW_LOCK_UNLOCKED; + sctp_proto.ep_hashbucket[i].chain = NULL; + } + + /* Allocate and initialize the SCTP port hash table. */ + sctp_proto.port_hashsize = 4096; + sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) + kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.port_hashtable) { + printk (KERN_ERR "SCTP: Failed bind hash alloc."); + status = -ENOMEM; + goto err_bhash_alloc; + } + + sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED; + sctp_proto.port_rover = sysctl_local_port_range[0] - 1; + for (i = 0; i < sctp_proto.port_hashsize; i++) { + sctp_proto.port_hashtable[i].lock = SPIN_LOCK_UNLOCKED; + sctp_proto.port_hashtable[i].chain = NULL; + } + + sctp_sysctl_register(); + + INIT_LIST_HEAD(&sctp_proto.address_families); + INIT_LIST_HEAD(&sctp_ipv4_specific.list); + list_add_tail(&sctp_ipv4_specific.list, &sctp_proto.address_families); + + status = sctp_v6_init(); + if (status) + goto err_v6_init; + + /* Initialize the control inode/socket for handling OOTB packets. */ + if ((status = sctp_ctl_sock_init())) { + printk (KERN_ERR + "SCTP: Failed to initialize the SCTP control sock.\n"); + goto err_ctl_sock_init; + } + + /* Initialize the local address list. */ + INIT_LIST_HEAD(&sctp_proto.local_addr_list); + sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; + + register_inetaddr_notifier(&sctp_netdev_notifier); + sctp_get_local_addr_list(&sctp_proto); + + return 0; + +err_ctl_sock_init: + sctp_v6_exit(); +err_v6_init: + sctp_sysctl_unregister(); + list_del(&sctp_ipv4_specific.list); + kfree(sctp_proto.port_hashtable); +err_bhash_alloc: + kfree(sctp_proto.ep_hashbucket); +err_ehash_alloc: + kfree(sctp_proto.assoc_hashbucket); +err_ahash_alloc: + sctp_dbg_objcnt_exit(); + sctp_proc_exit(); + inet_del_protocol(&sctp_protocol); + inet_unregister_protosw(&sctp_protosw); + return status; +} + +/* Exit handler for the SCTP protocol. */ +void sctp_exit(void) +{ + /* BUG. This should probably do something useful like clean + * up all the remaining associations and all that memory. + */ + + /* Free the local address list. */ + unregister_inetaddr_notifier(&sctp_netdev_notifier); + sctp_free_local_addr_list(&sctp_proto); + + /* Free the control endpoint. */ + sock_release(sctp_ctl_socket); + + sctp_v6_exit(); + sctp_sysctl_unregister(); + list_del(&sctp_ipv4_specific.list); + + kfree(sctp_proto.assoc_hashbucket); + kfree(sctp_proto.ep_hashbucket); + kfree(sctp_proto.port_hashtable); + + sctp_dbg_objcnt_exit(); + sctp_proc_exit(); + + inet_del_protocol(&sctp_protocol); + inet_unregister_protosw(&sctp_protosw); +} + +module_init(sctp_init); +module_exit(sctp_exit); + +MODULE_AUTHOR("Linux Kernel SCTP developers "); +MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)"); +MODULE_LICENSE("GPL"); + diff -Nru a/net/sctp/sla1.c b/net/sctp/sla1.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sla1.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,281 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * (It's really SHA-1 but Hey I was tired when I created this + * file, and on a plane to France :-) + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * kmorneau@cisco.com + * qxie1@email.mot.com + * + * Based on: + * Randy Stewart, et al. SCTP Reference Implementation which is licenced + * under the GPL. + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include /* for memcpy */ +#include /* dead chicken for in.h */ +#include /* for htonl and ntohl */ + +#include + +void SLA1_Init(struct SLA_1_Context *ctx) +{ + /* Init the SLA-1 context structure. */ + ctx->A = 0; + ctx->B = 0; + ctx->C = 0; + ctx->D = 0; + ctx->E = 0; + ctx->H0 = H0INIT; + ctx->H1 = H1INIT; + ctx->H2 = H2INIT; + ctx->H3 = H3INIT; + ctx->H4 = H4INIT; + ctx->TEMP = 0; + memset(ctx->words, 0, sizeof(ctx->words)); + ctx->howManyInBlock = 0; + ctx->runningTotal = 0; +} + +void SLA1processABlock(struct SLA_1_Context *ctx,unsigned int *block) +{ + int i; + /* init the W0-W15 to the block of words being + * hashed. + */ + /* step a) */ + + for (i = 0; i < 16; i++) + ctx->words[i] = ntohl(block[i]); + + /* now init the rest based on the SLA-1 formula, step b) */ + for (i = 16; i < 80; i++) + ctx->words[i] = + CSHIFT(1, ((ctx->words[(i-3)]) ^ + (ctx->words[(i-8)]) ^ + (ctx->words[(i-14)]) ^ + (ctx->words[(i-16)]))); + + /* step c) */ + ctx->A = ctx->H0; + ctx->B = ctx->H1; + ctx->C = ctx->H2; + ctx->D = ctx->H3; + ctx->E = ctx->H4; + + /* step d) */ + for (i = 0; i < 80; i++) { + if (i < 20) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F1(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + ctx->words[i] + + K1 + ); + } else if (i < 40) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F2(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K2 + ); + } else if (i < 60) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F3(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K3 + ); + } else { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F4(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K4 + ); + } + ctx->E = ctx->D; + ctx->D = ctx->C; + ctx->C = CSHIFT(30, ctx->B); + ctx->B = ctx->A; + ctx->A = ctx->TEMP; + } + + /* step e) */ + ctx->H0 = (ctx->H0) + (ctx->A); + ctx->H1 = (ctx->H1) + (ctx->B); + ctx->H2 = (ctx->H2) + (ctx->C); + ctx->H3 = (ctx->H3) + (ctx->D); + ctx->H4 = (ctx->H4) + (ctx->E); +} + +void SLA1_Process(struct SLA_1_Context *ctx, const unsigned char *ptr, int siz) +{ + int numberLeft, leftToFill; + + numberLeft = siz; + while (numberLeft > 0) { + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if (leftToFill > numberLeft) { + /* can only partially fill up this one */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock], + ptr, numberLeft); + ctx->howManyInBlock += siz; + ctx->runningTotal += siz; + break; + } else { + /* block is now full, process it */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock], + ptr, leftToFill); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + numberLeft -= leftToFill; + ctx->runningTotal += leftToFill; + ctx->howManyInBlock = 0; + } + } +} + +void SLA1_Final(struct SLA_1_Context *ctx, unsigned char *digestBuf) +{ + /* if any left in block fill with padding + * and process. Then transfer the digest to + * the pointer. At the last block some special + * rules need to apply. We must add a 1 bit + * following the message, then we pad with + * 0's. The total size is encoded as a 64 bit + * number at the end. Now if the last buffer has + * more than 55 octets in it we cannot fit + * the 64 bit number + 10000000 pad on the end + * and must add the 10000000 pad, pad the rest + * of the message with 0's and then create a + * all 0 message with just the 64 bit size + * at the end and run this block through by itself. + * Also the 64 bit int must be in network byte + * order. + */ + int i, leftToFill; + unsigned int *ptr; + + if (ctx->howManyInBlock > 55) { + /* special case, we need to process two + * blocks here. One for the current stuff + * plus possibly the pad. The other for + * the size. + */ + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if (leftToFill == 0) { + /* Should not really happen but I am paranoid */ + /* Not paranoid enough! It is possible for leftToFill + * to become negative! AAA!!!! This is another reason + * to pick MD5 :-)... + */ + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block, a bit different then the rest :-) */ + ctx->SLAblock[0] = 0x80; + for (i = 1; i < sizeof(ctx->SLAblock); i++) { + ctx->SLAblock[i] = 0x0; + } + } else if (leftToFill == 1) { + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock)); + } else { + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for (i = (ctx->howManyInBlock + 1); + i < sizeof(ctx->SLAblock); + i++) { + ctx->SLAblock[i] = 0x0; + } + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock)); + } + /* This is in bits so multiply by 8 */ + ctx->runningTotal *= 8; + ptr = (unsigned int *) &ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + } else { + /* easy case, we just pad this + * message to size - end with 0 + * add the magic 0x80 to the next + * word and then put the network byte + * order size in the last spot and + * process the block. + */ + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for (i = (ctx->howManyInBlock + 1); + i < sizeof(ctx->SLAblock); + i++) { + ctx->SLAblock[i] = 0x0; + } + /* get last int spot */ + ctx->runningTotal *= 8; + ptr = (unsigned int *) &ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + } + /* Now at this point all we need do is transfer the + * digest back to the user + */ + digestBuf[3] = (ctx->H0 & 0xff); + digestBuf[2] = ((ctx->H0 >> 8) & 0xff); + digestBuf[1] = ((ctx->H0 >> 16) & 0xff); + digestBuf[0] = ((ctx->H0 >> 24) & 0xff); + + digestBuf[7] = (ctx->H1 & 0xff); + digestBuf[6] = ((ctx->H1 >> 8) & 0xff); + digestBuf[5] = ((ctx->H1 >> 16) & 0xff); + digestBuf[4] = ((ctx->H1 >> 24) & 0xff); + + digestBuf[11] = (ctx->H2 & 0xff); + digestBuf[10] = ((ctx->H2 >> 8) & 0xff); + digestBuf[9] = ((ctx->H2 >> 16) & 0xff); + digestBuf[8] = ((ctx->H2 >> 24) & 0xff); + + digestBuf[15] = (ctx->H3 & 0xff); + digestBuf[14] = ((ctx->H3 >> 8) & 0xff); + digestBuf[13] = ((ctx->H3 >> 16) & 0xff); + digestBuf[12] = ((ctx->H3 >> 24) & 0xff); + + digestBuf[19] = (ctx->H4 & 0xff); + digestBuf[18] = ((ctx->H4 >> 8) & 0xff); + digestBuf[17] = ((ctx->H4 >> 16) & 0xff); + digestBuf[16] = ((ctx->H4 >> 24) & 0xff); +} diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sm_make_chunk.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,1762 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file includes part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * These functions work with the state functions in sctp_sm_statefuns.c + * to implement the state operations. These functions implement the + * steps which require modifying existing data structures. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * C. Robin + * Jon Grimm + * Xingang Guo + * Dajiang Zhang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* for get_random_bytes */ +#include +#include + +/* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 4: This parameter, when present, specifies all the + * address types the sending endpoint can support. The absence + * of this parameter indicates that the sending endpoint can + * support any address type. + */ +static const sctp_supported_addrs_param_t sat_param = { + { + SCTP_PARAM_SUPPORTED_ADDRESS_TYPES, + __constant_htons(SCTP_SAT_LEN), + }, + { /* types[] */ + SCTP_PARAM_IPV4_ADDRESS, + SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) + } +}; + +/* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 2: The ECN capable field is reserved for future use of + * Explicit Congestion Notification. + */ +static const sctp_ecn_capable_param_t ecap_param = { + { + SCTP_PARAM_ECN_CAPABLE, + __constant_htons(sizeof(sctp_ecn_capable_param_t)), + } +}; + +/* A helper to initilize to initilize an op error inside a + * provided chunk, as most cause codes will be embedded inside an + * abort chunk. + */ +void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, + const void *payload, size_t paylen) +{ + sctp_errhdr_t err; + int padlen; + __u16 len; + + /* Cause code constants are now defined in network order. */ + err.cause = cause_code; + len = sizeof(sctp_errhdr_t) + paylen; + padlen = len % 4; + len += padlen; + err.length = htons(len); + sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); + chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload); +} + +/* 3.3.2 Initiation (INIT) (1) + * + * This chunk is used to initiate a SCTP association between two + * endpoints. The format of the INIT chunk is shown below: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 1 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initiate Tag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Advertised Receiver Window Credit (a_rwnd) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Outbound Streams | Number of Inbound Streams | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initial TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Optional/Variable-Length Parameters / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * The INIT chunk contains the following parameters. Unless otherwise + * noted, each parameter MUST only be included once in the INIT chunk. + * + * Fixed Parameters Status + * ---------------------------------------------- + * Initiate Tag Mandatory + * Advertised Receiver Window Credit Mandatory + * Number of Outbound Streams Mandatory + * Number of Inbound Streams Mandatory + * Initial TSN Mandatory + * + * Variable Parameters Status Type Value + * ------------------------------------------------------------- + * IPv4 Address (Note 1) Optional 5 + * IPv6 Address (Note 1) Optional 6 + * Cookie Preservative Optional 9 + * Reserved for ECN Capable (Note 2) Optional 32768 (0x8000) + * Host Name Address (Note 3) Optional 11 + * Supported Address Types (Note 4) Optional 12 + */ +sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, + const sctp_bind_addr_t *bp, + int priority) +{ + sctp_inithdr_t init; + sctpParam_t addrs; + size_t chunksize; + sctp_chunk_t *retval = NULL; + int addrs_len = 0; + + /* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 1: The INIT chunks can contain multiple addresses that + * can be IPv4 and/or IPv6 in any combination. + */ + retval = NULL; + addrs.v = NULL; + + /* Convert the provided bind address list to raw format */ + addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); + if (!addrs.v) + goto nodata; + + init.init_tag = htonl(asoc->c.my_vtag); + init.a_rwnd = htonl(asoc->rwnd); + init.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + init.initial_tsn = htonl(asoc->c.initial_tsn); + + chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; + chunksize += sizeof(ecap_param); + + /* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 3: An INIT chunk MUST NOT contain more than one Host + * Name address parameter. Moreover, the sender of the INIT + * MUST NOT combine any other address types with the Host Name + * address in the INIT. The receiver of INIT MUST ignore any + * other address types if the Host Name address parameter is + * present in the received INIT chunk. + * + * PLEASE DO NOT FIXME [This version does not support Host Name.] + */ + + retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); + if (!retval) + goto nodata; + + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(init), &init); + retval->param_hdr.v = + sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, SCTP_SAT_LEN, &sat_param); + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + +nodata: + if (addrs.v) + kfree(addrs.v); + return retval; +} + +sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + int priority) +{ + sctp_inithdr_t initack; + sctp_chunk_t *retval; + sctpParam_t addrs; + int addrs_len; + sctp_cookie_param_t *cookie; + int cookie_len; + size_t chunksize; + int error; + sctp_scope_t scope; + sctp_bind_addr_t *bp = NULL; + int flags; + + retval = NULL; + + /* Build up the bind address list for the association based on + * info from the local endpoint and the remote peer. + */ + bp = sctp_bind_addr_new(priority); + if (!bp) + goto nomem_bindaddr; + + /* Look for supported address types parameter and then build + * our address list based on that. + */ + scope = sctp_scope(&asoc->peer.active_path->ipaddr); + flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + if (asoc->peer.ipv4_address) + flags |= SCTP_ADDR4_PEERSUPP; + if (asoc->peer.ipv6_address) + flags |= SCTP_ADDR6_PEERSUPP; + error = sctp_bind_addr_copy(bp, &asoc->ep->base.bind_addr, + scope, priority, flags); + if (error) + goto nomem_copyaddr; + + addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); + if (!addrs.v) + goto nomem_rawaddr; + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(asoc->rwnd); + initack.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + initack.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + initack.initial_tsn = htonl(asoc->c.initial_tsn); + + /* FIXME: We really ought to build the cookie right + * into the packet instead of allocating more fresh memory. + */ + cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len, + addrs.v, addrs_len); + if (!cookie) + goto nomem_cookie; + + chunksize = sizeof(initack) + addrs_len + cookie_len; + + /* Tell peer that we'll do ECN only if peer advertised such cap. */ + if (asoc->peer.ecn_capable) + chunksize += sizeof(ecap_param); + + /* Now allocate and fill out the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); + if (!retval) + goto nomem_chunk; + + /* Per the advice in RFC 2960 6.4, send this reply to + * the source of the INIT packet. + */ + retval->transport = chunk->transport; + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(initack), &initack); + retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, cookie_len, cookie); + if (asoc->peer.ecn_capable) + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + + /* We need to remove the const qualifier at this point. */ + retval->asoc = (sctp_association_t *) asoc; + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it received the DATA or control chunk + * to which it is replying. + * + * [INIT ACK back to where the INIT came from.] + */ + if (chunk) + retval->transport = chunk->transport; + +nomem_chunk: + kfree(cookie); +nomem_cookie: + kfree(addrs.v); +nomem_rawaddr: +nomem_copyaddr: + sctp_bind_addr_free(bp); +nomem_bindaddr: + return retval; +} + +/* 3.3.11 Cookie Echo (COOKIE ECHO) (10): + * + * This chunk is used only during the initialization of an association. + * It is sent by the initiator of an association to its peer to complete + * the initialization process. This chunk MUST precede any DATA chunk + * sent within the association, but MAY be bundled with one or more DATA + * chunks in the same packet. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 10 |Chunk Flags | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Cookie / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bit + * + * Set to zero on transmit and ignored on receipt. + * + * Length: 16 bits (unsigned integer) + * + * Set to the size of the chunk in bytes, including the 4 bytes of + * the chunk header and the size of the Cookie. + * + * Cookie: variable size + * + * This field must contain the exact cookie received in the + * State Cookie parameter from the previous INIT ACK. + * + * An implementation SHOULD make the cookie as small as possible + * to insure interoperability. + */ +sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + void *cookie; + int cookie_len; + + cookie = asoc->peer.cookie; + cookie_len = asoc->peer.cookie_len; + + /* Build a cookie echo chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); + if (!retval) + goto nodata; + retval->subh.cookie_hdr = + sctp_addto_chunk(retval, cookie_len, cookie); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [COOKIE ECHO back to where the INIT ACK came from.] + */ + if (chunk) + retval->transport = chunk->transport; + +nodata: + return retval; +} + +/* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11): + * + * This chunk is used only during the initialization of an + * association. It is used to acknowledge the receipt of a COOKIE + * ECHO chunk. This chunk MUST precede any DATA or SACK chunk sent + * within the association, but MAY be bundled with one or more DATA + * chunks or SACK chunk in the same SCTP packet. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 11 |Chunk Flags | Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bits + * + * Set to zero on transmit and ignored on receipt. + */ +sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [COOKIE ACK back to where the COOKIE ECHO came from.] + */ + if (retval && chunk) + retval->transport = chunk->transport; + + return retval; +} + +/* + * Appendix A: Explicit Congestion Notification: + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in the header of + * its next outbound TCP segment to indicate to its peer that it has + * reduced its congestion window. This is termed the CWR bit. For + * SCTP the same indication is made by including the CWR chunk. + * This chunk contains one data element, i.e. the TSN number that + * was sent in the ECNE chunk. This element represents the lowest + * TSN number in the datagram that was originally marked with the + * CE bit. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Chunk Type=13 | Flags=00000000| Chunk Length = 8 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Lowest TSN Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Note: The CWR is considered a Control chunk. + */ +sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, + const __u32 lowest_tsn, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + sctp_cwrhdr_t cwr; + + cwr.lowest_tsn = htonl(lowest_tsn); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, + sizeof(sctp_cwrhdr_t)); + + if (!retval) + goto nodata; + + retval->subh.ecn_cwr_hdr = + sctp_addto_chunk(retval, sizeof(cwr), &cwr); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [Report a reduced congestion window back to where the ECNE + * came from.] + */ + if (chunk) + retval->transport = chunk->transport; + +nodata: + return retval; +} + +/* Make an ECNE chunk. This is a congestion experienced report. */ +sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, + const __u32 lowest_tsn) +{ + sctp_chunk_t *retval; + sctp_ecnehdr_t ecne; + + ecne.lowest_tsn = htonl(lowest_tsn); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, + sizeof(sctp_ecnehdr_t)); + if (!retval) + goto nodata; + retval->subh.ecne_hdr = + sctp_addto_chunk(retval, sizeof(ecne), &ecne); + +nodata: + return retval; +} + +/* Make a DATA chunk for the given association from the provided + * parameters. However, do not populate the data payload. + */ +sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, __u8 flags, __u16 ssn) +{ + sctp_chunk_t *retval; + sctp_datahdr_t dp; + int chunk_len; + + /* We assign the TSN as LATE as possible, not here when + * creating the chunk. + */ + dp.tsn= 1000000; /* This marker is a debugging aid. */ + dp.stream = htons(sinfo->sinfo_stream); + dp.ppid = htonl(sinfo->sinfo_ppid); + dp.ssn = htons(ssn); + + /* Set the flags for an unordered send. */ + if (sinfo->sinfo_flags & MSG_UNORDERED) + flags |= SCTP_DATA_UNORDERED; + + chunk_len = sizeof(dp) + data_len; + retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); + if (!retval) + goto nodata; + + retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); + memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); + +nodata: + return retval; +} + +/* Make a DATA chunk for the given association. Populate the data + * payload. + */ +sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const __u8 *data, + __u8 flags, __u16 ssn) +{ + sctp_chunk_t *retval; + + retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); + if (retval) + sctp_addto_chunk(retval, data_len, data); + + return retval; +} + +/* Make a DATA chunk for the given association to ride on stream id + * 'stream', with a payload id of 'payload', and a body of 'data'. + */ +sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const __u8 *data) +{ + sctp_chunk_t *retval = NULL; + + retval = sctp_make_data_empty(asoc, sinfo, data_len); + if (retval) + sctp_addto_chunk(retval, data_len, data); + return retval; +} + +/* Make a DATA chunk for the given association to ride on stream id + * 'stream', with a payload id of 'payload', and a body big enough to + * hold 'data_len' octets of data. We use this version when we need + * to build the message AFTER allocating memory. + */ +sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len) +{ + __u16 ssn; + __u8 flags = SCTP_DATA_NOT_FRAG; + + /* Sockets API Extensions for SCTP 5.2.2 + * MSG_UNORDERED - This flag requests the un-ordered delivery of the + * message. If this flag is clear, the datagram is considered an + * ordered send and a new ssn is generated. The flags field is set + * in the inner routine - sctp_make_datafrag_empty(). + */ + if (sinfo->sinfo_flags & MSG_UNORDERED) { + ssn = 0; + } else { + ssn = __sctp_association_get_next_ssn(asoc, + sinfo->sinfo_stream); + } + + return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); +} + +/* Create a selective ackowledgement (SACK) for the given + * association. This reports on which TSN's we've seen to date, + * including duplicates and gaps. + */ +sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) +{ + sctp_chunk_t *retval; + sctp_sackhdr_t sack; + sctp_gap_ack_block_t gab; + int length; + __u32 ctsn; + sctp_tsnmap_iter_t iter; + __u16 num_gabs; + __u16 num_dup_tsns = asoc->peer.next_dup_tsn; + const sctp_tsnmap_t *map = &asoc->peer.tsn_map; + + ctsn = sctp_tsnmap_get_ctsn(map); + SCTP_DEBUG_PRINTK("make_sack: sackCTSNAck sent is 0x%x.\n", + ctsn); + + /* Count the number of Gap Ack Blocks. */ + sctp_tsnmap_iter_init(map, &iter); + for (num_gabs = 0; + sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); + num_gabs++) { + /* Do nothing. */ + } + + /* Initialize the SACK header. */ + sack.cum_tsn_ack = htonl(ctsn); + sack.a_rwnd = htonl(asoc->rwnd); + sack.num_gap_ack_blocks = htons(num_gabs); + sack.num_dup_tsns = htons(num_dup_tsns); + + length = sizeof(sack) + + sizeof(sctp_gap_ack_block_t) * num_gabs + + sizeof(sctp_dup_tsn_t) * num_dup_tsns; + + /* Create the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); + if (!retval) + goto nodata; + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, etc.) to the same destination transport + * address from which it received the DATA or control chunk to + * which it is replying. This rule should also be followed if + * the endpoint is bundling DATA chunks together with the + * reply chunk. + * + * However, when acknowledging multiple DATA chunks received + * in packets from different source addresses in a single + * SACK, the SACK chunk may be transmitted to one of the + * destination transport addresses from which the DATA or + * control chunks being acknowledged were received. + * + * [BUG: We do not implement the following paragraph. + * Perhaps we should remember the last transport we used for a + * SACK and avoid that (if possible) if we have seen any + * duplicates. --piggy] + * + * When a receiver of a duplicate DATA chunk sends a SACK to a + * multi- homed endpoint it MAY be beneficial to vary the + * destination address and not use the source address of the + * DATA chunk. The reason being that receiving a duplicate + * from a multi-homed endpoint might indicate that the return + * path (as specified in the source address of the DATA chunk) + * for the SACK is broken. + * + * [Send to the address from which we last received a DATA chunk.] + */ + retval->transport = asoc->peer.last_data_from; + + retval->subh.sack_hdr = + sctp_addto_chunk(retval, sizeof(sack), &sack); + + /* Put the Gap Ack Blocks into the chunk. */ + sctp_tsnmap_iter_init(map, &iter); + while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { + gab.start = htons(gab.start); + gab.end = htons(gab.end); + sctp_addto_chunk(retval, + sizeof(sctp_gap_ack_block_t), + &gab); + } + + /* Register the duplicates. */ + sctp_addto_chunk(retval, + sizeof(sctp_dup_tsn_t) * num_dup_tsns, + &asoc->peer.dup_tsns); + +nodata: + return retval; +} + +sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) +{ + sctp_chunk_t *retval; + sctp_shutdownhdr_t shut; + __u32 ctsn; + + ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + shut.cum_tsn_ack = htonl(ctsn); + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, + sizeof(sctp_shutdownhdr_t)); + if (!retval) + goto nodata; + + retval->subh.shutdown_hdr = + sctp_addto_chunk(retval, sizeof(shut), &shut); + +nodata: + return retval; +} + +sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ACK back to where the SHUTDOWN came from.] + */ + if (retval && chunk) + retval->transport = chunk->transport; + + return retval; +} + +sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + __u8 flags = 0; + + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK + * came from.] + */ + if (retval && chunk) + retval->transport = chunk->transport; + + return retval; +} + +/* Create an ABORT. Note that we set the T bit if we have no + * association. + */ +sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + const size_t hint) +{ + sctp_chunk_t *retval; + __u8 flags = 0; + + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + + retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ABORT back to where the offender came from.] + */ + if (retval && chunk) + retval->transport = chunk->transport; + + return retval; +} + +/* Helper to create ABORT with a NO_USER_DATA error. */ +sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, __u32 tsn) +{ + sctp_chunk_t *retval; + __u32 payload; + + retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + + sizeof(tsn)); + + if (!retval) + goto no_mem; + + /* Put the tsn back into network byte order. */ + payload = htonl(tsn); + sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, + sizeof(payload)); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ABORT back to where the offender came from.] + */ + if (chunk) + retval->transport = chunk->transport; + +no_mem: + return retval; +} + +/* Make a HEARTBEAT chunk. */ +sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, + const sctp_transport_t *transport, + const void *payload, const size_t paylen) +{ + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, + 0, paylen); + + if (!retval) + goto nodata; + + /* Cast away the 'const', as this is just telling the chunk + * what transport it belongs to. + */ + retval->transport = (sctp_transport_t *) transport; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + +nodata: + return retval; +} + +sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + const void *payload, const size_t paylen) +{ + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, + 0, paylen); + + if (!retval) + goto nodata; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [HBACK back to where the HEARTBEAT came from.] + */ + if (chunk) + retval->transport = chunk->transport; + +nodata: + return retval; +} + +/* Create an Operation Error chunk. */ +sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + __u16 cause_code, const void *payload, + size_t paylen) +{ + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, + sizeof(sctp_errhdr_t) + paylen); + + if (!retval) + goto nodata; + sctp_init_cause(retval, cause_code, payload, paylen); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + */ + if (chunk) + retval->transport = chunk->transport; + +nodata: + return retval; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Turn an skb into a chunk. + * FIXME: Eventually move the structure directly inside the skb->cb[]. + */ +sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, + struct sock *sk) +{ + sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); + + if (!retval) + goto nodata; + memset(retval, 0, sizeof(sctp_chunk_t)); + + if (!sk) { + SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); + } + + retval->skb = skb; + retval->asoc = (sctp_association_t *) asoc; + retval->num_times_sent = 0; + retval->has_tsn = 0; + retval->rtt_in_progress = 0; + retval->sent_at = jiffies; + retval->singleton = 1; + retval->end_of_packet = 0; + retval->ecn_ce_done = 0; + retval->pdiscard = 0; + + /* sctpimpguide-05.txt Section 2.8.2 + * M1) Each time a new DATA chunk is transmitted + * set the 'TSN.Missing.Report' count for that TSN to 0. The + * 'TSN.Missing.Report' count will be used to determine missing chunks + * and when to fast retransmit. + */ + retval->tsn_missing_report = 0; + retval->tsn_gap_acked = 0; + retval->fast_retransmit = 0; + + /* Polish the bead hole. */ + INIT_LIST_HEAD(&retval->transmitted_list); + INIT_LIST_HEAD(&retval->frag_list); + SCTP_DBG_OBJCNT_INC(chunk); + +nodata: + return retval; +} + +/* Set chunk->source based on the IP header in chunk->skb. */ +void sctp_init_source(sctp_chunk_t *chunk) +{ + sockaddr_storage_t *source; + struct sk_buff *skb; + struct sctphdr *sh; + struct iphdr *ih4; + struct ipv6hdr *ih6; + + source = &chunk->source; + skb = chunk->skb; + ih4 = skb->nh.iph; + ih6 = skb->nh.ipv6h; + sh = chunk->sctp_hdr; + + switch (ih4->version) { + case 4: + source->v4.sin_family = AF_INET; + source->v4.sin_port = ntohs(sh->source); + source->v4.sin_addr.s_addr = ih4->saddr; + break; + + case 6: + SCTP_V6( + source->v6.sin6_family = AF_INET6; + source->v6.sin6_port = ntohs(sh->source); + source->v6.sin6_addr = ih6->saddr; + /* FIXME: What do we do with scope, etc. ? */ + break; + ) + + default: + /* This is a bogus address type, just bail. */ + break; + }; +} + +/* Extract the source address from a chunk. */ +const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk) +{ + /* If we have a known transport, use that. */ + if (chunk->transport) { + return &chunk->transport->ipaddr; + } else { + /* Otherwise, extract it from the IP header. */ + return &chunk->source; + } +} + +/* Create a new chunk, setting the type and flags headers from the + * arguments, reserving enough space for a 'paylen' byte payload. + */ +sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, + __u8 type, __u8 flags, int paylen) +{ + sctp_chunk_t *retval; + sctp_chunkhdr_t *chunk_hdr; + struct sk_buff *skb; + struct sock *sk; + + skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen)); + if (!skb) + goto nodata; + + /* Make room for the chunk header. */ + chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); + skb_pull(skb, sizeof(sctp_chunkhdr_t)); + + chunk_hdr->type = type; + chunk_hdr->flags = flags; + chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); + + /* Move the data pointer back up to the start of the chunk. */ + skb_push(skb, sizeof(sctp_chunkhdr_t)); + + sk = asoc ? asoc->base.sk : NULL; + retval = sctp_chunkify(skb, asoc, sk); + if (!retval) { + dev_kfree_skb(skb); + goto nodata; + } + + retval->chunk_hdr = chunk_hdr; + retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(sctp_chunkhdr_t); + + /* Set the skb to the belonging sock for accounting. */ + skb->sk = sk; + + return retval; + +nodata: + return NULL; +} + +/* Release the memory occupied by a chunk. */ +void sctp_free_chunk(sctp_chunk_t *chunk) +{ + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *) chunk); + list_del(&chunk->transmitted_list); + + /* Free the chunk skb data and the SCTP_chunk stub itself. */ + dev_kfree_skb(chunk->skb); + + kfree(chunk); + SCTP_DBG_OBJCNT_DEC(chunk); +} + +/* Do a deep copy of a chunk. */ +sctp_chunk_t *sctp_copy_chunk(sctp_chunk_t *chunk, const int priority) +{ + sctp_chunk_t *retval; + long offset; + + retval = t_new(sctp_chunk_t, priority); + if (!retval) + goto nodata; + + /* Do the shallow copy. */ + *retval = *chunk; + + /* Make sure that the copy does NOT think it is on any lists. */ + retval->next = NULL; + retval->prev = NULL; + retval->list = NULL; + INIT_LIST_HEAD(&retval->transmitted_list); + INIT_LIST_HEAD(&retval->frag_list); + + /* Now we copy the deep structure. */ + retval->skb = skb_copy(chunk->skb, priority); + if (!retval->skb) { + kfree(retval); + goto nodata; + } + + /* Move the copy headers to point into the new skb. */ + offset = ((__u8 *)retval->skb->head) + - ((__u8 *)chunk->skb->head); + + if (retval->param_hdr.v) + retval->param_hdr.v += offset; + if (retval->subh.v) + retval->subh.v += offset; + if (retval->chunk_end) + ((__u8 *) retval->chunk_end) += offset; + if (retval->chunk_hdr) + ((__u8 *) retval->chunk_hdr) += offset; + if (retval->sctp_hdr) + ((__u8 *) retval->sctp_hdr) += offset; + SCTP_DBG_OBJCNT_INC(chunk); + return retval; + +nodata: + return NULL; +} + +/* Append bytes to the end of a chunk. Will panic if chunk is not big + * enough. + */ +void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +{ + void *target; + void *padding; + int chunklen = ntohs(chunk->chunk_hdr->length); + int padlen = chunklen % 4; + + padding = skb_put(chunk->skb, padlen); + target = skb_put(chunk->skb, len); + + memset(padding, 0, padlen); + memcpy(target, data, len); + + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = htons(chunklen + padlen + len); + chunk->chunk_end = chunk->skb->tail; + + return target; +} + +/* Append bytes from user space to the end of a chunk. Will panic if + * chunk is not big enough. + * Returns a kernel err value. + */ +int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data) +{ + __u8 *target; + int err = 0; + + /* Make room in chunk for data. */ + target = skb_put(chunk->skb, len); + + /* Copy data (whole iovec) into chunk */ + if ((err = memcpy_fromiovec(target, data, len))) + goto out; + + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = + htons(ntohs(chunk->chunk_hdr->length) + len); + chunk->chunk_end = chunk->skb->tail; + +out: + return err; +} + +/* Helper function to assign a TSN if needed. This assumes that both + * the data_hdr and association have already been assigned. + */ +void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +{ + if (!chunk->has_tsn) { + /* This is the last possible instant to + * assign a TSN. + */ + chunk->subh.data_hdr->tsn = + htonl(__sctp_association_get_next_tsn(chunk->asoc)); + chunk->has_tsn = 1; + } +} + +/* Create a CLOSED association to use with an incoming packet. */ +sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *ep, + sctp_chunk_t *chunk, + int priority) +{ + sctp_association_t *asoc; + sctp_scope_t scope; + + /* Create the bare association. */ + scope = sctp_scope(sctp_source(chunk)); + asoc = sctp_association_new(ep, ep->base.sk, scope, priority); + if (!asoc) + goto nodata; + + /* Create an entry for the source address of the packet. */ + switch (chunk->skb->nh.iph->version) { + case 4: + asoc->c.peer_addr.v4.sin_family = AF_INET; + asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source); + asoc->c.peer_addr.v4.sin_addr.s_addr = + chunk->skb->nh.iph->saddr; + break; + + case 6: + asoc->c.peer_addr.v6.sin6_family = AF_INET6; + asoc->c.peer_addr.v6.sin6_port + = ntohs(chunk->sctp_hdr->source); + asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */ + asoc->c.peer_addr.v6.sin6_addr = chunk->skb->nh.ipv6h->saddr; + asoc->c.peer_addr.v6.sin6_scope_id = 0; /* BUG BUG BUG */ + break; + + default: + /* Yikes! I never heard of this kind of address. */ + goto fail; + }; + +nodata: + return asoc; + +fail: + sctp_association_free(asoc); + return NULL; +} + +/* Build a cookie representing asoc. + * This INCLUDES the param header needed to put the cookie in the INIT ACK. + */ +sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_chunk_t *init_chunk, + int *cookie_len, + const __u8 *raw_addrs, int addrs_len) +{ + sctp_cookie_param_t *retval; + sctp_signed_cookie_t *cookie; + int headersize, bodysize; + + headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; + bodysize = sizeof(sctp_cookie_t) + + ntohs(init_chunk->chunk_hdr->length) + addrs_len; + + /* Pad out the cookie to a multiple to make the signature + * functions simpler to write. + */ + if (bodysize % SCTP_COOKIE_MULTIPLE) + bodysize += SCTP_COOKIE_MULTIPLE + - (bodysize % SCTP_COOKIE_MULTIPLE); + *cookie_len = headersize + bodysize; + + retval = (sctp_cookie_param_t *) + kmalloc(*cookie_len, GFP_ATOMIC); + if (!retval) { + *cookie_len = 0; + goto nodata; + } + + /* Clear this memory since we are sending this data structure + * out on the network. + */ + memset(retval, 0x00, *cookie_len); + cookie = (sctp_signed_cookie_t *) retval->body; + + /* Set up the parameter header. */ + retval->p.type = SCTP_PARAM_STATE_COOKIE; + retval->p.length = htons(*cookie_len); + + /* Copy the cookie part of the association itself. */ + cookie->c = asoc->c; + /* Save the raw address list length in the cookie. */ + cookie->c.raw_addr_list_len = addrs_len; + + /* Set an expiration time for the cookie. */ + do_gettimeofday(&cookie->c.expiration); + tv_add(&asoc->cookie_life, &cookie->c.expiration); + + /* Copy the peer's init packet. */ + memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, + ntohs(init_chunk->chunk_hdr->length)); + + /* Copy the raw local address list of the association. */ + memcpy((__u8 *)&cookie->c.peer_init[0] + + ntohs(init_chunk->chunk_hdr->length), raw_addrs, + addrs_len); + + /* Sign the message. */ + sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, + (__u8 *) &cookie->c, bodysize, cookie->signature); + +nodata: + return retval; +} + +/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ +sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, int priority, + int *error) +{ + sctp_association_t *retval = NULL; + sctp_signed_cookie_t *cookie; + sctp_cookie_t *bear_cookie; + int headersize, bodysize; + int fixed_size, var_size1, var_size2, var_size3; + __u8 digest_buf[SCTP_SIGNATURE_SIZE]; + int secret; + sctp_scope_t scope; + __u8 *raw_addr_list; + + headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; + bodysize = ntohs(chunk->chunk_hdr->length) - headersize; + fixed_size = headersize + sizeof(sctp_cookie_t); + + /* Verify that the chunk looks like it even has a cookie. + * There must be enough room for our cookie and our peer's + * INIT chunk. + */ + if (ntohs(chunk->chunk_hdr->length) < + (fixed_size + sizeof(sctp_chunkhdr_t))) + goto malformed; + + /* Verify that the cookie has been padded out. */ + if (bodysize % SCTP_COOKIE_MULTIPLE) + goto malformed; + + /* Process the cookie. */ + cookie = chunk->subh.cookie_hdr; + bear_cookie = &cookie->c; + var_size1 = ntohs(chunk->chunk_hdr->length) - fixed_size; + var_size2 = ntohs(bear_cookie->peer_init->chunk_hdr.length); + var_size3 = bear_cookie->raw_addr_list_len; + + /* Check the signature. */ + secret = ep->current_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (__u8 *) bear_cookie, bodysize, + digest_buf); + if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + /* Try the previous key. */ + secret = ep->last_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (__u8 *) bear_cookie, bodysize, digest_buf); + if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + /* Yikes! Still bad signature! */ + *error = -SCTP_IERROR_BAD_SIG; + goto fail; + } + } + + /* Check to see if the cookie is stale. If there is already + * an association, there is no need to check cookie's expiration + * for init collision case of lost COOKIE ACK. + */ + if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { + *error = -SCTP_IERROR_STALE_COOKIE; + goto fail; + } + + /* Make a new base association. */ + scope = sctp_scope(sctp_source(chunk)); + retval = sctp_association_new(ep, ep->base.sk, scope, priority); + if (!retval) { + *error = -SCTP_IERROR_NOMEM; + goto fail; + } + + /* Set up our peer's port number. */ + retval->peer.port = ntohs(chunk->sctp_hdr->source); + + /* Populate the association from the cookie. */ + retval->c = *bear_cookie; + + /* Build the bind address list based on the cookie. */ + raw_addr_list = (__u8 *) bear_cookie + + sizeof(sctp_cookie_t) + var_size2; + if (sctp_raw_to_bind_addrs(&retval->base.bind_addr, raw_addr_list, + var_size3, retval->base.bind_addr.port, + priority)) { + *error = -SCTP_IERROR_NOMEM; + goto fail; + } + + retval->next_tsn = retval->c.initial_tsn; + retval->ctsn_ack_point = retval->next_tsn - 1; + + /* The INIT stuff will be done by the side effects. */ + return retval; + +fail: + if (retval) + sctp_association_free(retval); + + return NULL; + +malformed: + /* Yikes! The packet is either corrupt or deliberately + * malformed. + */ + *error = -SCTP_IERROR_MALFORMED; + goto fail; +} + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + +/* Unpack the parameters in an INIT packet. + * FIXME: There is no return status to allow callers to do + * error handling. + */ +void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, + const sockaddr_storage_t *peer_addr, + sctp_init_chunk_t *peer_init, + int priority) +{ + sctpParam_t param; + __u8 *end; + sctp_transport_t *transport; + list_t *pos, *temp; + + /* We must include the address that the INIT packet came from. + * This is the only address that matters for an INIT packet. + * When processing a COOKIE ECHO, we retrieve the from address + * of the INIT from the cookie. + */ + + /* This implementation defaults to making the first transport + * added as the primary transport. The source address seems to + * be a a better choice than any of the embedded addresses. + */ + if (peer_addr) + sctp_assoc_add_peer(asoc, peer_addr, priority); + + /* Process the initialization parameters. */ + end = ((__u8 *)peer_init + ntohs(peer_init->chunk_hdr.length)); + for (param.v = peer_init->init_hdr.params; + param.v < end; + param.v += WORD_ROUND(ntohs(param.p->length))) { + if (!sctp_process_param(asoc, param, peer_addr, cid, + priority)) + goto clean_up; + } + + /* The fixed INIT headers are always in network byte + * order. + */ + asoc->peer.i.init_tag = + ntohl(peer_init->init_hdr.init_tag); + asoc->peer.i.a_rwnd = + ntohl(peer_init->init_hdr.a_rwnd); + asoc->peer.i.num_outbound_streams = + ntohs(peer_init->init_hdr.num_outbound_streams); + asoc->peer.i.num_inbound_streams = + ntohs(peer_init->init_hdr.num_inbound_streams); + asoc->peer.i.initial_tsn = + ntohl(peer_init->init_hdr.initial_tsn); + + /* Apply the upper bounds for output streams based on peer's + * number of inbound streams. + */ + if (asoc->c.sinit_num_ostreams > + ntohs(peer_init->init_hdr.num_inbound_streams)) { + asoc->c.sinit_num_ostreams = + ntohs(peer_init->init_hdr.num_inbound_streams); + } + + /* Copy Initiation tag from INIT to VT_peer in cookie. */ + asoc->c.peer_vtag = asoc->peer.i.init_tag; + + /* Peer Rwnd : Current calculated value of the peer's rwnd. */ + asoc->peer.rwnd = asoc->peer.i.a_rwnd; + + /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily + * high (for example, implementations MAY use the size of the receiver + * advertised window). + */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + transport->ssthresh = asoc->peer.i.a_rwnd; + } + + /* Set up the TSN tracking pieces. */ + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, + asoc->peer.i.initial_tsn); + + /* ADDIP Section 4.1 ASCONF Chunk Procedures + * + * When an endpoint has an ASCONF signaled change to be sent to the + * remote endpoint it should do the following: + * ... + * A2) A serial number should be assigned to the Chunk. The serial + * number should be a monotonically increasing number. All serial + * numbers are defined to be initialized at the start of the + * association to the same value as the Initial TSN. + */ + asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; + return; + +clean_up: + /* Release the transport structures. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + list_del(pos); + sctp_transport_free(transport); + } +} + +/* Update asoc with the option described in param. + * + * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT + * + * asoc is the association to update. + * param is the variable length parameter to use for update. + * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO. + * If the current packet is an INIT we want to minimize the amount of + * work we do. In particular, we should not build transport + * structures for the addresses. + */ +int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, + const sockaddr_storage_t *peer_addr, + sctp_cid_t cid, int priority) +{ + sockaddr_storage_t addr; + int j; + int i; + int retval = 1; + sctp_scope_t scope; + + /* We maintain all INIT parameters in network byte order all the + * time. This allows us to not worry about whether the parameters + * came from a fresh INIT, and INIT ACK, or were stored in a cookie. + */ + switch (param.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + if (SCTP_CID_INIT != cid) { + sctp_param2sockaddr(&addr, param, asoc->peer.port); + scope = sctp_scope(peer_addr); + if (sctp_in_scope(&addr, scope)) + sctp_assoc_add_peer(asoc, &addr, priority); + } + break; + + case SCTP_PARAM_IPV6_ADDRESS: + if (SCTP_CID_INIT != cid) { + if (PF_INET6 == asoc->base.sk->family) { + sctp_param2sockaddr(&addr, param, + asoc->peer.port); + scope = sctp_scope(peer_addr); + if (sctp_in_scope(&addr, scope)) + sctp_assoc_add_peer(asoc, &addr, + priority); + } + } + break; + + case SCTP_PARAM_COOKIE_PRESERVATIVE: + asoc->cookie_preserve = + ntohl(param.bht->lifespan_increment); + break; + + case SCTP_PARAM_HOST_NAME_ADDRESS: + SCTP_DEBUG_PRINTK("unimplmented SCTP_HOST_NAME_ADDRESS\n"); + break; + + case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: + /* Turn off the default values first so we'll know which + * ones are really set by the peer. + */ + asoc->peer.ipv4_address = 0; + asoc->peer.ipv6_address = 0; + + j = (ntohs(param.p->length) - + sizeof(sctp_paramhdr_t)) / + sizeof(__u16); + for (i = 0; i < j; ++i) { + switch (param.sat->types[i]) { + case SCTP_PARAM_IPV4_ADDRESS: + asoc->peer.ipv4_address = 1; + break; + + case SCTP_PARAM_IPV6_ADDRESS: + asoc->peer.ipv6_address = 1; + break; + + case SCTP_PARAM_HOST_NAME_ADDRESS: + asoc->peer.hostname_address = 1; + break; + + default: /* Just ignore anything else. */ + break; + }; + } + break; + + case SCTP_PARAM_STATE_COOKIE: + asoc->peer.cookie_len = + ntohs(param.p->length) = + sizeof(sctp_paramhdr_t); + asoc->peer.cookie = param.cookie->body; + break; + + case SCTP_PARAM_HEATBEAT_INFO: + SCTP_DEBUG_PRINTK("unimplmented " + "SCTP_PARAM_HEATBEAT_INFO\n"); + break; + + case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: + SCTP_DEBUG_PRINTK("unimplemented " + "SCTP_PARAM_UNRECOGNIZED_PARAMETERS\n"); + break; + + case SCTP_PARAM_ECN_CAPABLE: + asoc->peer.ecn_capable = 1; + break; + + default: + SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", + ntohs(param.p->type), asoc); + /* FIXME: The entire parameter processing really needs + * redesigned. For now, always return success as doing + * otherwise craters the system. + */ + retval = 1; + + break; + }; + + return retval; +} + +/* Select a new verification tag. */ +__u32 sctp_generate_tag(const sctp_endpoint_t *ep) +{ + /* I believe that this random number generator complies with RFC1750. + * A tag of 0 is reserved for special cases (e.g. INIT). + */ + __u32 x; + + do { + get_random_bytes(&x, sizeof(__u32)); + } while (x == 0); + + return x; +} + +/* Select an initial TSN to send during startup. */ +__u32 sctp_generate_tsn(const sctp_endpoint_t *ep) +{ + /* I believe that this random number generator complies with RFC1750. */ + __u32 retval; + + get_random_bytes(&retval, sizeof(__u32)); + return retval; +} + +/******************************************************************** + * 4th Level Abstractions + ********************************************************************/ + +/* Convert from an SCTP IP parameter to a sockaddr_storage_t. */ +void sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, __u16 port) +{ + switch(param.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = port; + addr->v4.sin_addr.s_addr = param.v4->addr.s_addr; + break; + + case SCTP_PARAM_IPV6_ADDRESS: + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = port; + addr->v6.sin6_flowinfo = 0; /* BUG */ + addr->v6.sin6_addr = param.v6->addr; + addr->v6.sin6_scope_id = 0; /* BUG */ + break; + + default: + SCTP_DEBUG_PRINTK("Illegal address type %d\n", + ntohs(param.p->type)); + break; + }; +} + +/* Convert an IP address in an SCTP param into a sockaddr_in. */ +/* Returns true if a valid conversion was possible. */ +int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) +{ + if (!p.v) + return 0; + + switch (p.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); + sa->v4.sin_family = AF_INET; + break; + + case SCTP_PARAM_IPV6_ADDRESS: + *((struct in6_addr *)&sa->v4.sin_addr) + = p.v6->addr; + sa->v4.sin_family = AF_INET6; + break; + + default: + return 0; + }; + + return 1; +} + +/* Convert from an IP version number to an Address Family symbol. */ +int ipver2af(__u8 ipver) +{ + int family; + + switch (ipver) { + case 4: + family = AF_INET; + break; + + case 6: + family = AF_INET6; + break; + + default: + family = 0; + break; + }; + + return family; +} + +/* Convert a sockaddr_in to IP address in an SCTP para. */ +/* Returns true if a valid conversion was possible. */ +int sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctpParam_t p) +{ + int len = 0; + + switch (sa->v4.sin_family) { + case AF_INET: + p.p->type = SCTP_PARAM_IPV4_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv4addr_param_t)); + len = sizeof(sctp_ipv4addr_param_t); + p.v4->addr.s_addr = sa->v4.sin_addr.s_addr; + break; + + case AF_INET6: + p.p->type = SCTP_PARAM_IPV6_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv6addr_param_t)); + len = sizeof(sctp_ipv6addr_param_t); + p.v6->addr = *(&sa->v6.sin6_addr); + break; + + default: + printk(KERN_WARNING "sockaddr2sctp_addr: Illegal family %d.\n", + sa->v4.sin_family); + return 0; + }; + + return len; +} diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sm_sideeffect.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,1168 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions work with the state functions in sctp_sm_statefuns.c + * to implement that state operations. These functions implement the + * steps which require modifying existing data structures. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Hui Huang + * Dajiang Zhang + * Daisy Chang + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Do forward declarations of static functions. */ +static void sctp_do_ecn_ce_work(sctp_association_t *asoc, + __u32 lowest_tsn); +static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, + __u32 lowest_tsn, + sctp_chunk_t *); +static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, + __u32 lowest_tsn); + +static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, + sctp_transport_t *transport); +static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); +static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); +static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_init_chunk_t *peer_init, + int priority); +static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); +static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, + sctp_bind_addr_t *); +static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *); +static void sctp_cmd_transport_on(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *, sctp_chunk_t *); +static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, + sctp_sackhdr_t *); +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, + sctp_chunk_t *); + +/* 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. + */ +#define DEBUG_PRE \ + SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \ + "ep %p, %s, %s, asoc %p[%s], %s\n", \ + ep, sctp_evttype_tbl[event_type], \ + (*debug_fn)(subtype), asoc, \ + sctp_state_tbl[state], state_fn->name) + +#define DEBUG_POST \ + SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \ + "asoc %p, status: %s\n", \ + asoc, sctp_status_tbl[status]) + +#define DEBUG_POST_SFX \ + SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \ + error, asoc, \ + sctp_state_tbl[sctp_id2assoc(ep->base.sk, \ + sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED]) + +/* + * This is the master state machine processing function. + * + * If you want to understand all of lksctp, this is a + * good place to start. + */ +int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + int priority) +{ + sctp_cmd_seq_t commands; + sctp_sm_table_entry_t *state_fn; + sctp_disposition_t status; + int error = 0; + typedef const char *(printfn_t)(sctp_subtype_t); + + static printfn_t *table[] = { + NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname, + }; + printfn_t *debug_fn __attribute__ ((unused)) = table[event_type]; + + /* Look up the state function, run it, and then process the + * side effects. These three steps are the heart of lksctp. + */ + state_fn = sctp_sm_lookup_event(event_type, state, subtype); + + sctp_init_cmd_seq(&commands); + + DEBUG_PRE; + status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands); + DEBUG_POST; + + error = sctp_side_effects(event_type, subtype, state, + ep, asoc, event_arg, + status, &commands, + priority); + DEBUG_POST_SFX; + + return error; +} + +#undef DEBUG_PRE +#undef DEBUG_POST + +/***************************************************************** + * This the master state function side effect processing function. + *****************************************************************/ +int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *commands, + int priority) +{ + int error; + + /* FIXME - Most of the dispositions left today would be categorized + * as "exceptional" dispositions. For those dispositions, it + * may not be proper to run through any of the commands at all. + * For example, the command interpreter might be run only with + * disposition SCTP_DISPOSITION_CONSUME. + */ + if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, + ep, asoc, + event_arg, status, + commands, priority))) + goto bail; + + switch (status) { + case SCTP_DISPOSITION_DISCARD: + SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + break; + + case SCTP_DISPOSITION_NOMEM: + /* We ran out of memory, so we need to discard this + * packet. + */ + /* BUG--we should now recover some memory, probably by + * reneging... + */ + break; + + case SCTP_DISPOSITION_DELETE_TCB: + /* This should now be a command. */ + break; + + case SCTP_DISPOSITION_CONSUME: + case SCTP_DISPOSITION_ABORT: + /* + * We should no longer have much work to do here as the + * real work has been done as explicit commands above. + */ + break; + + case SCTP_DISPOSITION_VIOLATION: + printk(KERN_ERR "sctp protocol violation state %d " + "chunkid %d\n", state, subtype.chunk); + break; + + case SCTP_DISPOSITION_NOT_IMPL: + printk(KERN_WARNING "sctp unimplemented feature in state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + break; + + case SCTP_DISPOSITION_BUG: + printk(KERN_ERR "sctp bug in state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + BUG(); + break; + + default: + printk(KERN_ERR "sctp impossible disposition %d " + "in state %d, event_type %d, event_id %d\n", + status, state, event_type, subtype.chunk); + BUG(); + break; + }; + +bail: + return error; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* This is the side-effect interpreter. */ +int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, sctp_endpoint_t *ep, + sctp_association_t *asoc, void *event_arg, + sctp_disposition_t status, sctp_cmd_seq_t *commands, + int priority) +{ + int error = 0; + int force; + sctp_cmd_t *command; + sctp_chunk_t *new_obj; + sctp_chunk_t *chunk; + sctp_packet_t *packet; + struct timer_list *timer; + unsigned long timeout; + sctp_transport_t *t; + sctp_sackhdr_t sackh; + + chunk = (sctp_chunk_t *) event_arg; + + /* Note: This whole file is a huge candidate for rework. + * For example, each command could either have its own handler, so + * the loop would look like: + * while (cmds) + * cmd->handle(x, y, z) + * --jgrimm + */ + while (NULL != (command = sctp_next_cmd(commands))) { + switch (command->verb) { + case SCTP_CMD_NOP: + /* Do nothing. */ + break; + + case SCTP_CMD_NEW_ASOC: + /* Register a new association. */ + asoc = command->obj.ptr; + /* Register with the endpoint. */ + sctp_endpoint_add_asoc(ep, asoc); + sctp_hash_established(asoc); + break; + + case SCTP_CMD_UPDATE_ASSOC: + sctp_assoc_update(asoc, command->obj.ptr); + break; + + case SCTP_CMD_PURGE_OUTQUEUE: + sctp_outqueue_teardown(&asoc->outqueue); + break; + + case SCTP_CMD_DELETE_TCB: + /* Delete the current association. */ + sctp_unhash_established(asoc); + sctp_association_free(asoc); + asoc = NULL; + break; + + case SCTP_CMD_NEW_STATE: + /* Enter a new state. */ + asoc->state = command->obj.state; + asoc->state_timestamp = jiffies; + break; + + case SCTP_CMD_REPORT_TSN: + /* Record the arrival of a TSN. */ + sctp_tsnmap_mark(&asoc->peer.tsn_map, + command->obj.u32); + break; + + case SCTP_CMD_GEN_SACK: + /* Generate a Selective ACK. + * The argument tells us whether to just count + * the packet and MAYBE generate a SACK, or + * force a SACK out. + */ + force = command->obj.i32; + error = sctp_gen_sack(asoc, force, commands); + break; + + case SCTP_CMD_PROCESS_SACK: + /* Process an inbound SACK. */ + error = sctp_cmd_process_sack(commands, asoc, + command->obj.ptr); + break; + + case SCTP_CMD_GEN_INIT_ACK: + /* Generate an INIT ACK chunk. */ + new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC); + if (!new_obj) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_PEER_INIT: + /* Process a unified INIT from the peer. */ + sctp_cmd_process_init(commands, + asoc, chunk, command->obj.ptr, + priority); + break; + + case SCTP_CMD_GEN_COOKIE_ECHO: + /* Generate a COOKIE ECHO chunk. */ + new_obj = sctp_make_cookie_echo(asoc, chunk); + if (!new_obj) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_GEN_SHUTDOWN: + /* Generate SHUTDOWN when in SHUTDOWN_SENT state. + * Reset error counts. + */ + asoc->overall_error_count = 0; + + /* Generate a SHUTDOWN chunk. */ + new_obj = sctp_make_shutdown(asoc); + if (!new_obj) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_CHUNK_ULP: + /* Send a chunk to the sockets layer. */ + SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", + "chunk_up:", + command->obj.ptr, + "ulpq:", + &asoc->ulpq); + sctp_ulpqueue_tail_data(&asoc->ulpq, + command->obj.ptr, + GFP_ATOMIC); + break; + + case SCTP_CMD_EVENT_ULP: + /* Send a notification to the sockets layer. */ + SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", + "event_up:", + command->obj.ptr, + "ulpq:", + &asoc->ulpq); + sctp_ulpqueue_tail_event(&asoc->ulpq, + command->obj.ptr); + break; + + case SCTP_CMD_REPLY: + /* Send a chunk to our peer. */ + error = sctp_push_outqueue(&asoc->outqueue, + command->obj.ptr); + break; + + case SCTP_CMD_SEND_PKT: + /* Send a full packet to our peer. */ + packet = command->obj.ptr; + sctp_packet_transmit(packet); + sctp_transport_free(packet->transport); + sctp_packet_free(packet); + break; + + case SCTP_CMD_RETRAN: + /* Mark a transport for retransmission. */ + sctp_retransmit(&asoc->outqueue, + command->obj.transport, 0); + break; + + case SCTP_CMD_TRANSMIT: + /* Kick start transmission. */ + error = sctp_flush_outqueue(&asoc->outqueue, 0); + break; + + case SCTP_CMD_ECN_CE: + /* Do delayed CE processing. */ + sctp_do_ecn_ce_work(asoc, command->obj.u32); + break; + + case SCTP_CMD_ECN_ECNE: + /* Do delayed ECNE processing. */ + new_obj = sctp_do_ecn_ecne_work(asoc, + command->obj.u32, + chunk); + if (new_obj) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + } + break; + + case SCTP_CMD_ECN_CWR: + /* Do delayed CWR processing. */ + sctp_do_ecn_cwr_work(asoc, command->obj.u32); + break; + + case SCTP_CMD_SETUP_T2: + sctp_cmd_setup_t2(commands, asoc, command->obj.ptr); + break; + + case SCTP_CMD_TIMER_START: + timer = &asoc->timers[command->obj.to]; + timeout = asoc->timeouts[command->obj.to]; + if (!timeout) + BUG(); + + timer->expires = jiffies + timeout; + sctp_association_hold(asoc); + add_timer(timer); + break; + + case SCTP_CMD_TIMER_RESTART: + timer = &asoc->timers[command->obj.to]; + timeout = asoc->timeouts[command->obj.to]; + if (!mod_timer(timer, jiffies + timeout)) + sctp_association_hold(asoc); + break; + + case SCTP_CMD_TIMER_STOP: + timer = &asoc->timers[command->obj.to]; + if (timer_pending(timer) && del_timer(timer)) + sctp_association_put(asoc); + break; + + case SCTP_CMD_INIT_RESTART: + /* Do the needed accounting and updates + * associated with restarting an initialization + * timer. + */ + asoc->counters[SCTP_COUNTER_INIT_ERROR]++; + asoc->timeouts[command->obj.to] *= 2; + if (asoc->timeouts[command->obj.to] > + asoc->max_init_timeo) { + asoc->timeouts[command->obj.to] = + asoc->max_init_timeo; + } + + sctp_add_cmd_sf(commands, + SCTP_CMD_TIMER_RESTART, + SCTP_TO(command->obj.to)); + break; + + case SCTP_CMD_INIT_FAILED: + sctp_cmd_init_failed(commands, asoc); + break; + + case SCTP_CMD_ASSOC_FAILED: + sctp_cmd_assoc_failed(commands, asoc); + break; + + case SCTP_CMD_COUNTER_INC: + asoc->counters[command->obj.counter]++; + break; + + case SCTP_CMD_COUNTER_RESET: + asoc->counters[command->obj.counter] = 0; + break; + + case SCTP_CMD_REPORT_DUP: + if (asoc->peer.next_dup_tsn < SCTP_MAX_DUP_TSNS) { + asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] = + ntohl(command->obj.u32); + } + break; + + case SCTP_CMD_REPORT_BIGGAP: + SCTP_DEBUG_PRINTK("Big gap: %x to %x\n", + sctp_tsnmap_get_ctsn( + &asoc->peer.tsn_map), + command->obj.u32); + break; + + case SCTP_CMD_REPORT_BAD_TAG: + SCTP_DEBUG_PRINTK("vtag mismatch!\n"); + break; + + case SCTP_CMD_SET_BIND_ADDR: + sctp_cmd_set_bind_addrs(commands, asoc, + command->obj.bp); + break; + + case SCTP_CMD_STRIKE: + /* Mark one strike against a transport. */ + sctp_do_8_2_transport_strike(asoc, + command->obj.transport); + break; + + case SCTP_CMD_TRANSPORT_RESET: + t = command->obj.transport; + sctp_cmd_transport_reset(commands, asoc, t); + break; + + case SCTP_CMD_TRANSPORT_ON: + t = command->obj.transport; + sctp_cmd_transport_on(commands, asoc, t, chunk); + break; + + case SCTP_CMD_HB_TIMERS_START: + sctp_cmd_hb_timers_start(commands, asoc); + break; + + case SCTP_CMD_REPORT_ERROR: + error = command->obj.error; + break; + + case SCTP_CMD_PROCESS_CTSN: + /* Dummy up a SACK for processing. */ + sackh.cum_tsn_ack = command->obj.u32; + sackh.a_rwnd = 0; + sackh.num_gap_ack_blocks = 0; + sackh.num_dup_tsns = 0; + sctp_add_cmd_sf(commands, + SCTP_CMD_PROCESS_SACK, + SCTP_SACKH(&sackh)); + break; + + case SCTP_CMD_DISCARD_PACKET: + /* We need to discard the whole packet. */ + chunk->pdiscard = 1; + break; + + default: + printk(KERN_WARNING "Impossible command: %u, %p\n", + command->verb, command->obj.ptr); + break; + }; + } + + return error; + +nomem: + error = -ENOMEM; + return error; +} + +/* A helper function for delayed processing of INET ECN CE bit. */ +static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) +{ + /* + * Save the TSN away for comparison when we receive CWR + * Note: dp->TSN is expected in host endian + */ + + asoc->last_ecne_tsn = lowest_tsn; + asoc->need_ecne = 1; +} + +/* Helper function for delayed processing of SCTP ECNE chunk. */ +/* RFC 2960 Appendix A + * + * RFC 2481 details a specific bit for a sender to send in + * the header of its next outbound TCP segment to indicate to + * its peer that it has reduced its congestion window. This + * is termed the CWR bit. For SCTP the same indication is made + * by including the CWR chunk. This chunk contains one data + * element, i.e. the TSN number that was sent in the ECNE chunk. + * This element represents the lowest TSN number in the datagram + * that was originally marked with the CE bit. + */ +static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, + __u32 lowest_tsn, + sctp_chunk_t *chunk) +{ + sctp_chunk_t *repl; + sctp_transport_t *transport; + + /* Our previously transmitted packet ran into some congestion + * so we should take action by reducing cwnd and ssthresh + * and then ACK our peer that we we've done so by + * sending a CWR. + */ + + /* Find which transport's congestion variables + * need to be adjusted. + */ + + transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn); + + /* Update the congestion variables. */ + if (transport) + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE); + + /* Save away a rough idea of when we last sent out a CWR. + * We compare against this value (see above) to decide if + * this is a fairly new request. + * Note that this is not a perfect solution. We may + * have moved beyond the window (several times) by the + * next time we get an ECNE. However, it is cute. This idea + * came from Randy's reference code. + * + * Here's what RFC 2960 has to say about CWR. This is NOT + * what we do. + * + * RFC 2960 Appendix A + * + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in + * the header of its next outbound TCP segment to indicate + * to its peer that it has reduced its congestion window. + * This is termed the CWR bit. For SCTP the same + * indication is made by including the CWR chunk. This + * chunk contains one data element, i.e. the TSN number + * that was sent in the ECNE chunk. This element + * represents the lowest TSN number in the datagram that + * was originally marked with the CE bit. + */ + asoc->last_cwr_tsn = asoc->next_tsn - 1; + + repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); + + /* If we run out of memory, it will look like a lost CWR. We'll + * get back in sync eventually. + */ + return repl; +} + +/* Helper function to do delayed processing of ECN CWR chunk. */ +static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, + __u32 lowest_tsn) +{ + /* Turn off ECNE getting auto-prepended to every outgoing + * packet + */ + asoc->need_ecne = 0; +} + +/* This macro is to compress the text a bit... */ +#define AP(v) asoc->peer.v + +/* Generate SACK if necessary. We call this at the end of a packet. */ +int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands) +{ + __u32 ctsn, max_tsn_seen; + sctp_chunk_t *sack; + int error = 0; + + if (force) + asoc->peer.sack_needed = 1; + + ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map); + + /* From 12.2 Parameters necessary per association (i.e. the TCB): + * + * Ack State : This flag indicates if the next received packet + * : is to be responded to with a SACK. ... + * : When DATA chunks are out of order, SACK's + * : are not delayed (see Section 6). + * + * [This is actually not mentioned in Section 6, but we + * implement it here anyway. --piggy] + */ + if (max_tsn_seen != ctsn) + asoc->peer.sack_needed = 1; + + /* From 6.2 Acknowledgement on Reception of DATA Chunks: + * + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, + * an acknowledgement SHOULD be generated for at least every + * second packet (not every second DATA chunk) received, and + * SHOULD be generated within 200 ms of the arrival of any + * unacknowledged DATA chunk. ... + */ + if (!asoc->peer.sack_needed) { + /* We will need a SACK for the next packet. */ + asoc->peer.sack_needed = 1; + goto out; + } else { + sack = sctp_make_sack(asoc); + if (!sack) + goto nomem; + + asoc->peer.sack_needed = 0; + asoc->peer.next_dup_tsn = 0; + + error = sctp_push_outqueue(&asoc->outqueue, sack); + + /* Stop the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } + +out: + return error; + +nomem: + error = -ENOMEM; + return error; +} + +/* Handle a duplicate TSN. */ +void sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, long gap) +{ +#if 0 + sctp_chunk_t *sack; + + /* Caution: gap < 2 * SCTP_TSN_MAP_SIZE + * so gap can be negative. + * + * --xguo + */ + + /* Count this TSN. */ + if (gap < SCTP_TSN_MAP_SIZE) { + asoc->peer.tsn_map[gap]++; + } else { + asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++; + } + + /* From 6.2 Acknowledgement on Reception of DATA Chunks + * + * When a packet arrives with duplicate DATA chunk(s) + * and with no new DATA chunk(s), the endpoint MUST + * immediately send a SACK with no delay. If a packet + * arrives with duplicate DATA chunk(s) bundled with + * new DATA chunks, the endpoint MAY immediately send a + * SACK. Normally receipt of duplicate DATA chunks + * will occur when the original SACK chunk was lost and + * the peer's RTO has expired. The duplicate TSN + * number(s) SHOULD be reported in the SACK as + * duplicate. + */ + asoc->counters[SctpCounterAckState] = 2; +#endif /* 0 */ +} /* sctp_do_TSNdup() */ + +#undef AP + +/* When the T3-RTX timer expires, it calls this function to create the + * relevant state machine event. + */ +void sctp_generate_t3_rtx_event(unsigned long peer) +{ + int error; + sctp_transport_t *transport = (sctp_transport_t *) peer; + sctp_association_t *asoc = transport->asoc; + + /* Check whether a task is in the sock. */ + + sctp_bh_lock_sock(asoc->base.sk); + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__); + + /* Try again later. */ + if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20))) + sctp_transport_hold(transport); + goto out_unlock; + } + + /* Is this transport really dead and just waiting around for + * the timer to let go of the reference? + */ + if (transport->dead) + goto out_unlock; + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX), + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); + + if (error) + asoc->base.sk->err = -error; + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_transport_put(transport); +} + +/* This is a sa interface for producing timeout events. It works + * for timeouts which use the association as their parameter. + */ +static void sctp_generate_timeout_event(sctp_association_t *asoc, + sctp_event_timeout_t timeout_type) +{ + int error = 0; + + sctp_bh_lock_sock(asoc->base.sk); + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n", + __FUNCTION__, + timeout_type); + + /* Try again later. */ + if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20))) + sctp_association_hold(asoc); + goto out_unlock; + } + + /* Is this association really dead and just waiting around for + * the timer to let go of the reference? + */ + if (asoc->base.dead) + goto out_unlock; + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(timeout_type), + asoc->state, asoc->ep, asoc, + (void *)timeout_type, + GFP_ATOMIC); + + if (error) + asoc->base.sk->err = -error; + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_association_put(asoc); +} + +void sctp_generate_t1_cookie_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); +} + +void sctp_generate_t1_init_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); +} + +void sctp_generate_t2_shutdown_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); +} + +void sctp_generate_autoclose_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); +} + +/* Generate a heart beat event. If the sock is busy, reschedule. Make + * sure that the transport is still valid. + */ +void sctp_generate_heartbeat_event(unsigned long data) +{ + int error = 0; + sctp_transport_t *transport = (sctp_transport_t *) data; + sctp_association_t *asoc = transport->asoc; + + sctp_bh_lock_sock(asoc->base.sk); + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__); + + /* Try again later. */ + if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20))) + sctp_transport_hold(transport); + goto out_unlock; + } + + /* Is this structure just waiting around for us to actually + * get destroyed? + */ + if (transport->dead) + goto out_unlock; + + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); + + if (error) + asoc->base.sk->err = -error; + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_transport_put(transport); +} + +/* Inject a SACK Timeout event into the state machine. */ +void sctp_generate_sack_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); +} + +void sctp_generate_pmtu_raise_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_PMTU_RAISE); +} + +sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { + NULL, + sctp_generate_t1_cookie_event, + sctp_generate_t1_init_event, + sctp_generate_t2_shutdown_event, + NULL, + NULL, + sctp_generate_heartbeat_event, + sctp_generate_sack_event, + sctp_generate_autoclose_event, + sctp_generate_pmtu_raise_event, +}; + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + +/* RFC 2960 8.2 Path Failure Detection + * + * When its peer endpoint is multi-homed, an endpoint should keep a + * error counter for each of the destination transport addresses of the + * peer endpoint. + * + * Each time the T3-rtx timer expires on any address, or when a + * HEARTBEAT sent to an idle address is not acknowledged within a RTO, + * the error counter of that destination address will be incremented. + * When the value in the error counter exceeds the protocol parameter + * 'Path.Max.Retrans' of that destination address, the endpoint should + * mark the destination transport address as inactive, and a + * notification SHOULD be sent to the upper layer. + * + */ +static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, + sctp_transport_t *transport) +{ + /* The check for association's overall error counter exceeding the + * threshold is done in the state function. + */ + asoc->overall_error_count++; + + if (transport->state.active && + (transport->error_count++ >= transport->error_threshold)) { + SCTP_DEBUG_PRINTK("transport_strike: transport " + "IP:%d.%d.%d.%d failed.\n", + NIPQUAD(transport->ipaddr.v4.sin_addr)); + sctp_assoc_control_transport(asoc, transport, + SCTP_TRANSPORT_DOWN, + SCTP_FAILED_THRESHOLD); + } + + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ + transport->rto = min((transport->rto * 2), transport->asoc->rto_max); +} + +/* Worker routine to handle INIT command failure. */ +static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, + sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + event = sctp_ulpevent_make_assoc_change(asoc, + 0, + SCTP_CANT_STR_ASSOC, + 0, 0, 0, + GFP_ATOMIC); + + if (event) + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(event)); + + /* FIXME: We need to handle data possibly either + * sent via COOKIE-ECHO bundling or just waiting in + * the transmit queue, if the user has enabled + * SEND_FAILED notifications. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); +} + +/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */ +static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, + sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + event = sctp_ulpevent_make_assoc_change(asoc, + 0, + SCTP_COMM_LOST, + 0, 0, 0, + GFP_ATOMIC); + + if (event) + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(event)); + + /* FIXME: We need to handle data that could not be sent or was not + * acked, if the user has enabled SEND_FAILED notifications. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); +} + +/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT + * inside the cookie. + */ +static void sctp_cmd_process_init(sctp_cmd_seq_t *commands, + sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_init_chunk_t *peer_init, + int priority) +{ + /* The command sequence holds commands assuming that the + * processing will happen successfully. If this is not the + * case, rewind the sequence and add appropriate error handling + * to the sequence. + */ + sctp_process_init(asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, + priority); +} + +/* Helper function to break out starting up of heartbeat timers. */ +static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, + sctp_association_t *asoc) +{ + sctp_transport_t *t; + list_t *pos; + + /* Start a heartbeat timer for each transport on the association. + * hold a reference on the transport to make sure none of + * the needed data structures go away. + */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + if (!mod_timer(&t->hb_timer, + t->hb_interval + t->rto + jiffies)) { + sctp_transport_hold(t); + } + } +} + +/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ +void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_bind_addr_t *bp) +{ + list_t *pos, *temp; + + list_for_each_safe(pos, temp, &bp->address_list) { + list_del_init(pos); + list_add_tail(pos, &asoc->base.bind_addr.address_list); + } + + /* Free the temporary bind addr header, otherwise + * there will a memory leak. + */ + sctp_bind_addr_free(bp); +} + +/* Helper function to handle the reception of an HEARTBEAT ACK. */ +static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_transport_t *t, sctp_chunk_t *chunk) +{ + sctp_sender_hb_info_t *hbinfo; + + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the + * HEARTBEAT should clear the error counter of the destination + * transport address to which the HEARTBEAT was sent. + * The association's overall error count is also cleared. + */ + t->error_count = 0; + t->asoc->overall_error_count = 0; + + /* Mark the destination transport address as active if it is not so + * marked. + */ + if (!t->state.active) + sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, + SCTP_HEARTBEAT_SUCCESS); + + /* The receiver of the HEARTBEAT ACK should also perform an + * RTT measurement for that destination transport address + * using the time value carried in the HEARTBEAT ACK chunk. + */ + hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; + sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at)); +} + +/* Helper function to do a transport reset at the expiry of the hearbeat + * timer. + */ +static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, + sctp_association_t *asoc, + sctp_transport_t *t) +{ + sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); + + /* Mark one strike against a transport. */ + sctp_do_8_2_transport_strike(asoc, t); + + /* Update the heartbeat timer. */ + if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) + sctp_transport_hold(t); +} + +/* Helper function to process the process SACK command. */ +static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_sackhdr_t *sackh) +{ + int err; + + if (sctp_sack_outqueue(&asoc->outqueue, sackh)) { + /* There are no more TSNs awaiting SACK. */ + err = sctp_do_sm(SCTP_EVENT_T_OTHER, + SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), + asoc->state, asoc->ep, asoc, NULL, + GFP_ATOMIC); + } else { + /* Windows may have opened, so we need + * to check if we have DATA to transmit + */ + err = sctp_flush_outqueue(&asoc->outqueue, 0); + } + + return err; +} + +/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set + * the transport for a shutdown chunk. + */ +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_chunk_t *chunk) +{ + sctp_transport_t *t; + + t = sctp_assoc_choose_shutdown_transport(asoc); + asoc->shutdown_last_sent_to = t; + asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; + chunk->transport = t; +} diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sm_statefuns.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,3697 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2002 International Business Machines, Corp. + * Copyright (c) 2002 Nokia Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This is part of the SCTP Linux Kernel Reference Implementation. + * + * These are the state functions for the state machine. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Mathew Kotowsky + * Sridhar Samudrala + * Jon Grimm + * Hui Huang + * Dajiang Zhang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************** + * These are the state functions for handling chunk events. + **********************************************************/ + +/* + * Process the final SHUTDOWN COMPLETE. + * + * Section: 4 (C) (diagram), 9.2 + * Upon reception of the SHUTDOWN COMPLETE chunk the endpoint will verify + * that it is in SHUTDOWN-ACK-SENT state, if it is not the chunk should be + * discarded. If the endpoint is in the SHUTDOWN-ACK-SENT state the endpoint + * should stop the T2-shutdown timer and remove all knowledge of the + * association (and thus the association enters the CLOSED state). + * + * Verification Tag: 8.5.1(C) + * C) Rules for packet carrying SHUTDOWN COMPLETE: + * ... + * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the + * Verification Tag field of the packet matches its own tag OR it is + * set to its peer's tag and the T bit is set in the Chunk Flags. + * Otherwise, the receiver MUST silently discard the packet and take + * no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if + * it is not in the SHUTDOWN-ACK-SENT state. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_ulpevent_t *ev; + + /* RFC 2960 6.10 Bundling + * + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) + return SCTP_DISPOSITION_VIOLATION; + + /* RFC 2960 8.5.1 Exceptions in Verification Tag Rules + * + * (C) The receiver of a SHUTDOWN COMPLETE shall accept the + * packet if the Verification Tag field of the packet + * matches its own tag OR it is set to its peer's tag and + * the T bit is set in the Chunk Flags. Otherwise, the + * receiver MUST silently discard the packet and take no + * further action.... + */ + if ((ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) && + !(sctp_test_T_bit(chunk) || + (ntohl(chunk->sctp_hdr->vtag) != asoc->peer.i.init_tag))) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + /* RFC 2960 10.2 SCTP-to-ULP + * + * H) SHUTDOWN COMPLETE notification + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, + 0, 0, 0, GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint + * will verify that it is in SHUTDOWN-ACK-SENT state, if it is + * not the chunk should be discarded. If the endpoint is in + * the SHUTDOWN-ACK-SENT state the endpoint should stop the + * T2-shutdown timer and remove all knowledge of the + * association (and thus the association enters the CLOSED + * state). + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Discard the whole packet. + * + * Section: 8.4 2) + * + * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST + * silently discard the OOTB packet and take no further action. + * Otherwise, + * + * Verification Tag: No verification necessary + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Respond to a normal INIT chunk. + * We are the side that is being asked for an association. + * + * Section: 5.1 Normal Establishment of an Association, B + * B) "Z" shall respond immediately with an INIT ACK chunk. The + * destination IP address of the INIT ACK MUST be set to the source + * IP address of the INIT to which this INIT ACK is responding. In + * the response, besides filling in other parameters, "Z" must set the + * Verification Tag field to Tag_A, and also provide its own + * Verification Tag (Tag_Z) in the Initiate Tag field. + * + * Verification Tag: No checking. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *repl; + sctp_association_t *new_asoc; + + /* If the packet is an OOTB packet which is temporarily on the + * control endpoint, responding with an ABORT. + */ + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) + return sctp_sf_ootb(ep, asoc, type, arg, commands); + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) + return SCTP_DISPOSITION_VIOLATION; + + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + + /* Tag the variable length parameters. */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); + if (!new_asoc) + goto nomem; + + /* FIXME: sctp_process_init can fail, but there is no + * status nor handling. + */ + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + + /* B) "Z" shall respond immediately with an INIT ACK chunk. */ + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + if (!repl) + goto nomem_ack; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* + * Note: After sending out INIT ACK with the State Cookie parameter, + * "Z" MUST NOT allocate any resources, nor keep any states for the + * new association. Otherwise, "Z" will be vulnerable to resource + * attacks. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + +nomem_ack: + sctp_association_free(new_asoc); +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Respond to a normal INIT ACK chunk. + * We are the side that is initiating the association. + * + * Section: 5.1 Normal Establishment of an Association, C + * C) Upon reception of the INIT ACK from "Z", "A" shall stop the T1-init + * timer and leave COOKIE-WAIT state. "A" shall then send the State + * Cookie received in the INIT ACK chunk in a COOKIE ECHO chunk, start + * the T1-cookie timer, and enter the COOKIE-ECHOED state. + * + * Note: The COOKIE ECHO chunk can be bundled with any pending outbound + * DATA chunks, but it MUST be the first chunk in the packet and + * until the COOKIE ACK is returned the sender MUST NOT send any + * other packets to the peer. + * + * Verification Tag: 3.3.3 + * If the value of the Initiate Tag in a received INIT ACK chunk is + * found to be 0, the receiver MUST treat it as an error and close the + * association by transmitting an ABORT. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_init_chunk_t *initchunk; + __u32 init_tag; + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) + return SCTP_DISPOSITION_VIOLATION; + + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; + + init_tag = ntohl(chunk->subh.init_hdr->init_tag); + + /* Verification Tag: 3.3.3 + * If the value of the Initiate Tag in a received INIT ACK + * chunk is found to be 0, the receiver MUST treat it as an + * error and close the association by transmitting an ABORT. + */ + if (!init_tag) { + sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); + if (!reply) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(reply)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* Tag the variable length paramters. Note that we never + * convert the parameters in an INIT chunk. + */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr; + + sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, + SCTP_PEER_INIT(initchunk)); + + /* 5.1 C) "A" shall stop the T1-init timer and leave + * COOKIE-WAIT state. "A" shall then ... start the T1-cookie + * timer, and enter the COOKIE-ECHOED state. + */ + 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, + SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); + + /* 5.1 C) "A" shall then send the State Cookie received in the + * INIT ACK chunk in a COOKIE ECHO chunk, ... + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Respond to a normal COOKIE ECHO chunk. + * We are the side that is being asked for an association. + * + * Section: 5.1 Normal Establishment of an Association, D + * D) Upon reception of the COOKIE ECHO chunk, Endpoint "Z" will reply + * with a COOKIE ACK chunk after building a TCB and moving to + * the ESTABLISHED state. A COOKIE ACK chunk may be bundled with + * any pending DATA chunks (and/or SACK chunks), but the COOKIE ACK + * chunk MUST be the first chunk in the packet. + * + * IMPLEMENTATION NOTE: An implementation may choose to send the + * Communication Up notification to the SCTP user upon reception + * of a valid COOKIE ECHO chunk. + * + * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules + * D) Rules for packet carrying a COOKIE ECHO + * + * - When sending a COOKIE ECHO, the endpoint MUST use the value of the + * Initial Tag received in the INIT ACK. + * + * - The receiver of a COOKIE ECHO follows the procedures in Section 5. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_association_t *new_asoc; + sctp_init_chunk_t *peer_init; + sctp_chunk_t *repl; + sctp_ulpevent_t *ev; + int error = 0; + + /* If the packet is an OOTB packet which is temporarily on the + * control endpoint, responding with an ABORT. + */ + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) + return sctp_sf_ootb(ep, asoc, type, arg, commands); + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ + chunk->subh.cookie_hdr = + (sctp_signed_cookie_t *)chunk->skb->data; + skb_pull(chunk->skb, + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + + /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint + * "Z" will reply with a COOKIE ACK chunk after building a TCB + * and moving to the ESTABLISHED state. + */ + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + + /* FIXME: + * If the re-build failed, what is the proper error path + * from here? + * + * [We should abort the association. --piggy] + */ + if (!new_asoc) { + /* FIXME: Several errors are possible. A bad cookie should + * be silently discarded, but think about logging it too. + */ + switch (error) { + case -SCTP_IERROR_NOMEM: + goto nomem; + + case -SCTP_IERROR_BAD_SIG: + default: + return sctp_sf_pdiscard(ep, asoc, type, + arg, commands); + }; + } + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + if (new_asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* Re-build the bind address for the association is done in + * the sctp_unpack_cookie() already. + */ + /* This is a brand-new association, so these are not yet side + * effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + &chunk->subh.cookie_hdr->c.peer_addr, peer_init, + GFP_ATOMIC); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) + goto nomem_repl; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose to + * send the Communication Up notification to the SCTP user + * upon reception of a valid COOKIE ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + 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: + sctp_free_chunk(repl); + +nomem_repl: + sctp_association_free(new_asoc); + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Respond to a normal COOKIE ACK chunk. + * We are the side that is being asked for an association. + * + * RFC 2960 5.1 Normal Establishment of an Association + * + * E) Upon reception of the COOKIE ACK, endpoint "A" will move from the + * COOKIE-ECHOED state to the ESTABLISHED state, stopping the T1-cookie + * timer. It may also notify its ULP about the successful + * establishment of the association with a Communication Up + * notification (see Section 10). + * + * Verification Tag: + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_ulpevent_t *ev; + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * E) Upon reception of the COOKIE ACK, endpoint "A" will move + * from the COOKIE-ECHOED state to the ESTABLISHED state, + * stopping the T1-cookie timer. + */ + 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, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* It may also notify its ULP about the successful + * establishment of the association with a Communication Up + * notification (see Section 10). + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, + 0, asoc->c.sinit_num_ostreams, + asoc->c.sinit_max_instreams, + 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; +} + +/* Generate a HEARTBEAT packet on the given transport. */ +sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = (sctp_transport_t *) arg; + sctp_chunk_t *reply; + sctp_sender_hb_info_t hbinfo; + size_t paylen = 0; + + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* Section 3.3.5. + * The Sender-specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent (see Section 8.3). + */ + + hbinfo.param_hdr.type = SCTP_PARAM_HEATBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; + + /* Set rto_pending indicating that an RTT measurement is started + * with this heartbeat chunk. + */ + transport->rto_pending = 1; + + /* Send a heartbeat to our peer. */ + paylen = sizeof(sctp_sender_hb_info_t); + reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); + if (!reply) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(reply)); + + /* Set transport error counter and association error counter + * when sending heartbeat. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, + SCTP_TRANSPORT(transport)); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Process an heartbeat request. + * + * Section: 8.3 Path Heartbeat + * The receiver of the HEARTBEAT should immediately respond with a + * HEARTBEAT ACK that contains the Heartbeat Information field copied + * from the received HEARTBEAT chunk. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * When receiving an SCTP packet, the endpoint MUST ensure that the + * value in the Verification Tag field of the received SCTP packet + * matches its own Tag. If the received Verification Tag value does not + * match the receiver's own tag value, the receiver shall silently + * discard the packet and shall not process it any further except for + * those cases listed in Section 8.5.1 below. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *reply; + size_t paylen = 0; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + /* 8.3 The receiver of the HEARTBEAT should immediately + * respond with a HEARTBEAT ACK that contains the Heartbeat + * Information field copied from the received HEARTBEAT chunk. + */ + chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; + paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); + skb_pull(chunk->skb, paylen); + + reply = sctp_make_heartbeat_ack(asoc, chunk, + chunk->subh.hb_hdr, paylen); + if (!reply) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Process the returning HEARTBEAT ACK. + * + * Section: 8.3 Path Heartbeat + * Upon the receipt of the HEARTBEAT ACK, the sender of the HEARTBEAT + * should clear the error counter of the destination transport + * address to which the HEARTBEAT was sent, and mark the destination + * transport address as active if it is not so marked. The endpoint may + * optionally report to the upper layer when an inactive destination + * address is marked as active due to the reception of the latest + * HEARTBEAT ACK. The receiver of the HEARTBEAT ACK must also + * clear the association overall error count as well (as defined + * in section 8.1). + * + * The receiver of the HEARTBEAT ACK should also perform an RTT + * measurement for that destination transport address using the time + * value carried in the HEARTBEAT ACK chunk. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sockaddr_storage_t from_addr; + sctp_transport_t *link; + sctp_sender_hb_info_t *hbinfo; + unsigned long max_interval; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; + from_addr = hbinfo->daddr; + link = sctp_assoc_lookup_paddr(asoc, &from_addr); + + /* This should never happen, but lets log it if so. */ + if (!link) { + printk(KERN_WARNING + "%s: Could not find address %d.%d.%d.%d\n", + __FUNCTION__, NIPQUAD(from_addr.v4.sin_addr)); + return SCTP_DISPOSITION_DISCARD; + } + + max_interval = link->hb_interval + link->rto; + + /* Check if the timestamp looks valid. */ + if (time_after(hbinfo->sent_at, jiffies) || + time_after(jiffies, hbinfo->sent_at + max_interval)) { + SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp + received for transport: %p\n", + __FUNCTION__, link); + return SCTP_DISPOSITION_DISCARD; + } + + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of + * the HEARTBEAT should clear the error counter of the + * destination transport address to which the HEARTBEAT was + * sent and mark the destination transport address as active if + * it is not so marked. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, + SCTP_TRANSPORT(link)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* Populate the verification/tie tags based on overlapping INIT + * scenario. + * + * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. + */ +static void sctp_tietags_populate(sctp_association_t *new_asoc, + const sctp_association_t *asoc) +{ + switch (asoc->state) { + + /* 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State */ + + case SCTP_STATE_COOKIE_WAIT: + new_asoc->c.my_vtag = asoc->c.my_vtag; + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = 0; + break; + + case SCTP_STATE_COOKIE_ECHOED: + new_asoc->c.my_vtag = asoc->c.my_vtag; + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = asoc->c.peer_vtag; + break; + + /* 5.2.2 Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED, + * COOKIE-WAIT and SHUTDOWN-ACK-SENT + */ + default: + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = asoc->c.peer_vtag; + break; + }; + + /* Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of + * outbound streams) into the INIT ACK and cookie. + */ + new_asoc->rwnd = asoc->rwnd; + new_asoc->c.sinit_num_ostreams = asoc->c.sinit_num_ostreams; + new_asoc->c.sinit_max_instreams = asoc->c.sinit_max_instreams; + new_asoc->c.initial_tsn = asoc->c.initial_tsn; +} + +/* + * Compare vtag/tietag values to determine unexpected COOKIE-ECHO + * handling action. + * + * RFC 2960 5.2.4 Handle a COOKIE ECHO when a TCB exists. + * + * Returns value representing action to be taken. These action values + * correspond to Action/Description values in RFC 2960, Table 2. + */ +static char sctp_tietags_compare(sctp_association_t *new_asoc, + const sctp_association_t *asoc) +{ + /* In this case, the peer may have restarted. */ + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && + (asoc->c.peer_vtag != new_asoc->c.peer_vtag) && + (asoc->c.my_vtag == new_asoc->c.my_ttag) && + (asoc->c.peer_vtag == new_asoc->c.peer_ttag)) + return 'A'; + + /* Collision case D. + * Note: Test case D first, otherwise it may be incorrectly + * identified as second case of B if the value of the Tie_tag is + * not filled into the state cookie. + */ + if ((asoc->c.my_vtag == new_asoc->c.my_vtag) && + (asoc->c.peer_vtag == new_asoc->c.peer_vtag)) + return 'D'; + + /* Collision case B. */ + if ((asoc->c.my_vtag == new_asoc->c.my_vtag) && + ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) || + (!new_asoc->c.my_ttag && !new_asoc->c.peer_ttag))) + return 'B'; + + /* Collision case C. */ + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && + (asoc->c.peer_vtag == new_asoc->c.peer_vtag) && + (0 == new_asoc->c.my_ttag) && + (0 == new_asoc->c.peer_ttag)) + return 'C'; + + return 'E'; /* No such case available. */ +} + +/* Common helper routine for both duplicate and simulataneous INIT + * chunk handling. + */ +static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, const sctp_subtype_t type, + void *arg, sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *repl; + sctp_association_t *new_asoc; + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) + return SCTP_DISPOSITION_VIOLATION; + + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; + + /* Tag the variable length parameters. */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + /* + * Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of + * outbound streams) into the INIT ACK and cookie. + * FIXME: We are copying parameters from the endpoint not the + * association. + */ + new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); + if (!new_asoc) + goto nomem; + + /* In the outbound INIT ACK the endpoint MUST copy its current + * Verification Tag and Peers Verification tag into a reserved + * place (local tie-tag and per tie-tag) within the state cookie. + */ + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC); + sctp_tietags_populate(new_asoc, asoc); + + /* B) "Z" shall respond immediately with an INIT ACK chunk. */ + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* + * Note: After sending out INIT ACK with the State Cookie parameter, + * "Z" MUST NOT allocate any resources for this new association. + * Otherwise, "Z" will be vulnerable to resource attacks. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Handle simultanous INIT. + * This means we started an INIT and then we got an INIT request from + * our peer. + * + * Section: 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State (Item B) + * This usually indicates an initialization collision, i.e., each + * endpoint is attempting, at about the same time, to establish an + * association with the other endpoint. + * + * Upon receipt of an INIT in the COOKIE-WAIT or COOKIE-ECHOED state, an + * endpoint MUST respond with an INIT ACK using the same parameters it + * sent in its original INIT chunk (including its Verification Tag, + * unchanged). These original parameters are combined with those from the + * newly received INIT chunk. The endpoint shall also generate a State + * Cookie with the INIT ACK. The endpoint uses the parameters sent in its + * INIT to calculate the State Cookie. + * + * After that, the endpoint MUST NOT change its state, the T1-init + * timer shall be left running and the corresponding TCB MUST NOT be + * destroyed. The normal procedures for handling State Cookies when + * a TCB exists will resolve the duplicate INITs to a single association. + * + * For an endpoint that is in the COOKIE-ECHOED state it MUST populate + * its Tie-Tags with the Tag information of itself and its peer (see + * section 5.2.2 for a description of the Tie-Tags). + * + * Verification Tag: Not explicit, but an INIT can not have a valid + * verification tag, so we skip the check. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* Call helper to do the real work for both simulataneous and + * duplicate INIT chunk handling. + */ + return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); +} + +/* + * Handle duplicated INIT messages. These are usually delayed + * restransmissions. + * + * Section: 5.2.2 Unexpected INIT in States Other than CLOSED, + * COOKIE-ECHOED and COOKIE-WAIT + * + * Unless otherwise stated, upon reception of an unexpected INIT for + * this association, the endpoint shall generate an INIT ACK with a + * State Cookie. In the outbound INIT ACK the endpoint MUST copy its + * current Verification Tag and peer's Verification Tag into a reserved + * place within the state cookie. We shall refer to these locations as + * the Peer's-Tie-Tag and the Local-Tie-Tag. The outbound SCTP packet + * containing this INIT ACK MUST carry a Verification Tag value equal to + * the Initiation Tag found in the unexpected INIT. And the INIT ACK + * MUST contain a new Initiation Tag (randomly generated see Section + * 5.3.1). Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of outbound + * streams) into the INIT ACK and cookie. + * + * After sending out the INIT ACK, the endpoint shall take no further + * actions, i.e., the existing association, including its current state, + * and the corresponding TCB MUST NOT be changed. + * + * Note: Only when a TCB exists and the association is not in a COOKIE- + * WAIT state are the Tie-Tags populated. For a normal association INIT + * (i.e. the endpoint is in a COOKIE-WAIT state), the Tie-Tags MUST be + * set to 0 (indicating that no previous TCB existed). The INIT ACK and + * State Cookie are populated as specified in section 5.2.1. + * + * Verification Tag: Not specifed, but an INIT has no way of knowing + * what the verification tag could be, so we ignore it. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* Call helper to do the real work for both simulataneous and + * duplicate INIT chunk handling. + */ + return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); +} + +/* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A') + * + * Section 5.2.4 + * A) In this case, the peer may have restarted. + */ +static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_init_chunk_t *peer_init; + sctp_ulpevent_t *ev; + sctp_chunk_t *repl; + sctp_transport_t *new_addr, *addr; + list_t *pos, *pos2, *temp; + int found, error; + + /* new_asoc is a brand-new association, so these are not yet + * side effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC); + + /* Make sure peer is not adding new addresses. */ + found = 0; + new_addr = NULL; + list_for_each(pos, &new_asoc->peer.transport_addr_list) { + new_addr = list_entry(pos, sctp_transport_t, transports); + found = 1; + list_for_each_safe(pos2, temp, + &asoc->peer.transport_addr_list) { + addr = list_entry(pos2, sctp_transport_t, transports); + if (!sctp_cmp_addr_exact(&new_addr->ipaddr, + &addr->ipaddr)) { + found = 0; + break; + } + } + if (!found) + break; + } + + if (!found) { + sctp_bind_addr_t *bp; + sctpParam_t rawaddr; + int len; + + bp = sctp_bind_addr_new(GFP_ATOMIC); + if (!bp) + goto nomem; + + error = sctp_add_bind_addr(bp, &new_addr->ipaddr, GFP_ATOMIC); + if (error) + goto nomem_add; + + rawaddr = sctp_bind_addrs_to_raw(bp, &len, GFP_ATOMIC); + if (!rawaddr.v) + goto nomem_raw; + + repl = sctp_make_abort(asoc, chunk, len+sizeof(sctp_errhdr_t)); + if (!repl) + goto nomem_abort; + sctp_init_cause(repl, SCTP_ERROR_RESTART, rawaddr.v, len); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + return SCTP_DISPOSITION_CONSUME; + + nomem_abort: + kfree(rawaddr.v); + + nomem_raw: + nomem_add: + sctp_bind_addr_free(bp); + goto nomem; + } + + /* For now, fail any unsent/unacked data. Consider the optional + * choice of resending of this data. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Update the content of current association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* Report association restart to upper layer. */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + 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: + sctp_free_chunk(repl); + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'B') + * + * Section 5.2.4 + * B) In this case, both sides may be attempting to start an association + * at about the same time but the peer endpoint started its INIT + * after responding to the local endpoint's INIT + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_init_chunk_t *peer_init; + sctp_ulpevent_t *ev; + sctp_chunk_t *repl; + + /* new_asoc is a brand-new association, so these are not yet + * side effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC); + + /* Update the content of current association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose to + * send the Communication Up notification to the SCTP user + * upon reception of a valid COOKIE ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + 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: + sctp_free_chunk(repl); +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'C') + * + * Section 5.2.4 + * C) In this case, the local endpoint's cookie has arrived late. + * Before it arrived, the local endpoint sent an INIT and received an + * INIT-ACK and finally sent a COOKIE ECHO with the peer's same tag + * but a new tag of its own. + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + /* The cookie should be silently discarded. + * The endpoint SHOULD NOT change states and should leave + * any timers running. + */ + return SCTP_DISPOSITION_DISCARD; +} + +/* Unexpected COOKIE-ECHO handler lost chunk (Table 2, action 'D') + * + * Section 5.2.4 + * + * D) When both local and remote tags match the endpoint should always + * enter the ESTABLISHED state, if it has not already done so. + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_ulpevent_t *ev = NULL; + sctp_chunk_t *repl; + + /* The local endpoint cannot use any value from the received + * state cookie and need to immediately resend a COOKIE-ACK + * and move into ESTABLISHED if it hasn't done so. + */ + if (SCTP_STATE_ESTABLISHED != asoc->state) { + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, + SCTP_NULL()); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose + * to send the Communication Up notification to the + * SCTP user upon reception of a valid COOKIE + * ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, + SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + 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()); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + +nomem: + if (ev) + sctp_ulpevent_free(ev); + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Handle a duplicate COOKIE-ECHO. This usually means a cookie-carrying + * chunk was retransmitted and then delayed in the network. + * + * Section: 5.2.4 Handle a COOKIE ECHO when a TCB exists + * + * Verification Tag: None. Do cookie validation. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_disposition_t retval; + sctp_chunk_t *chunk = arg; + sctp_association_t *new_asoc; + int error = 0; + char action; + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ + chunk->subh.cookie_hdr = + (sctp_signed_cookie_t *) chunk->skb->data; + skb_pull(chunk->skb, + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + + /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie + * of a duplicate COOKIE ECHO match the Verification Tags of the + * current association, consider the State Cookie valid even if + * the lifespan is exceeded. + */ + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + + /* FIXME: + * If the re-build failed, what is the proper error path + * from here? + * + * [We should abort the association. --piggy] + */ + if (!new_asoc) { + /* FIXME: Several errors are possible. A bad cookie should + * be silently discarded, but think about logging it too. + */ + switch (error) { + case -SCTP_IERROR_NOMEM: + goto nomem; + + case -SCTP_IERROR_BAD_SIG: + default: + return sctp_sf_pdiscard(ep, asoc, type, + arg, commands); + }; + } + + /* Compare the tie_tag in cookie with the verification tag of + * current association. + */ + action = sctp_tietags_compare(new_asoc, asoc); + + switch (action) { + case 'A': /* Association restart. */ + retval = sctp_sf_do_dupcook_a(ep, asoc, chunk, commands, + new_asoc); + break; + + case 'B': /* Collision case B. */ + retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands, + new_asoc); + break; + + case 'C': /* Collisioun case C. */ + retval = sctp_sf_do_dupcook_c(ep, asoc, chunk, commands, + new_asoc); + break; + + case 'D': /* Collision case D. */ + retval = sctp_sf_do_dupcook_d(ep, asoc, chunk, commands, + new_asoc); + break; + + default: /* No such case, discard it. */ + printk(KERN_WARNING "%s:unknown case\n", __FUNCTION__); + retval = SCTP_DISPOSITION_DISCARD; + break; + }; + + /* Delete the tempory new association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return retval; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +#if 0 +/* + * Handle a Stale COOKIE Error + * + * Section: 5.2.6 Handle Stale COOKIE Error + * If the association is in the COOKIE-ECHOED state, the endpoint may elect + * one of the following three alternatives. + * ... + * 3) Send a new INIT chunk to the endpoint, adding a Cookie + * Preservative parameter requesting an extension to the lifetime of + * the State Cookie. When calculating the time extension, an + * implementation SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no more + * than 1 second beyond the measured RTT, due to long State Cookie + * lifetimes making the endpoint more subject to a replay attack. + * + * Verification Tag: Not explicit, but safe to ignore. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* This is not a real chunk type. It is a subtype of the + * ERROR chunk type. The ERROR chunk processing will bring us + * here. + */ + sctp_chunk_t *in_packet; + stp_chunk_t *reply; + sctp_inithdr_t initack; + __u8 *addrs; + int addrs_len; + time_t rtt; + struct sctpCookiePreserve bht; + + /* If we have gotten too many failures, give up. */ + if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts) { + /* FIXME: Move to new ulpevent. */ + retval->event_up = sctp_make_ulp_init_timeout(asoc); + if (!retval->event_up) + goto nomem; + sctp_add_cmd_sf(retval->commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + retval->counters[0] = SCTP_COUNTER_INCR; + retval->counters[0] = SctpCounterInits; + retval->counters[1] = 0; + retval->counters[1] = 0; + + /* Calculate the RTT in ms. */ + /* BUG--we should get the send time of the HEARTBEAT REQUEST. */ + in_packet = chunk; + rtt = 1000 * timeval_sub(in_packet->skb->stamp, + asoc->c.state_timestamp); + + /* When calculating the time extension, an implementation + * SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no + * more than 1 second beyond the measured RTT, due to long + * State Cookie lifetimes making the endpoint more subject to + * a replay attack. + */ + bht.p = {SCTP_COOKIE_PRESERVE, 8}; + bht.extraTime = htonl(rtt + 1000); + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(atomic_read(&asoc->rnwd)); + initack.num_outbound_streams = htons(asoc->streamoutcnt); + initack.num_inbound_streams = htons(asoc->streamincnt); + initack.initial_tsn = htonl(asoc->c.initSeqNumber); + + sctp_get_my_addrs(asoc, &addrs, &addrs_len); + + /* Build that new INIT chunk. */ + reply = sctp_make_chunk(SCTP_INITIATION, 0, + sizeof(initack) + + sizeof(bht) + + addrs_len); + if (!reply) + goto nomem; + sctp_addto_chunk(reply, sizeof(initack), &initack); + sctp_addto_chunk(reply, sizeof(bht), &bht); + sctp_addto_chunk(reply, addrs_len, addrs); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} +#endif /* 0 */ + +/* + * Process an ABORT. + * + * Section: 9.1 + * After checking the Verification Tag, the receiving endpoint shall + * remove the association from its record, and shall report the + * termination to its upper layer. + * + * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules + * B) Rules for packet carrying ABORT: + * + * - The endpoint shall always fill in the Verification Tag field of the + * outbound packet with the destination endpoint's tag value if it + * is known. + * + * - If the ABORT is sent in response to an OOTB packet, the endpoint + * MUST follow the procedure described in Section 8.4. + * + * - The receiver MUST accept the packet if the Verification Tag + * matches either its own tag, OR the tag of its peer. Otherwise, the + * receiver MUST silently discard the packet and take no further + * action. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* Check the verification tag. */ + /* BUG: WRITE ME. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + /* BUG? This does not look complete... */ + return SCTP_DISPOSITION_ABORT; +} + +/* + * Process an ABORT. (COOKIE-WAIT state) + * + * See sctp_sf_do_9_1_abort() above. + */ +sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + /* CMD_INIT_FAILED will DELETE_TCB. */ + sctp_add_cmd_sf(commands,SCTP_CMD_INIT_FAILED, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; +} + +/* + * Process an ABORT. (COOKIE-ECHOED state) + * + * See sctp_sf_do_9_1_abort() above. + */ +sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands); +} + +#if 0 +/* + * Handle a shutdown timeout or INIT during a shutdown phase. + * + * Section: 9.2 + * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk + * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination + * transport addresses (either in the IP addresses or in the INIT chunk) + * that belong to this association, it should discard the INIT chunk and + * retransmit the SHUTDOWN ACK chunk. + *... + * While in SHUTDOWN-SENT state ... If the timer expires, the endpoint + * must re-send the SHUTDOWN ACK. + * + * Verification Tag: Neither the INIT nor the timeout will have a + * valid verification tag, so it is safe to ignore. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_do_9_2_reshutack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* If this was a timeout (not an INIT), then do the counter + * work. We might need to just dump the association. + */ + if (!chunk) { + if (1 + asoc->counters[SctpCounterRetran] > + asoc->maxRetrans) { + sctp_add_cmd(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + retval->counters[0] = SCTP_COUNTER_INCR; + retval->counters[0] = SctpCounterRetran; + retval->counters[1] = 0; + retval->counters[1] = 0; + } + + reply = sctp_make_shutdown_ack(asoc, chunk); + if (!reply) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} +#endif /* 0 */ + +/* + * sctp_sf_do_9_2_shut + * + * Section: 9.2 + * Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, + * + * - stop accepting new data from its SCTP user + * + * - verify, by checking the Cumulative TSN Ack field of the chunk, + * that all its outstanding DATA chunks have been received by the + * SHUTDOWN sender. + * + * Once an endpoint as reached the SHUTDOWN-RECEIVED state it MUST NOT + * send a SHUTDOWN in response to a ULP request. And should discard + * subsequent SHUTDOWN chunks. + * + * If there are still outstanding DATA chunks left, the SHUTDOWN + * receiver shall continue to follow normal data transmission + * procedures defined in Section 6 until all outstanding DATA chunks + * are acknowledged; however, the SHUTDOWN receiver MUST NOT accept + * new data from its SCTP user. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_shutdownhdr_t *sdh; + sctp_disposition_t disposition; + + /* Convert the elaborate header. */ + sdh = (sctp_shutdownhdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); + chunk->subh.shutdown_hdr = sdh; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + /* Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, + * - stop accepting new data from its SCTP user + * + * [This is implicit in the new state.] + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED)); + disposition = SCTP_DISPOSITION_CONSUME; + + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_shutdown_ack(ep, asoc, type, + arg, commands); + } + + /* - verify, by checking the Cumulative TSN Ack field of the + * chunk, that all its outstanding DATA chunks have been + * received by the SHUTDOWN sender. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, + SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); + return disposition; +} + +/* + * sctp_sf_do_ecn_cwr + * + * Section: Appendix A: Explicit Congestion Notification + * + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in the header of + * its next outbound TCP segment to indicate to its peer that it has + * reduced its congestion window. This is termed the CWR bit. For + * SCTP the same indication is made by including the CWR chunk. + * This chunk contains one data element, i.e. the TSN number that + * was sent in the ECNE chunk. This element represents the lowest + * TSN number in the datagram that was originally marked with the + * CE bit. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_cwrhdr_t *cwr; + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + cwr = (sctp_cwrhdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t)); + + cwr->lowest_tsn = ntohl(cwr->lowest_tsn); + + /* Does this CWR ack the last sent congestion notification? */ + if (TSN_lte(asoc->last_ecne_tsn, cwr->lowest_tsn)) { + /* Stop sending ECNE. */ + sctp_add_cmd_sf(commands, + SCTP_CMD_ECN_CWR, + SCTP_U32(cwr->lowest_tsn)); + } + return SCTP_DISPOSITION_CONSUME; +} + +/* + * sctp_sf_do_ecne + * + * Section: Appendix A: Explicit Congestion Notification + * + * ECN-Echo + * + * RFC 2481 details a specific bit for a receiver to send back in its + * TCP acknowledgements to notify the sender of the Congestion + * Experienced (CE) bit having arrived from the network. For SCTP this + * same indication is made by including the ECNE chunk. This chunk + * contains one data element, i.e. the lowest TSN associated with the IP + * datagram marked with the CE bit..... + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_ecnehdr_t *ecne; + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + ecne = (sctp_ecnehdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t)); + ecne->lowest_tsn = ntohl(ecne->lowest_tsn); + + /* Casting away the const, as we are just modifying the spinlock, + * not the association itself. This should go away in the near + * future when we move to an endpoint based lock. + */ + + /* If this is a newer ECNE than the last CWR packet we sent out */ + if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)) { + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE, + SCTP_U32(ecne->lowest_tsn)); + } + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Section: 6.2 Acknowledgement on Reception of DATA Chunks + * + * The SCTP endpoint MUST always acknowledge the reception of each valid + * DATA chunk. + * + * The guidelines on delayed acknowledgement algorithm specified in + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, an + * acknowledgement SHOULD be generated for at least every second packet + * (not every second DATA chunk) received, and SHOULD be generated within + * 200 ms of the arrival of any unacknowledged DATA chunk. In some + * situations it may be beneficial for an SCTP transmitter to be more + * conservative than the algorithms detailed in this document allow. + * However, an SCTP transmitter MUST NOT be more aggressive than the + * following algorithms allow. + * + * A SCTP receiver MUST NOT generate more than one SACK for every + * incoming packet, other than to update the offered window as the + * receiving application consumes new data. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; + sctp_chunk_t *err; + size_t datalen; + int tmp; + __u32 tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + 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); + SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); + + /* 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) { + chunk->ecn_ce_done = 1; + if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && + 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 discard_noforce; + } else if (tmp > 0) { + /* This is a duplicate. Record it. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + goto discard_force; + } + + /* This is a new TSN. */ + + /* If we don't have any room in our receive window, discard. + * Actually, allow a little bit of overflow (up to a MTU of + * of overflow). + */ + datalen = ntohs(chunk->chunk_hdr->length); + datalen -= sizeof(sctp_data_chunk_t); + + if (!asoc->rwnd || (datalen > asoc->frag_point)) { + SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %Zd, " + "rwnd: %d\n", tsn, datalen, asoc->rwnd); + goto discard_noforce; + } + + /* + * 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_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + 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)); + + /* 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, SCTP_CMD_CHUNK_ULP, SCTP_CHUNK(chunk)); + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + /* If this is the last chunk in a packet, we need to count it + * toward sack generation. Note that we need to SACK every + * OTHER packet containing data chunks, EVEN IF WE DISCARD + * THEM. We elect to NOT generate SACK's if the chunk fails + * the verification tag test. + * + * RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks + * + * The SCTP endpoint MUST always acknowledge the reception of + * each valid DATA chunk. + * + * The guidelines on delayed acknowledgement algorithm + * specified in Section 4.2 of [RFC2581] SHOULD be followed. + * Specifically, an acknowledgement SHOULD be generated for at + * least every second packet (not every second DATA chunk) + * received, and SHOULD be generated within 200 ms of the + * arrival of any unacknowledged DATA chunk. In some + * situations it may be beneficial for an SCTP transmitter to + * be more conservative than the algorithms detailed in this + * document allow. However, an SCTP transmitter MUST NOT be + * more aggressive than the following algorithms allow. + */ + if (chunk->end_of_packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + + /* Start the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } + + return SCTP_DISPOSITION_CONSUME; + +discard_force: + /* RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks + * + * When a packet arrives with duplicate DATA chunk(s) and with + * no new DATA chunk(s), the endpoint MUST immediately send a + * SACK with no delay. If a packet arrives with duplicate + * DATA chunk(s) bundled with new DATA chunks, the endpoint + * MAY immediately send a SACK. Normally receipt of duplicate + * DATA chunks will occur when the original SACK chunk was lost + * and the peer's RTO has expired. The duplicate TSN number(s) + * SHOULD be reported in the SACK as duplicate. + */ + /* In our case, we split the MAY SACK advice up whether or not + * the last chunk is a duplicate.' + */ + if (chunk->end_of_packet) + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + return SCTP_DISPOSITION_DISCARD; + +discard_noforce: + if (chunk->end_of_packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + + /* Start the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } + return SCTP_DISPOSITION_DISCARD; +} + +/* + * sctp_sf_eat_data_fast_4_4 + * + * Section: 4 (4) + * (4) In SHUTDOWN-SENT state the endpoint MUST acknowledge any received + * DATA chunks without delay. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; + sctp_chunk_t *err; + size_t datalen; + int tmp; + __u32 tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + 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) { + chunk->ecn_ce_done = 1; + if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && + 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_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + 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)); + + /* 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)); + } + } + + /* 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 + * respond to each received packet containing one or more DATA chunk(s) + * with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer + */ + if (chunk->end_of_packet) { + /* We must delay the chunk creation since the cumulative + * TSN has not been updated yet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + } + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Section: 6.2 Processing a Received SACK + * D) Any time a SACK arrives, the endpoint performs the following: + * + * i) If Cumulative TSN Ack is less than the Cumulative TSN Ack Point, + * then drop the SACK. Since Cumulative TSN Ack is monotonically + * increasing, a SACK whose Cumulative TSN Ack is less than the + * Cumulative TSN Ack Point indicates an out-of-order SACK. + * + * ii) Set rwnd equal to the newly received a_rwnd minus the number + * of bytes still outstanding after processing the Cumulative TSN Ack + * and the Gap Ack Blocks. + * + * iii) If the SACK is missing a TSN that was previously + * acknowledged via a Gap Ack Block (e.g., the data receiver + * reneged on the data), then mark the corresponding DATA chunk + * as available for retransmit: Mark it as missing for fast + * retransmit as described in Section 7.2.4 and if no retransmit + * timer is running for the destination address to which the DATA + * chunk was originally transmitted, then T3-rtx is started for + * that destination address. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_sackhdr_t *sackh; + __u32 ctsn; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + /* Pull the SACK chunk from the data buffer */ + sackh = sctp_sm_pull_sack(chunk); + chunk->subh.sack_hdr = sackh; + ctsn = ntohl(sackh->cum_tsn_ack); + + /* i) If Cumulative TSN Ack is less than the Cumulative TSN + * Ack Point, then drop the SACK. Since Cumulative TSN + * Ack is monotonically increasing, a SACK whose + * Cumulative TSN Ack is less than the Cumulative TSN Ack + * Point indicates an out-of-order SACK. + */ + if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { + SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); + SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", + asoc->ctsn_ack_point); + return SCTP_DISPOSITION_DISCARD; + } + + /* Return this SACK for further processing. */ + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, + SCTP_SACKH(sackh)); + + /* Note: We do the rest of the work on the PROCESS_SACK + * sideeffect. + */ + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Generate an ABORT in response to a packet. + * + * Section: 8.4 Handle "Out of the blue" Packets + * + * 8) The receiver should respond to the sender of the OOTB packet + * with an ABORT. When sending the ABORT, the receiver of the + * OOTB packet MUST fill in the Verification Tag field of the + * outbound packet with the value found in the Verification Tag + * field of the OOTB packet and set the T-bit in the Chunk Flags + * to indicate that no TCB was found. After sending this ABORT, + * the receiver of the OOTB packet shall discard the OOTB packet + * and take no further action. + * + * Verification Tag: + * + * The return value is the disposition of the chunk. +*/ +sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *abort; + __u16 sport; + __u16 dport; + __u32 vtag; + + /* Grub in chunk and endpoint for kewl bitz. */ + sport = ntohs(chunk->sctp_hdr->dest); + dport = ntohs(chunk->sctp_hdr->source); + /* -- Make sure the ABORT packet's V-tag is the same as the + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + if (asoc) + vtag = asoc->peer.i.init_tag; + else + vtag = ntohl(chunk->sctp_hdr->vtag); + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + if (!transport) + goto nomem; + + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) + goto nomem_packet; + + packet = sctp_packet_init(packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0, NULL); + + /* Make an ABORT. + * This will set the T bit since we have no association. + */ + abort = sctp_make_abort(NULL, chunk, 0); + if (!abort) + goto nomem_chunk; + + /* Set the skb to the belonging sock for accounting. */ + abort->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, abort); + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + return SCTP_DISPOSITION_DISCARD; + +nomem_chunk: + sctp_packet_free(packet); + +nomem_packet: + sctp_transport_free(transport); + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Received an ERROR chunk from peer. Generate SCTP_REMOTE_ERROR + * event as ULP notification for each cause included in the chunk. + * + * API 5.3.1.3 - SCTP_REMOTE_ERROR + * + * The return value is the disposition of the chunk. +*/ +sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_ulpevent_t *ev; + + while (chunk->chunk_end > chunk->skb->data) { + ev = sctp_ulpevent_make_remote_error(asoc,chunk,0, GFP_ATOMIC); + if (!ev) + goto nomem; + + if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev))) { + sctp_ulpevent_free(ev); + goto nomem; + } + } + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Process an inbound SHUTDOWN ACK. + * + * From Section 9.2: + * Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall + * stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its + * peer, and remove all record of the association. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *reply; + sctp_ulpevent_t *ev; + + /* 10.2 H) SHUTDOWN COMPLETE notification + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, + 0, 0, 0, GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall + * stop the T2-shutdown timer, + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ + reply = sctp_make_shutdown_complete(asoc, chunk); + if (!reply) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + /* ...and remove all record of the association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets + * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB + * packet must fill in the Verification Tag field of the outbound + * packet with the Verification Tag received in the SHUTDOWN ACK and + * set the T-bit in the Chunk Flags to indicate that no TCB was + * found. Otherwise, + * + * 8) The receiver should respond to the sender of the OOTB packet with + * an ABORT. When sending the ABORT, the receiver of the OOTB packet + * MUST fill in the Verification Tag field of the outbound packet + * with the value found in the Verification Tag field of the OOTB + * packet and set the T-bit in the Chunk Flags to indicate that no + * TCB was found. After sending this ABORT, the receiver of the OOTB + * packet shall discard the OOTB packet and take no further action. + */ +sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + struct sk_buff *skb = chunk->skb; + sctp_chunkhdr_t *ch; + __u8 *ch_end; + int ootb_shut_ack = 0; + + ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; + do { + ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + + if (SCTP_CID_SHUTDOWN_ACK == ch->type) + ootb_shut_ack = 1; + + ch = (sctp_chunkhdr_t *) ch_end; + } while (ch_end < skb->tail); + + if (ootb_shut_ack) + sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); + else + sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); + + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); +} + +/* + * Handle an "Out of the blue" SHUTDOWN ACK. + * + * Section: 8.4 5) + * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet + * must fill in the Verification Tag field of the outbound packet with + * the Verification Tag received in the SHUTDOWN ACK and set the + * T-bit in the Chunk Flags to indicate that no TCB was found. + * + * Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK + * If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the + * procedures in section 8.4 SHOULD be followed, in other words it + * should be treated as an Out Of The Blue packet. + * [This means that we do NOT check the Verification Tag on these + * chunks. --piggy ] + * + * Inputs + * (endpoint, asoc, type, arg, commands) + * + * Outputs + * (sctp_disposition_t) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *shut; + __u16 sport; + __u16 dport; + __u32 vtag; + + /* Grub in chunk and endpoint for kewl bitz. */ + sport = ntohs(chunk->sctp_hdr->dest); + dport = ntohs(chunk->sctp_hdr->source); + + /* Make sure the ABORT packet's V-tag is the same as the + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + vtag = ntohl(chunk->sctp_hdr->vtag); + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + if (!transport) + goto nomem; + + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) + goto nomem_packet; + + packet = sctp_packet_init(packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0, NULL); + + /* Make an ABORT. + * This will set the T bit since we have no association. + */ + shut = sctp_make_shutdown_complete(NULL, chunk); + if (!shut) + goto nomem_chunk; + + /* Set the skb to the belonging sock for accounting. */ + shut->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, shut); + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + + return SCTP_DISPOSITION_CONSUME; + +nomem_chunk: + sctp_packet_free(packet); + +nomem_packet: + sctp_transport_free(transport); + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +#if 0 +/* + * We did something stupid but got lucky. Namely, we sent a HEARTBEAT + * before the association was all the way up and we did NOT get an + * ABORT. + * + * Log the fact and then process normally. + * + * Section: Not specified + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t lucky(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} +#endif /* 0 */ + +#if 0 +/* + * The other end is doing something very stupid. We'll ignore them + * after logging their idiocy. :-) + * + * Section: Not specified + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} +#endif /* 0 */ + +/* + * The other end is violating protocol. + * + * Section: Not specified + * Verification Tag: Not specified + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * We simply tag the chunk as a violation. The state machine will log + * the violation and continue. + */ +sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_VIOLATION; +} + +/*************************************************************************** + * These are the state functions for handling primitive (Section 10) events. + ***************************************************************************/ +/* + * sctp_sf_do_prm_asoc + * + * Section: 10.1 ULP-to-SCTP + * B) Associate + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) + * -> association id [,destination transport addr list] [,outbound stream + * count] + * + * This primitive allows the upper layer to initiate an association to a + * specific peer endpoint. + * + * The peer endpoint shall be specified by one of the transport addresses + * which defines the endpoint (see Section 1.4). If the local SCTP + * instance has not been initialized, the ASSOCIATE is considered an + * error. + * [This is not relevant for the kernel implementation since we do all + * initialization at boot time. It we hadn't initialized we wouldn't + * get anywhere near this code.] + * + * An association id, which is a local handle to the SCTP association, + * will be returned on successful establishment of the association. If + * SCTP is not able to open an SCTP association with the peer endpoint, + * an error is returned. + * [In the kernel implementation, the sctp_association_t needs to + * be created BEFORE causing this primitive to run.] + * + * Other association parameters may be returned, including the + * complete destination transport addresses of the peer as well as the + * outbound stream count of the local endpoint. One of the transport + * address from the returned destination addresses will be selected by + * the local endpoint as default primary path for sending SCTP packets + * to this peer. The returned "destination transport addr list" can + * be used by the ULP to change the default primary path or to force + * sending a packet to a specific transport address. [All of this + * stuff happens when the INIT ACK arrives. This is a NON-BLOCKING + * function.] + * + * Mandatory attributes: + * + * o local SCTP instance name - obtained from the INITIALIZE operation. + * [This is the argument asoc.] + * o destination transport addr - specified as one of the transport + * addresses of the peer endpoint with which the association is to be + * established. + * [This is asoc->peer.active_path.] + * o outbound stream count - the number of outbound streams the ULP + * would like to open towards this peer endpoint. + * [BUG: This is not currently implemented.] + * Optional attributes: + * + * None. + * + * The return value is a disposition. + */ +sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *repl; + sctp_bind_addr_t *bp; + sctp_scope_t scope; + int error; + int flags; + + /* The comment below says that we enter COOKIE-WAIT AFTER + * sending the INIT, but that doesn't actually work in our + * implementation... + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_COOKIE_WAIT)); + + /* Build up the bind address list for the association based on + * info from the local endpoint and the remote peer. + */ + bp = sctp_bind_addr_new(GFP_ATOMIC); + if (!bp) + goto nomem; + + /* Use scoping rules to determine the subset of addresses from + * the endpoint. + */ + scope = sctp_scope(&asoc->peer.active_path->ipaddr); + flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + if (asoc->peer.ipv4_address) + flags |= SCTP_ADDR4_PEERSUPP; + if (asoc->peer.ipv6_address) + flags |= SCTP_ADDR6_PEERSUPP; + error = sctp_bind_addr_copy(bp, &ep->base.bind_addr, scope, + GFP_ATOMIC, flags); + if (error) + goto nomem; + + /* FIXME: Either move address assignment out of this function + * or else move the association allocation/init into this function. + * The association structure is brand new before calling this + * function, so would not be a sideeffect if the allocation + * moved into this function. --jgrimm + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SET_BIND_ADDR, (sctp_arg_t) bp); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * A) "A" first sends an INIT chunk to "Z". In the INIT, "A" + * must provide its Verification Tag (Tag_A) in the Initiate + * Tag field. Tag_A SHOULD be a random number in the range of + * 1 to 4294967295 (see 5.3.1 for Tag value selection). ... + */ + + repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + if (!repl) + goto nomem; + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, + SCTP_ASOC((sctp_association_t *) asoc)); + + /* After sending the INIT, "A" starts the T1-init timer and + * enters the COOKIE-WAIT state. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + return SCTP_DISPOSITION_CONSUME; + +nomem: + if (bp) + sctp_bind_addr_free(bp); + + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Process the SEND primitive. + * + * Section: 10.1 ULP-to-SCTP + * E) Send + * + * Format: SEND(association id, buffer address, byte count [,context] + * [,stream id] [,life time] [,destination transport address] + * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) + * -> result + * + * This is the main method to send user data via SCTP. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o buffer address - the location where the user message to be + * transmitted is stored; + * + * o byte count - The size of the user data in number of bytes; + * + * Optional attributes: + * + * o context - an optional 32 bit integer that will be carried in the + * sending failure notification to the ULP if the transportation of + * this User Message fails. + * + * o stream id - to indicate which stream to send the data on. If not + * specified, stream 0 will be used. + * + * o life time - specifies the life time of the user data. The user data + * will not be sent by SCTP after the life time expires. This + * parameter can be used to avoid efforts to transmit stale + * user messages. SCTP notifies the ULP if the data cannot be + * initiated to transport (i.e. sent to the destination via SCTP's + * send primitive) within the life time variable. However, the + * user data will be transmitted if SCTP has attempted to transmit a + * chunk before the life time expired. + * + * o destination transport address - specified as one of the destination + * transport addresses of the peer endpoint to which this packet + * should be sent. Whenever possible, SCTP should use this destination + * transport address for sending the packets, instead of the current + * primary path. + * + * o unorder flag - this flag, if present, indicates that the user + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * message). + * + * o no-bundle flag - instructs SCTP not to bundle this user data with + * other outbound DATA chunks. SCTP MAY still bundle even when + * this flag is present, when faced with network congestion. + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data + * being transmitted. This value is passed as opaque data by SCTP. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Process the SHUTDOWN primitive. + * + * Section: 10.1: + * C) Shutdown + * + * Format: SHUTDOWN(association id) + * -> result + * + * Gracefully closes an association. Any locally queued user data + * will be delivered to the peer. The association will be terminated only + * after the peer acknowledges all the SCTP packets sent. A success code + * will be returned on successful termination of the association. If + * attempting to terminate the association results in a failure, an error + * code shall be returned. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * Optional attributes: + * + * None. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); + + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + arg, commands); + } + return disposition; +} + +/* + * Process the ABORT primitive. + * + * Section: 10.1: + * C) Abort + * + * Format: Abort(association id [, cause code]) + * -> result + * + * Ungracefully closes an association. Any locally queued user data + * will be discarded and an ABORT chunk is sent to the peer. A success code + * will be returned on successful abortion of the association. If + * attempting to abort the association results in a failure, an error + * code shall be returned. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * Optional attributes: + * + * o cause code - reason of the abort to be passed to the peer + * + * None. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* From 9.1 Abort of an Association + * Upon receipt of the ABORT primitive from its upper + * layer, the endpoint enters CLOSED state and + * discard all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + sctp_chunk_t *abort; + sctp_disposition_t retval; + + retval = SCTP_DISPOSITION_CONSUME; + + /* Generate ABORT chunk to send the peer. */ + abort = sctp_make_abort(asoc, NULL, 0); + if (!abort) + retval = SCTP_DISPOSITION_NOMEM; + else + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + + /* Even if we can't send the ABORT due to low memory delete the + * TCB. This is a departure from our typical NOMEM handling. + */ + + /* Change to CLOSED state. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + /* Delete the established association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return retval; +} + +/* We tried an illegal operation on an association which is closed. */ +sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, SCTP_ERROR(-EINVAL)); + return SCTP_DISPOSITION_CONSUME; +} + +/* We tried an illegal operation on an association which is shutting + * down. + */ +sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, + SCTP_ERROR(-ESHUTDOWN)); + return SCTP_DISPOSITION_CONSUME; +} + +/* + * sctp_cookie_wait_prm_shutdown + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explicitly address this issue, but is the route through the + * state table when someone issues a shutdown while in COOKIE_WAIT state. + * + * Outputs + * (timers) + */ +sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; +} + +/* + * sctp_cookie_echoed_prm_shutdown + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explcitly address this issue, but is the route through the + * state table when someone issues a shutdown while in COOKIE_ECHOED state. + * + * Outputs + * (timers) + */ +sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( + const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, sctp_cmd_seq_t *commands) +{ + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_prm_shutdown(ep, asoc, type, arg, commands); +} + +/* + * sctp_cookie_wait_prm_abort + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explicitly address this issue, but is the route through the + * state table when someone issues an abort while in COOKIE_WAIT state. + * + * Outputs + * (timers) + */ +sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* Stop T1-init timer */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands); +} + +/* + * sctp_cookie_echoed_prm_abort + * + * Section: 4 Note: 3 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explcitly address this issue, but is the route through the + * state table when someone issues an abort while in COOKIE_ECHOED state. + * + * Outputs + * (timers) + */ +sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands); +} + +/* + * Ignore the primitive event + * + * The return value is the disposition of the primitive. + */ +sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); + return SCTP_DISPOSITION_DISCARD; +} + +/*************************************************************************** + * These are the state functions for the OTHER events. + ***************************************************************************/ + +/* + * Start the shutdown negotiation. + * + * From Section 9.2: + * Once all its outstanding data has been acknowledged, the endpoint + * shall send a SHUTDOWN chunk to its peer including in the Cumulative + * TSN Ack field the last sequential TSN it has received from the peer. + * It shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT + * state. If the timer expires, the endpoint must re-send the SHUTDOWN + * with the updated last sequential TSN received from its peer. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *reply; + + /* Once all its outstanding data has been acknowledged, the + * endpoint shall send a SHUTDOWN chunk to its peer including + * in the Cumulative TSN Ack field the last sequential TSN it + * has received from the peer. + */ + reply = sctp_make_shutdown(asoc); + if (!reply) + goto nomem; + + /* Set the transport for the SHUTDOWN chunk and the timeout for the + * T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* It shall then start the T2-shutdown timer */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + + /* and enter the SHUTDOWN-SENT state. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_SENT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Generate a SHUTDOWN ACK now that everything is SACK'd. + * + * From Section 9.2: + * + * If it has no more outstanding DATA chunks, the SHUTDOWN receiver + * shall send a SHUTDOWN ACK and start a T2-shutdown timer of its own, + * entering the SHUTDOWN-ACK-SENT state. If the timer expires, the + * endpoint must re-send the SHUTDOWN ACK. + * + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = (sctp_chunk_t *) arg; + sctp_chunk_t *reply; + + /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver + * shall send a SHUTDOWN ACK ... + */ + reply = sctp_make_shutdown_ack(asoc, chunk); + if (!reply) + goto nomem; + + /* Set the transport for the SHUTDOWN ACK chunk and the timeout for + * the T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* and start/restart a T2-shutdown timer of its own, */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + + /* Enter the SHUTDOWN-ACK-SENT state. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_ACK_SENT)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* + * Ignore the event defined as other + * + * The return value is the disposition of the event. + */ +sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", + type.other); + return SCTP_DISPOSITION_DISCARD; +} + +/************************************************************ + * These are the state functions for handling timeout events. + ************************************************************/ + +/* + * RTX Timeout + * + * Section: 6.3.3 Handle T3-rtx Expiration + * + * Whenever the retransmission timer T3-rtx expires for a destination + * address, do the following: + * [See below] + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = arg; + + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* E1) For the destination address for which the timer + * expires, adjust its ssthresh with rules defined in Section + * 7.2.3 and set the cwnd <- MTU. + */ + + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ + + /* E3) Determine how many of the earliest (i.e., lowest TSN) + * outstanding DATA chunks for the address for which the + * T3-rtx has expired will fit into a single packet, subject + * to the MTU constraint for the path corresponding to the + * destination transport address to which the retransmission + * is being sent (this may be different from the address for + * which the timer expires [see Section 6.4]). Call this + * value K. Bundle and retransmit those K DATA chunks in a + * single packet to the destination endpoint. + * + * Note: Any DATA chunks that were sent to the address for + * which the T3-rtx timer expired but did not fit in one MTU + * (rule E3 above), should be marked for retransmission and + * sent as soon as cwnd allows (normally when a SACK arrives). + */ + + /* NB: Rules E4 and F1 are implicit in R1. */ + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport)); + + /* Do some failure management (Section 8.2). */ + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Generate delayed SACK on timeout + * + * Section: 6.2 Acknowledgement on Reception of DATA Chunks + * + * The guidelines on delayed acknowledgement algorithm specified in + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, an + * acknowledgement SHOULD be generated for at least every second packet + * (not every second DATA chunk) received, and SHOULD be generated + * within 200 ms of the arrival of any unacknowledged DATA chunk. In + * some situations it may be beneficial for an SCTP transmitter to be + * more conservative than the algorithms detailed in this document + * allow. However, an SCTP transmitter MUST NOT be more aggressive than + * the following algorithms allow. + */ +sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + return SCTP_DISPOSITION_CONSUME; +} + +/* + * sctp_sf_t1_timer_expire + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * RFC 2960 Section 4 Notes + * 2) If the T1-init timer expires, the endpoint MUST retransmit INIT + * and re-start the T1-init timer without changing state. This MUST + * be repeated up to 'Max.Init.Retransmits' times. After that, the + * endpoint MUST abort the initialization process and report the + * error to SCTP user. + * + * 3) If the T1-cookie timer expires, the endpoint MUST retransmit + * COOKIE ECHO and re-start the T1-cookie timer without changing + * state. This MUST be repeated up to 'Max.Init.Retransmits' times. + * After that, the endpoint MUST abort the initialization process and + * report the error to SCTP user. + * + * Outputs + * (timers, events) + * + */ +sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *repl; + sctp_bind_addr_t *bp; + sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; + int timeout; + int attempts; + + timeout = asoc->timeouts[timer]; + attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; + repl = NULL; + + SCTP_DEBUG_PRINTK("Timer T1 expired.\n"); + + if ((timeout < asoc->max_init_timeo) && + (attempts < asoc->max_init_attempts)) { + switch (timer) { + case SCTP_EVENT_TIMEOUT_T1_INIT: + bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + break; + + case SCTP_EVENT_TIMEOUT_T1_COOKIE: + repl = sctp_make_cookie_echo(asoc, NULL); + break; + + default: + BUG(); + break; + }; + + if (!repl) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* Issue a sideeffect to do the needed accounting. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, + SCTP_TO(timer)); + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* RFC2960 9.2 If the timer expires, the endpoint must re-send the SHUTDOWN + * with the updated last sequential TSN received from its peer. + * + * An endpoint should limit the number of retransmissions of the + * SHUTDOWN chunk to the protocol parameter 'Association.Max.Retrans'. + * If this threshold is exceeded the endpoint should destroy the TCB and + * MUST report the peer endpoint unreachable to the upper layer (and + * thus the association enters the CLOSED state). The reception of any + * packet from its peer (i.e. as the peer sends all of its queued DATA + * chunks) should clear the endpoint's retransmission count and restart + * the T2-Shutdown timer, giving its peer ample opportunity to transmit + * all of its queued DATA chunks that have not yet been sent. + */ +sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *reply = NULL; + + SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + switch (asoc->state) { + case SCTP_STATE_SHUTDOWN_SENT: + reply = sctp_make_shutdown(asoc); + break; + + case SCTP_STATE_SHUTDOWN_ACK_SENT: + reply = sctp_make_shutdown_ack(asoc, NULL); + break; + + default: + BUG(); + break; + }; + + if (!reply) + goto nomem; + + /* Do some failure management (Section 8.2). */ + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); + + /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for + * the T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* Restart the T2-shutdown timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; +} + +/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires, + * the association is automatically closed by starting the shutdown process. + * The work that needs to be done is same as when SHUTDOWN is initiated by + * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). + */ +sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); + + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + arg, commands); + } + return disposition; +} + +/***************************************************************************** + * These are sa state functions which could apply to all types of events. + ****************************************************************************/ + +/* + * This table entry is not implemented. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_NOT_IMPL; +} + +/* + * This table entry represents a bug. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_BUG; +} + +/* + * This table entry represents the firing of a timer in the wrong state. + * Since timer deletion cannot be guaranteed a timer 'may' end up firing + * when the association is in the wrong state. This event should + * be ignored, so as to prevent any rearming of the timer. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Timer %d ignored.\n", type.chunk); + return SCTP_DISPOSITION_CONSUME; +} + +/* + * Discard the chunk. + * + * Section: 0.2, 5.2.3, 5.2.5, 5.2.6, 6.0, 8.4.6, 8.5.1c, 9.2 + * [Too numerous to mention...] + * Verification Tag: No verification needed. + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); + return SCTP_DISPOSITION_DISCARD; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Pull the SACK chunk based on the SACK header. */ +sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) +{ + sctp_sackhdr_t *sack; + __u16 num_blocks; + __u16 num_dup_tsns; + + sack = (sctp_sackhdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_sackhdr_t)); + + num_blocks = ntohs(sack->num_gap_ack_blocks); + num_dup_tsns = ntohs(sack->num_dup_tsns); + + skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32)); + return sack; +} diff -Nru a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sm_statetable.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,1146 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * These are the state tables for the SCTP state machine. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Hui Huang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include + +sctp_sm_table_entry_t nop = {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk"}; +sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; + +#define DO_LOOKUP(_max, _type, _table) \ + if ((event_subtype._type > (_max))) { \ + printk(KERN_WARNING \ + "sctp table %p possible attack:" \ + " event %d exceeds max %d\n", \ + _table, event_subtype._type, _max); \ + return(&bug); \ + } \ + return(&_table[event_subtype._type][(int)state]); + +sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, + sctp_state_t state, + sctp_subtype_t event_subtype) +{ + switch (event_type) { + case SCTP_EVENT_T_CHUNK: + return sctp_chunk_event_lookup(event_subtype.chunk, state); + break; + case SCTP_EVENT_T_TIMEOUT: + DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, + timeout_event_table); + break; + + case SCTP_EVENT_T_OTHER: + DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table); + break; + + case SCTP_EVENT_T_PRIMITIVE: + DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive, + primitive_event_table); + break; + + default: + /* Yikes! We got an illegal event type. */ + return &bug; + }; +} + +#define TYPE_SCTP_DATA { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_eat_data_fast_4_4, name: "sctp_sf_eat_data_fast_4_4"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_DATA */ + +#define TYPE_SCTP_INIT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1B_init, name: "sctp_sf_do_5_1B_init"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_INIT */ + +#define TYPE_SCTP_INIT_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_1C_ack, name: "sctp_sf_do_5_1C_ack"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_INIT_ACK */ + +#define TYPE_SCTP_SACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_SACK */ + +#define TYPE_SCTP_HEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + /* This should not happen, but we are nice. */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +} /* TYPE_SCTP_HEARTBEAT */ + +#define TYPE_SCTP_HEARTBEAT_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_HEARTBEAT_ACK */ + +#define TYPE_SCTP_ABORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_pdiscard, name: "sctp_sf_pdiscard"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_cookie_wait_abort, name: "sctp_sf_cookie_wait_abort"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_abort, \ + name: "sctp_sf_cookie_echoed_abort"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +} /* TYPE_SCTP_ABORT */ + +#define TYPE_SCTP_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_shutdown, name: "sctp_sf_do_9_2_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ + name: "sctp_sf_do_9_2_shutdown_ack"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_SHUTDOWN */ + +#define TYPE_SCTP_SHUTDOWN_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ +} /* TYPE_SCTP_SHUTDOWN_ACK */ + +#define TYPE_SCTP_ERROR { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_operr_notify, name: "sctp_sf_operr_notify"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_ERROR */ + +#define TYPE_SCTP_COOKIE_ECHO { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1D_ce, name: "sctp_sf_do_5_1D_ce"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +} /* TYPE_SCTP_COOKIE_ECHO */ + +#define TYPE_SCTP_COOKIE_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_1E_ca, name: "sctp_sf_do_5_1E_ca"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_COOKIE_ACK */ + +#define TYPE_SCTP_ECN_ECNE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +} /* TYPE_SCTP_ECN_ECNE */ + +#define TYPE_SCTP_ECN_CWR { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +} /* TYPE_SCTP_ECN_CWR */ + +#define TYPE_SCTP_SHUTDOWN_COMPLETE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_4_C, name: "sctp_sf_do_4_C"}, \ +} /* TYPE_SCTP_SHUTDOWN_COMPLETE */ + +/* The primary index for this table is the chunk type. + * The secondary index for this table is the state. + * + * For base protocol (RFC 2960). + */ +sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_DATA, + TYPE_SCTP_INIT, + TYPE_SCTP_INIT_ACK, + TYPE_SCTP_SACK, + TYPE_SCTP_HEARTBEAT, + TYPE_SCTP_HEARTBEAT_ACK, + TYPE_SCTP_ABORT, + TYPE_SCTP_SHUTDOWN, + TYPE_SCTP_SHUTDOWN_ACK, + TYPE_SCTP_ERROR, + TYPE_SCTP_COOKIE_ECHO, + TYPE_SCTP_COOKIE_ACK, + TYPE_SCTP_ECN_ECNE, + TYPE_SCTP_ECN_CWR, + TYPE_SCTP_SHUTDOWN_COMPLETE, +}; /* state_fn_t chunk_event_table[][] */ + +static sctp_sm_table_entry_t +chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = { + /* SCTP_STATE_EMPTY */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_CLOSED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_WAIT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_ECHOED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + + /* SCTP_STATE_ESTABLISHED */ + {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"}, + + /* SCTP_STATE_SHUTDOWN_PENDING */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_RECEIVED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, +}; /* chunk asconf */ + +static sctp_sm_table_entry_t +chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { + /* SCTP_STATE_EMPTY */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_CLOSED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_WAIT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_ECHOED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + + /* SCTP_STATE_ESTABLISHED */ + {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"}, + + /* SCTP_STATE_SHUTDOWN_PENDING */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_RECEIVED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, +}; /* chunk asconf_ack */ + +#define TYPE_SCTP_PRIMITIVE_INITIALIZE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_INITIALIZE */ + +#define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_prm_asoc, name: "sctp_sf_do_prm_asoc"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ + +#define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_cookie_wait_prm_shutdown, \ + name: "sctp_sf_cookie_wait_prm_shutdown"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_prm_shutdown, \ + name:"sctp_sf_cookie_echoed_prm_shutdown"},\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_prm_shutdown, \ + name: "sctp_sf_do_9_2_prm_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ +} /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ + +#define TYPE_SCTP_PRIMITIVE_ABORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_cookie_wait_prm_abort, \ + name: "sctp_sf_cookie_wait_prm_abort"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_prm_abort, \ + name: "sctp_sf_cookie_echoed_prm_abort"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ +} /* TYPE_SCTP_PRIMITIVE_ABORT */ + +#define TYPE_SCTP_PRIMITIVE_SEND { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ +} /* TYPE_SCTP_PRIMITIVE_SEND */ + +#define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE */ + +#define TYPE_SCTP_PRIMITIVE_STATUS { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_STATUS */ + +#define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */ + +#define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ + +#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */ + +#define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */ + +#define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */ + +#define TYPE_SCTP_PRIMITIVE_DESTROY { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_DESTROY */ + +/* The primary index for this table is the primitive type. + * The secondary index for this table is the state. + */ +sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_PRIMITIVE_INITIALIZE, + TYPE_SCTP_PRIMITIVE_ASSOCIATE, + TYPE_SCTP_PRIMITIVE_SHUTDOWN, + TYPE_SCTP_PRIMITIVE_ABORT, + TYPE_SCTP_PRIMITIVE_SEND, + TYPE_SCTP_PRIMITIVE_SETPRIMARY, + TYPE_SCTP_PRIMITIVE_RECEIVE, + TYPE_SCTP_PRIMITIVE_STATUS, + TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT, + TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT, + TYPE_SCTP_PRIMITIVE_GETSRTTREPORT, + TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD, + TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED, + TYPE_SCTP_PRIMITIVE_DESTROY, +}; + +#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_2_start_shutdown, \ + name: "sctp_do_9_2_start_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ + name: "sctp_sf_do_9_2_shutdown_ack"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +} + +#define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} + +sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_OTHER_NO_PENDING_TSN, + TYPE_SCTP_OTHER_ICMP_UNREACHFRAG, +}; + +#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_autoclose_timer_expire, \ + name: "sctp_sf_autoclose_timer_expire"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} + +#define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} + +sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_EVENT_TIMEOUT_NONE, + TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, + TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, + TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, + TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, + TYPE_SCTP_EVENT_TIMEOUT_T4_RTO, + TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, + TYPE_SCTP_EVENT_TIMEOUT_SACK, + TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, + TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE, +}; + +sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) +{ + if (state > SCTP_STATE_MAX) + BUG(); + if (cid < 0) + return &nop; + + if (cid <= SCTP_CID_BASE_MAX) + return &chunk_event_table[cid][state]; + + switch (cid) { + case SCTP_CID_ASCONF: + return &chunk_event_table_asconf[state]; + + case SCTP_CID_ASCONF_ACK: + return &chunk_event_table_asconf_ack[state]; + default: + return &nop; + }; + + return &nop; +} diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/socket.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,2702 @@ +/* Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions interface with the sockets layer to implement the + * SCTP Extensions for the Sockets API. + * + * Note that the descriptions from the specification are USER level + * functions--this file is the functions which populate the struct proto + * for SCTP which is the BOTTOM of the sockets interface. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Narasimha Budihal + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Daisy Chang + * Sridhar Samudrala + * Inaky Perez-Gonzalez + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include /* for sa_family_t */ +#include +#include + +/* Forward declarations for internal helper functions. */ +static void __sctp_write_space(sctp_association_t *asoc); +static int sctp_writeable(struct sock *sk); +static inline int sctp_wspace(sctp_association_t *asoc); +static inline void sctp_set_owner_w(sctp_chunk_t *chunk); +static void sctp_wfree(struct sk_buff *skb); +static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, + int msg_len); +static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); +static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, + int *addr_len, struct sk_buff *skb); +static inline void sctp_sk_addr_set(struct sock *, + const sockaddr_storage_t *newaddr, + sockaddr_storage_t *saveaddr); +static inline void sctp_sk_addr_restore(struct sock *, + const sockaddr_storage_t *); +static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); +static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); +static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); +static int sctp_do_bind(struct sock *, sockaddr_storage_t *, int); +static int sctp_autobind(struct sock *sk); +static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, + unsigned short snum); + +/* API 3.1.2 bind() - UDP Style Syntax + * The syntax of bind() is, + * + * ret = bind(int sd, struct sockaddr *addr, int addrlen); + * + * sd - the socket descriptor returned by socket(). + * addr - the address structure (struct sockaddr_in or struct + * sockaddr_in6 [RFC 2553]), + * addrlen - the size of the address structure. + * + * The caller should use struct sockaddr_storage described in RFC 2553 + * to represent addr for portability reason. + */ +int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + int retval = 0; + + sctp_lock_sock(sk); + + SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n", + sk, uaddr, addr_len); + + /* Disallow binding twice. */ + if (!sctp_sk(sk)->ep->base.bind_addr.port) + retval = sctp_do_bind(sk, (sockaddr_storage_t *)uaddr, + addr_len); + else + retval = -EINVAL; + + sctp_release_sock(sk); + + return retval; +} + +static long sctp_get_port_local(struct sock *, unsigned short); + +/* Bind a local address either to an endpoint or to an association. */ +static int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + sctp_bind_addr_t *bp = &ep->base.bind_addr; + unsigned short sa_family = newaddr->sa.sa_family; + sockaddr_storage_t tmpaddr, saveaddr; + unsigned short *snum; + int ret = 0; + + SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", + sk, newaddr, addr_len); + + /* FIXME: This function needs to handle v4-mapped-on-v6 + * addresses! + */ + if (PF_INET == sk->family) { + if (sa_family != AF_INET) + return -EINVAL; + } + + /* Make a local copy of the new address. */ + tmpaddr = *newaddr; + + switch (sa_family) { + case AF_INET: + if (addr_len < sizeof(struct sockaddr_in)) + return -EINVAL; + + ret = inet_addr_type(newaddr->v4.sin_addr.s_addr); + + /* FIXME: + * Should we allow apps to bind to non-local addresses by + * checking the IP sysctl parameter "ip_nonlocal_bind"? + */ + if (newaddr->v4.sin_addr.s_addr != INADDR_ANY && + ret != RTN_LOCAL) + return -EADDRNOTAVAIL; + + tmpaddr.v4.sin_port = htons(tmpaddr.v4.sin_port); + snum = &tmpaddr.v4.sin_port; + break; + + case AF_INET6: + SCTP_V6( + /* FIXME: Hui, please verify this. Looking at + * the ipv6 code I see a SIN6_LEN_RFC2133 check. + * I'm guessing that scope_id is a newer addition. + */ + if (addr_len < sizeof(struct sockaddr_in6)) + return -EINVAL; + + /* FIXME - The support for IPv6 multiple types + * of addresses need to be added later. + */ + ret = sctp_ipv6_addr_type(&newaddr->v6.sin6_addr); + tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port); + snum = &tmpaddr.v6.sin6_port; + break; + ) + + default: + return -EINVAL; + }; + + SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", + bp->port, *snum); + + /* We must either be unbound, or bind to the same port. */ + if (bp->port && (*snum != bp->port)) { + SCTP_DEBUG_PRINTK("sctp_do_bind:" + " New port %d does not match existing port " + "%d.\n", *snum, bp->port); + return -EINVAL; + } + + if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + /* FIXME - Make socket understand that there might be multiple bind + * addresses and there will be multiple source addresses involved in + * routing and failover decisions. + */ + sctp_sk_addr_set(sk, &tmpaddr, &saveaddr); + + /* Make sure we are allowed to bind here. + * The function sctp_get_port_local() does duplicate address + * detection. + */ + if ((ret = sctp_get_port_local(sk, *snum))) { + sctp_sk_addr_restore(sk, &saveaddr); + if (ret == (long) sk) { + /* This endpoint has a conflicting address. */ + return -EINVAL; + } else { + return -EADDRINUSE; + } + } + + /* Refresh ephemeral port. */ + if (!*snum) + *snum = inet_sk(sk)->num; + + /* The getsockname() API depends on 'sport' being set. */ + inet_sk(sk)->sport = htons(inet_sk(sk)->num); + + /* Add the address to the bind address list. */ + sctp_local_bh_disable(); + sctp_write_lock(&ep->base.addr_lock); + + /* Use GFP_ATOMIC since BHs are disabled. */ + if ((ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { + sctp_sk_addr_restore(sk, &saveaddr); + } else if (!bp->port) { + bp->port = *snum; + } + + sctp_write_unlock(&ep->base.addr_lock); + sctp_local_bh_enable(); + return ret; +} + +/* API 8.1 sctp_bindx() + * + * The syntax of sctp_bindx() is, + * + * ret = sctp_bindx(int sd, + * struct sockaddr_storage *addrs, + * int addrcnt, + * int flags); + * + * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. + * If the sd is an IPv6 socket, the addresses passed can either be IPv4 + * or IPv6 addresses. + * + * A single address may be specified as INADDR_ANY or IPV6_ADDR_ANY, see + * section 3.1.2 for this usage. + * + * addrs is a pointer to an array of one or more socket addresses. Each + * address is contained in a struct sockaddr_storage, so each address is + * fixed length. The caller specifies the number of addresses in the + * array with addrcnt. + * + * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns -1, + * and sets errno to the appropriate error code. [ Editor's note: need + * to fill in all error code? ] + * + * For SCTP, the port given in each socket address must be the same, or + * sctp_bindx() will fail, setting errno to EINVAL . + * + * The flags parameter is formed from the bitwise OR of zero or + * more of the following currently defined flags: + * + * SCTP_BINDX_ADD_ADDR + * SCTP_BINDX_REM_ADDR + * + * SCTP_BIND_ADD_ADDR directs SCTP to add the given addresses to the + * association, and SCTP_BIND_REM_ADDR directs SCTP to remove the given + * addresses from the association. The two flags are mutually exclusive; + * if both are given, sctp_bindx() will fail with EINVAL. A caller may not + * remove all addresses from an association; sctp_bindx() will reject such + * an attempt with EINVAL. + * + * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate + * additional addresses with an endpoint after calling bind(). Or use + * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening + * socket is associated with so that no new association accepted will be + * associated with those addresses. + * + * SCTP_BIND_ADD_ADDR is defined as 0, so that it becomes the default + * behavior for sctp_bindx() when no flags are given. + * + * Adding and removing addresses from a connected association is optional + * functionality. Implementations that do not support this functionality + * should return EOPNOTSUPP. + * + * NOTE: This could be integrated into sctp_setsockopt_bindx(), + * but keeping it this way makes it easier if sometime sys_bindx is + * added. + */ + +/* Unprotected by locks. Call only with socket lock sk->lock held! See + * sctp_bindx() for a lock-protected call. + */ + +static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, + int addrcnt, int flags) +{ + int retval = 0; + + SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " + "flags: %s)\n", sk, addrs, addrcnt, + (BINDX_ADD_ADDR == flags)?"ADD": + ((BINDX_REM_ADDR == flags)?"REM":"BOGUS")); + + switch (flags) { + case BINDX_ADD_ADDR: + retval = sctp_bindx_add(sk, addrs, addrcnt); + break; + + case BINDX_REM_ADDR: + retval = sctp_bindx_rem(sk, addrs, addrcnt); + break; + + default: + retval = -EINVAL; + break; + }; + + return retval; +} + +/* BINDX with locks. + * + * NOTE: Currently unused at all ... + */ +int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, + int flags) +{ + int retval; + + sctp_lock_sock(sk); + retval = __sctp_bindx(sk, addrs, addrcnt, flags); + sctp_release_sock(sk); + + return retval; +} + +/* Add a list of addresses as bind addresses to local endpoint or + * association. + * + * Basically run through each address specified in the addrs/addrcnt + * array/length pair, determine if it is IPv6 or IPv4 and call + * sctp_do_bind() on it. + * + * If any of them fails, then the operation will be reversed and the + * ones that were added will be removed. + * + * Only __sctp_bindx() is supposed to call this function. + */ +int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +{ + int cnt; + int retval = 0; + int addr_len; + + SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n", + sk, addrs, addrcnt); + + for (cnt = 0; cnt < addrcnt; cnt++) { + /* The list may contain either IPv4 or IPv6 address; + * determine the address length for walking thru the list. + */ + switch (((struct sockaddr *)&addrs[cnt])->sa_family) { + case AF_INET: + addr_len = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + addr_len = sizeof(struct sockaddr_in6); + break; + + default: + retval = -EINVAL; + goto err_bindx_add; + }; + + retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], + addr_len); + +err_bindx_add: + if (retval < 0) { + /* Failed. Cleanup the ones that has been added */ + if (cnt > 0) + sctp_bindx_rem(sk, addrs, cnt); + return retval; + } + } + + /* Notify the peer(s), assuming we have (an) association(s). + * FIXME: for UDP, we have a 1-1-many mapping amongst sk, ep and asoc, + * so we don't have to do much work on locating associations. + * + * However, when the separation of ep and asoc kicks in, especially + * for TCP style connection, it becomes n-1-n mapping. We will need + * to do more fine work. Until then, hold my peace. + * --xguo + * + * Really, I don't think that will be a problem. The bind() + * call on a socket will either know the endpoint + * (e.g. TCP-style listen()ing socket, or UDP-style socket), + * or exactly one association. The former case is EXACTLY + * what we have now. In the former case we know the + * association already. --piggy + * + * This code will be working on either a UDP style or a TCP style + * socket, or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the + * ADDIP code. + * --daisy + */ + +#if CONFIG_IP_SCTP_ADDIP + /* Add these addresses to all associations on this endpoint. */ + if (retval >= 0) { + list_t *pos; + sctp_endpoint_t *ep; + sctp_association_t *asoc; + ep = sctp_sk(sk)->ep; + + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + + sctp_addip_addr_config(asoc, + SCTP_PARAM_ADD_IP, + addrs, addrcnt); + } + } +#endif + + return retval; +} + +/* Remove a list of addresses from bind addresses list. Do not remove the + * last address. + * + * Basically run through each address specified in the addrs/addrcnt + * array/length pair, determine if it is IPv6 or IPv4 and call + * sctp_del_bind() on it. + * + * If any of them fails, then the operation will be reversed and the + * ones that were removed will be added back. + * + * At least one address has to be left; if only one address is + * available, the operation will return -EBUSY. + * + * Only __sctp_bindx() is supposed to call this function. + */ +int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + int cnt; + sctp_bind_addr_t *bp = &ep->base.bind_addr; + int retval = 0; + sockaddr_storage_t saveaddr; + + SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", + sk, addrs, addrcnt); + + for (cnt = 0; cnt < addrcnt; cnt++) { + /* If there is only one bind address, there is nothing more + * to be removed (we need at least one address here). + */ + if (list_empty(&bp->address_list)) { + retval = -EBUSY; + goto err_bindx_rem; + } + + /* The list may contain either IPv4 or IPv6 address; + * determine the address length for walking thru the list. + */ + switch (((struct sockaddr *)&addrs[cnt])->sa_family) { + case AF_INET: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v4.sin_port = + ntohs(saveaddr.v4.sin_port); + /* verify the port */ + if (saveaddr.v4.sin_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } + break; + + case AF_INET6: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v6.sin6_port = + ntohs(saveaddr.v6.sin6_port); + /* verify the port */ + if (saveaddr.v6.sin6_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } + break; + + default: + retval = -EINVAL; + goto err_bindx_rem; + }; + + /* FIXME - There is probably a need to check if sk->saddr and + * sk->rcv_addr are currently set to one of the addresses to + * be removed. This is something which needs to be looked into + * when we are fixing the outstanding issues with multi-homing + * socket routing and failover schemes. Refer to comments in + * sctp_do_bind(). -daisy + */ + sctp_local_bh_disable(); + sctp_write_lock(&ep->base.addr_lock); + + retval = sctp_del_bind_addr(bp, &saveaddr); + + sctp_write_unlock(&ep->base.addr_lock); + sctp_local_bh_enable(); + +err_bindx_rem: + if (retval < 0) { + /* Failed. Add the ones that has been removed back */ + if (cnt > 0) + sctp_bindx_add(sk, addrs, cnt); + return retval; + } + } + + /* + * This code will be working on either a UDP style or a TCP style + * socket, * or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the + * ADDIP code. + * --daisy + */ +#if CONFIG_IP_SCTP_ADDIP + /* Remove these addresses from all associations on this endpoint. */ + if (retval >= 0) { + list_t *pos; + sctp_endpoint_t *ep; + sctp_association_t *asoc; + + ep = sctp_sk(sk)->ep; + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, + addrs, addrcnt); + } + } +#endif + return retval; +} + +/* Helper for tunneling sys_bindx() requests through sctp_setsockopt() + * + * Basically do nothing but copying the addresses from user to kernel + * land and invoking sctp_bindx on the sk. This is used for tunneling + * the sctp_bindx() [sys_bindx()] request through sctp_setsockopt() + * from userspace. + * + * Note I don't use move_addr_to_kernel(): the reason is we would be + * iterating over an array of struct sockaddr_storage passing always + * what we know is a good size (sizeof (struct sock...)), so it is + * pointless. Instead check the whole area for read access and copy + * it. + * + * We don't use copy_from_user() for optimization: we first do the + * sanity checks (buffer size -fast- and access check-healthy + * pointer); if all of those succeed, then we can alloc the memory + * (expensive operation) needed to copy the data to kernel. Then we do + * the copying without checking the user space area + * (__copy_from_user()). + * + * On exit there is no need to do sockfd_put(), sys_setsockopt() does + * it. + * + * sk The sk of the socket + * addrs The pointer to the addresses in user land + * addrssize Size of the addrs buffer + * op Operation to perform (add or remove, see the flags of + * sctp_bindx) + * + * Returns 0 if ok, <0 errno code on error. + */ +static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, + int addrssize, int op) +{ + struct sockaddr_storage *kaddrs; + int err; + size_t addrcnt; + + SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" + " addrssize %d opt %d\n", sk, addrs, + addrssize, op); + + /* Do we have an integer number of structs sockaddr_storage? */ + if (unlikely(addrssize <= 0 || + addrssize % sizeof(struct sockaddr_storage) != 0)) + return -EINVAL; + + /* Check the user passed a healthy pointer. */ + if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize))) + return -EFAULT; + + /* Alloc space for the address array in kernel memory. */ + kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); + if (unlikely(NULL == kaddrs)) + return -ENOMEM; + + if (copy_from_user(kaddrs, addrs, addrssize)) { + kfree(kaddrs); + return -EFAULT; + } + + addrcnt = addrssize / sizeof(struct sockaddr_storage); + err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */ + kfree(kaddrs); + + return err; +} + +/* API 3.1.4 close() - UDP Style Syntax + * Applications use close() to perform graceful shutdown (as described in + * Section 10.1 of [SCTP]) on ALL the associations currently represented + * by a UDP-style socket. + * + * The syntax is + * + * ret = close(int sd); + * + * sd - the socket descriptor of the associations to be closed. + * + * To gracefully shutdown a specific association represented by the + * UDP-style socket, an application should use the sendmsg() call, + * passing no user data, but including the appropriate flag in the + * ancillary data (see Section xxxx). + * + * If sd in the close() call is a branched-off socket representing only + * one association, the shutdown is performed on that association only. + */ +static void sctp_close(struct sock *sk, long timeout) +{ + sctp_endpoint_t *ep; + sctp_association_t *asoc; + list_t *pos, *temp; + + SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); + + sctp_lock_sock(sk); + sk->shutdown = SHUTDOWN_MASK; + + ep = sctp_sk(sk)->ep; + + /* Walk all associations on a socket, not on an endpoint. */ + list_for_each_safe(pos, temp, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + sctp_primitive_SHUTDOWN(asoc, NULL); + } + + /* Clean up any skbs sitting on the receive queue. */ + skb_queue_purge(&sk->receive_queue); + + /* This will run the backlog queue. */ + sctp_release_sock(sk); + + /* Supposedly, no process has access to the socket, but + * the net layers still may. + */ + sctp_local_bh_disable(); + sctp_bh_lock_sock(sk); + + /* Hold the sock, since inet_sock_release() will put sock_put() + * and we have just a little more cleanup. + */ + sock_hold(sk); + inet_sock_release(sk); + + sctp_bh_unlock_sock(sk); + sctp_local_bh_enable(); + + sock_put(sk); + + SCTP_DBG_OBJCNT_DEC(sock); +} + +/* API 3.1.3 sendmsg() - UDP Style Syntax + * + * An application uses sendmsg() and recvmsg() calls to transmit data to + * and receive data from its peer. + * + * ssize_t sendmsg(int socket, const struct msghdr *message, + * int flags); + * + * socket - the socket descriptor of the endpoint. + * message - pointer to the msghdr structure which contains a single + * user message and possibly some ancillary data. + * + * See Section 5 for complete description of the data + * structures. + * + * flags - flags sent or received with the user message, see Section + * 5 for complete description of the flags. + * + * NB: The argument 'msg' is a user space address. + */ +/* BUG: We do not implement timeouts. */ +/* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ + +static int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); + +static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) +{ + sctp_opt_t *sp; + sctp_endpoint_t *ep; + sctp_association_t *asoc = NULL; + sctp_transport_t *transport; + sctp_chunk_t *chunk = NULL; + sockaddr_storage_t to; + struct sockaddr *msg_name = NULL; + struct sctp_sndrcvinfo default_sinfo = { 0 }; + struct sctp_sndrcvinfo *sinfo; + struct sctp_initmsg *sinit; + sctp_assoc_t associd = NULL; + sctp_cmsgs_t cmsgs = { 0 }; + int err; + size_t msg_len; + sctp_scope_t scope; + long timeo; + __u16 sinfo_flags = 0; + + SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, " + "size: %d)\n", sk, msg, size); + + err = 0; + sp = sctp_sk(sk); + ep = sp->ep; + + SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); + + /* Parse out the SCTP CMSGs. */ + err = sctp_msghdr_parse(msg, &cmsgs); + + if (err) { + SCTP_DEBUG_PRINTK("msghdr parse err = %x\n", err); + goto out_nounlock; + } + + /* Fetch the destination address for this packet. This + * address only selects the association--it is not necessarily + * the address we will send to. + * For a peeled-off socket, msg_name is ignored. + */ + if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { + err = sctp_sendmsg_verify_name(sk, msg); + if (err) + return err; + + memcpy(&to, msg->msg_name, msg->msg_namelen); + SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is " + "0x%x:%u.\n", + to.v4.sin_addr.s_addr, to.v4.sin_port); + + to.v4.sin_port = ntohs(to.v4.sin_port); + msg_name = msg->msg_name; + } + + msg_len = get_user_iov_size(msg->msg_iov, msg->msg_iovlen); + + sinfo = cmsgs.info; + sinit = cmsgs.init; + + /* Did the user specify SNDRCVINFO? */ + if (sinfo) { + sinfo_flags = sinfo->sinfo_flags; + associd = sinfo->sinfo_assoc_id; + } + + SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", + msg_len, sinfo_flags); + + /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow + * sending 0-length messages when MSG_EOF|MSG_ABORT is not set. + */ + if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) || + (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { + err = -EINVAL; + goto out_nounlock; + } + + sctp_lock_sock(sk); + + transport = NULL; + + SCTP_DEBUG_PRINTK("About to look up association.\n"); + + /* If a msg_name has been specified, assume this is to be used. */ + if (msg_name) { + asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); + } else { + /* For a peeled-off socket, ignore any associd specified by + * the user with SNDRCVINFO. + */ + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) { + if (list_empty(&ep->asocs)) { + err = -EINVAL; + goto out_unlock; + } + asoc = list_entry(ep->asocs.next, sctp_association_t, + asocs); + } else if (associd) { + asoc = sctp_id2assoc(sk, associd); + } + if (!asoc) { + err = -EINVAL; + goto out_unlock; + } + } + + if (asoc) { + SCTP_DEBUG_PRINTK("Just looked up association: " + "%s. \n", asoc->debug_name); + if (sinfo_flags & MSG_EOF) { + SCTP_DEBUG_PRINTK("Shutting down association: %p\n", + asoc); + sctp_primitive_SHUTDOWN(asoc, NULL); + err = 0; + goto out_unlock; + } + if (sinfo_flags & MSG_ABORT) { + SCTP_DEBUG_PRINTK("Aborting association: %p\n",asoc); + sctp_primitive_ABORT(asoc, NULL); + err = 0; + goto out_unlock; + } + } + + /* Do we need to create the association? */ + if (!asoc) { + SCTP_DEBUG_PRINTK("There is no association yet.\n"); + + /* Check for invalid stream against the stream counts, + * either the default or the user specified stream counts. + */ + if (sinfo) { + if (!sinit || + (sinit && !sinit->sinit_num_ostreams)) { + /* Check against the defaults. */ + if (sinfo->sinfo_stream >= + sp->initmsg.sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + } else { + /* Check against the defaults. */ + if (sinfo->sinfo_stream >= + sp->initmsg.sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + + /* Check against the requested. */ + if (sinfo->sinfo_stream >= + sinit->sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + } + } + + /* + * API 3.1.2 bind() - UDP Style Syntax + * If a bind() or sctp_bindx() is not called prior to a + * sendmsg() call that initiates a new association, the + * system picks an ephemeral port and will choose an address + * set equivalent to binding with a wildcard address. + */ + if (!ep->base.bind_addr.port) { + if (sctp_autobind(sk)) { + err = -EAGAIN; + goto out_unlock; + } + } + + scope = sctp_scope(&to); + asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); + if (!asoc) { + err = -ENOMEM; + goto out_unlock; + } + + /* If the SCTP_INIT ancillary data is specified, set all + * the association init values accordingly. + */ + if (sinit) { + if (sinit->sinit_num_ostreams) { + asoc->c.sinit_num_ostreams = + sinit->sinit_num_ostreams; + } + if (sinit->sinit_max_instreams) { + if (sinit->sinit_max_instreams <= + SCTP_MAX_STREAM) { + asoc->c.sinit_max_instreams = + sinit->sinit_max_instreams; + } else { + asoc->c.sinit_max_instreams = + SCTP_MAX_STREAM; + } + } + if (sinit->sinit_max_attempts) { + asoc->max_init_attempts + = sinit->sinit_max_attempts; + } + if (sinit->sinit_max_init_timeo) { + asoc->max_init_timeo + = sinit->sinit_max_init_timeo * HZ; + } + } + + /* Prime the peer's transport structures. */ + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); + } + + /* ASSERT: we have a valid association at this point. */ + SCTP_DEBUG_PRINTK("We have a valid association. \n"); + + /* API 7.1.7, the sndbuf size per association bounds the + * maximum size of data that can be sent in a single send call. + */ + if (msg_len > sk->sndbuf) { + err = -EMSGSIZE; + goto out_free; + } + + /* FIXME: In the current implementation, a single chunk is created + * for the entire message initially, even if it has to be fragmented + * later. As the length field in the chunkhdr is used to set + * the chunk length, the maximum size of the chunk and hence the + * message is limited by its type(__u16). + * The real fix is to fragment the message before creating the chunks. + */ + if (msg_len > ((__u16)(~(__u16)0) - + WORD_ROUND(sizeof(sctp_data_chunk_t)+1))) { + err = -EMSGSIZE; + goto out_free; + } + + /* If fragmentation is disabled and the message length exceeds the + * association fragmentation point, return EMSGSIZE. The I-D + * does not specify what this error is, but this looks like + * a great fit. + */ + if (sctp_sk(sk)->disable_fragments && (msg_len > asoc->frag_point)) { + err = -EMSGSIZE; + goto out_free; + } + + if (sinfo) { + /* Check for invalid stream. */ + if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { + err = -EINVAL; + goto out_free; + } + } else { + /* If the user didn't specify SNDRCVINFO, make up one with + * some defaults. + */ + default_sinfo.sinfo_stream = asoc->defaults.stream; + default_sinfo.sinfo_ppid = asoc->defaults.ppid; + sinfo = &default_sinfo; + } + + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); + if (!sctp_wspace(asoc)) { + err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); + if (err) + goto out_free; + } + + /* Get enough memory for the whole message. */ + chunk = sctp_make_data_empty(asoc, sinfo, msg_len); + if (!chunk) { + err = -ENOMEM; + goto out_free; + } + +#if 0 + /* FIXME: This looks wrong so I'll comment out. + * We should be able to use this same technique for + * primary address override! --jgrimm + */ + /* If the user gave us an address, copy it in. */ + if (msg->msg_name) { + chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk->transport) { + err = -EINVAL; + goto out_free; + } + } +#endif /* 0 */ + + /* Copy the message from the user. */ + err = sctp_user_addto_chunk(chunk, msg_len, msg->msg_iov); + if (err < 0) + goto out_free; + + SCTP_DEBUG_PRINTK("Copied message to chunk: %p.\n", chunk); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + + /* Do accounting for the write space. */ + sctp_set_owner_w(chunk); + + if (SCTP_STATE_CLOSED == asoc->state) { + err = sctp_primitive_ASSOCIATE(asoc, NULL); + if (err < 0) + goto out_free; + SCTP_DEBUG_PRINTK("We associated primitively.\n"); + } + + /* Send it to the lower layers. */ + err = sctp_primitive_SEND(asoc, chunk); + + SCTP_DEBUG_PRINTK("We sent primitively.\n"); + + /* BUG: SCTP_CHECK_TIMER(sk); */ + if (!err) { + err = msg_len; + goto out_unlock; + } + +out_free: + if (SCTP_STATE_CLOSED == asoc->state) + sctp_association_free(asoc); + if (chunk) + sctp_free_chunk(chunk); + +out_unlock: + sctp_release_sock(sk); + +out_nounlock: + return err; + +#if 0 +do_sock_err: + if (msg_len) + err = msg_len; + else + err = sock_error(sk); + goto out; + +do_interrupted: + if (msg_len) + err = msg_len; + goto out; +#endif /* 0 */ +} + +/* API 3.1.3 recvmsg() - UDP Style Syntax + * + * ssize_t recvmsg(int socket, struct msghdr *message, + * int flags); + * + * socket - the socket descriptor of the endpoint. + * message - pointer to the msghdr structure which contains a single + * user message and possibly some ancillary data. + * + * See Section 5 for complete description of the data + * structures. + * + * flags - flags sent or received with the user message, see Section + * 5 for complete description of the flags. + */ +static struct sk_buff * sctp_skb_recv_datagram(struct sock *, int, int, int *); + +static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, + int noblock, int flags, int *addr_len) +{ + sctp_ulpevent_t *event = NULL; + struct sk_buff *skb; + int copied; + int err = 0; + + SCTP_DEBUG_PRINTK("sctp_recvmsg(" + "%s: %p, %s: %p, %s: %d, %s: %d, %s: " + "0x%x, %s: %p)\n", + "sk", sk, + "msghdr", msg, + "len", len, + "knoblauch", noblock, + "flags", flags, + "addr_len", addr_len); + + sctp_lock_sock(sk); + skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; + list; + list = list->next) + copied += list->len; + } + + if (copied > len) { + copied = len; + msg->msg_flags |= MSG_TRUNC; + } + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + + event = (sctp_ulpevent_t *) skb->cb; + + if (err) + goto out_free; + + sock_recv_timestamp(msg, sk, skb); + if (sctp_ulpevent_is_notification(event)) { + msg->msg_flags |= MSG_NOTIFICATION; + } else { + /* Copy the address. */ + if (addr_len && msg->msg_name) + sctp_sk_memcpy_msgname(sk, msg->msg_name, + addr_len, skb); + } + + /* Check if we allow SCTP_SNDRCVINFO. */ + if (sctp_sk(sk)->subscribe.sctp_data_io_event) + sctp_ulpevent_read_sndrcvinfo(event, msg); + +#if 0 + /* FIXME: we should be calling IP layer too. */ + if (sk->protinfo.af_inet.cmsg_flags) + ip_cmsg_recv(msg, skb); +#endif + + err = copied; + + /* FIXME: We need to support MSG_EOR correctly. */ + msg->msg_flags |= MSG_EOR; + +out_free: + sctp_ulpevent_free(event); /* Free the skb. */ +out: + sctp_release_sock(sk); + return err; +} + +static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (get_user(val, (int *)optval)) + return -EFAULT; + + sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; + + return 0; +} + +static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) +{ + if (optlen != sizeof(struct sctp_event_subscribe)) + return -EINVAL; + if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) + return -EFAULT; + return 0; +} + +static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) +{ + sctp_opt_t *sp = sctp_sk(sk); + + if (optlen != sizeof(int)) + return -EINVAL; + if (copy_from_user(&sp->autoclose, optval, optlen)) + return -EFAULT; + + sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; + return 0; +} + +/* API 6.2 setsockopt(), getsockopt() + * + * Applications use setsockopt() and getsockopt() to set or retrieve + * socket options. Socket options are used to change the default + * behavior of sockets calls. They are described in Section 7. + * + * The syntax is: + * + * ret = getsockopt(int sd, int level, int optname, void *optval, + * int *optlen); + * ret = setsockopt(int sd, int level, int optname, const void *optval, + * int optlen); + * + * sd - the socket descript. + * level - set to IPPROTO_SCTP for all SCTP options. + * optname - the option name. + * optval - the buffer to store the value of the option. + * optlen - the size of the buffer. + */ +static int sctp_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + int retval = 0; + char * tmp; + sctp_protocol_t *proto = sctp_get_protocol(); + list_t *pos; + sctp_func_t *af; + + SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", + sk, optname); + + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of setsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ + if (level != SOL_SCTP) { + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + + retval = af->setsockopt(sk, level, optname, optval, + optlen); + if (retval < 0) + goto out_nounlock; + } + } + + sctp_lock_sock(sk); + + switch (optname) { + case SCTP_SOCKOPT_DEBUG_NAME: + /* BUG! we don't ever seem to free this memory. --jgrimm */ + if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { + retval = -ENOMEM; + goto out_unlock; + } + + if (copy_from_user(tmp, optval, optlen)) { + retval = -EFAULT; + goto out_unlock; + } + tmp[optlen] = '\000'; + sctp_sk(sk)->ep->debug_name = tmp; + break; + + case SCTP_SOCKOPT_BINDX_ADD: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + optval, optlen, BINDX_ADD_ADDR); + break; + + case SCTP_SOCKOPT_BINDX_REM: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + optval, optlen, BINDX_REM_ADDR); + break; + + case SCTP_DISABLE_FRAGMENTS: + retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); + break; + + case SCTP_SET_EVENTS: + retval = sctp_setsockopt_set_events(sk, optval, optlen); + break; + + case SCTP_AUTOCLOSE: + retval = sctp_setsockopt_autoclose(sk, optval, optlen); + break; + + default: + retval = -ENOPROTOOPT; + break; + }; + +out_unlock: + sctp_release_sock(sk); + +out_nounlock: + return retval; +} + +/* FIXME: Write comments. */ +static int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + return -EOPNOTSUPP; /* STUB */ +} + +/* FIXME: Write comments. */ +static int sctp_disconnect(struct sock *sk, int flags) +{ + return -EOPNOTSUPP; /* STUB */ +} + +/* FIXME: Write comments. */ +static struct sock *sctp_accept(struct sock *sk, int flags, int *err) +{ + int error = -EOPNOTSUPP; + + *err = error; + return NULL; +} + +/* FIXME: Write Comments. */ +static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + return -EOPNOTSUPP; /* STUB */ +} + +/* This is the function which gets called during socket creation to + * initialized the SCTP-specific portion of the sock. + * The sock structure should already be zero-filled memory. + */ +static int sctp_init_sock(struct sock *sk) +{ + sctp_endpoint_t *ep; + sctp_protocol_t *proto; + sctp_opt_t *sp; + + SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); + + proto = sctp_get_protocol(); + + /* Create a per socket endpoint structure. Even if we + * change the data structure relationships, this may still + * be useful for storing pre-connect address information. + */ + ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); + if (!ep) + return -ENOMEM; + + sp = sctp_sk(sk); + + /* Initialize the SCTP per socket area. */ + + sp->ep = ep; + sp->type = SCTP_SOCKET_UDP; + + /* FIXME: The next draft (04) of the SCTP Sockets Extensions + * should include a socket option for manipulating these + * message parameters (and a few others). + */ + sp->default_stream = 0; + sp->default_ppid = 0; + + /* Initialize default setup parameters. These parameters + * can be modified with the SCTP_INITMSG socket option or + * overridden by the SCTP_INIT CMSG. + */ + sp->initmsg.sinit_num_ostreams = proto->max_outstreams; + sp->initmsg.sinit_max_instreams = proto->max_instreams; + sp->initmsg.sinit_max_attempts = proto->max_retrans_init; + sp->initmsg.sinit_max_init_timeo = proto->rto_max / HZ; + + /* Initialize default RTO related parameters. These parameters can + * be modified for with the SCTP_RTOINFO socket option. + * FIXME: This are not used yet. + */ + sp->rtoinfo.srto_initial = proto->rto_initial; + sp->rtoinfo.srto_max = proto->rto_max; + sp->rtoinfo.srto_min = proto->rto_min; + + /* Initialize default event subscriptions. + * the struct sock is initialized to zero, so only + * enable the events needed. By default, UDP-style + * sockets enable io and association change notifications. + */ + if (SCTP_SOCKET_UDP == sp->type) { + sp->subscribe.sctp_data_io_event = 1; + sp->subscribe.sctp_association_event = 1; + } + + /* Default Peer Address Parameters. These defaults can + * be modified via SCTP_SET_PEER_ADDR_PARAMS + */ + sp->paddrparam.spp_hbinterval = proto->hb_interval / HZ; + sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; + + /* If enabled no SCTP message fragmentation will be performed. + * Configure through SCTP_DISABLE_FRAGMENTS socket option. + */ + sp->disable_fragments = 0; + + /* Turn on/off any Nagle-like algorithm. */ + sp->nodelay = 0; + + /* Auto-close idle associations after the configured + * number of seconds. A value of 0 disables this + * feature. Configure through the SCTP_AUTOCLOSE socket option, + * for UDP-style sockets only. + */ + sp->autoclose = 0; + + SCTP_DBG_OBJCNT_INC(sock); + return 0; +} + +/* Cleanup any SCTP per socket resources. */ +static int sctp_destroy_sock(struct sock *sk) +{ + sctp_endpoint_t *ep; + + SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); + + /* Release our hold on the endpoint. */ + ep = sctp_sk(sk)->ep; + sctp_endpoint_free(ep); + + return 0; +} + +/* FIXME: Comments needed. */ +static void sctp_shutdown(struct sock *sk, int how) +{ + /* UDP-style sockets do not support shutdown. */ + /* STUB */ +} + +static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, + int *optlen) +{ + struct sctp_status status; + sctp_endpoint_t *ep; + sctp_association_t *assoc = NULL; + sctp_transport_t *transport; + sctp_assoc_t associd; + int retval = 0; + + if (len != sizeof(status)) { + retval = -EINVAL; + goto out_nounlock; + } + + if (copy_from_user(&status, optval, sizeof(status))) { + retval = -EFAULT; + goto out_nounlock; + } + + sctp_lock_sock(sk); + + associd = status.sstat_assoc_id; + if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) { + assoc = sctp_id2assoc(sk, associd); + if (!assoc) { + retval = -EINVAL; + goto out_unlock; + } + } else { + ep = sctp_sk(sk)->ep; + if (list_empty(&ep->asocs)) { + retval = -EINVAL; + goto out_unlock; + } + + assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); + } + + transport = assoc->peer.primary_path; + + status.sstat_assoc_id = sctp_assoc2id(assoc); + status.sstat_state = assoc->state; + status.sstat_rwnd = assoc->peer.rwnd; + status.sstat_unackdata = assoc->unack_data; + status.sstat_penddata = assoc->peer.tsn_map.pending_data; + status.sstat_instrms = assoc->c.sinit_max_instreams; + status.sstat_outstrms = assoc->c.sinit_num_ostreams; + status.sstat_fragmentation_point = assoc->frag_point; + status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); + memcpy(&status.sstat_primary.spinfo_address, + &(transport->ipaddr), sizeof(sockaddr_storage_t)); + status.sstat_primary.spinfo_state = transport->state.active; + status.sstat_primary.spinfo_cwnd = transport->cwnd; + status.sstat_primary.spinfo_srtt = transport->srtt; + status.sstat_primary.spinfo_rto = transport->rto; + status.sstat_primary.spinfo_mtu = transport->pmtu; + + if (put_user(len, optlen)) { + retval = -EFAULT; + goto out_unlock; + } + + SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", + len, status.sstat_state, status.sstat_rwnd, + status.sstat_assoc_id); + + if (copy_to_user(optval, &status, len)) { + retval = -EFAULT; + goto out_unlock; + } + +out_unlock: + sctp_release_sock(sk); + +out_nounlock: + return (retval); +} + +static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + val = (sctp_sk(sk)->disable_fragments == 1); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; +} + +static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +{ + if (len != sizeof(struct sctp_event_subscribe)) + return -EINVAL; + if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) + return -EFAULT; + return 0; +} + +static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) +{ + if (len != sizeof(int)) + return -EINVAL; + if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) + return -EFAULT; + return 0; +} + +/* Helper routine to branch off an association to a new socket. */ +static int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +{ + struct sock *oldsk = assoc->base.sk; + struct sock *newsk; + struct socket *tmpsock; + sctp_endpoint_t *newep; + sctp_opt_t *oldsp = sctp_sk(oldsk); + sctp_opt_t *newsp; + int err = 0; + + /* An association cannot be branched off from an already peeled-off + * socket. + */ + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type) + return -EINVAL; + + /* Create a new socket. */ + err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock); + if (err < 0) + return err; + + newsk = tmpsock->sk; + newsp = sctp_sk(newsk); + newep = newsp->ep; + + /* Migrate socket buffer sizes and all the socket level options to the + * new socket. + */ + newsk->sndbuf = oldsk->sndbuf; + newsk->rcvbuf = oldsk->rcvbuf; + *newsp = *oldsp; + + /* Restore the ep value that was overwritten with the above structure + * copy. + */ + newsp->ep = newep; + + /* Set the type of socket to indicate that it is peeled off from the + * original socket. + */ + newsp->type = SCTP_SOCKET_UDP_HIGH_BANDWIDTH; + + /* Migrate the association to the new socket. */ + sctp_assoc_migrate(assoc, newsk); + + *newsock = tmpsock; + + return err; +} + +static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) +{ + sctp_peeloff_arg_t peeloff; + struct socket *newsock; + int err, sd; + sctp_association_t *assoc; + + if (len != sizeof(sctp_peeloff_arg_t)) + return -EINVAL; + if (copy_from_user(&peeloff, optval, len)) + return -EFAULT; + assoc = sctp_id2assoc(sk, peeloff.associd); + if (NULL == assoc) + return -EINVAL; + + SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); + + err = sctp_do_peeloff(assoc, &newsock); + if (err < 0) + return err; + + /* Map the socket to an unused fd that can be returned to the user. */ + sd = sock_map_fd(newsock); + if (sd < 0) { + sock_release(newsock); + return sd; + } + + SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", + __FUNCTION__, sk, assoc, newsock->sk, sd); + + /* Return the fd mapped to the new socket. */ + peeloff.sd = sd; + if (copy_to_user(optval, &peeloff, len)) + return -EFAULT; + + return 0; +} + +static int sctp_getsockopt(struct sock *sk, int level, int optname, + char *optval, int *optlen) +{ + int retval = 0; + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *af; + list_t *pos; + int len; + + SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); + + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of getsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ + if (level != SOL_SCTP) { + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + retval = af->getsockopt(sk, level, optname, + optval, optlen); + if (retval < 0) + return retval; + } + } + + if (get_user(len, optlen)) + return -EFAULT; + + switch (optname) { + case SCTP_STATUS: + retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); + break; + + case SCTP_DISABLE_FRAGMENTS: + retval = sctp_getsockopt_disable_fragments(sk, len, optval, + optlen); + break; + + case SCTP_SET_EVENTS: + retval = sctp_getsockopt_set_events(sk, len, optval, optlen); + break; + + case SCTP_AUTOCLOSE: + retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); + break; + + case SCTP_SOCKOPT_PEELOFF: + retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); + break; + + default: + retval = -ENOPROTOOPT; + break; + }; + + return retval; +} + +static void sctp_hash(struct sock *sk) +{ + /* STUB */ +} + +static void sctp_unhash(struct sock *sk) +{ + /* STUB */ +} + +/* Check if port is acceptable. Possibly find first available port. + * + * The port hash table (contained in the 'global' SCTP protocol storage + * returned by sctp_protocol_t * sctp_get_protocol()). The hash + * table is an array of 4096 lists (sctp_bind_hashbucket_t). Each + * list (the list number is the port number hashed out, so as you + * would expect from a hash function, all the ports in a given list have + * such a number that hashes out to the same list number; you were + * expecting that, right?); so each list has a set of ports, with a + * link to the socket (struct sock) that uses it, the port number and + * a fastreuse flag (FIXME: NPI ipg). + */ +static long sctp_get_port_local(struct sock *sk, unsigned short snum) +{ + sctp_bind_hashbucket_t *head; /* hash list */ + sctp_bind_bucket_t *pp; /* hash list port iterator */ + sctp_protocol_t *sctp = sctp_get_protocol(); + int ret; + + SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); + + sctp_local_bh_disable(); + + if (snum == 0) { + /* Search for an available port. + * + * 'sctp->port_rover' was the last port assigned, so + * we start to search from 'sctp->port_rover + + * 1'. What we do is first check if port 'rover' is + * already in the hash table; if not, we use that; if + * it is, we try next. + */ + int low = sysctl_local_port_range[0]; + int high = sysctl_local_port_range[1]; + int remaining = (high - low) + 1; + int rover; + int index; + + sctp_spin_lock(&sctp->port_alloc_lock); + rover = sctp->port_rover; + do { + rover++; + if ((rover < low) || (rover > high)) + rover = low; + index = sctp_phashfn(rover); + head = &sctp->port_hashtable[index]; + sctp_spin_lock(&head->lock); + for (pp = head->chain; pp; pp = pp->next) + if (pp->port == rover) + goto next; + break; + next: + sctp_spin_unlock(&head->lock); + } while (--remaining > 0); + sctp->port_rover = rover; + sctp_spin_unlock(&sctp->port_alloc_lock); + + /* Exhausted local port range during search? */ + ret = 1; + if (remaining <= 0) + goto fail; + + /* OK, here is the one we will use. HEAD (the port + * hash table list entry) is non-NULL and we hold it's + * mutex. + */ + snum = rover; + pp = NULL; + } else { + /* We are given an specific port number; we verify + * that it is not being used. If it is used, we will + * exahust the search in the hash list corresponding + * to the port number (snum) - we detect that with the + * port iterator, pp being NULL. + */ + head = &sctp->port_hashtable[sctp_phashfn(snum)]; + sctp_spin_lock(&head->lock); + for (pp = head->chain; pp; pp = pp->next) { + if (pp->port == snum) + break; + } + } + + if (pp != NULL && pp->sk != NULL) { + /* We had a port hash table hit - there is an + * available port (pp != NULL) and it is being + * used by other socket (pp->sk != NULL); that other + * socket is going to be sk2. + */ + int sk_reuse = sk->reuse; + sockaddr_storage_t tmpaddr; + struct sock *sk2 = pp->sk; + + SCTP_DEBUG_PRINTK("sctp_get_port() found a " + "possible match\n"); + if (pp->fastreuse != 0 && sk->reuse != 0) + goto success; + + /* FIXME - multiple addresses need to be supported + * later. + */ + switch (sk->family) { + case PF_INET: + tmpaddr.v4.sin_family = AF_INET; + tmpaddr.v4.sin_port = snum; + tmpaddr.v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; + break; + + case PF_INET6: + SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; + tmpaddr.v6.sin6_port = snum; + tmpaddr.v6.sin6_addr = + inet6_sk(sk)->rcv_saddr; + ) + break; + + default: + break; + }; + + /* Run through the list of sockets bound to the port + * (pp->port) [via the pointers bind_next and + * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, + * we get the endpoint they describe and run through + * the endpoint's list of IP (v4 or v6) addresses, + * comparing each of the addresses with the address of + * the socket sk. If we find a match, then that means + * that this port/socket (sk) combination are already + * in an endpoint. + */ + for( ; sk2 != NULL; sk2 = sk2->bind_next) { + sctp_endpoint_t *ep2; + ep2 = sctp_sk(sk2)->ep; + + if (!sk_reuse || !sk2->reuse) { + if (sctp_bind_addr_has_addr( + &ep2->base.bind_addr, &tmpaddr)) { + goto found; + } + } + } + + found: + /* If we found a conflict, fail. */ + if (sk2 != NULL) { + ret = (long) sk2; + goto fail_unlock; + } + SCTP_DEBUG_PRINTK("sctp_get_port(): Found a match\n"); + } + + /* If there was a hash table miss, create a new port. */ + ret = 1; + + if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) + goto fail_unlock; + + /* In either case (hit or miss), make sure fastreuse is 1 only + * if sk->reuse is too (that is, if the caller requested + * SO_REUSEADDR on this socket -sk-). + */ + if (pp->sk == NULL) { + pp->fastreuse = sk->reuse? 1 : 0; + } else if (pp->fastreuse && sk->reuse == 0) { + pp->fastreuse = 0; + } + + /* We are set, so fill up all the data in the hash table + * entry, tie the socket list information with the rest of the + * sockets FIXME: Blurry, NPI (ipg). + */ +success: + inet_sk(sk)->num = snum; + if (sk->prev == NULL) { + if ((sk->bind_next = pp->sk) != NULL) + pp->sk->bind_pprev = &sk->bind_next; + pp->sk = sk; + sk->bind_pprev = &pp->sk; + sk->prev = (struct sock *) pp; + } + ret = 0; + +fail_unlock: + sctp_spin_unlock(&head->lock); + +fail: + sctp_local_bh_enable(); + + SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret); + return ret; +} + +static int sctp_get_port(struct sock *sk, unsigned short snum) +{ + long ret = sctp_get_port_local(sk, snum); + + return (ret ? 1 : 0); +} + +/* + * 3.1.3 listen() - UDP Style Syntax + * + * By default, new associations are not accepted for UDP style sockets. + * An application uses listen() to mark a socket as being able to + * accept new associations. + */ +static int sctp_seqpacket_listen(struct sock *sk, int backlog) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + + /* Only UDP style sockets that are not peeled off are allowed to + * listen(). + */ + if (SCTP_SOCKET_UDP != sp->type) + return -EINVAL; + + /* + * If a bind() or sctp_bindx() is not called prior to a listen() + * call that allows new associations to be accepted, the system + * picks an ephemeral port and will choose an address set equivalent + * to binding with a wildcard address. + * + * This is not currently spelled out in the SCTP sockets + * extensions draft, but follows the practice as seen in TCP + * sockets. + */ + if (!ep->base.bind_addr.port) { + if (sctp_autobind(sk)) + return -EAGAIN; + } + sk->state = SCTP_SS_LISTENING; + sctp_hash_endpoint(ep); + return 0; +} + +/* + * Move a socket to LISTENING state. + */ +int sctp_inet_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err; + + sctp_lock_sock(sk); + + err = -EINVAL; + if (sock->state != SS_UNCONNECTED) + goto out; + switch (sock->type) { + case SOCK_SEQPACKET: + err = sctp_seqpacket_listen(sk, backlog); + break; + + case SOCK_STREAM: + /* FIXME for TCP-style sockets. */ + err = -EOPNOTSUPP; + + default: + goto out; + }; + +out: + sctp_release_sock(sk); + return err; +} + +/* + * This function is done by modeling the current datagram_poll() and the + * tcp_poll(). Note that, based on these implementations, we don't + * lock the socket in this function, even though it seems that, + * ideally, locking or some other mechanisms can be used to ensure + * the integrity of the counters (sndbuf and wmem_queued) used + * in this place. We assume that we don't need locks either until proven + * otherwise. + * + * Another thing to note is that we include the Async I/O support + * here, again, by modeling the current TCP/UDP code. We don't have + * a good way to test with it yet. + */ +unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + + poll_wait(file, sk->sleep, wait); + mask = 0; + + /* Is there any exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)) + mask |= POLLERR; + if (sk->shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + /* Is it readable? Reconsider this code with TCP-style support. */ + if (!skb_queue_empty(&sk->receive_queue) || + (sk->shutdown & RCV_SHUTDOWN)) + mask |= POLLIN | POLLRDNORM; + + /* + * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and + * peeled off sockets. Additionally, TCP-style needs to consider + * other establishment conditions. + */ + if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { + /* The association is going away. */ + if (SCTP_SS_DISCONNECTING == sk->state) + mask |= POLLHUP; + /* The association is either gone or not ready. */ + if (SCTP_SS_CLOSED == sk->state) + return mask; + } + + /* Is it writable? */ + if (sctp_writeable(sk)) { + mask |= POLLOUT | POLLWRNORM; + } else { + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + /* + * Since the socket is not locked, the buffer + * might be made available after the writeable check and + * before the bit is set. This could cause a lost I/O + * signal. tcp_poll() has a race breaker for this race + * condition. Based on their implementation, we put + * in the following code to cover it as well. + */ + if (sctp_writeable(sk)) + mask |= POLLOUT | POLLWRNORM; + } + return mask; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) +{ + sctp_bind_bucket_t *pp; + + SCTP_DEBUG_PRINTK( "sctp_bucket_create() begins, snum=%d\n", snum); + pp = kmalloc(sizeof(sctp_bind_bucket_t), GFP_ATOMIC); + if (pp) { + pp->port = snum; + pp->fastreuse = 0; + pp->sk = NULL; + if ((pp->next = head->chain) != NULL) + pp->next->pprev = &pp->next; + head->chain= pp; + pp->pprev = &head->chain; + } + SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); + return pp; +} + +/* FIXME: Commments! */ +static __inline__ void __sctp_put_port(struct sock *sk) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + sctp_bind_hashbucket_t *head = + &sctp_proto->port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; + sctp_bind_bucket_t *pp; + + sctp_spin_lock(&head->lock); + pp = (sctp_bind_bucket_t *) sk->prev; + if (sk->bind_next) + sk->bind_next->bind_pprev = sk->bind_pprev; + *(sk->bind_pprev) = sk->bind_next; + sk->prev = NULL; + inet_sk(sk)->num = 0; + if (pp->sk) { + if (pp->next) + pp->next->pprev = pp->pprev; + *(pp->pprev) = pp->next; + kfree(pp); + } + sctp_spin_unlock(&head->lock); +} + +void sctp_put_port(struct sock *sk) +{ + sctp_local_bh_disable(); + __sctp_put_port(sk); + sctp_local_bh_enable(); +} + +/* + * The system picks an ephemeral port and choose an address set equivalent + * to binding with a wildcard address. + * One of those addresses will be the primary address for the association. + * This automatically enables the multihoming capability of SCTP. + */ +static int sctp_autobind(struct sock *sk) +{ + sockaddr_storage_t autoaddr; + int addr_len = 0; + + memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); + + switch (sk->family) { + case PF_INET: + autoaddr.v4.sin_family = AF_INET; + autoaddr.v4.sin_addr.s_addr = INADDR_ANY; + autoaddr.v4.sin_port = htons(inet_sk(sk)->num); + addr_len = sizeof(struct sockaddr_in); + break; + + case PF_INET6: + SCTP_V6( + /* FIXME: Write me for v6! */ + BUG(); + autoaddr.v6.sin6_family = AF_INET6; + autoaddr.v6.sin6_port = htons(inet_sk(sk)->num); + addr_len = sizeof(struct sockaddr_in6); + ); + break; + + default: /* This should not happen. */ + break; + }; + + return sctp_do_bind(sk, &autoaddr, addr_len); +} + +/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. + * + * From RFC 2292 + * 4.2 The cmsghdr Structure * + * + * When ancillary data is sent or received, any number of ancillary data + * objects can be specified by the msg_control and msg_controllen members of + * the msghdr structure, because each object is preceded by + * a cmsghdr structure defining the object's length (the cmsg_len member). + * Historically Berkeley-derived implementations have passed only one object + * at a time, but this API allows multiple objects to be + * passed in a single call to sendmsg() or recvmsg(). The following example + * shows two ancillary data objects in a control buffer. + * + * |<--------------------------- msg_controllen -------------------------->| + * | | + * + * |<----- ancillary data object ----->|<----- ancillary data object ----->| + * + * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| + * | | | + * + * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | + * + * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | + * | | | | | + * + * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ + * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| + * + * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| + * + * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ + * ^ + * | + * + * msg_control + * points here + */ +static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) +{ + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { + /* Check for minimum length. The SCM code has this check. */ + if (cmsg->cmsg_len < sizeof(struct cmsghdr) || + (unsigned long)(((char*)cmsg - (char*)msg->msg_control) + + cmsg->cmsg_len) > msg->msg_controllen) { + return -EINVAL; + } + + /* Should we parse this header or ignore? */ + if (cmsg->cmsg_level != IPPROTO_SCTP) + continue; + + /* Strictly check lengths following example in SCM code. */ + switch (cmsg->cmsg_type) { + case SCTP_INIT: + /* SCTP Socket API Extension (draft 1) + * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for + * initializing new SCTP associations with sendmsg(). + * The SCTP_INITMSG socket option uses this same data + * structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + */ + if (cmsg->cmsg_len != + CMSG_LEN(sizeof(struct sctp_initmsg))) + return -EINVAL; + cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); + break; + + case SCTP_SNDRCV: + /* SCTP Socket API Extension (draft 1) + * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for + * sendmsg() and describes SCTP header information + * about a received message through recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + */ + if (cmsg->cmsg_len != + CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) + return -EINVAL; + + cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + + /* Minimally, validate the sinfo_flags. */ + if (cmsgs->info->sinfo_flags & + ~(MSG_UNORDERED | MSG_ADDR_OVER | + MSG_ABORT | MSG_EOF)) + return -EINVAL; + break; + + default: + return -EINVAL; + }; + } + return 0; +} + +/* Setup sk->rcv_saddr before calling get_port(). */ +static inline void sctp_sk_addr_set(struct sock *sk, + const sockaddr_storage_t *newaddr, + sockaddr_storage_t *saveaddr) +{ + struct inet_opt *inet = inet_sk(sk); + + saveaddr->sa.sa_family = newaddr->sa.sa_family; + + switch (newaddr->sa.sa_family) { + case AF_INET: + saveaddr->v4.sin_addr.s_addr = inet->rcv_saddr; + inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr; + break; + + case AF_INET6: + SCTP_V6({ + struct ipv6_pinfo *np = inet6_sk(sk); + + saveaddr->v6.sin6_addr = np->rcv_saddr; + np->rcv_saddr = np->saddr = newaddr->v6.sin6_addr; + break; + }) + + default: + break; + }; +} + +/* Restore sk->rcv_saddr after failing get_port(). */ +static inline void sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) +{ + struct inet_opt *inet = inet_sk(sk); + + switch (addr->sa.sa_family) { + case AF_INET: + inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr; + break; + + case AF_INET6: + SCTP_V6({ + struct ipv6_pinfo *np = inet6_sk(sk); + + np->rcv_saddr = np->saddr = addr->v6.sin6_addr; + break; + }) + + default: + break; + }; +} + +/* + * Wait for a packet.. + * Note: This function is the same function as in core/datagram.c + * with a few modifications to make lksctp work. + */ +static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) +{ + int error; + DECLARE_WAITQUEUE(wait, current); + + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue_exclusive(sk->sleep, &wait); + + /* Socket errors? */ + error = sock_error(sk); + if (error) + goto out; + + if (!skb_queue_empty(&sk->receive_queue)) + goto ready; + + /* Socket shut down? */ + if (sk->shutdown & RCV_SHUTDOWN) + goto out; + + /* Sequenced packets can come disconnected. If so we report the + * problem. + */ + error = -ENOTCONN; + + /* Is there a good reason to think that we may receive some data? */ + if ((list_empty(&sctp_sk(sk)->ep->asocs)) && + (sk->state != SCTP_SS_LISTENING)) + goto out; + + /* Handle signals. */ + if (signal_pending(current)) + goto interrupted; + + /* Let another process have a go. Since we are going to sleep + * anyway. Note: This may cause odd behaviors if the message + * does not fit in the user's buffer, but this seems to be the + * only way to honor MSG_DONTWAIT realistically. + */ + sctp_release_sock(sk); + *timeo_p = schedule_timeout(*timeo_p); + sctp_lock_sock(sk); + +ready: + remove_wait_queue(sk->sleep, &wait); + __set_current_state(TASK_RUNNING); + return 0; + +interrupted: + error = sock_intr_errno(*timeo_p); + +out: + remove_wait_queue(sk->sleep, &wait); + __set_current_state(TASK_RUNNING); + *err = error; + return error; +} + +/* Receive a datagram. + * Note: This is pretty much the same routine as in core/datagram.c + * with a few changes to make lksctp work. + */ +static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +{ + int error; + struct sk_buff *skb; + long timeo; + + /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + error = sock_error(sk); + if (error) + goto no_packet; + + timeo = sock_rcvtimeo(sk, noblock); + + SCTP_DEBUG_PRINTK("Timeout: timeo: %ld, MAX: %ld.\n", + timeo, MAX_SCHEDULE_TIMEOUT); + + do { + /* Again only user level code calls this function, + * so nothing interrupt level + * will suddenly eat the receive_queue. + * + * Look at current nfs client by the way... + * However, this function was corrent in any case. 8) + */ + if (flags & MSG_PEEK) { + unsigned long cpu_flags; + + sctp_spin_lock_irqsave(&sk->receive_queue.lock, + cpu_flags); + skb = skb_peek(&sk->receive_queue); + if (skb) + atomic_inc(&skb->users); + sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, + cpu_flags); + } else { + skb = skb_dequeue(&sk->receive_queue); + } + + if (skb) + return skb; + + /* User doesn't want to wait. */ + error = -EAGAIN; + if (!timeo) + goto no_packet; + } while (sctp_wait_for_packet(sk, err, &timeo) == 0); + + return NULL; + +no_packet: + *err = error; + return NULL; +} + +/* Copy an approriately formatted address for msg_name. */ +static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, + int *addr_len, struct sk_buff *skb) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6 __attribute__ ((unused)); + struct sctphdr *sh; + + /* The sockets layer handles copying this out to user space. */ + switch (sk->family) { + case PF_INET: + sin = (struct sockaddr_in *)msgname; + if (addr_len) + *addr_len = sizeof(struct sockaddr_in); + sin->sin_family = AF_INET; + sh = (struct sctphdr *) skb->h.raw; + sin->sin_port = sh->source; + sin->sin_addr.s_addr = skb->nh.iph->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + break; + + case PF_INET6: + SCTP_V6( + /* FIXME: Need v6 code here. We should convert + * V4 addresses to PF_INET6 format. See ipv6/udp.c + * for an example. --jgrimm + */ + ); + break; + + default: /* Should not get here. */ + break; + }; +} + +static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) +{ + sockaddr_storage_t *sa; + + if (msg->msg_namelen < sizeof (struct sockaddr)) + return -EINVAL; + + sa = (sockaddr_storage_t *) msg->msg_name; + switch (sa->sa.sa_family) { + case AF_INET: + if (msg->msg_namelen < sizeof(struct sockaddr_in)) + return -EINVAL; + break; + + case AF_INET6: + if (PF_INET == sk->family) + return -EINVAL; + SCTP_V6( + if (msg->msg_namelen < sizeof(struct sockaddr_in6)) + return -EINVAL; + break; + ); + + default: + return -EINVAL; + }; + + /* Disallow any illegal addresses to be used as destinations. */ + if (!sctp_addr_is_valid(sa)) + return -EINVAL; + + return 0; +} + +/* Get the sndbuf space available at the time on the association. */ +static inline int sctp_wspace(sctp_association_t *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = 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(sctp_chunk_t *chunk) +{ + sctp_association_t *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. */ + *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); +} + +/* Do accounting for the sndbuf space. + * Decrement the used sndbuf space of the corresponding association by the + * data size which was just transmitted(freed). + */ +static void sctp_wfree(struct sk_buff *skb) +{ + sctp_association_t *asoc; + sctp_chunk_t *chunk; + struct sock *sk; + + /* Get the saved chunk pointer. */ + chunk = *((sctp_chunk_t **)(skb->cb)); + asoc = chunk->asoc; + sk = asoc->base.sk; + asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); + sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + __sctp_write_space(asoc); + + sctp_association_put(asoc); +} + +/* Helper function to wait for space in the sndbuf. */ +static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len) +{ + struct sock *sk = asoc->base.sk; + int err = 0; + long current_timeo = *timeo_p; + DECLARE_WAITQUEUE(wait, current); + + SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", + asoc, (long)(*timeo_p), msg_len); + + /* Wait on the association specific sndbuf space. */ + add_wait_queue_exclusive(&asoc->wait, &wait); + + /* Increment the association's refcnt. */ + sctp_association_hold(asoc); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (!*timeo_p) + goto do_nonblock; + if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + asoc->base.dead) + goto do_error; + if (signal_pending(current)) + goto do_interrupted; + if (msg_len <= sctp_wspace(asoc)) + break; + + /* Let another process have a go. Since we are going + * to sleep anyway. + */ + sctp_release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + sctp_lock_sock(sk); + + *timeo_p = current_timeo; + } + +out: + remove_wait_queue(&asoc->wait, &wait); + + /* Release the association's refcnt. */ + sctp_association_put(asoc); + + __set_current_state(TASK_RUNNING); + return err; + +do_error: + err = -EPIPE; + goto out; + +do_interrupted: + err = sock_intr_errno(*timeo_p); + goto out; + +do_nonblock: + err = -EAGAIN; + goto out; +} + +/* If sndbuf has changed, wake up per association sndbuf waiters. */ +static void __sctp_write_space(sctp_association_t *asoc) +{ + struct sock *sk = asoc->base.sk; + struct socket *sock = sk->socket; + + if ((sctp_wspace(asoc) > 0) && sock) { + if (waitqueue_active(&asoc->wait)) + wake_up_interruptible(&asoc->wait); + + if (sctp_writeable(sk)) { + if (sk->sleep && waitqueue_active(sk->sleep)) + wake_up_interruptible(sk->sleep); + + /* Note that we try to include the Async I/O support + * here by modeling from the current TCP/UDP code. + * We have not tested with it yet. + */ + if (sock->fasync_list && + !(sk->shutdown & SEND_SHUTDOWN)) + sock_wake_async(sock, 2, POLL_OUT); + } + } +} + +/* If socket sndbuf has changed, wake up all per association waiters. */ +void sctp_write_space(struct sock *sk) +{ + sctp_association_t *asoc; + list_t *pos; + + /* Wake up the tasks in each wait queue. */ + list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { + asoc = list_entry(pos, sctp_association_t, asocs); + __sctp_write_space(asoc); + } +} + +/* Is there any sndbuf space available on the socket? + * + * Note that wmem_queued is the sum of the send buffers on all of the + * associations on the same socket. For a UDP-style socket with + * multiple associations, it is possible for it to be "unwriteable" + * prematurely. I assume that this is acceptable because + * a premature "unwriteable" is better than an accidental "writeable" which + * would cause an unwanted block under certain circumstances. For the 1-1 + * UDP-style sockets or TCP-style sockets, this code should work. + * - Daisy + */ +static int sctp_writeable(struct sock *sk) +{ + int amt = 0; + + amt = sk->sndbuf - sk->wmem_queued; + if (amt < 0) + amt = 0; + return amt; +} + +/* This proto struct describes the ULP interface for SCTP. */ +struct proto sctp_prot = { + .name = "SCTP", + .close = sctp_close, + .connect = sctp_connect, + .disconnect = sctp_disconnect, + .accept = sctp_accept, + .ioctl = sctp_ioctl, + .init = sctp_init_sock, + .destroy = sctp_destroy_sock, + .shutdown = sctp_shutdown, + .setsockopt = sctp_setsockopt, + .getsockopt = sctp_getsockopt, + .sendmsg = sctp_sendmsg, + .recvmsg = sctp_recvmsg, + .bind = sctp_bind, + .backlog_rcv = sctp_backlog_rcv, + .hash = sctp_hash, + .unhash = sctp_unhash, + .get_port = sctp_get_port, +}; diff -Nru a/net/sctp/sysctl.c b/net/sctp/sysctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/sysctl.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,104 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * Sysctl related interfaces for SCTP. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Mingqin Liu + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include + +extern sctp_protocol_t sctp_proto; + +static ctl_table sctp_table[] = { + { NET_SCTP_RTO_INITIAL, "rto_initial", + &sctp_proto.rto_initial, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_MIN, "rto_min", + &sctp_proto.rto_min, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_MAX, "rto_max", + &sctp_proto.rto_max, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_VALID_COOKIE_LIFE, "valid_cookie_life", + &sctp_proto.valid_cookie_life, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_MAX_BURST, "max_burst", + &sctp_proto.max_burst, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_ASSOCIATION_MAX_RETRANS, "association_max_retrans", + &sctp_proto.max_retrans_association, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_PATH_MAX_RETRANS, "path_max_retrans", + &sctp_proto.max_retrans_path, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_MAX_INIT_RETRANSMITS, "max_init_retransmits", + &sctp_proto.max_retrans_init, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_HB_INTERVAL, "hb_interval", + &sctp_proto.hb_interval, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor", + &sctp_proto.rto_alpha, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_RTO_BETA, "rto_beta_exp_divisor", + &sctp_proto.rto_beta, sizeof(int), 0644, NULL, + &proc_dointvec }, + { 0 } +}; + +static ctl_table sctp_net_table[] = { + { NET_SCTP, "sctp", NULL, 0, 0555, sctp_table }, + { 0 } +}; + +static ctl_table sctp_root_table[] = { + { CTL_NET, "net", NULL, 0, 0555, sctp_net_table }, + { 0 } +}; + +static struct ctl_table_header * sctp_sysctl_header; + +/* Sysctl registration. */ +void sctp_sysctl_register(void) +{ + sctp_sysctl_header = register_sysctl_table(sctp_root_table, 0); +} + +/* Sysctl deregistration. */ +void sctp_sysctl_unregister(void) +{ + unregister_sysctl_table(sctp_sysctl_header); +} diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/transport.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,442 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * This module provides the abstraction for an SCTP tranport representing + * a remote transport address. For local transport addresses, we just use + * sockaddr_storage_t. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include + +/* 1st Level Abstractions. */ + +/* Allocate and initialize a new transport. */ +sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priority) +{ + sctp_transport_t *transport; + + transport = t_new(sctp_transport_t, priority); + if (!transport) + goto fail; + + if (!sctp_transport_init(transport, addr, priority)) + goto fail_init; + + transport->malloced = 1; + SCTP_DBG_OBJCNT_INC(transport); + + return transport; + +fail_init: + kfree(transport); + +fail: + return NULL; +} + +/* Intialize a new transport from provided memory. */ +sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, + const sockaddr_storage_t *addr, + int priority) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + + /* Copy in the address. */ + peer->ipaddr = *addr; + peer->af_specific = sctp_get_af_specific(addr); + peer->asoc = NULL; + peer->pmtu = peer->af_specific->get_dst_mtu(addr); + + /* From 6.3.1 RTO Calculation: + * + * C1) Until an RTT measurement has been made for a packet sent to the + * given destination transport address, set RTO to the protocol + * parameter 'RTO.Initial'. + */ + peer->rtt = 0; + peer->rto = proto->rto_initial; + peer->rttvar = 0; + peer->srtt = 0; + peer->rto_pending = 0; + + peer->last_time_heard = jiffies; + peer->last_time_used = jiffies; + peer->last_time_ecne_reduced = jiffies; + + peer->state.active = 1; + peer->state.hb_allowed = 0; + + /* Initialize the default path max_retrans. */ + peer->max_retrans = proto->max_retrans_path; + peer->error_threshold = 0; + peer->error_count = 0; + + peer->debug_name = "unnamedtransport"; + + INIT_LIST_HEAD(&peer->transmitted); + INIT_LIST_HEAD(&peer->send_ready); + INIT_LIST_HEAD(&peer->transports); + + /* Set up the retransmission timer. */ + init_timer(&peer->T3_rtx_timer); + peer->T3_rtx_timer.function = sctp_generate_t3_rtx_event; + peer->T3_rtx_timer.data = (unsigned long)peer; + + /* Set up the heartbeat timer. */ + init_timer(&peer->hb_timer); + peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + peer->hb_timer.function = sctp_generate_heartbeat_event; + peer->hb_timer.data = (unsigned long)peer; + + atomic_set(&peer->refcnt, 1); + peer->dead = 0; + + peer->malloced = 0; + return peer; +} + +/* This transport is no longer needed. Free up if possible, or + * delay until it last reference count. + */ +void sctp_transport_free(sctp_transport_t *transport) +{ + transport->dead = 1; + + /* Try to delete the heartbeat timer. */ + if (del_timer(&transport->hb_timer)) + sctp_transport_put(transport); + + sctp_transport_put(transport); +} + +/* Destroy the transport data structure. + * Assumes there are no more users of this structure. + */ +void sctp_transport_destroy(sctp_transport_t *transport) +{ + SCTP_ASSERT(transport->dead, "Transport is not dead", return); + + if (transport->asoc) + sctp_association_put(transport->asoc); + + kfree(transport); + SCTP_DBG_OBJCNT_DEC(transport); +} + +/* Start T3_rtx timer if it is not already running and update the heartbeat + * timer. This routine is called everytime a DATA chunk is sent. + */ +void sctp_transport_reset_timers(sctp_transport_t *transport) +{ + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R1) Every time a DATA chunk is sent to any address(including a + * retransmission), if the T3-rtx timer of that address is not running + * start it running so that it will expire after the RTO of that + * address. + */ + if (!timer_pending(&transport->T3_rtx_timer)) { + if (!mod_timer(&transport->T3_rtx_timer, + jiffies + transport->rto)) + sctp_transport_hold(transport); + } + + /* When a data chunk is sent, reset the heartbeat interval. */ + if (!mod_timer(&transport->hb_timer, + transport->hb_interval + transport->rto + jiffies)) + sctp_transport_hold(transport); +} + +/* This transport has been assigned to an association. + * Initialize fields from the association or from the sock itself. + * Register the reference count in the association. + */ +void sctp_transport_set_owner(sctp_transport_t *transport, + sctp_association_t *asoc) +{ + transport->asoc = asoc; + sctp_association_hold(asoc); +} + +/* Hold a reference to a transport. */ +void sctp_transport_hold(sctp_transport_t *transport) +{ + atomic_inc(&transport->refcnt); +} + +/* Release a reference to a transport and clean up + * if there are no more references. + */ +void sctp_transport_put(sctp_transport_t *transport) +{ + if (atomic_dec_and_test(&transport->refcnt)) + sctp_transport_destroy(transport); +} + +/* Update transport's RTO based on the newly calculated RTT. */ +void sctp_transport_update_rto(sctp_transport_t *tp, __u32 rtt) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + + /* Check for valid transport. */ + SCTP_ASSERT(tp, "NULL transport", return); + + /* We should not be doing any RTO updates unless rto_pending is set. */ + SCTP_ASSERT(tp->rto_pending, "rto_pending not set", return); + + if (tp->rttvar || tp->srtt) { + /* 6.3.1 C3) When a new RTT measurement R' is made, set + * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| + * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' + */ + + /* Note: The above algorithm has been rewritten to + * express rto_beta and rto_alpha as inverse powers + * of two. + * For example, assuming the default value of RTO.Alpha of + * 1/8, rto_alpha would be expressed as 3. + */ + tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) + + ((abs(tp->srtt - rtt)) >> proto->rto_beta); + tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) + + (rtt >> proto->rto_alpha); + } else { + /* 6.3.1 C2) When the first RTT measurement R is made, set + * SRTT <- R, RTTVAR <- R/2. + */ + tp->srtt = rtt; + tp->rttvar = rtt >> 1; + } + + /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then + * adjust RTTVAR <- G, where G is the CLOCK GRANULARITY. + */ + if (tp->rttvar == 0) + tp->rttvar = SCTP_CLOCK_GRANULARITY; + + /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ + tp->rto = tp->srtt + (tp->rttvar << 2); + + /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min + * seconds then it is rounded up to RTO.Min seconds. + */ + if (tp->rto < tp->asoc->rto_min) + tp->rto = tp->asoc->rto_min; + + /* 6.3.1 C7) A maximum value may be placed on RTO provided it is + * at least RTO.max seconds. + */ + if (tp->rto > tp->asoc->rto_max) + tp->rto = tp->asoc->rto_max; + + tp->rtt = rtt; + + /* Reset rto_pending so that a new RTT measurement is started when a + * new data chunk is sent. + */ + tp->rto_pending = 0; + + SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d " + "rttvar: %d, rto: %d\n", __FUNCTION__, + tp, rtt, tp->srtt, tp->rttvar, tp->rto); +} + +/* This routine updates the transport's cwnd and partial_bytes_acked + * parameters based on the bytes acked in the received SACK. + */ +void sctp_transport_raise_cwnd(sctp_transport_t *transport, __u32 sack_ctsn, + __u32 bytes_acked) +{ + __u32 cwnd, ssthresh, flight_size, pba, pmtu; + + cwnd = transport->cwnd; + flight_size = transport->flight_size; + + /* The appropriate cwnd increase algorithm is performed if, and only + * if the cumulative TSN has advanced and the congestion window is + * being fully utilized. + */ + if ((transport->asoc->ctsn_ack_point >= sack_ctsn) || + (flight_size < cwnd)) + return; + + ssthresh = transport->ssthresh; + pba = transport->partial_bytes_acked; + pmtu = transport->asoc->pmtu; + + if (cwnd <= ssthresh) { + /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less + * than or equal to ssthresh an SCTP endpoint MUST use the + * slow start algorithm to increase cwnd only if the current + * congestion window is being fully utilized and an incoming + * SACK advances the Cumulative TSN Ack Point. Only when these + * two conditions are met can the cwnd be increased otherwise + * the cwnd MUST not be increased. If these conditions are met + * then cwnd MUST be increased by at most the lesser of + * 1) the total size of the previously outstanding DATA chunk(s) + * acknowledged, and 2) the destination's path MTU. + */ + if (bytes_acked > pmtu) + cwnd += pmtu; + else + cwnd += bytes_acked; + SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, " + "bytes_acked: %d, cwnd: %d, ssthresh: %d, " + "flight_size: %d, pba: %d\n", + __FUNCTION__, + transport, bytes_acked, cwnd, + ssthresh, flight_size, pba); + } else { + /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, upon + * each SACK arrival that advances the Cumulative TSN Ack Point, + * increase partial_bytes_acked by the total number of bytes of + * all new chunks acknowledged in that SACK including chunks + * acknowledged by the new Cumulative TSN Ack and by Gap Ack + * Blocks. + * + * When partial_bytes_acked is equal to or greater than cwnd and + * before the arrival of the SACK the sender had cwnd or more + * bytes of data outstanding (i.e., before arrival of the SACK, + * flightsize was greater than or equal to cwnd), increase cwnd + * by MTU, and reset partial_bytes_acked to + * (partial_bytes_acked - cwnd). + */ + pba += bytes_acked; + if (pba >= cwnd) { + cwnd += pmtu; + pba = ((cwnd < pba) ? (pba - cwnd) : 0); + } + SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: " + "transport: %p, bytes_acked: %d, cwnd: %d, " + "ssthresh: %d, flight_size: %d, pba: %d\n", + __FUNCTION__, + transport, bytes_acked, cwnd, + ssthresh, flight_size, pba); + } + + transport->cwnd = cwnd; + transport->partial_bytes_acked = pba; +} + +/* This routine is used to lower the transport's cwnd when congestion is + * detected. + */ +void sctp_transport_lower_cwnd(sctp_transport_t *transport, + sctp_lower_cwnd_t reason) +{ + switch (reason) { + case SCTP_LOWER_CWND_T3_RTX: + /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 + * When the T3-rtx timer expires on an address, SCTP should + * perform slow start by: + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = 1*MTU + * partial_bytes_acked = 0 + */ + transport->ssthresh = max(transport->cwnd/2, + 2*transport->asoc->pmtu); + transport->cwnd = transport->asoc->pmtu; + break; + + case SCTP_LOWER_CWND_FAST_RTX: + /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the + * destination address(es) to which the missing DATA chunks + * 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 + * should do the following: + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = ssthresh + * partial_bytes_acked = 0 + */ + transport->ssthresh = max(transport->cwnd/2, + 2*transport->asoc->pmtu); + transport->cwnd = transport->ssthresh; + break; + + case SCTP_LOWER_CWND_ECNE: + /* RFC 2481 Section 6.1.2. + * If the sender receives an ECN-Echo ACK packet + * then the sender knows that congestion was encountered in the + * network on the path from the sender to the receiver. The + * indication of congestion should be treated just as a + * congestion loss in non-ECN Capable TCP. That is, the TCP + * source halves the congestion window "cwnd" and reduces the + * slow start threshold "ssthresh". + * A critical condition is that TCP does not react to + * congestion indications more than once every window of + * data (or more loosely more than once every round-trip time). + */ + if ((jiffies - transport->last_time_ecne_reduced) > + transport->rtt) { + transport->ssthresh = max(transport->cwnd/2, + 2*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. + * 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; + break; + }; + + transport->partial_bytes_acked = 0; + SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: " + "%d ssthresh: %d\n", __FUNCTION__, + transport, reason, + transport->cwnd, transport->ssthresh); +} diff -Nru a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/tsnmap.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,383 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * These functions manipulate sctp tsn mapping array. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Jon Grimm + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include + +static void _sctp_tsnmap_update(sctp_tsnmap_t *map); +static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map); +static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, + __u16 len, __u16 base, + int *started, __u16 *start, + int *ended, __u16 *end); + +/* Create a new sctp_tsnmap. + * Allocate room to store at least 'len' contiguous TSNs. + */ +sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) +{ + sctp_tsnmap_t *retval; + + retval = kmalloc(sizeof(sctp_tsnmap_t) + + sctp_tsnmap_storage_size(len), + priority); + if (!retval) + goto fail; + + if (!sctp_tsnmap_init(retval, len, initial_tsn)) + goto fail_map; + retval->malloced = 1; + return retval; + +fail_map: + kfree(retval); + +fail: + return NULL; +} + +/* Initialize a block of memory as a tsnmap. */ +sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn) +{ + map->tsn_map = map->raw_map; + map->overflow_map = map->tsn_map + len; + map->len = len; + + /* Clear out a TSN ack status. */ + memset(map->tsn_map, 0x00, map->len + map->len); + + /* Keep track of TSNs represented by tsn_map. */ + map->base_tsn = initial_tsn; + map->overflow_tsn = initial_tsn + map->len; + map->cumulative_tsn_ack_point = initial_tsn - 1; + map->max_tsn_seen = map->cumulative_tsn_ack_point; + map->malloced = 0; + map->pending_data = 0; + + return map; +} + +/* Test the tracking state of this TSN. + * Returns: + * 0 if the TSN has not yet been seen + * >0 if the TSN has been seen (duplicate) + * <0 if the TSN is invalid (too large to track) + */ +int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn) +{ + __s32 gap; + int dup; + + /* Calculate the index into the mapping arrays. */ + gap = tsn - map->base_tsn; + + /* Verify that we can hold this TSN. */ + if (gap >= (/* base */ map->len + /* overflow */ map->len)) { + dup = -1; + goto out; + } + + /* Honk if we've already seen this TSN. + * We have three cases: + * 1. The TSN is ancient or belongs to a previous tsn_map. + * 2. The TSN is already marked in the tsn_map. + * 3. The TSN is already marked in the tsn_map_overflow. + */ + if (gap < 0 || + (gap < map->len && map->tsn_map[gap]) || + (gap >= map->len && map->overflow_map[gap - map->len])) + dup = 1; + else + dup = 0; + +out: + return dup; +} + +/* Is there a gap in the TSN map? */ +int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map) +{ + int has_gap; + + has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen); + return has_gap; +} + +/* Mark this TSN as seen. */ +void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn) +{ + __s32 gap; + + /* Vacuously mark any TSN which precedes the map base or + * exceeds the end of the map. + */ + if (TSN_lt(tsn, map->base_tsn)) + return; + if (!TSN_lt(tsn, map->base_tsn + map->len + map->len)) + return; + + /* Bump the max. */ + if (TSN_lt(map->max_tsn_seen, tsn)) + map->max_tsn_seen = tsn; + + /* Assert: TSN is in range. */ + gap = tsn - map->base_tsn; + + /* Mark the TSN as received. */ + if (gap < map->len) + map->tsn_map[gap]++; + else + map->overflow_map[gap - map->len]++; + + /* Go fixup any internal TSN mapping variables including + * cumulative_tsn_ack_point. + */ + _sctp_tsnmap_update(map); +} + +/* Retrieve the Cumulative TSN Ack Point. */ +__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map) +{ + return map->cumulative_tsn_ack_point; +} + +/* Retrieve the highest TSN we've seen. */ +__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map) +{ + return map->max_tsn_seen; +} + +/* Dispose of a tsnmap. */ +void sctp_tsnmap_free(sctp_tsnmap_t *map) +{ + if (map->malloced) + kfree(map); +} + +/* Initialize a Gap Ack Block iterator from memory being provided. */ +void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter) +{ + /* Only start looking one past the Cumulative TSN Ack Point. */ + iter->start = map->cumulative_tsn_ack_point + 1; +} + +/* Get the next Gap Ack Blocks. Returns 0 if there was not + * another block to get. + */ +int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + __u16 *start, __u16 *end) +{ + int started, ended; + __u16 _start, _end, offset; + + /* We haven't found a gap yet. */ + started = ended = 0; + + /* Search the first mapping array. */ + if (iter->start - map->base_tsn < map->len) { + offset = iter->start - map->base_tsn; + _sctp_tsnmap_find_gap_ack(map->tsn_map, + offset, + map->len, 0, + &started, &_start, + &ended, &_end); + } + + /* Do we need to check the overflow map? */ + if (!ended) { + /* Fix up where we'd like to start searching in the + * overflow map. + */ + if (iter->start - map->base_tsn < map->len) + offset = 0; + else + offset = iter->start - map->base_tsn - map->len; + + /* Search the overflow map. */ + _sctp_tsnmap_find_gap_ack(map->overflow_map, + offset, + map->len, + map->len, + &started, &_start, + &ended, &_end); + } + + /* The Gap Ack Block happens to end at the end of the + * overflow map. + */ + if (started & !ended) { + ended++; + _end = map->len + map->len - 1; + } + + /* If we found a Gap Ack Block, return the start and end and + * bump the iterator forward. + */ + if (ended) { + /* Fix up the start and end based on the + * Cumulative TSN Ack offset into the map. + */ + int gap = map->cumulative_tsn_ack_point - + map->base_tsn; + + *start = _start - gap; + *end = _end - gap; + + /* Move the iterator forward. */ + iter->start = map->cumulative_tsn_ack_point + *end + 1; + } + + return ended; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* This private helper function updates the tsnmap buffers and + * the Cumulative TSN Ack Point. + */ +static void _sctp_tsnmap_update(sctp_tsnmap_t *map) +{ + __u32 ctsn; + + ctsn = map->cumulative_tsn_ack_point; + do { + ctsn++; + if (ctsn == map->overflow_tsn) { + /* Now tsn_map must have been all '1's, + * so we swap the map and check the overflow table + */ + __u8 *tmp = map->tsn_map; + memset(tmp, 0, map->len); + map->tsn_map = map->overflow_map; + map->overflow_map = tmp; + + /* Update the tsn_map boundaries. */ + map->base_tsn += map->len; + map->overflow_tsn += map->len; + } + } while (map->tsn_map[ctsn - map->base_tsn]); + + map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ + _sctp_tsnmap_update_pending_data(map); +} + +static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) +{ + __u32 cum_tsn = map->cumulative_tsn_ack_point; + __u32 max_tsn = map->max_tsn_seen; + __u32 base_tsn = map->base_tsn; + __u16 pending_data; + __s32 gap, start, end, i; + + pending_data = max_tsn - cum_tsn; + gap = max_tsn - base_tsn; + + if (gap <= 0 || gap >= (map->len + map->len)) + goto out; + + start = ((cum_tsn >= base_tsn) ? (cum_tsn - base_tsn + 1) : 0); + end = ((gap > map->len ) ? map->len : gap + 1); + + for (i = start; i < end; i++) { + if (map->tsn_map[i]) + pending_data--; + } + + if (gap >= map->len) { + start = 0; + end = gap - map->len + 1; + for (i = start; i < end; i++) { + if (map->overflow_map[i]) + pending_data--; + } + } + +out: + map->pending_data = pending_data; +} + +/* This is a private helper for finding Gap Ack Blocks. It searches a + * single array for the start and end of a Gap Ack Block. + * + * The flags "started" and "ended" tell is if we found the beginning + * or (respectively) the end of a Gap Ack Block. + */ +static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, + __u16 len, __u16 base, + int *started, __u16 *start, + int *ended, __u16 *end) +{ + int i = off; + + /* Let's look through the entire array, but break out + * early if we have found the end of the Gap Ack Block. + */ + + /* Look for the start. */ + if (!(*started)) { + for (; i < len; i++) { + if (map[i]) { + (*started)++; + *start = base + i; + break; + } + } + } + + /* Look for the end. */ + if (*started) { + /* We have found the start, let's find the + * end. If we find the end, break out. + */ + for (; i < len; i++) { + if (!map[i]) { + (*ended)++; + *end = base + i - 1; + break; + } + } + } +} diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/ulpevent.c Sat Aug 31 15:06:06 2002 @@ -0,0 +1,840 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * These functions manipulate an sctp event. The sctp_ulpevent_t is used + * to carry notifications and data to the ULP (sockets). + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include + +static void sctp_rcvmsg_rfree(struct sk_buff *skb); +static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, + sctp_association_t *asoc); + +/* Create a new sctp_ulpevent. */ +sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority) +{ + sctp_ulpevent_t *event; + struct sk_buff *skb; + + skb = alloc_skb(size, priority); + if (!skb) + goto fail; + + event = (sctp_ulpevent_t *) skb->cb; + event = sctp_ulpevent_init(event, skb, msg_flags); + if (!event) + goto fail_init; + + event->malloced = 1; + return event; + +fail_init: + kfree_skb(event->parent); + +fail: + return NULL; +} + +/* Initialize an ULP event from an given skb. */ +sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, + struct sk_buff *parent, + int msg_flags) +{ + memset(event, sizeof(sctp_ulpevent_t), 0x00); + event->msg_flags = msg_flags; + event->parent = parent; + event->malloced = 0; + return event; +} + +/* Dispose of an event. */ +void sctp_ulpevent_free(sctp_ulpevent_t *event) +{ + if (event->malloced) + kfree_skb(event->parent); +} + +/* Is this a MSG_NOTIFICATION? */ +int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) +{ + return event->msg_flags & MSG_NOTIFICATION; +} + +/* Create and initialize an SCTP_ASSOC_CHANGE event. + * + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notification. + * + * Note: There is no field checking here. If a field is unused it will be + * zero'd out. + */ +sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, + __u16 flags, + __u16 state, + __u16 error, + __u16 outbound, + __u16 inbound, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_assoc_change *sac; + + event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + MSG_NOTIFICATION, + priority); + if (!event) + goto fail; + + sac = (struct sctp_assoc_change *) + skb_put(event->parent, + sizeof(struct sctp_assoc_change)); + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_type: + * It should be SCTP_ASSOC_CHANGE. + */ + sac->sac_type = SCTP_ASSOC_CHANGE; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_state: 32 bits (signed integer) + * This field holds one of a number of values that communicate the + * event that happened to the association. + */ + sac->sac_state = state; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_flags: 16 bits (unsigned integer) + * Currently unused. + */ + sac->sac_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_length: sizeof (__u32) + * This field is the total length of the notification data, including + * the notification header. + */ + sac->sac_length = sizeof(struct sctp_assoc_change); + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_error: 32 bits (signed integer) + * + * If the state was reached due to a error condition (e.g. + * COMMUNICATION_LOST) any relevant error information is available in + * this field. This corresponds to the protocol error codes defined in + * [SCTP]. + */ + sac->sac_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_outbound_streams: 16 bits (unsigned integer) + * sac_inbound_streams: 16 bits (unsigned integer) + * + * The maximum number of streams allowed in each direction are + * available in sac_outbound_streams and sac_inbound streams. + */ + sac->sac_outbound_streams = outbound; + sac->sac_inbound_streams = inbound; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_assoc_id: sizeof (sctp_assoc_t) + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + sac->sac_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail: + return NULL; +} + +/* Create and initialize an SCTP_PEER_ADDR_CHANGE event. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. + */ +sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( + const sctp_association_t *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_paddr_change *spc; + + event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), + MSG_NOTIFICATION, + priority); + if (!event) + goto fail; + + spc = (struct sctp_paddr_change *) + skb_put(event->parent, + sizeof(struct sctp_paddr_change)); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_type: + * + * It should be SCTP_PEER_ADDR_CHANGE. + */ + spc->spc_type = SCTP_PEER_ADDR_CHANGE; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_length: sizeof (__u32) + * + * This field is the total length of the notification data, including + * the notification header. + */ + spc->spc_length = sizeof(struct sctp_paddr_change); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_flags: 16 bits (unsigned integer) + * Currently unused. + */ + spc->spc_flags = 0; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. + */ + spc->spc_state = state; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_error: 32 bits (signed integer) + * + * If the state was reached due to any error condition (e.g. + * ADDRESS_UNREACHABLE) any relevant error information is available in + * this field. + */ + spc->spc_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_assoc_id: sizeof (sctp_assoc_t) + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + spc->spc_assoc_id = sctp_assoc2id(asoc); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_aaddr: sizeof (struct sockaddr_storage) + * + * The affected address field, holds the remote peer's address that is + * encountering the change of state. + */ + memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); + + return event; + +fail: + return NULL; +} + +/* Create and initialize an SCTP_REMOTE_ERROR notification. + * + * Note: This assumes that the chunk->skb->data already points to the + * operation error payload. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. + */ +sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + __u16 flags, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_remote_error *sre; + struct sk_buff *skb; + sctp_errhdr_t *ch; + __u16 cause; + int elen; + + ch = (sctp_errhdr_t *)(chunk->skb->data); + cause = ch->cause; + elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); + + /* Pull off the ERROR header. */ + skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); + + /* Copy the skb to a new skb with room for us to prepend + * notification with. + */ + skb = skb_copy_expand(chunk->skb, + sizeof(struct sctp_remote_error), /* headroom */ + 0, /* tailroom */ + priority); + + /* Pull off the rest of the cause TLV from the chunk. */ + skb_pull(chunk->skb, elen); + if (!skb) + goto fail; + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; + event = sctp_ulpevent_init(event, + skb, + MSG_NOTIFICATION); + if (!event) + goto fail; + + event->malloced = 1; + sre = (struct sctp_remote_error *) + skb_push(skb, sizeof(struct sctp_remote_error)); + + /* Trim the buffer to the right length. */ + skb_trim(skb, sizeof(struct sctp_remote_error) + elen); + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_type: + * It should be SCTP_REMOTE_ERROR. + */ + sre->sre_type = SCTP_REMOTE_ERROR; + + /* + * Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_flags: 16 bits (unsigned integer) + * Currently unused. + */ + sre->sre_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_length: sizeof (__u32) + * + * This field is the total length of the notification data, + * including the notification header. + */ + sre->sre_length = skb->len; + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_error: 16 bits (unsigned integer) + * This value represents one of the Operational Error causes defined in + * the SCTP specification, in network byte order. + */ + sre->sre_error = cause; + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_assoc_id: sizeof (sctp_assoc_t) + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + sre->sre_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail: + return NULL; +} + +/* Create and initialize a SCTP_SEND_FAILED notification. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.4 SCTP_SEND_FAILED + */ +sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + __u16 flags, + __u32 error, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_send_failed *ssf; + struct sk_buff *skb; + + /* Make skb with more room so we can prepend notification. */ + skb = skb_copy_expand(chunk->skb, + sizeof(struct sctp_send_failed), /* headroom */ + 0, /* tailroom */ + priority); + if (!skb) + goto fail; + + /* Pull off the common chunk header and DATA header. */ + skb_pull(skb, sizeof(sctp_data_chunk_t)); + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; + event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); + if (!event) + goto fail; + + /* Mark as malloced, even though the constructor was not + * called. + */ + event->malloced = 1; + + ssf = (struct sctp_send_failed *) + skb_push(skb, sizeof(struct sctp_send_failed)); + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_type: + * It should be SCTP_SEND_FAILED. + */ + ssf->ssf_type = SCTP_SEND_FAILED; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_flags: 16 bits (unsigned integer) + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ + ssf->ssf_flags = flags; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_length: sizeof (__u32) + * This field is the total length of the notification data, including + * the notification header. + */ + ssf->ssf_length = skb->len; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_error: 16 bits (unsigned integer) + * This value represents the reason why the send failed, and if set, + * will be a SCTP protocol error code as defined in [SCTP] section + * 3.3.10. + */ + ssf->ssf_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_info: sizeof (struct sctp_sndrcvinfo) + * The original send information associated with the undelivered + * message. + */ + memcpy(&ssf->ssf_info, + &chunk->sinfo, + sizeof(struct sctp_sndrcvinfo)); + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_assoc_id: sizeof (sctp_assoc_t) + * The association id field, sf_assoc_id, holds the identifier for the + * association. All notifications for a given association have the + * same association identifier. For TCP style socket, this field is + * ignored. + */ + ssf->ssf_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail: + return NULL; +} + +/* Create and initialize a SCTP_SHUTDOWN_EVENT notification. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + */ +sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, + __u16 flags, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_shutdown_event *sse; + + event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + MSG_NOTIFICATION, + priority); + if (!event) + goto fail; + + sse = (struct sctp_shutdown_event *) + skb_put(event->parent, + sizeof(struct sctp_shutdown_event)); + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_type + * It should be SCTP_SHUTDOWN_EVENT + */ + sse->sse_type = SCTP_SHUTDOWN_EVENT; + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_flags: 16 bits (unsigned integer) + * Currently unused. + */ + sse->sse_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_length: sizeof (__u32) + * This field is the total length of the notification data, including + * the notification header. + */ + sse->sse_length = sizeof(struct sctp_shutdown_event); + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_assoc_id: sizeof (sctp_assoc_t) + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + sse->sse_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. + * + * Socket Extensions for SCTP - draft-01 + * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + */ +sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, + sctp_chunk_t *chunk, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_sndrcvinfo *info; + struct sk_buff *skb; + size_t padding, len; + + /* Clone the original skb, sharing the data. */ + skb = skb_clone(chunk->skb, priority); + if (!skb) + goto fail; + + /* First calculate the padding, so we don't inadvertently + * pass up the wrong length to the user. + * + * RFC 2960 - Section 3.2 Chunk Field Descriptions + * + * The total length of a chunk(including Type, Length and Value fields) + * MUST be a multiple of 4 bytes. If the length of the chunk is not a + * multiple of 4 bytes, the sender MUST pad the chunk with all zero + * bytes and this padding is not included in the chunk length field. + * The sender should never pad with more than 3 bytes. The receiver + * MUST ignore the padding bytes. + */ + len = ntohs(chunk->chunk_hdr->length); + padding = WORD_ROUND(len) - len; + + /* Fixup cloned skb with just this chunks data. */ + skb_trim(skb, chunk->chunk_end - padding - skb->data); + + /* Set up a destructor to do rwnd accounting. */ + sctp_ulpevent_set_owner_r(skb, asoc); + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; + + /* Initialize event with flags 0. */ + event = sctp_ulpevent_init(event, skb, 0); + if (!event) + goto fail_init; + + event->malloced = 1; + + info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_stream: 16 bits (unsigned integer) + * + * For recvmsg() the SCTP stack places the message's stream number in + * this value. + */ + info->sinfo_stream = ntohs(chunk->subh.data_hdr->stream); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_ssn: 16 bits (unsigned integer) + * + * For recvmsg() this value contains the stream sequence number that + * the remote endpoint placed in the DATA chunk. For fragmented + * messages this is the same number for all deliveries of the message + * (if more than one recvmsg() is needed to read the message). + */ + info->sinfo_ssn = ntohs(chunk->subh.data_hdr->ssn); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_ppid: 32 bits (unsigned integer) + * + * In recvmsg() this value is + * the same information that was passed by the upper layer in the peer + * application. Please note that byte order issues are NOT accounted + * for and this information is passed opaquely by the SCTP stack from + * one end to the other. + */ + info->sinfo_ppid = ntohl(chunk->subh.data_hdr->ppid); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + * + * recvmsg() flags: + * + * MSG_UNORDERED - This flag is present when the message was sent + * non-ordered. + */ + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + info->sinfo_flags |= MSG_UNORDERED; + + /* FIXME: For reassembly, we need to have the fragmentation bits. + * This really does not belong in the event structure, but + * its difficult to fix everything at the same time. Eventually, + * we should create and skb based chunk structure. This structure + * storage can be converted to an event. --jgrimm + */ + event->chunk_flags = chunk->chunk_hdr->flags; + + /* With -04 draft, tsn moves into sndrcvinfo. */ + info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn); + + /* Context is not used on receive. */ + info->sinfo_context = 0; + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_assoc_id: sizeof (sctp_assoc_t) + * + * The association handle field, sinfo_assoc_id, holds the identifier + * for the association announced in the COMMUNICATION_UP notification. + * All notifications for a given association have the same identifier. + * Ignored for TCP-style sockets. + */ + info->sinfo_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail_init: + kfree_skb(skb); + +fail: + return NULL; +} + +/* Return the notification type, assuming this is a notification + * event. + */ +__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) +{ + union sctp_notification *notification; + + notification = (union sctp_notification *) event->parent->data; + return notification->h.sn_type; +} + +/* Copy out the sndrcvinfo into a msghdr. */ +void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr) +{ + if (!sctp_ulpevent_is_notification(event)) { + put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, + sizeof(struct sctp_sndrcvinfo), + (void *) &event->sndrcvinfo); + } +} + +/* Do accounting for bytes just read by user. */ +static void sctp_rcvmsg_rfree(struct sk_buff *skb) +{ + sctp_association_t *asoc; + sctp_ulpevent_t *event; + + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * Use the local private area of the skb to track the owning + * association. + */ + event = (sctp_ulpevent_t *) skb->cb; + asoc = event->asoc; + if (asoc->rwnd_over) { + if (asoc->rwnd_over >= skb->len) { + asoc->rwnd_over -= skb->len; + } else { + asoc->rwnd += (skb->len - asoc->rwnd_over); + asoc->rwnd_over = 0; + } + } else { + asoc->rwnd += skb->len; + } + + SCTP_DEBUG_PRINTK("rwnd increased by %d to (%u, %u)\n", + skb->len, asoc->rwnd, asoc->rwnd_over); + + sctp_association_put(asoc); +} + +/* Charge receive window for bytes recieved. */ +static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + /* The current stack structures assume that the rcv buffer is + * per socket. For UDP-style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * We use the local private area of the skb to track the owning + * association. + */ + sctp_association_hold(asoc); + skb->sk = asoc->base.sk; + event = (sctp_ulpevent_t *) skb->cb; + event->asoc = asoc; + + skb->destructor = sctp_rcvmsg_rfree; + + SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); + SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); + if (asoc->rwnd >= skb->len) { + asoc->rwnd -= skb->len; + } else { + asoc->rwnd_over = skb->len - asoc->rwnd; + asoc->rwnd = 0; + } + + SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n", + skb->len, asoc->rwnd, asoc->rwnd_over); +} + + + + + + + + + + + + + + + + diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/ulpqueue.c Sat Aug 31 15:06:07 2002 @@ -0,0 +1,476 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2002 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This abstraction carries sctp events to the ULP (sockets). + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static inline sctp_ulpevent_t * sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event); +static inline sctp_ulpevent_t *sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event); + +/* 1st Level Abstractions */ + +/* Create a new ULP queue. */ +sctp_ulpqueue_t *sctp_ulpqueue_new(sctp_association_t *asoc, + __u16 inbound, int priority) +{ + sctp_ulpqueue_t *ulpq; + size_t size; + + /* Today, there is only a fixed size of storage needed for + * stream support, but make the interfaces acceptable for + * the future. + */ + size = sizeof(sctp_ulpqueue_t)+sctp_ulpqueue_storage_size(inbound); + ulpq = kmalloc(size, priority); + if (!ulpq) + goto fail; + if (!sctp_ulpqueue_init(ulpq, asoc, inbound)) + goto fail_init; + ulpq->malloced = 1; + return ulpq; + +fail_init: + kfree(ulpq); + +fail: + return NULL; +} + +/* Initialize a ULP queue from a block of memory. */ +sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, + sctp_association_t *asoc, + __u16 inbound) +{ + memset(ulpq, + sizeof(sctp_ulpqueue_t) + sctp_ulpqueue_storage_size(inbound), + 0x00); + + ulpq->asoc = asoc; + spin_lock_init(&ulpq->lock); + skb_queue_head_init(&ulpq->reasm); + skb_queue_head_init(&ulpq->lobby); + ulpq->malloced = 0; + + return ulpq; +} + +/* Flush the reassembly and ordering queues. */ +void sctp_ulpqueue_flush(sctp_ulpqueue_t *ulpq) +{ + struct sk_buff *skb; + sctp_ulpevent_t *event; + + while ((skb = skb_dequeue(&ulpq->lobby))) { + event = (sctp_ulpevent_t *) skb->cb; + sctp_ulpevent_free(event); + } + + while ((skb = skb_dequeue(&ulpq->reasm))) { + event = (sctp_ulpevent_t *) skb->cb; + sctp_ulpevent_free(event); + } +} + +/* Dispose of a ulpqueue. */ +void sctp_ulpqueue_free(sctp_ulpqueue_t *ulpq) +{ + sctp_ulpqueue_flush(ulpq); + if (ulpq->malloced) + kfree(ulpq); +} + +/* Process an incoming DATA chunk. */ +int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk, + int priority) +{ + struct sk_buff_head temp; + sctp_data_chunk_t *hdr; + sctp_ulpevent_t *event; + + hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; + + /* FIXME: Instead of event being the skb clone, we really should + * have a new skb based chunk structure that we can convert to + * an event. Temporarily, I'm carrying a few chunk fields in + * the event to allow reassembly. Its too painful to change + * everything at once. --jgrimm + */ + event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); + if (!event) + return -ENOMEM; + + /* Do reassembly if needed. */ + event = sctp_ulpqueue_reasm(ulpq, event); + + /* Do ordering if needed. */ + if (event) { + /* Create a temporary list to collect chunks on. */ + skb_queue_head_init(&temp); + skb_queue_tail(&temp, event->parent); + + event = sctp_ulpqueue_order(ulpq, event); + } + + /* Send event to the ULP. */ + if (event) + sctp_ulpqueue_tail_event(ulpq, event); + + return 0; +} + +/* Add a new event for propogation to the ULP. */ +int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + struct sock *sk = ulpq->asoc->base.sk; + + /* If the socket is just going to throw this away, do not + * even try to deliver it. + */ + if (sk->dead || (sk->shutdown & RCV_SHUTDOWN)) + goto out_free; + + /* Check if the user wishes to receive this event. */ + if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) + goto out_free; + + /* If we are harvesting multiple skbs they will be + * collected on a list. + */ + if (event->parent->list) + sctp_skb_list_tail(event->parent->list, &sk->receive_queue); + else + skb_queue_tail(&sk->receive_queue, event->parent); + + wake_up_interruptible(sk->sleep); + return 1; + +out_free: + if (event->parent->list) + skb_queue_purge(event->parent->list); + else + kfree_skb(event->parent); + return 0; +} + +/* 2nd Level Abstractions */ + +/* Helper function to store chunks that need to be reassembled. */ +static inline void sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + __u32 tsn, ctsn; + unsigned long flags __attribute ((unused)); + + tsn = event->sndrcvinfo.sinfo_tsn; + + sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); + + /* Find the right place in this list. We store them by TSN. */ + sctp_skb_for_each(pos, &ulpq->reasm, tmp) { + cevent = (sctp_ulpevent_t *)pos->cb; + ctsn = cevent->sndrcvinfo.sinfo_tsn; + + if (TSN_lt(tsn, ctsn)) + break; + } + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->reasm)) + __skb_insert(event->parent, pos->prev, pos, &ulpq->reasm); + else + __skb_queue_tail(&ulpq->reasm, event->parent); + + sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); +} + +/* Helper function to return an event corresponding to the reassembled + * datagram. + */ +static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) +{ + struct sk_buff *pos; + sctp_ulpevent_t *event; + struct sk_buff *pnext; + + pos = f_frag->next; + + /* Set the first fragment's frag_list to point to the 2nd fragment. */ + skb_shinfo(f_frag)->frag_list = pos; + + /* Remove the first fragment from the reassembly queue. */ + __skb_unlink(f_frag, f_frag->list); + do { + pnext = pos->next; + + /* Remove the fragment from the reassembly queue. */ + __skb_unlink(pos, pos->list); + + /* Break if we have reached the last fragment. */ + if (pos == l_frag) + break; + + pos->next = pnext; + pos = pnext; + } while (1); + + event = (sctp_ulpevent_t *) f_frag->cb; + + return event; +} + +/* Helper function to check if an incoming chunk has filled up the last + * missing fragment in a SCTP datagram and return the corresponding event. + */ +static inline sctp_ulpevent_t *sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_t *ulpq) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + struct sk_buff *first_frag = NULL; + __u32 ctsn, next_tsn; + unsigned long flags __attribute ((unused)); + sctp_ulpevent_t *retval = NULL; + + /* Initialized to 0 just to avoid compiler warning message. Will + * never be used with this value. It is referenced only after it + * is set when we find the first fragment of a message. + */ + next_tsn = 0; + + sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); + + /* The chunks are held in the reasm queue sorted by TSN. + * Walk through the queue sequentially and look for a sequence of + * fragmented chunks that complete a datagram. + * 'first_frag' and next_tsn are reset when we find a chunk which + * is the first fragment of a datagram. Once these 2 fields are set + * we expect to find the remaining middle fragments and the last + * fragment in order. If not, first_frag is reset to NULL and we + * start the next pass when we find another first fragment. + */ + sctp_skb_for_each(pos, &ulpq->reasm, tmp) { + cevent = (sctp_ulpevent_t *) pos->cb; + ctsn = cevent->sndrcvinfo.sinfo_tsn; + + switch (cevent->chunk_flags & SCTP_DATA_FRAG_MASK) { + case SCTP_DATA_FIRST_FRAG: + first_frag = pos; + next_tsn = ctsn + 1; + break; + + case SCTP_DATA_MIDDLE_FRAG: + if ((first_frag) && (ctsn == next_tsn)) + next_tsn++; + else + first_frag = NULL; + break; + + case SCTP_DATA_LAST_FRAG: + if ((first_frag) && (ctsn == next_tsn)) + retval = sctp_make_reassembled_event( + first_frag, pos); + else + first_frag = NULL; + break; + }; + + /* We have the reassembled event. There is no need to look + * further. + */ + if (retval) + break; + } + sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); + + return retval; +} + +/* Helper function to reassemble chunks. Hold chunks on the reasm queue that + * need reassembling. + */ +static inline sctp_ulpevent_t *sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + sctp_ulpevent_t *retval = NULL; + + /* FIXME: We should be using some new chunk structure here + * instead of carrying chunk fields in the event structure. + * This is temporary as it is too painful to change everything + * at once. + */ + + /* Check if this is part of a fragmented message. */ + if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) + return event; + + sctp_ulpqueue_store_reasm(ulpq, event); + retval = sctp_ulpqueue_retrieve_reassembled(ulpq); + + return retval; +} + +/* Helper function to gather skbs that have possibly become + * ordered by an an incoming chunk. + */ +static inline void sctp_ulpqueue_retrieve_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + __u16 sid, csid; + __u16 ssn, cssn; + unsigned long flags __attribute ((unused)); + + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + /* We are holding the chunks by stream, by SSN. */ + sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); + sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + cevent = (sctp_ulpevent_t *) pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + + /* Have we gone too far? */ + if (csid > sid) + break; + + /* Have we not gone far enough? */ + if (csid < sid) + continue; + + if (cssn != ulpq->ssn[sid]) + break; + + ulpq->ssn[sid]++; + __skb_unlink(pos, pos->list); + + /* Attach all gathered skbs to the event. */ + __skb_queue_tail(event->parent->list, pos); + } + sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); +} + +/* Helper function to store chunks needing ordering. */ +static inline void sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + __u16 sid, csid; + __u16 ssn, cssn; + unsigned long flags __attribute ((unused)); + + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); + + /* Find the right place in this list. We store them by + * stream ID and then by SSN. + */ + sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + cevent = (sctp_ulpevent_t *) pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + + if (csid > sid) + break; + if (csid == sid && SSN_lt(ssn, cssn)) + break; + } + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->lobby)) + __skb_insert(event->parent, pos->prev, pos, &ulpq->lobby); + else + __skb_queue_tail(&ulpq->lobby, event->parent); + + sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); +} + +static inline sctp_ulpevent_t *sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + __u16 sid, ssn; + + /* FIXME: We should be using some new chunk structure here + * instead of carrying chunk fields in the event structure. + * This is temporary as it is too painful to change everything + * at once. + */ + + /* Check if this message needs ordering. */ + if (SCTP_DATA_UNORDERED & event->chunk_flags) + return event; + + /* Note: The stream ID must be verified before this routine. */ + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + /* Is this the expected SSN for this stream ID? */ + if (ssn != ulpq->ssn[sid]) { + /* We've received something out of order, so find where it + * needs to be placed. We order by stream and then by SSN. + */ + sctp_ulpqueue_store_ordered(ulpq, event); + return NULL; + } + + /* Mark that the next chunk has been found. */ + ulpq->ssn[sid]++; + + /* Go find any other chunks that were waiting for + * ordering. + */ + sctp_ulpqueue_retrieve_ordered(ulpq, event); + + return event; +} diff -Nru a/net/socket.c b/net/socket.c --- a/net/socket.c Sat Aug 31 15:05:59 2002 +++ b/net/socket.c Sat Aug 31 15:05:59 2002 @@ -355,7 +355,7 @@ * but we take care of internal coherence yet. */ -static int sock_map_fd(struct socket *sock) +int sock_map_fd(struct socket *sock) { int fd; struct qstr this; diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c --- a/net/sunrpc/sched.c Sat Aug 31 15:06:00 2002 +++ b/net/sunrpc/sched.c Sat Aug 31 15:06:00 2002 @@ -1030,6 +1030,7 @@ wake_up(assassin); dprintk("RPC: rpciod exiting\n"); + unlock_kernel(); MOD_DEC_USE_COUNT; return 0; } diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c --- a/net/sunrpc/svcsock.c Sat Aug 31 15:05:54 2002 +++ b/net/sunrpc/svcsock.c Sat Aug 31 15:05:54 2002 @@ -703,11 +703,10 @@ * tell us anything. For now just warn about unpriv connections. */ if (ntohs(sin.sin_port) >= 1024) { - if (net_ratelimit()) - printk(KERN_WARNING - "%s: connect from unprivileged port: %u.%u.%u.%u:%d\n", - serv->sv_name, - NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + dprintk(KERN_WARNING + "%s: connect from unprivileged port: %u.%u.%u.%u:%d\n", + serv->sv_name, + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); } dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name, @@ -1286,7 +1285,7 @@ kfree(svsk); } else { spin_unlock_bh(&serv->sv_lock); - printk(KERN_NOTICE "svc: server socket destroy delayed\n"); + dprintk(KERN_NOTICE "svc: server socket destroy delayed\n"); /* svsk->sk_server = NULL; */ } } diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Sat Aug 31 15:05:54 2002 +++ b/net/sunrpc/xprt.c Sat Aug 31 15:05:54 2002 @@ -147,7 +147,7 @@ dprintk("RPC: %4d TCP write queue full\n", task->tk_pid); task->tk_timeout = 0; task->tk_status = -EAGAIN; - if (task->tk_rqstp->rq_nresend) + if (task->tk_rqstp && task->tk_rqstp->rq_nresend) rpc_sleep_on(&xprt->resend, task, NULL, NULL); else rpc_sleep_on(&xprt->sending, task, NULL, NULL); @@ -952,8 +952,10 @@ } /* - * The following 2 routines allow a task to sleep while socket memory is - * low. + * Called when more output buffer space is available for this socket. + * We try not to wake our writers until they can make "significant" + * progress, otherwise we'll waste resources thrashing sock_sendmsg + * with a bunch of small requests. */ static void xprt_write_space(struct sock *sk) @@ -967,8 +969,15 @@ return; /* Wait until we have enough socket memory */ - if (!sock_writeable(sk)) - return; + if (xprt->stream) { + /* from net/ipv4/tcp.c:tcp_write_space */ + if (tcp_wspace(sk) < tcp_min_write_space(sk)) + return; + } else { + /* from net/core/sock.c:sock_def_write_space */ + if (!sock_writeable(sk)) + return; + } if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) return; diff -Nru a/security/security.c b/security/security.c --- a/security/security.c Sat Aug 31 15:05:54 2002 +++ b/security/security.c Sat Aug 31 15:05:54 2002 @@ -52,7 +52,7 @@ /* verify the security_operations structure exists */ if (!ops) { printk (KERN_INFO "Passed a NULL security_operations " - "pointer, " __FUNCTION__ " failed.\n"); + "pointer, %s failed.\n", __FUNCTION__); return -EINVAL; } @@ -69,8 +69,8 @@ if (err) { printk (KERN_INFO "Not enough functions specified in the " - "security_operation structure, " __FUNCTION__ - " failed.\n"); + "security_operation structure, %s failed.\n", + __FUNCTION__); return -EINVAL; } return 0; @@ -108,13 +108,13 @@ { if (verify (ops)) { - printk (KERN_INFO __FUNCTION__ " could not verify " - "security_operations structure.\n"); + printk (KERN_INFO "%s could not verify " + "security_operations structure.\n", __FUNCTION__); return -EINVAL; } if (security_ops != &dummy_security_ops) { printk (KERN_INFO "There is already a security " - "framework initialized, " __FUNCTION__ " failed.\n"); + "framework initialized, %s failed.\n", __FUNCTION__); return -EINVAL; } @@ -137,9 +137,9 @@ int unregister_security (struct security_operations *ops) { if (ops != security_ops) { - printk (KERN_INFO __FUNCTION__ ": trying to unregister " + printk (KERN_INFO "%s: trying to unregister " "a security_opts structure that is not " - "registered, failing.\n"); + "registered, failing.\n", __FUNCTION__); return -EINVAL; } @@ -163,14 +163,14 @@ int mod_reg_security (const char *name, struct security_operations *ops) { if (verify (ops)) { - printk (KERN_INFO __FUNCTION__ " could not verify " - "security operations.\n"); + printk (KERN_INFO "%s could not verify " + "security operations.\n", __FUNCTION__); return -EINVAL; } if (ops == security_ops) { - printk (KERN_INFO __FUNCTION__ " security operations " - "already registered.\n"); + printk (KERN_INFO "%s security operations " + "already registered.\n", __FUNCTION__); return -EINVAL; } @@ -193,8 +193,8 @@ int mod_unreg_security (const char *name, struct security_operations *ops) { if (ops == security_ops) { - printk (KERN_INFO __FUNCTION__ " invalid attempt to unregister " - " primary security ops.\n"); + printk (KERN_INFO "%s invalid attempt to unregister " + " primary security ops.\n", __FUNCTION__); return -EINVAL; } diff -Nru a/sound/oss/ad1816.c b/sound/oss/ad1816.c --- a/sound/oss/ad1816.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/ad1816.c Sat Aug 31 15:06:06 2002 @@ -37,7 +37,7 @@ #include #include #include - +#include #include "sound_config.h" #define DEBUGNOISE(x) @@ -77,7 +77,7 @@ in ad1816_info */ int irq_ok; int *osp; - + spinlock_t lock; } ad1816_info; static int nr_ad1816_devs; @@ -109,12 +109,11 @@ CHECK_FOR_POWER; - save_flags (flags); /* make register access atomic */ - cli (); + spin_lock_irqsave(&devc->lock,flags); /* make register access atomic */ outb ((unsigned char) (reg & 0x3f), devc->base+0); result = inb(devc->base+2); result+= inb(devc->base+3)<<8; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); return (result); } @@ -126,12 +125,11 @@ CHECK_FOR_POWER; - save_flags (flags); /* make register access atomic */ - cli (); + spin_lock_irqsave(&devc->lock,flags); /* make register access atomic */ outb ((unsigned char) (reg & 0xff), devc->base+0); outb ((unsigned char) (data & 0xff),devc->base+2); outb ((unsigned char) ((data>>8)&0xff),devc->base+3); - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } @@ -147,8 +145,7 @@ DEBUGINFO (printk("ad1816: halt_input called\n")); - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); if(!isa_dma_bridge_buggy) { disable_dma(audio_devs[dev]->dmap_in->dma); @@ -168,7 +165,7 @@ outb (~0x40, devc->base+1); devc->audio_mode &= ~PCM_ENABLE_INPUT; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1816_halt_output (int dev) @@ -180,8 +177,7 @@ DEBUGINFO (printk("ad1816: halt_output called!\n")); - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); /* Mute pcm output */ ad_write(devc, 4, ad_read(devc,4)|0x8080); @@ -203,7 +199,7 @@ outb ((unsigned char)~0x80, devc->base+1); devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1816_output_block (int dev, unsigned long buf, @@ -217,14 +213,13 @@ cnt = count/4 - 1; - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); /* set transfer count */ ad_write (devc, 8, cnt & 0xffff); devc->audio_mode |= PCM_ENABLE_OUTPUT; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } @@ -239,14 +234,13 @@ cnt = count/4 - 1; - save_flags (flags); /* make register access atomic */ - cli (); + spin_lock_irqsave(&devc->lock,flags); /* set transfer count */ ad_write (devc, 10, cnt & 0xffff); devc->audio_mode |= PCM_ENABLE_INPUT; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } static int ad1816_prepare_for_input (int dev, int bsize, int bcount) @@ -258,8 +252,7 @@ DEBUGINFO (printk ("ad1816: prepare_for_input called: bsize=%d bcount=%d\n",bsize,bcount)); - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); fmt_bits= (devc->format_bits&0x7)<<3; @@ -290,7 +283,7 @@ ad_write (devc, 2, freq & 0xffff); ad_write (devc, 3, freq & 0xffff); - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); ad1816_halt_input(dev); return 0; @@ -305,8 +298,7 @@ DEBUGINFO (printk ("ad1816: prepare_for_output called: bsize=%d bcount=%d\n",bsize,bcount)); - save_flags (flags); /* make register access atomic */ - cli (); + spin_lock_irqsave(&devc->lock,flags); fmt_bits= (devc->format_bits&0x7)<<3; /* set mono/stereo mode */ @@ -335,7 +327,7 @@ ad_write (devc, 2, freq & 0xffff); ad_write (devc, 3, freq & 0xffff); - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); ad1816_halt_output(dev); return 0; @@ -351,8 +343,7 @@ /* mode may have changed */ - save_flags (flags); /* make register access atomic */ - cli (); + spin_lock_irqsave(&devc->lock,flags); /* mask out modes not specified on open call */ state &= devc->audio_mode; @@ -377,7 +368,7 @@ /* disable capture */ outb(inb(devc->base+8)&~0x01, devc->base+8); } - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } @@ -480,11 +471,10 @@ devc = (ad1816_info *) audio_devs[dev]->devc; /* make check if device already open atomic */ - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); if (devc->opened) { - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); return -(EBUSY); } @@ -497,7 +487,7 @@ devc->channels=1; ad1816_reset(devc->dev_no); /* halt all pending output */ - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); return 0; } @@ -506,8 +496,7 @@ unsigned long flags; ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); /* halt all pending output */ ad1816_reset(devc->dev_no); @@ -518,8 +507,7 @@ devc->audio_format=AFMT_U8; devc->format_bits = 0; - - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } @@ -556,7 +544,6 @@ unsigned char status; ad1816_info *devc; int dev; - unsigned long flags; if (irq < 0 || irq > 15) { @@ -574,8 +561,7 @@ devc = (ad1816_info *) audio_devs[dev]->devc; - save_flags(flags); - cli(); + spin_lock(&devc->lock); /* read interrupt register */ status = inb (devc->base+1); @@ -595,7 +581,7 @@ if (devc->opened && (devc->audio_mode & PCM_ENABLE_OUTPUT) && (status & 128)) DMAbuf_outputintr (dev, 1); - restore_flags(flags); + spin_unlock(&devc->lock); } /* ------------------------------------------------------------------- */ @@ -1033,6 +1019,7 @@ devc->irq = 0; devc->opened = 0; devc->osp = osp; + spin_lock_init(&devc->lock); /* base+0: bit 1 must be set but not 255 */ tmp=inb(devc->base); diff -Nru a/sound/oss/ad1848.c b/sound/oss/ad1848.c --- a/sound/oss/ad1848.c Sat Aug 31 15:06:03 2002 +++ b/sound/oss/ad1848.c Sat Aug 31 15:06:03 2002 @@ -47,6 +47,7 @@ #include #include #include +#include #define DEB(x) #define DEB1(x) @@ -57,6 +58,7 @@ typedef struct { + spinlock_t lock; int base; int irq; int dma1, dma2; @@ -212,8 +214,7 @@ while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if(reg < 32) { @@ -230,7 +231,7 @@ outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); x = inb(io_Indexed_Data(devc)); } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return x; } @@ -243,8 +244,7 @@ while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ timeout--; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if(reg < 32) { @@ -261,7 +261,7 @@ outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); outb((unsigned char) (data & 0xff), io_Indexed_Data(devc)); } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void wait_for_calibration(ad1848_info * devc) @@ -324,18 +324,17 @@ while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); devc->MCE_bit = 0x40; prev = inb(io_Index_Addr(devc)); if (prev & 0x40) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } outb((devc->MCE_bit), io_Index_Addr(devc)); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad_leave_MCE(ad1848_info * devc) @@ -347,8 +346,7 @@ while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); acal = ad_read(devc, 9); @@ -358,13 +356,13 @@ if ((prev & 0x40) == 0) /* Not in MCE mode */ { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ if (acal & 0x08) /* Auto calibration is enabled */ wait_for_calibration(devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static int ad1848_set_recmask(ad1848_info * devc, int mask) @@ -975,7 +973,7 @@ static int ad1848_open(int dev, int mode) { - ad1848_info *devc = NULL; + ad1848_info *devc; ad1848_port_info *portc; unsigned long flags; @@ -985,11 +983,10 @@ devc = (ad1848_info *) audio_devs[dev]->devc; portc = (ad1848_port_info *) audio_devs[dev]->portc; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (portc->open_mode || (devc->open_mode & mode)) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return -EBUSY; } devc->dual_dma = 0; @@ -1008,7 +1005,7 @@ devc->record_dev = dev; if (mode & OPEN_WRITE) devc->playback_dev = dev; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); /* * Mute output until the playback really starts. This decreases clicking (hope so). */ @@ -1025,8 +1022,7 @@ DEB(printk("ad1848_close(void)\n")); - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); devc->intr_active = 0; ad1848_halt(dev); @@ -1036,7 +1032,7 @@ portc->open_mode = 0; ad_unmute(devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) @@ -1070,8 +1066,7 @@ * Auto DMA mode on. No need to react */ } - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_write(devc, 15, (unsigned char) (cnt & 0xff)); ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); @@ -1079,7 +1074,7 @@ devc->xfer_count = cnt; devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) @@ -1112,8 +1107,7 @@ * Auto DMA mode on. No need to react */ } - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (devc->model == MD_1848) { @@ -1131,7 +1125,7 @@ devc->xfer_count = cnt; devc->audio_mode |= PCM_ENABLE_INPUT; devc->intr_active = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static int ad1848_prepare_for_output(int dev, int bsize, int bcount) @@ -1144,8 +1138,7 @@ ad_mute(devc); - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); fs = portc->speed_bits | (portc->format_bits << 5); if (portc->channels > 1) @@ -1189,7 +1182,7 @@ ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); devc->xfer_count = 0; #ifndef EXCLUDE_TIMERS @@ -1214,8 +1207,7 @@ if (devc->audio_mode) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); fs = portc->speed_bits | (portc->format_bits << 5); if (portc->channels > 1) @@ -1303,7 +1295,7 @@ ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); devc->xfer_count = 0; #ifndef EXCLUDE_TIMERS @@ -1342,8 +1334,7 @@ if (!(ad_read(devc, 9) & 0x02)) return; /* Capture not enabled */ - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_mute(devc); @@ -1368,7 +1359,7 @@ devc->audio_mode &= ~PCM_ENABLE_INPUT; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_halt_output(int dev) @@ -1379,8 +1370,7 @@ if (!(ad_read(devc, 9) & 0x01)) return; /* Playback not enabled */ - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_mute(devc); { @@ -1405,7 +1395,7 @@ devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_trigger(int dev, int state) @@ -1415,8 +1405,7 @@ unsigned long flags; unsigned char tmp, old; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); state &= devc->audio_mode; tmp = old = ad_read(devc, 9); @@ -1441,7 +1430,7 @@ ad_write(devc, 9, tmp); ad_unmute(devc); } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_init_hw(ad1848_info * devc) @@ -1978,6 +1967,7 @@ ad1848_port_info *portc = NULL; + spin_lock_init(&devc->lock); devc->irq = (irq > 0) ? irq : 0; devc->open_mode = 0; devc->timer_ticks = 0; @@ -2245,10 +2235,8 @@ { if (devc->model == MD_C930) { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - save_flags(flags); - cli(); + spin_lock(&devc->lock); /* 0xe0e is C930 address port * 0xe0f is C930 data port @@ -2257,7 +2245,7 @@ c930_stat = inb(0xe0f); outb((~c930_stat), 0xe0f); - restore_flags(flags); + spin_unlock(&devc->lock); alt_stat = (c930_stat << 2) & 0x30; } @@ -2733,8 +2721,7 @@ unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ unsigned long divider; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); /* * Length of the timer interval (in nanoseconds) depends on the @@ -2766,7 +2753,7 @@ ad_write(devc, 20, divider & 0xff); /* Set lower bits */ ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */ devc->timer_running = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return current_interval = (divider * xtal_nsecs + 500) / 1000; } @@ -2787,11 +2774,10 @@ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_write(devc, 16, ad_read(devc, 16) & ~0x40); devc->timer_running = 0; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void ad1848_tmr_restart(int dev) @@ -2802,11 +2788,10 @@ if (current_interval == 0) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_write(devc, 16, ad_read(devc, 16) | 0x40); devc->timer_running = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static struct sound_lowlev_timer ad1848_tmr = @@ -2834,12 +2819,11 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ad_mute(devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 0; } @@ -2848,8 +2832,7 @@ unsigned long flags; int mixer_levels[32], i; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); /* Thinkpad is a bit more of PITA than normal. The BIOS tends to restore it in a different config to the one we use. Need to @@ -2875,7 +2858,7 @@ bits = interrupt_bits[devc->irq]; if (bits == -1) { printk(KERN_ERR "MSS: Bad IRQ %d\n", devc->irq); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return -1; } @@ -2890,8 +2873,8 @@ outb((bits | dma_bits[devc->dma1] | dma2_bit), config_port); } - restore_flags(flags); - return 0; + spin_unlock_irqrestore(&devc->lock,flags); + return 0; } static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) diff -Nru a/sound/oss/audio.c b/sound/oss/audio.c --- a/sound/oss/audio.c Sat Aug 31 15:05:59 2002 +++ b/sound/oss/audio.c Sat Aug 31 15:05:59 2002 @@ -291,10 +291,6 @@ if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { - /* - * This just allows interrupts while the conversion is running - */ - sti(); translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); } c -= used; @@ -352,11 +348,6 @@ if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { - /* - * This just allows interrupts while the conversion is running - */ - sti(); - translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); } @@ -515,8 +506,7 @@ break; } - save_flags (flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); /* Compute number of bytes that have been played */ count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); if (count < dmap->fragment_size && dmap->qhead != 0) @@ -527,7 +517,7 @@ count = dmap->user_counter - count; if (count < 0) count = 0; - restore_flags (flags); + spin_unlock_irqrestore(&dmap->lock,flags); val = count; break; @@ -836,15 +826,14 @@ if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); changed = audio_devs[dev]->enable_bits ^ bits; if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) { reorganize_buffers(dev, dmap_in, 1); if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) { - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return -err; } dmap_in->dma_mode = DMODE_INPUT; @@ -867,7 +856,7 @@ if (changed && audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); #endif - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); /* Falls through... */ case SNDCTL_DSP_GETTRIGGER: @@ -884,8 +873,7 @@ case SNDCTL_DSP_GETIPTR: if (!(audio_devs[dev]->open_mode & OPEN_READ)) return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); cinfo.bytes = dmap_in->byte_counter; cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) @@ -894,7 +882,7 @@ cinfo.bytes += cinfo.ptr; if (dmap_in->mapping_flags & DMA_MAP_MAPPED) dmap_in->qlen = 0; /* Reset interrupt counter */ - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); if (copy_to_user(arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -903,8 +891,7 @@ if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); cinfo.bytes = dmap_out->byte_counter; cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) @@ -913,7 +900,7 @@ cinfo.bytes += cinfo.ptr; if (dmap_out->mapping_flags & DMA_MAP_MAPPED) dmap_out->qlen = 0; /* Reset interrupt counter */ - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); if (copy_to_user(arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -926,8 +913,7 @@ ret=0; break; } - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); /* Compute number of bytes that have been played */ count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); if (count < dmap_out->fragment_size && dmap_out->qhead != 0) @@ -937,7 +923,7 @@ count = dmap_out->user_counter - count; if (count < 0) count = 0; - restore_flags (flags); + spin_unlock_irqrestore(&dmap->lock,flags); ret = count; break; diff -Nru a/sound/oss/cmpci.c b/sound/oss/cmpci.c --- a/sound/oss/cmpci.c Sat Aug 31 15:05:53 2002 +++ b/sound/oss/cmpci.c Sat Aug 31 15:05:53 2002 @@ -1791,14 +1791,14 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; if (s->status & DO_DUAL_DAC) s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } return 0; @@ -3166,7 +3166,7 @@ while ((s = devs)) { devs = devs->next; outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ - synchronize_irq(); + synchronize_irq(s->irq); outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ free_irq(s->irq, s); diff -Nru a/sound/oss/dev_table.h b/sound/oss/dev_table.h --- a/sound/oss/dev_table.h Sat Aug 31 15:06:06 2002 +++ b/sound/oss/dev_table.h Sat Aug 31 15:06:06 2002 @@ -15,6 +15,7 @@ #ifndef _DEV_TABLE_H_ #define _DEV_TABLE_H_ +#include /* * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) * Numbers 1000 to N are reserved for driver's internal use. @@ -107,9 +108,11 @@ /* * Queue parameters. */ - int qlen; - int qhead; - int qtail; + int qlen; + int qhead; + int qtail; + spinlock_t lock; + int cfrag; /* Current incomplete fragment (write) */ int nbufs; @@ -205,7 +208,7 @@ int format_mask; /* Bitmask for supported audio formats */ void *devc; /* Driver specific info */ struct audio_driver *d; - void *portc; /* Driver spesific info */ + void *portc; /* Driver specific info */ struct dma_buffparms *dmap_in, *dmap_out; struct coproc_operations *coproc; int mixer_dev; @@ -292,7 +295,7 @@ { /* MIDI input scanner variables */ #define MI_MAX 10 - int m_busy; + volatile int m_busy; unsigned char m_buf[MI_MAX]; unsigned char m_prev_status; /* For running status */ int m_ptr; diff -Nru a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c --- a/sound/oss/dmabuf.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/dmabuf.c Sat Aug 31 15:05:54 2002 @@ -199,6 +199,7 @@ return -EBUSY; } dma_init_buffers(dmap); + spin_lock_init(&dmap->lock); dmap->open_mode = mode; dmap->subdivision = dmap->underrun_count = 0; dmap->fragment_size = 0; @@ -319,7 +320,7 @@ adev->dmap_out->bytes_in_use); return 0; } - +/* MUST not hold the spinlock */ void DMAbuf_reset(int dev) { if (audio_devs[dev]->open_mode & OPEN_WRITE) @@ -341,15 +342,17 @@ /* * First wait until the current fragment has been played completely */ - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); adev->dmap_out->flags |= DMA_SYNCING; adev->dmap_out->underrun_count = 0; if (!signal_pending(current) && adev->dmap_out->qlen && - adev->dmap_out->underrun_count == 0) + adev->dmap_out->underrun_count == 0){ + spin_unlock_irqrestore(&dmap->lock,flags); interruptible_sleep_on_timeout(&adev->out_sleeper, dmabuf_timeout(dmap)); + spin_lock_irqsave(&dmap->lock,flags); + } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* @@ -366,10 +369,10 @@ disable_dma(dmap->dma); release_dma_lock(f); - restore_flags(flags); dmap->byte_counter = 0; reorganize_buffers(dev, adev->dmap_out, 0); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + spin_unlock_irqrestore(&dmap->lock,flags); } static void dma_reset_input(int dev) @@ -378,20 +381,19 @@ unsigned long flags; struct dma_buffparms *dmap = adev->dmap_in; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input) adev->d->halt_io(dev); else adev->d->halt_input(dev); adev->dmap_in->flags &= ~DMA_STARTED; - restore_flags(flags); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; reorganize_buffers(dev, adev->dmap_in, 1); + spin_unlock_irqrestore(&dmap->lock,flags); } - +/* MUST be called with holding the dmap->lock */ void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { struct audio_operations *adev = audio_devs[dev]; @@ -432,8 +434,7 @@ if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { dmap = adev->dmap_out; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) DMAbuf_launch_output(dev, dmap); adev->dmap_out->flags |= DMA_SYNCING; @@ -441,31 +442,33 @@ while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { long t = dmabuf_timeout(dmap); - t = interruptible_sleep_on_timeout(&adev->out_sleeper, - t); + spin_unlock_irqrestore(&dmap->lock,flags); + t = interruptible_sleep_on_timeout(&adev->out_sleeper, t); + spin_lock_irqsave(&dmap->lock,flags); if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return adev->dmap_out->qlen; } } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags(flags); /* * Some devices such as GUS have huge amount of on board RAM for the * audio data. We have to wait until the device has finished playing. */ - save_flags(flags); - cli(); + /* still holding the lock */ if (adev->d->local_qlen) { /* Device has hidden buffers */ while (!signal_pending(current) && - adev->d->local_qlen(dev)) + adev->d->local_qlen(dev)){ + spin_unlock_irqrestore(&dmap->lock,flags); interruptible_sleep_on_timeout(&adev->out_sleeper, dmabuf_timeout(dmap)); + spin_lock_irqsave(&dmap->lock,flags); + } } - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); } adev->dmap_out->dma_mode = DMODE_NONE; return adev->dmap_out->qlen; @@ -474,23 +477,26 @@ int DMAbuf_release(int dev, int mode) { struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap; unsigned long flags; + dmap = adev->dmap_out; if (adev->open_mode & OPEN_WRITE) adev->dmap_out->closing = 1; - if (adev->open_mode & OPEN_READ) - adev->dmap_in->closing = 1; + if (adev->open_mode & OPEN_READ){ + adev->dmap_in->closing = 1; + dmap = adev->dmap_in; + } if (adev->open_mode & OPEN_WRITE) if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) DMAbuf_sync(dev); if (adev->dmap_out->dma_mode == DMODE_OUTPUT) memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); - save_flags(flags); - cli(); DMAbuf_reset(dev); + spin_lock_irqsave(&dmap->lock,flags); adev->d->close(dev); if (adev->open_mode & OPEN_WRITE) @@ -501,10 +507,10 @@ (adev->flags & DMA_DUPLEX))) close_dmap(adev, adev->dmap_in); adev->open_mode = 0; - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return 0; } - +/* called with dmap->lock dold */ int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { struct audio_operations *adev = audio_devs[dev]; @@ -515,8 +521,12 @@ if (!(adev->enable_bits & PCM_ENABLE_INPUT)) return 0; if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ + unsigned long flags; + /* release lock - it's not recursive */ + spin_unlock_irqrestore(&dmap->lock,flags); DMAbuf_sync(dev); DMAbuf_reset(dev); + spin_lock_irqsave(&dmap->lock,flags); dmap->dma_mode = DMODE_NONE; } if (!dmap->dma_mode) { @@ -538,7 +548,7 @@ } return 0; } - +/* aquires lock */ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) { struct audio_operations *adev = audio_devs[dev]; @@ -549,34 +559,36 @@ if (!(adev->open_mode & OPEN_READ)) return -EIO; + spin_lock_irqsave(&dmap->lock,flags); if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - save_flags(flags); - cli(); if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) { /* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return -EINVAL; } else while (dmap->qlen <= 0 && n++ < 10) { long timeout = MAX_SCHEDULE_TIMEOUT; if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return -EAGAIN; } if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return err; } /* Wait for the next block */ if (dontblock) { - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return -EAGAIN; } if ((go = adev->go)) timeout = dmabuf_timeout(dmap); + + spin_unlock_irqrestore(&dmap->lock,flags); timeout = interruptible_sleep_on_timeout(&adev->in_sleeper, timeout); + spin_lock_irqsave(&dmap->lock,flags); if (!timeout) { /* FIXME: include device name */ err = -EIO; @@ -585,7 +597,7 @@ } else err = -EINTR; } - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); if (dmap->qlen <= 0) return err ? err : -EINTR; @@ -617,7 +629,7 @@ return 0; } - +/* MUST be called with dmap->lock hold */ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) { /* @@ -626,11 +638,8 @@ */ int pos; - unsigned long flags; unsigned long f; - save_flags(flags); - cli(); if (!(dmap->flags & DMA_ACTIVE)) pos = 0; else { @@ -667,7 +676,6 @@ release_dma_lock(f); } - restore_flags(flags); /* printk( "%04x ", pos); */ return pos; @@ -698,7 +706,7 @@ adev->d->trigger(dev,adev->enable_bits * adev->go); } } - +/* via poll called without a lock ?*/ int DMAbuf_space_in_queue(int dev) { struct audio_operations *adev = audio_devs[dev]; @@ -735,7 +743,7 @@ return 0; return max - len; } - +/* MUST not hold the spinlock - this function may sleep */ static int output_sleep(int dev, int dontblock) { struct audio_operations *adev = audio_devs[dev]; @@ -770,12 +778,11 @@ } return err; } - +/* called with the lock held */ static int find_output_space(int dev, char **buf, int *size) { struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_out; - unsigned long flags; unsigned long active_offs; long len, offs; int maxfrags; @@ -784,8 +791,6 @@ *buf = dmap->raw_buf; if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) return 0; - save_flags(flags); - cli(); #ifdef BE_CONSERVATIVE active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; @@ -799,7 +804,6 @@ offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; if (offs < 0 || offs >= dmap->bytes_in_use) { - restore_flags(flags); printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs); printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); return 0; @@ -811,16 +815,14 @@ if ((offs + len) > dmap->bytes_in_use) len = dmap->bytes_in_use - offs; if (len < 0) { - restore_flags(flags); return 0; } if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) len = (maxfrags * dmap->fragment_size) - occupied_bytes; *size = len & ~SAMPLE_ROUNDUP; - restore_flags(flags); return (*size > 0); } - +/* aquires lock */ int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { struct audio_operations *adev = audio_devs[dev]; @@ -828,39 +830,45 @@ int err = -EIO; struct dma_buffparms *dmap = adev->dmap_out; - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ return -EINVAL; } + spin_lock_irqsave(&dmap->lock,flags); + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ + spin_unlock_irqrestore(&dmap->lock,flags); DMAbuf_reset(dev); - dmap->dma_mode = DMODE_NONE; + spin_lock_irqsave(&dmap->lock,flags); } dmap->dma_mode = DMODE_OUTPUT; - save_flags(flags); - cli(); while (find_output_space(dev, buf, size) <= 0) { + spin_unlock_irqrestore(&dmap->lock,flags); if ((err = output_sleep(dev, dontblock)) < 0) { - restore_flags(flags); return err; } + spin_lock_irqsave(&dmap->lock,flags); } - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); return 0; } - +/* has to aquire dmap->lock */ int DMAbuf_move_wrpointer(int dev, int l) { struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; + unsigned long ptr; unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); + int post; + unsigned long flags; + + spin_lock_irqsave(&dmap->lock,flags); + post= (dmap->flags & DMA_POST); + ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; dmap->flags &= ~DMA_POST; dmap->cfrag = -1; @@ -890,7 +898,7 @@ dmap->counts[dmap->qtail] = dmap->user_counter - ptr; /* - * Let the low level driver to perform some postprocessing to + * Let the low level driver perform some postprocessing to * the written data. */ if (adev->d->postprocess_write) @@ -899,6 +907,8 @@ if (!(dmap->flags & DMA_ACTIVE)) if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) DMAbuf_launch_output(dev, dmap); + + spin_unlock_irqrestore(&dmap->lock,flags); return 0; } @@ -945,11 +955,10 @@ wake_up(&adev->out_sleeper); wake_up(&adev->poll_sleeper); } - +/* called with dmap->lock held in irq context*/ static void do_outputintr(int dev, int dummy) { struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; struct dma_buffparms *dmap = adev->dmap_out; int this_fragment; @@ -977,8 +986,6 @@ finish_output_interrupt(dev, dmap); return; } - save_flags(flags); - cli(); dmap->qlen--; this_fragment = dmap->qhead; @@ -1014,18 +1021,16 @@ } if (dmap->qlen > 0) DMAbuf_launch_output(dev, dmap); - restore_flags(flags); finish_output_interrupt(dev, dmap); } - +/* called in irq context */ void DMAbuf_outputintr(int dev, int notify_only) { struct audio_operations *adev = audio_devs[dev]; unsigned long flags; struct dma_buffparms *dmap = adev->dmap_out; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; unsigned long f; @@ -1049,9 +1054,9 @@ } else do_outputintr(dev, notify_only); - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); } - +/* called with dmap->lock held in irq context */ static void do_inputintr(int dev) { struct audio_operations *adev = audio_devs[dev]; @@ -1117,15 +1122,14 @@ wake_up(&adev->poll_sleeper); } } - +/* called in irq context */ void DMAbuf_inputintr(int dev) { struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_in; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; @@ -1149,7 +1153,7 @@ do_inputintr(dev); } else do_inputintr(dev); - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); } int DMAbuf_open_dma(int dev) @@ -1240,10 +1244,9 @@ !dmap->qlen && adev->go) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&dmap->lock,flags); DMAbuf_activate_recording(dev, dmap); - restore_flags(flags); + spin_unlock_irqrestore(&dmap->lock,flags); } return 0; } diff -Nru a/sound/oss/es1370.c b/sound/oss/es1370.c --- a/sound/oss/es1370.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/es1370.c Sat Aug 31 15:06:00 2002 @@ -1406,12 +1406,12 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac2(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } return 0; @@ -1798,7 +1798,7 @@ down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac2(s); - synchronize_irq(); + synchronize_irq(s->irq); dealloc_dmabuf(s, &s->dma_dac2); } if (file->f_mode & FMODE_READ) { @@ -1976,7 +1976,7 @@ case SNDCTL_DSP_RESET: stop_dac1(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0; return 0; @@ -2704,7 +2704,7 @@ list_del(&s->devs); outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(); + synchronize_irq(s->irq); free_irq(s->irq, s); if (s->gameport.io) { gameport_unregister_port(&s->gameport); diff -Nru a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c --- a/sound/oss/esssolo1.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/esssolo1.c Sat Aug 31 15:05:54 2002 @@ -1284,12 +1284,12 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } prog_codec(s); @@ -2419,7 +2419,7 @@ outb(0, s->iobase+6); outb(0, s->ddmabase+0xd); /* DMA master clear */ outb(3, s->sbbase+6); /* reset sequencer and FIFO */ - synchronize_irq(); + synchronize_irq(s->irq); pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ free_irq(s->irq, s); if (s->gameport.io) { diff -Nru a/sound/oss/gus_card.c b/sound/oss/gus_card.c --- a/sound/oss/gus_card.c Sat Aug 31 15:05:53 2002 +++ b/sound/oss/gus_card.c Sat Aug 31 15:05:53 2002 @@ -123,8 +123,6 @@ unsigned char src; extern int gus_timer_enabled; - sti(); - #ifdef CONFIG_SOUND_GUSMAX if (have_gus_max) { struct address_info *hw_config = dev_id; diff -Nru a/sound/oss/ite8172.c b/sound/oss/ite8172.c --- a/sound/oss/ite8172.c Sat Aug 31 15:05:55 2002 +++ b/sound/oss/ite8172.c Sat Aug 31 15:05:55 2002 @@ -826,7 +826,7 @@ static int it8172_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; struct it8172_state *s; @@ -1196,13 +1196,13 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.count = s->dma_dac.total_bytes = 0; s->dma_dac.nextIn = s->dma_dac.nextOut = s->dma_dac.rawbuf; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.count = s->dma_adc.total_bytes = 0; s->dma_adc.nextIn = s->dma_adc.nextOut = s->dma_adc.rawbuf; } @@ -1541,7 +1541,7 @@ static int it8172_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -1911,7 +1911,7 @@ if (s->ps) remove_proc_entry(IT8172_MODULE_NAME, NULL); #endif /* IT8172_DEBUG */ - synchronize_irq(); + synchronize_irq(s->irq); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,0)); unregister_sound_dsp(s->dev_audio); diff -Nru a/sound/oss/mad16.c b/sound/oss/mad16.c --- a/sound/oss/mad16.c Sat Aug 31 15:05:55 2002 +++ b/sound/oss/mad16.c Sat Aug 31 15:05:55 2002 @@ -43,7 +43,7 @@ #include #include #include - +#include #include "sound_config.h" #include "ad1848.h" @@ -53,7 +53,7 @@ static int mad16_conf; static int mad16_cdsel; static struct gameport gameport; - +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static int already_initialized = 0; #define C928 1 @@ -106,8 +106,7 @@ unsigned long flags; unsigned char tmp; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); switch (board_type) /* Output password */ { @@ -142,7 +141,7 @@ if (!c924pnp) tmp = inb(port); else tmp = inb(port-0x80); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return tmp; } @@ -151,8 +150,7 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); switch (board_type) /* Output password */ { @@ -185,7 +183,7 @@ if (!c924pnp) outb(((unsigned char) (value & 0xff)), port); else outb(((unsigned char) (value & 0xff)), port-0x80); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static int __init detect_c930(void) diff -Nru a/sound/oss/maestro.c b/sound/oss/maestro.c --- a/sound/oss/maestro.c Sat Aug 31 15:05:59 2002 +++ b/sound/oss/maestro.c Sat Aug 31 15:05:59 2002 @@ -2552,12 +2552,12 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->card->pcidev->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->card->pcidev->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } return 0; @@ -3682,8 +3682,7 @@ unsigned long flags; int i,j; - save_flags(flags); - cli(); /* over-kill */ + spin_lock_irqsave(&card->lock,flags); /* over-kill */ M_printk("maestro: apm in dev %p\n",card); @@ -3711,7 +3710,7 @@ card->in_suspend++; - restore_flags(flags); + spin_unlock_irqrestore(&card->lock,flags); /* we trust in the bios to power down the chip on suspend. * XXX I'm also not sure that in_suspend will protect @@ -3725,8 +3724,7 @@ unsigned long flags; int i; - save_flags(flags); - cli(); /* over-kill */ + spin_lock_irqsave(&card->lock,flags); /* over-kill */ card->in_suspend = 0; @@ -3779,7 +3777,7 @@ } } - restore_flags(flags); + spin_unlock_irqrestore(&card->lock,flags); /* all right, we think things are ready, wake up people who were using the device diff -Nru a/sound/oss/maestro3.c b/sound/oss/maestro3.c --- a/sound/oss/maestro3.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/maestro3.c Sat Aug 31 15:06:06 2002 @@ -199,8 +199,11 @@ int index; /* this locks around the oss state in the driver */ - spinlock_t lock; - + /* no, this lock is removed - only use card->lock */ + /* otherwise: against what are you protecting on SMP + when irqhandler uses s->lock + and m3_assp_read uses card->lock ? + */ struct semaphore open_sem; wait_queue_head_t open_wait; mode_t open_mode; @@ -1066,8 +1069,6 @@ } -static void m3_interrupt(int irq, void *dev_id, struct pt_regs *regs); - static int prog_dmabuf(struct m3_state *s, unsigned rec) { @@ -1078,7 +1079,7 @@ unsigned char fmt; unsigned long flags; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); fmt = s->fmt; if (rec) { @@ -1126,7 +1127,7 @@ db->ready = 1; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); return 0; } @@ -1250,9 +1251,9 @@ if(ctl & DSP2HOST_REQ_TIMER) { outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS); /* update adc/dac info if it was a timer int */ - spin_lock(&s->lock); + spin_lock(&c->lock); m3_update_ptr(s); - spin_unlock(&s->lock); + spin_unlock(&c->lock); } } } @@ -1292,9 +1293,9 @@ set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); if (count <= 0) break; if (signal_pending(current)) @@ -1337,7 +1338,7 @@ return -EFAULT; ret = 0; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); while (count > 0) { int timed_out; @@ -1358,9 +1359,9 @@ goto out; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); if(timed_out) { printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n", @@ -1378,12 +1379,12 @@ continue; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { ret = ret ? ret : -EFAULT; return ret; } - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); swptr = (swptr + cnt) % s->dma_adc.dmasize; s->dma_adc.swptr = swptr; @@ -1395,7 +1396,7 @@ } out: - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); return ret; } @@ -1418,7 +1419,7 @@ return -EFAULT; ret = 0; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); while (count > 0) { int timed_out; @@ -1444,9 +1445,9 @@ if(!ret) ret = -EAGAIN; goto out; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); if(timed_out) { DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, @@ -1461,12 +1462,12 @@ } continue; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; return ret; } - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n", cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr); @@ -1482,7 +1483,7 @@ start_dac(s); } out: - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); return ret; } @@ -1498,7 +1499,7 @@ if (file->f_mode & FMODE_READ) poll_wait(file, &s->dma_adc.wait, wait); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->card->lock, flags); m3_update_ptr(s); if (file->f_mode & FMODE_READ) { @@ -1515,7 +1516,7 @@ } } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->card->lock, flags); return mask; } @@ -1572,6 +1573,7 @@ static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct m3_state *s = (struct m3_state *)file->private_data; + struct m3_card *card=s->card; unsigned long flags; audio_buf_info abinfo; count_info cinfo; @@ -1602,23 +1604,23 @@ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); case SNDCTL_DSP_RESET: - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->card->pcidev->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->card->pcidev->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; case SNDCTL_DSP_SPEED: get_user_ret(val, (int *)arg, -EFAULT); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1631,12 +1633,12 @@ set_dac_rate(s, val); } } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: get_user_ret(val, (int *)arg, -EFAULT); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -1656,12 +1658,12 @@ fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); } set_fmt(s, fmtm, fmtd); - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (val != 0) { fmtd = 0; fmtm = ~0; @@ -1683,7 +1685,7 @@ } set_fmt(s, fmtm, fmtd); } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg); @@ -1692,7 +1694,7 @@ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ get_user_ret(val, (int *)arg, -EFAULT); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -1714,7 +1716,7 @@ } set_fmt(s, fmtm, fmtd); } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? @@ -1758,13 +1760,13 @@ return -EINVAL; if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0) return val; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); m3_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: @@ -1772,13 +1774,13 @@ return -EINVAL; if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0) return val; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); m3_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; abinfo.bytes = s->dma_adc.count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: @@ -1788,23 +1790,23 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); m3_update_ptr(s); val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return put_user(val, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); m3_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -1812,14 +1814,14 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); m3_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -1836,7 +1838,7 @@ case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1857,7 +1859,7 @@ if (s->dma_dac.ossmaxfrags < 4) s->dma_dac.ossmaxfrags = 4; } - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; case SNDCTL_DSP_SUBDIVIDE: @@ -2019,7 +2021,7 @@ down(&s->open_sem); } - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&c->lock, flags); if (file->f_mode & FMODE_READ) { fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); @@ -2041,13 +2043,14 @@ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&c->lock, flags); return 0; } static int m3_release(struct inode *inode, struct file *file) { struct m3_state *s = (struct m3_state *)file->private_data; + struct m3_card *card=s->card; unsigned long flags; VALIDATE_STATE(s); @@ -2055,7 +2058,7 @@ drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&card->lock, flags); if (file->f_mode & FMODE_WRITE) { stop_dac(s); @@ -2074,7 +2077,7 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); @@ -2666,7 +2669,6 @@ init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); init_waitqueue_head(&s->open_wait); - spin_lock_init(&s->lock); init_MUTEX(&(s->open_sem)); s->magic = M3_STATE_MAGIC; @@ -2777,8 +2779,7 @@ struct m3_card *card = pci_get_drvdata(pci_dev); /* must be a better way.. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->lock, flags); DPRINTK(DPMOD, "pm in dev %p\n",card); @@ -2816,7 +2817,7 @@ card->in_suspend = 1; - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); return 0; } @@ -2828,8 +2829,7 @@ int i; struct m3_card *card = pci_get_drvdata(pci_dev); - save_flags(flags); /* paranoia */ - cli(); + spin_lock_irqsave(&card->lock, flags); card->in_suspend = 0; DPRINTK(DPMOD, "resuming\n"); @@ -2892,7 +2892,7 @@ start_adc(s); } - restore_flags(flags); + spin_unlock_irqrestore(&card->lock, flags); /* * all right, we think things are ready, diff -Nru a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c --- a/sound/oss/midi_synth.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/midi_synth.c Sat Aug 31 15:06:00 2002 @@ -418,7 +418,6 @@ { int orig_dev = synth_devs[dev]->midi_dev; int err; - unsigned long flags; struct midi_input_info *inc; if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) @@ -433,14 +432,15 @@ return err; inc = &midi_devs[orig_dev]->in_info; - save_flags(flags); - cli(); + /* save_flags(flags); + cli(); + don't know against what irqhandler to protect*/ inc->m_busy = 0; inc->m_state = MST_INIT; inc->m_ptr = 0; inc->m_left = 0; inc->m_prev_status = 0x00; - restore_flags(flags); + /* restore_flags(flags); */ return 1; } diff -Nru a/sound/oss/midibuf.c b/sound/oss/midibuf.c --- a/sound/oss/midibuf.c Sat Aug 31 15:05:59 2002 +++ b/sound/oss/midibuf.c Sat Aug 31 15:05:59 2002 @@ -15,7 +15,7 @@ */ #include #include - +#include #define MIDIBUF_C #include "sound_config.h" @@ -55,6 +55,7 @@ }; static volatile int open_devs = 0; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; #define DATA_AVAIL(q) (q->len) #define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len) @@ -63,20 +64,20 @@ if (SPACE_AVAIL(q)) \ { \ unsigned long flags; \ - save_flags( flags);cli(); \ + spin_lock_irqsave(&lock, flags); \ q->queue[q->tail] = (data); \ q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \ - restore_flags(flags); \ + spin_unlock_irqrestore(&lock, flags); \ } #define REMOVE_BYTE(q, data) \ if (DATA_AVAIL(q)) \ { \ unsigned long flags; \ - save_flags( flags);cli(); \ + spin_lock_irqsave(&lock, flags); \ data = q->queue[q->head]; \ q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \ - restore_flags(flags); \ + spin_unlock_irqrestore(&lock, flags); \ } static void drain_midi_queue(int dev) @@ -122,8 +123,7 @@ unsigned long flags; int dev; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (open_devs) { for (dev = 0; dev < num_midis; dev++) @@ -135,9 +135,9 @@ { int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - restore_flags(flags); /* Give some time to others */ + spin_unlock_irqrestore(&lock,flags);/* Give some time to others */ ok = midi_devs[dev]->outputc(dev, c); - cli(); + spin_lock_irqsave(&lock, flags); midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; midi_out_buf[dev]->len--; } @@ -151,7 +151,7 @@ * Come back later */ } - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); } int MIDIbuf_open(int dev, struct file *file) @@ -217,7 +217,6 @@ void MIDIbuf_release(int dev, struct file *file) { int mode; - unsigned long flags; dev = dev >> 4; mode = translate_mode(file); @@ -225,9 +224,6 @@ if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) return; - save_flags(flags); - cli(); - /* * Wait until the queue is empty */ @@ -249,7 +245,6 @@ * Ensure the output queues are empty */ } - restore_flags(flags); midi_devs[dev]->close(dev); @@ -267,7 +262,6 @@ int MIDIbuf_write(int dev, struct file *file, const char *buf, int count) { - unsigned long flags; int c, n, i; unsigned char tmp_data; @@ -276,9 +270,6 @@ if (!count) return 0; - save_flags(flags); - cli(); - c = 0; while (c < count) @@ -308,6 +299,8 @@ for (i = 0; i < n; i++) { /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */ + /* yes, think the same, so I removed the cli() brackets + QUEUE_BYTE is protected against interrupts */ if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) { c = -EFAULT; goto out; @@ -317,7 +310,6 @@ } } out: - restore_flags(flags); return c; } @@ -325,14 +317,10 @@ int MIDIbuf_read(int dev, struct file *file, char *buf, int count) { int n, c = 0; - unsigned long flags; unsigned char tmp_data; dev = dev >> 4; - save_flags(flags); - cli(); - if (!DATA_AVAIL(midi_in_buf[dev])) { /* * No data yet, wait */ @@ -361,6 +349,8 @@ REMOVE_BYTE(midi_in_buf[dev], tmp_data); fixit = (char *) &tmp_data; /* BROKE BROKE BROKE */ + /* yes removed the cli() brackets again + should q->len,tail&head be atomic_t? */ if (copy_to_user(&(buf)[c], fixit, 1)) { c = -EFAULT; goto out; @@ -369,7 +359,6 @@ } } out: - restore_flags(flags); return c; } @@ -440,7 +429,7 @@ int MIDIbuf_avail(int dev) { - if (midi_in_buf[dev]) + if (midi_in_buf[dev]) return DATA_AVAIL (midi_in_buf[dev]); return 0; } diff -Nru a/sound/oss/mpu401.c b/sound/oss/mpu401.c --- a/sound/oss/mpu401.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/mpu401.c Sat Aug 31 15:06:06 2002 @@ -19,7 +19,7 @@ #include #include - +#include #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS @@ -68,6 +68,7 @@ void (*inputintr) (int dev, unsigned char data); int shared_irq; int *osp; + spinlock_t lock; }; #define DATAPORT(base) (base) @@ -408,11 +409,10 @@ int busy; int n; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); busy = devc->m_busy; devc->m_busy = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); if (busy) /* Already inside the scanner */ return; @@ -447,7 +447,6 @@ struct mpu_config *devc; int dev = (int) dev_id; - sti(); devc = &dev_conf[dev]; if (input_avail(devc)) @@ -559,16 +558,15 @@ for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (!output_ready(devc)) { printk(KERN_WARNING "mpu401: Send data timeout\n"); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 0; } write_data(devc, midi_byte); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 1; } @@ -606,13 +604,12 @@ printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd); return -EIO; } - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (!output_ready(devc)) { - restore_flags(flags); - goto retry; + spin_unlock_irqrestore(&devc->lock,flags); + goto retry; } write_command(devc, cmd->cmd); @@ -636,7 +633,7 @@ } if (!ok) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return -EIO; } if (cmd->nr_args) @@ -647,7 +644,7 @@ if (!mpu401_out(dev, cmd->data[i])) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd); return -EIO; } @@ -669,12 +666,12 @@ } if (!ok) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return -EIO; } } } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return ret; } @@ -941,16 +938,15 @@ devc->version = devc->revision = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } devc->version = tmp; @@ -958,11 +954,11 @@ if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) { devc->version = 0; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } devc->revision = tmp; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } void attach_mpu401(struct address_info *hw_config, struct module *owner) @@ -995,6 +991,7 @@ devc->m_state = ST_INIT; devc->shared_irq = hw_config->always_detect; devc->irq = hw_config->irq; + spin_lock_init(&devc->lock); if (devc->irq < 0) { @@ -1020,12 +1017,11 @@ return; } } - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); mpu401_chk_version(m, devc); if (devc->version == 0) mpu401_chk_version(m, devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } request_region(hw_config->io_base, 2, "mpu401"); @@ -1154,12 +1150,11 @@ for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) { - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (input_avail(devc)) if (read_data(devc) == MPU_ACK) ok = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } } @@ -1289,16 +1284,15 @@ } -static void tmr_reset(void) +static void tmr_reset(struct mpu_config *devc) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); next_event_time = (unsigned long) -1; prev_event_time = 0; curr_ticks = curr_clocks = 0; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void set_timer_mode(int midi_dev) @@ -1353,7 +1347,9 @@ static int mpu_start_timer(int midi_dev) { - tmr_reset(); + struct mpu_config *devc= &dev_conf[midi_dev]; + + tmr_reset(devc); set_timer_mode(midi_dev); if (tmr_running) @@ -1378,11 +1374,12 @@ static int mpu_timer_open(int dev, int mode) { int midi_dev = sound_timer_devs[dev]->devlink; + struct mpu_config *devc= &dev_conf[midi_dev]; if (timer_open) return -EBUSY; - tmr_reset(); + tmr_reset(devc); curr_tempo = 50; mpu_cmd(midi_dev, 0xE0, 50); curr_timebase = hw_timebase = 120; diff -Nru a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c --- a/sound/oss/msnd_pinnacle.c Sat Aug 31 15:06:03 2002 +++ b/sound/oss/msnd_pinnacle.c Sat Aug 31 15:06:03 2002 @@ -645,7 +645,7 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); if (cmd == OSS_GETVERSION) { int sound_version = SOUND_VERSION; @@ -757,7 +757,7 @@ static int dev_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); int err = 0; if (minor == dev.dsp_minor) { @@ -792,7 +792,7 @@ static int dev_release(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); int err = 0; lock_kernel(); @@ -982,7 +982,7 @@ static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off) { - int minor = MINOR(file->f_dentry->d_inode->i_rdev); + int minor = minor(file->f_dentry->d_inode->i_rdev); if (minor == dev.dsp_minor) return dsp_read(buf, count); else @@ -991,7 +991,7 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off) { - int minor = MINOR(file->f_dentry->d_inode->i_rdev); + int minor = minor(file->f_dentry->d_inode->i_rdev); if (minor == dev.dsp_minor) return dsp_write(buf, count); else diff -Nru a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c --- a/sound/oss/nec_vrc5477.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/nec_vrc5477.c Sat Aug 31 15:06:06 2002 @@ -807,7 +807,7 @@ static int vrc5477_ac97_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; struct vrc5477_ac97_state *s; @@ -1331,13 +1331,13 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.count = 0; s->dma_dac.nextIn = s->dma_dac.nextOut = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.count = 0; s->dma_adc.nextIn = s->dma_adc.nextOut = 0; } @@ -1523,7 +1523,7 @@ static int vrc5477_ac97_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -1993,7 +1993,7 @@ if (s->ps) remove_proc_entry(VRC5477_AC97_MODULE_NAME, NULL); #endif /* CONFIG_LL_DEBUG */ - synchronize_irq(); + synchronize_irq(s->irq); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,0)); unregister_sound_dsp(s->dev_audio); diff -Nru a/sound/oss/nm256.h b/sound/oss/nm256.h --- a/sound/oss/nm256.h Sat Aug 31 15:05:54 2002 +++ b/sound/oss/nm256.h Sat Aug 31 15:05:54 2002 @@ -1,6 +1,7 @@ #ifndef _NM256_H_ #define _NM256_H_ +#include #include "ac97.h" /* The revisions that we currently handle. */ @@ -33,6 +34,8 @@ int dev_for_play; int dev_for_record; + spinlock_t lock; + /* The mixer device. */ int mixer_oss_dev; diff -Nru a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c --- a/sound/oss/nm256_audio.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/nm256_audio.c Sat Aug 31 15:06:00 2002 @@ -25,6 +25,7 @@ #include #include #include +#include #include "sound_config.h" #include "nm256.h" #include "nm256_coeff.h" @@ -262,8 +263,7 @@ return; } - save_flags (flags); - cli (); + spin_lock_irqsave(&card->lock,flags); /* * If we're not currently recording, set up the start and end registers * for the recording engine. @@ -283,7 +283,7 @@ } else { /* Not sure what else to do here. */ - restore_flags (flags); + spin_unlock_irqrestore(&card->lock,flags); return; } } @@ -303,7 +303,7 @@ nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN); - restore_flags (flags); + spin_unlock_irqrestore(&card->lock,flags); } /* Stop the play engine. */ @@ -370,8 +370,7 @@ card->requested_amt = amt; - save_flags (flags); - cli (); + spin_lock_irqsave(&card->lock,flags); if ((card->curPlayPos + amt) >= ringsize) { u32 rem = ringsize - card->curPlayPos; @@ -418,7 +417,7 @@ if (! card->playing) startPlay (card); - restore_flags (flags); + spin_unlock_irqrestore(&card->lock,flags); } /* We just got a card playback interrupt; process it. */ @@ -829,8 +828,7 @@ base = card->mixer; - save_flags (flags); - cli (); + spin_lock_irqsave(&card->lock,flags); nm256_isReady (dev); @@ -844,7 +842,7 @@ } - restore_flags (flags); + spin_unlock_irqrestore(&card->lock,flags); udelay (1000); return ! done; @@ -1055,6 +1053,7 @@ card->playing = 0; card->recording = 0; card->rev = rev; + spin_lock_init(&card->lock); /* Init the memory port info. */ for (x = 0; x < 2; x++) { diff -Nru a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c --- a/sound/oss/opl3sa.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/opl3sa.c Sat Aug 31 15:06:06 2002 @@ -22,6 +22,7 @@ #include #include +#include #undef SB_OK @@ -37,7 +38,7 @@ static int kilroy_was_here = 0; /* Don't detect twice */ static int mpu_initialized = 0; - +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static int *opl3sa_osp = NULL; static unsigned char opl3sa_read(int addr) @@ -45,12 +46,11 @@ unsigned long flags; unsigned char tmp; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); outb((0x1d), 0xf86); /* password */ outb(((unsigned char) addr), 0xf86); /* address */ tmp = inb(0xf87); /* data */ - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return tmp; } @@ -59,12 +59,11 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); outb((0x1d), 0xf86); /* password */ outb(((unsigned char) addr), 0xf86); /* address */ outb(((unsigned char) data), 0xf87); /* data */ - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static int __init opl3sa_detect(void) diff -Nru a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c --- a/sound/oss/opl3sa2.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/opl3sa2.c Sat Aug 31 15:05:54 2002 @@ -149,6 +149,8 @@ static struct address_info cfg_mss[OPL3SA2_CARDS_MAX]; static struct address_info cfg_mpu[OPL3SA2_CARDS_MAX]; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; + /* Our parameters */ static int __initdata io = -1; static int __initdata mss_io = -1; @@ -927,8 +929,7 @@ if (!pdev) return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); p = (opl3sa2_mixerdata *) pdev->data; p->in_suspend = 1; @@ -951,7 +952,7 @@ opl3sa2_read(p->cfg_port, OPL3SA2_PM, &p->reg); opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->reg | pm_mode); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; } @@ -964,15 +965,14 @@ return -EINVAL; p = (opl3sa2_mixerdata *) pdev->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); /* I don't think this is necessary */ opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->reg); opl3sa2_mixer_restore(p, p->card); p->in_suspend = 0; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; } diff -Nru a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c --- a/sound/oss/pas2_card.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/pas2_card.c Sat Aug 31 15:05:54 2002 @@ -7,6 +7,7 @@ #include #include #include +#include #include "sound_config.h" #include "pas2.h" @@ -38,6 +39,7 @@ static int pas_intr_mask = 0; static int pas_irq = 0; static int pas_sb_base = 0; +spinlock_t lock=SPIN_LOCK_UNLOCKED; #ifndef CONFIG_PAS_JOYSTICK static int joystick = 0; #else diff -Nru a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c --- a/sound/oss/pas2_midi.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/pas2_midi.c Sat Aug 31 15:05:54 2002 @@ -14,10 +14,13 @@ */ #include +#include #include "sound_config.h" #include "pas2.h" +extern spinlock_t lock; + static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -48,12 +51,11 @@ pas_write(0x20 | 0x40, 0x178b); - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if ((err = pas_set_intr(0x10)) < 0) { - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); return err; } /* @@ -81,7 +83,7 @@ pas_write(0xff, 0x1B88); - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); midi_busy = 1; qlen = qhead = qtail = 0; @@ -131,8 +133,7 @@ * Drain the local queue first */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); while (qlen && dump_to_midi(tmp_queue[qhead])) { @@ -140,7 +141,7 @@ qhead++; } - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); /* * Output the byte if the local queue is empty. @@ -157,14 +158,13 @@ if (qlen >= 256) return 0; /* Local queue full */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); tmp_queue[qtail] = midi_byte; qlen++; qtail++; - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); return 1; } @@ -226,7 +226,6 @@ { unsigned char stat; int i, incount; - unsigned long flags; stat = pas_read(0x1B88); @@ -245,8 +244,7 @@ } if (stat & (0x08 | 0x10)) { - save_flags(flags); - cli(); + spin_lock(&lock);/* called in irq context */ while (qlen && dump_to_midi(tmp_queue[qhead])) { @@ -254,7 +252,7 @@ qhead++; } - restore_flags(flags); + spin_unlock(&lock); } if (stat & 0x40) { diff -Nru a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c --- a/sound/oss/pas2_pcm.c Sat Aug 31 15:05:55 2002 +++ b/sound/oss/pas2_pcm.c Sat Aug 31 15:05:55 2002 @@ -16,6 +16,7 @@ */ #include +#include #include "sound_config.h" #include "pas2.h" @@ -44,6 +45,8 @@ int pas_audiodev = -1; static int open_mode = 0; +extern spinlock_t lock; + static int pcm_set_speed(int arg) { int foo, tmp; @@ -101,8 +104,7 @@ pcm_filter = tmp; #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); pas_write(0x00 | 0x30 | 0x04, 0x138B); @@ -110,7 +112,7 @@ pas_write((foo >> 8) & 0xff, 0x1388); pas_write(tmp, 0x0B8A); - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); return pcm_speed; } @@ -212,15 +214,14 @@ DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (pcm_busy) { - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); return -EBUSY; } pcm_busy = 1; - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) return err; @@ -238,15 +239,14 @@ DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n")); - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); pas_audio_reset(dev); pas_remove_intr(PAS_PCM_INTRBITS); pcm_mode = PCM_NON; pcm_busy = 0; - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); } static void pas_audio_output_block(int dev, unsigned long buf, int count, @@ -265,8 +265,7 @@ cnt == pcm_count) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); @@ -293,7 +292,7 @@ pcm_mode = PCM_DAC; - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); } static void pas_audio_start_input(int dev, unsigned long buf, int count, @@ -313,8 +312,7 @@ cnt == pcm_count) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ @@ -338,7 +336,7 @@ pcm_mode = PCM_ADC; - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); } #ifndef NO_TRIGGER @@ -346,8 +344,7 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); state &= open_mode; if (state & PCM_ENABLE_OUTPUT) @@ -357,7 +354,7 @@ else pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); - restore_flags(flags); + spin_unlock_irqrestore(&lock, flags); } #endif diff -Nru a/sound/oss/pss.c b/sound/oss/pss.c --- a/sound/oss/pss.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/pss.c Sat Aug 31 15:06:00 2002 @@ -60,6 +60,7 @@ #include #include #include +#include #include "sound_config.h" #include "sound_firmware.h" @@ -142,6 +143,7 @@ static pss_confdata pss_data; static pss_confdata *devc = &pss_data; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static int pss_initialized = 0; static int nonstandard_microcode = 0; @@ -838,18 +840,17 @@ return -EFAULT; } data = (unsigned short *)(mbuf->data); - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); for (i = 0; i < mbuf->len; i++) { if (!pss_put_dspword(devc, *data++)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); mbuf->len = i; /* feed back number of WORDs sent */ err = copy_to_user(arg, mbuf, sizeof(copr_msg)); vfree(mbuf); return err ? -EFAULT : -EIO; } } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); vfree(mbuf); return 0; @@ -859,8 +860,7 @@ if (mbuf == NULL) return -ENOSPC; data = (unsigned short *)mbuf->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) { mbuf->len = i; /* feed back number of WORDs read */ if (!pss_get_dspword(devc, data++)) { @@ -869,7 +869,7 @@ break; } } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); if (copy_to_user(arg, mbuf, sizeof(copr_msg))) err = -EFAULT; vfree(mbuf); @@ -878,22 +878,21 @@ case SNDCTL_COPR_RDATA: if (copy_from_user(&dbuf, arg, sizeof(dbuf))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (!pss_put_dspword(devc, 0x00d0)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_get_dspword(devc, &tmp)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } dbuf.parm1 = tmp; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); if (copy_to_user(arg, &dbuf, sizeof(dbuf))) return -EFAULT; return 0; @@ -901,74 +900,71 @@ case SNDCTL_COPR_WDATA: if (copy_from_user(&dbuf, arg, sizeof(dbuf))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (!pss_put_dspword(devc, 0x00d1)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } tmp = (unsigned int)dbuf.parm2 & 0xffff; if (!pss_put_dspword(devc, tmp)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; case SNDCTL_COPR_WCODE: if (copy_from_user(&dbuf, arg, sizeof(dbuf))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (!pss_put_dspword(devc, 0x00d3)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } tmp = (unsigned int)dbuf.parm2 & 0x00ff; if (!pss_put_dspword(devc, tmp)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff; if (!pss_put_dspword(devc, tmp)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; case SNDCTL_COPR_RCODE: if (copy_from_user(&dbuf, arg, sizeof(dbuf))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock, flags); if (!pss_put_dspword(devc, 0x00d2)) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */ - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } dbuf.parm1 = tmp << 8; if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */ - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return -EIO; } dbuf.parm1 |= tmp & 0x00ff; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); if (copy_to_user(arg, &dbuf, sizeof(dbuf))) return -EFAULT; return 0; diff -Nru a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c --- a/sound/oss/rme96xx.c Sat Aug 31 15:05:59 2002 +++ b/sound/oss/rme96xx.c Sat Aug 31 15:05:59 2002 @@ -10,6 +10,7 @@ * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree * 17 May 2001: 0.5 draining code didn't work on new cards * 18 May 2001: 0.6 remove synchronize_irq() call + * 10 Aug 2002: added synchronize_irq() again TODO: - test more than one card --- done @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include "rme96xx.h" @@ -786,8 +788,8 @@ } unregister_sound_mixer(s->mixer); -/* synchronize_irq(); This call got lost somehow ? */ - free_irq(s->irq,s); + synchronize_irq(s->irq); + free_irq(s->irq,s); busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL); busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL); kfree(s); diff -Nru a/sound/oss/sequencer.c b/sound/oss/sequencer.c --- a/sound/oss/sequencer.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/sequencer.c Sat Aug 31 15:06:00 2002 @@ -15,7 +15,7 @@ * Alan Cox : reformatted and fixed a pair of null pointer bugs */ #include - +#include #define SEQUENCER_C #include "sound_config.h" @@ -28,6 +28,7 @@ extern unsigned long seq_time; static int obsolete_api_used = 0; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; /* * Local counts for number of synth and MIDI devices. These are initialized @@ -95,37 +96,38 @@ ev_len = seq_mode == SEQ_1 ? 4 : 8; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); if (!iqlen) { + spin_unlock_irqrestore(&lock,flags); if (file->f_flags & O_NONBLOCK) { - restore_flags(flags); return -EAGAIN; } interruptible_sleep_on_timeout(&midi_sleeper, pre_event_timeout); + spin_lock_irqsave(&lock,flags); if (!iqlen) { - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; } } while (iqlen && c >= ev_len) { char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; + spin_unlock_irqrestore(&lock,flags); if (copy_to_user(&(buf)[p], fixit, ev_len)) - goto out; + return count - c; p += ev_len; c -= ev_len; + spin_lock_irqsave(&lock,flags); iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; } -out: - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return count - c; } @@ -152,13 +154,12 @@ if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; wake_up(&midi_sleeper); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static void sequencer_midi_input(int dev, unsigned char data) @@ -869,19 +870,19 @@ return 0; } +/* called also as timer in irq context */ static void seq_startplay(void) { - unsigned long flags; int this_one, action; + unsigned long flags; while (qlen > 0) { - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; qlen--; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); seq_playing = 1; @@ -947,7 +948,6 @@ { int retval, mode, i; int level, tmp; - unsigned long flags; if (!sequencer_ok) sequencer_init(); @@ -979,16 +979,12 @@ return -ENXIO; } } - save_flags(flags); - cli(); if (sequencer_busy) { - restore_flags(flags); return -EBUSY; } sequencer_busy = 1; obsolete_api_used = 0; - restore_flags(flags); max_mididev = num_midis; max_synthdev = num_synths; @@ -1203,16 +1199,11 @@ static int seq_sync(void) { - unsigned long flags; - if (qlen && !seq_playing && !signal_pending(current)) seq_startplay(); - save_flags(flags); - cli(); if (qlen > 0) interruptible_sleep_on_timeout(&seq_sleeper, HZ); - restore_flags(flags); return qlen; } @@ -1233,13 +1224,12 @@ n = 3 * HZ; /* Timeout */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); while (n && !midi_devs[dev]->outputc(dev, data)) { interruptible_sleep_on_timeout(&seq_sleeper, HZ/25); n--; } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static void seq_reset(void) @@ -1308,14 +1298,13 @@ seq_playing = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); if (waitqueue_active(&seq_sleeper)) { /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ wake_up(&seq_sleeper); } - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static void seq_panic(void) @@ -1499,10 +1488,9 @@ case SNDCTL_SEQ_OUTOFBAND: if (copy_from_user(&event_rec, arg, sizeof(event_rec))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); play_event(event_rec.arr); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return 0; case SNDCTL_MIDI_INFO: @@ -1554,8 +1542,7 @@ dev = dev >> 4; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); /* input */ poll_wait(file, &midi_sleeper, wait); if (iqlen) @@ -1565,7 +1552,7 @@ poll_wait(file, &seq_sleeper, wait); if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) mask |= POLLOUT | POLLWRNORM; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); return mask; } diff -Nru a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c --- a/sound/oss/sonicvibes.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/sonicvibes.c Sat Aug 31 15:06:00 2002 @@ -1589,12 +1589,12 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } return 0; @@ -2683,7 +2683,7 @@ return; list_del(&s->devs); outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ - synchronize_irq(); + synchronize_irq(s->irq); inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ /*outb(0, s->iodmaa + SV_DMA_RESET);*/ diff -Nru a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c --- a/sound/oss/sound_timer.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/sound_timer.c Sat Aug 31 15:05:54 2002 @@ -12,7 +12,7 @@ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) */ #include - +#include #include "sound_config.h" @@ -26,6 +26,7 @@ static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ static struct sound_lowlev_timer *tmr; +static spinlock_t lock; static unsigned long tmr2ticks(int tmr_value) { @@ -80,15 +81,14 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); tmr_offs = 0; ticks_offs = 0; tmr_ctr = 0; next_event_time = (unsigned long) -1; prev_event_time = 0; curr_ticks = 0; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static int timer_open(int dev, int mode) @@ -278,6 +278,8 @@ void sound_timer_interrupt(void) { + unsigned long flags; + if (!opened) return; @@ -286,6 +288,7 @@ if (!tmr_running) return; + spin_lock_irqsave(&lock,flags); tmr_ctr++; curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); @@ -294,6 +297,7 @@ next_event_time = (unsigned long) -1; sequencer_timer(0); } + spin_unlock_irqrestore(&lock,flags); } void sound_timer_init(struct sound_lowlev_timer *t, char *name) diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c --- a/sound/oss/soundcard.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/soundcard.c Sat Aug 31 15:06:00 2002 @@ -658,22 +658,16 @@ int sound_open_dma(int chn, char *deviceID) { - unsigned long flags; - if (!valid_dma(chn)) { printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); return 1; } - save_flags(flags); - cli(); if (dma_alloc_map[chn] != DMA_MAP_FREE) { printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); - restore_flags(flags); return 1; } dma_alloc_map[chn] = DMA_MAP_BUSY; - restore_flags(flags); return 0; } @@ -689,18 +683,11 @@ void sound_close_dma(int chn) { - unsigned long flags; - - save_flags(flags); - cli(); - if (dma_alloc_map[chn] != DMA_MAP_BUSY) { printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); - restore_flags(flags); return; } dma_alloc_map[chn] = DMA_MAP_FREE; - restore_flags(flags); } static void do_sequencer_timer(unsigned long dummy) diff -Nru a/sound/oss/sscape.c b/sound/oss/sscape.c --- a/sound/oss/sscape.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/sscape.c Sat Aug 31 15:05:54 2002 @@ -40,6 +40,7 @@ #include #include #include +#include #include "coproc.h" @@ -115,7 +116,7 @@ char* raw_buf; unsigned long raw_buf_phys; int buffsize; /* -------------------------- */ - + spinlock_t lock; int ok; /* Properly detected */ int failed; int dma_allocated; @@ -164,11 +165,10 @@ unsigned long flags; unsigned char val; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); outb(reg, PORT(ODIE_ADDR)); val = inb(PORT(ODIE_DATA)); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return val; } @@ -176,11 +176,10 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); outb(reg, PORT(ODIE_ADDR)); outb(data, PORT(ODIE_DATA)); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg) @@ -188,11 +187,10 @@ unsigned char res; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); outb( reg, devc -> codec); res = inb (devc -> codec + 1); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return res; } @@ -201,11 +199,10 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); outb( reg, devc -> codec); outb( data, devc -> codec + 1); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static void host_open(struct sscape_info *devc) @@ -223,9 +220,7 @@ unsigned long flags; int i, timeout_val; - save_flags(flags); - cli(); - + spin_lock_irqsave(&devc->lock,flags); /* * Send the command and data bytes */ @@ -238,12 +233,12 @@ if (timeout_val <= 0) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 0; } outb(data[i], PORT(HOST_DATA)); } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 1; } @@ -253,9 +248,7 @@ int timeout_val; unsigned char data; - save_flags(flags); - cli(); - + spin_lock_irqsave(&devc->lock,flags); /* * Read a byte */ @@ -266,11 +259,11 @@ if (timeout_val <= 0) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return -1; } data = inb(PORT(HOST_DATA)); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return data; } @@ -391,14 +384,13 @@ struct sscape_info *devc = dev_info; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (devc->dma_allocated) { sscape_write(devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ devc->dma_allocated = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return; } @@ -420,14 +412,13 @@ * before continuing. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); if (devc->dma_allocated == 0) devc->dma_allocated = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); sscape_write(devc, GA_HMCTL_REG, (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ @@ -449,8 +440,7 @@ } memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); /******** INTERRUPTS DISABLED NOW ********/ @@ -475,7 +465,7 @@ done = 1; } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); if (!done) return 0; @@ -494,9 +484,7 @@ /* * Wait until the ODB wakes up */ - - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); done = 0; timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) @@ -513,14 +501,13 @@ } sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); if (!done) { printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n"); return 0; } - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); done = 0; timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) @@ -529,7 +516,7 @@ if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); if (!done) { printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); @@ -675,8 +662,7 @@ if (!sscape_is_pnp) { - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); for (i = 1; i < 10; i++) { switch (i) @@ -710,7 +696,7 @@ sscape_write(devc, i, regs[i]); } } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } #ifdef SSCAPE_DEBUG2 /* @@ -960,8 +946,7 @@ return 0; } dt = data; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); while ( len > 0 ) { if (len > devc -> buffsize) l = devc->buffsize; else l = len; @@ -970,12 +955,12 @@ sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); sscape_pnp_start_dma ( devc, 0 ); if (sscape_pnp_wait_dma ( devc, 0 ) == 0) { - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); return 0; } } - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); vfree(data); outb(0, devc -> base + 2); @@ -1469,6 +1454,7 @@ devc->codec_type = 0; devc->ic_type = 0; devc->raw_buf = NULL; + spin_lock_init(&devc->lock); if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) { printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); diff -Nru a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c --- a/sound/oss/sys_timer.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/sys_timer.c Sat Aug 31 15:06:00 2002 @@ -15,6 +15,7 @@ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) */ +#include #include "sound_config.h" static volatile int opened = 0, tmr_running = 0; @@ -26,7 +27,7 @@ static unsigned long prev_event_time; static void poll_def_tmr(unsigned long dummy); - +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static struct timer_list def_tmr = {function: poll_def_tmr}; @@ -62,6 +63,7 @@ if (tmr_running) { + spin_lock(&lock); tmr_ctr++; curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); @@ -70,6 +72,7 @@ next_event_time = (unsigned long) -1; sequencer_timer(0); } + spin_unlock(&lock); } } } @@ -79,15 +82,14 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); tmr_offs = 0; ticks_offs = 0; tmr_ctr = 0; next_event_time = (unsigned long) -1; prev_event_time = 0; curr_ticks = 0; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static int diff -Nru a/sound/oss/trident.c b/sound/oss/trident.c --- a/sound/oss/trident.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/trident.c Sat Aug 31 15:06:06 2002 @@ -2150,14 +2150,14 @@ /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { stop_dac(state); - synchronize_irq(); + synchronize_irq(card->irq); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(state); - synchronize_irq(); + synchronize_irq(card->irq); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; diff -Nru a/sound/oss/uart401.c b/sound/oss/uart401.c --- a/sound/oss/uart401.c Sat Aug 31 15:06:06 2002 +++ b/sound/oss/uart401.c Sat Aug 31 15:06:06 2002 @@ -23,7 +23,7 @@ #include #include - +#include #include "sound_config.h" #include "mpu401.h" @@ -38,6 +38,7 @@ volatile unsigned char input_byte; int my_dev; int share_irq; + spinlock_t lock; } uart401_devc; @@ -152,13 +153,11 @@ * Test for input since pending input seems to block the output. */ - save_flags(flags); - cli(); - + spin_lock_irqsave(&devc->lock,flags); if (input_avail(devc)) uart401_input_loop(devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); /* * Sometimes it takes about 13000 loops before the output becomes ready @@ -222,8 +221,7 @@ int ok, timeout; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); devc->input_byte = 0; @@ -237,7 +235,7 @@ if (uart401_read(devc) == MPU_ACK) ok = 1; - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); } static int reset_uart401(uart401_devc * devc) @@ -320,11 +318,11 @@ devc->input_byte = 0; devc->my_dev = 0; devc->share_irq = 0; + spin_lock_init(&devc->lock); - save_flags(flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); ok = reset_uart401(devc); - restore_flags(flags); + spin_unlock_irqrestore(&devc->lock,flags); if (!ok) goto cleanup_devc; diff -Nru a/sound/oss/uart6850.c b/sound/oss/uart6850.c --- a/sound/oss/uart6850.c Sat Aug 31 15:05:54 2002 +++ b/sound/oss/uart6850.c Sat Aug 31 15:05:54 2002 @@ -23,7 +23,7 @@ #include #include - +#include /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: * added 6850 support, used with COVOX SoundMaster II and custom cards. */ @@ -71,6 +71,7 @@ static int uart6850_irq; static int uart6850_detected; static int my_dev; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static void (*midi_input_intr) (int dev, unsigned char data); static void poll_uart6850(unsigned long dummy); @@ -122,9 +123,7 @@ if (!(uart6850_opened & OPEN_READ)) return; /* Device has been closed */ - save_flags(flags); - cli(); - + spin_lock_irqsave(&lock,flags); if (input_avail()) uart6850_input_loop(); @@ -135,7 +134,7 @@ * Come back later */ - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); } static int uart6850_open(int dev, int mode, @@ -176,13 +175,12 @@ * Test for input since pending input seems to block the output. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); if (input_avail()) uart6850_input_loop(); - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); /* * Sometimes it takes about 13000 loops before the output becomes ready @@ -265,15 +263,14 @@ uart6850_osp = hw_config->osp; uart6850_irq = hw_config->irq; - save_flags(flags); - cli(); + spin_lock_irqsave(&lock,flags); for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* * Wait */ uart6850_cmd(UART_MODE_ON); ok = 1; - restore_flags(flags); + spin_unlock_irqrestore(&lock,flags); conf_printf("6850 Midi Interface", hw_config); diff -Nru a/sound/oss/v_midi.c b/sound/oss/v_midi.c --- a/sound/oss/v_midi.c Sat Aug 31 15:05:55 2002 +++ b/sound/oss/v_midi.c Sat Aug 31 15:05:55 2002 @@ -21,7 +21,7 @@ #include #include - +#include #include "sound_config.h" #include "v_midi.h" @@ -52,15 +52,14 @@ if (devc == NULL) return -(ENXIO); - save_flags (flags); - cli(); + spin_lock_irqsave(&devc->lock,flags); if (devc->opened) { - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); return -(EBUSY); } devc->opened = 1; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); devc->intr_active = 1; @@ -81,12 +80,11 @@ if (devc == NULL) return; - save_flags (flags); - cli (); + spin_lock_irqsave(&devc->lock,flags); devc->intr_active = 0; devc->input_opened = 0; devc->opened = 0; - restore_flags (flags); + spin_unlock_irqrestore(&devc->lock,flags); } static int v_midi_out (int dev, unsigned char midi_byte) @@ -222,6 +220,7 @@ v_devc[0]->opened = v_devc[0]->input_opened = 0; v_devc[0]->intr_active = 0; v_devc[0]->midi_input_intr = NULL; + spin_lock_init(&v_devc[0]->lock); midi_devs[midi1]->devc = v_devc[0]; @@ -242,6 +241,7 @@ v_devc[1]->opened = v_devc[1]->input_opened = 0; v_devc[1]->intr_active = 0; v_devc[1]->midi_input_intr = NULL; + spin_lock_init(&v_devc[1]->lock); midi_devs[midi2]->devc = v_devc[1]; midi_devs[midi2]->converter = &m->s_ops[1]; diff -Nru a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c --- a/sound/oss/via82cxxx_audio.c Sat Aug 31 15:05:55 2002 +++ b/sound/oss/via82cxxx_audio.c Sat Aug 31 15:05:55 2002 @@ -821,7 +821,7 @@ spin_unlock_irq (&card->lock); - synchronize_irq(); + synchronize_irq(card->pdev->irq); DPRINTK ("EXIT\n"); } diff -Nru a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c --- a/sound/oss/vwsnd.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/vwsnd.c Sat Aug 31 15:06:00 2002 @@ -2917,7 +2917,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) { vwsnd_dev_t *devc; - dev_t minor = MINOR(inode->i_rdev); + dev_t minor = minor(inode->i_rdev); int sw_samplefmt; DBGE("(inode=0x%p, file=0x%p)\n", inode, file); @@ -3064,7 +3064,7 @@ INC_USE_COUNT; for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) - if (devc->mixer_minor == MINOR(inode->i_rdev)) + if (devc->mixer_minor == minor(inode->i_rdev)) break; if (devc == NULL) { diff -Nru a/sound/oss/waveartist.c b/sound/oss/waveartist.c --- a/sound/oss/waveartist.c Sat Aug 31 15:05:59 2002 +++ b/sound/oss/waveartist.c Sat Aug 31 15:05:59 2002 @@ -839,6 +839,7 @@ wavnc_info *devc = (wavnc_info *)dev_id; int irqstatus, status; + spin_lock(&waveartist_lock); irqstatus = inb(devc->hw.io_base + IRQSTAT); status = inb(devc->hw.io_base + STATR); @@ -870,6 +871,7 @@ if (irqstatus & 0x2) // We do not use SB mode natively... printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); + spin_unlock(&waveartist_lock); } /* ------------------------------------------------------------------------- @@ -1523,8 +1525,7 @@ *CSR_TIMER1_LOAD = 0x00ffffff; - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); outb(0xFF, 0x201); *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; @@ -1534,7 +1535,7 @@ *CSR_TIMER1_CNTL = 0; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock,flags); volume = 0x00ffffff - *CSR_TIMER1_VALUE; diff -Nru a/sound/oss/wavfront.c b/sound/oss/wavfront.c --- a/sound/oss/wavfront.c Sat Aug 31 15:06:00 2002 +++ b/sound/oss/wavfront.c Sat Aug 31 15:06:00 2002 @@ -76,7 +76,7 @@ #include #include #include - +#include #include #include @@ -274,6 +274,7 @@ wait_queue_head_t interrupt_sleeper; } dev; +static spinlock_t lock=SPIN_LOCK_UNLOCKED; static int detect_wffx(void); static int wffx_ioctl (wavefront_fx_info *); static int wffx_init (void); @@ -2202,12 +2203,12 @@ { unsigned long flags; - save_flags (flags); - cli(); + /* this will not help on SMP - but at least it compiles */ + spin_lock_irqsave(&lock, flags); dev.irq_ok = 0; outb (val,port); interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout); - restore_flags (flags); + spin_unlock_irqrestore(&lock,flags); } static int __init wavefront_hw_reset (void) @@ -2222,8 +2223,6 @@ bits = wavefront_interrupt_bits (dev.irq); printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n"); - - sti (); irq_mask = probe_irq_on (); diff -Nru a/sound/ppc/awacs.c b/sound/ppc/awacs.c --- a/sound/ppc/awacs.c Sat Aug 31 15:06:00 2002 +++ b/sound/ppc/awacs.c Sat Aug 31 15:06:00 2002 @@ -165,10 +165,10 @@ #define AWACS_VOLUME(xname, xreg, xshift) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: 0, \ - info: snd_pmac_awacs_info_volume, \ - get: snd_pmac_awacs_get_volume, \ - put: snd_pmac_awacs_put_volume, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: 0, \ + .info = snd_pmac_awacs_info_volume, \ + .get = snd_pmac_awacs_get_volume, \ + .put = snd_pmac_awacs_put_volume, \ private_value: (xreg) | ((xshift) << 8) } /* @@ -214,10 +214,10 @@ } #define AWACS_SWITCH(xname, xreg, xshift, xinvert) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: 0, \ - info: snd_pmac_boolean_mono_info, \ - get: snd_pmac_awacs_get_switch, \ - put: snd_pmac_awacs_put_switch, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: 0, \ + .info = snd_pmac_boolean_mono_info, \ + .get = snd_pmac_awacs_get_switch, \ + .put = snd_pmac_awacs_put_switch, \ private_value: (xreg) | ((xshift) << 8) | ((xinvert) << 16) } @@ -422,58 +422,58 @@ #define AMP_CH_HD 1 static snd_kcontrol_new_t snd_pmac_awacs_amp_vol[] __initdata = { - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "PC Speaker Playback Volume", - info: snd_pmac_awacs_info_volume_amp, - get: snd_pmac_awacs_get_volume_amp, - put: snd_pmac_awacs_put_volume_amp, - private_value: AMP_CH_SPK, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PC Speaker Playback Volume", + .info = snd_pmac_awacs_info_volume_amp, + .get = snd_pmac_awacs_get_volume_amp, + .put = snd_pmac_awacs_put_volume_amp, + .private_value = AMP_CH_SPK, }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Headphone Playback Volume", - info: snd_pmac_awacs_info_volume_amp, - get: snd_pmac_awacs_get_volume_amp, - put: snd_pmac_awacs_put_volume_amp, - private_value: AMP_CH_HD, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Volume", + .info = snd_pmac_awacs_info_volume_amp, + .get = snd_pmac_awacs_get_volume_amp, + .put = snd_pmac_awacs_put_volume_amp, + .private_value = AMP_CH_HD, }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Tone Control - Bass", - info: snd_pmac_awacs_info_tone_amp, - get: snd_pmac_awacs_get_tone_amp, - put: snd_pmac_awacs_put_tone_amp, - private_value: 0, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Tone Control - Bass", + .info = snd_pmac_awacs_info_tone_amp, + .get = snd_pmac_awacs_get_tone_amp, + .put = snd_pmac_awacs_put_tone_amp, + .private_value = 0, }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Tone Control - Treble", - info: snd_pmac_awacs_info_tone_amp, - get: snd_pmac_awacs_get_tone_amp, - put: snd_pmac_awacs_put_tone_amp, - private_value: 1, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Tone Control - Treble", + .info = snd_pmac_awacs_info_tone_amp, + .get = snd_pmac_awacs_get_tone_amp, + .put = snd_pmac_awacs_put_tone_amp, + .private_value = 1, }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Amp Master Playback Volume", - info: snd_pmac_awacs_info_master_amp, - get: snd_pmac_awacs_get_master_amp, - put: snd_pmac_awacs_put_master_amp, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Amp Master Playback Volume", + .info = snd_pmac_awacs_info_master_amp, + .get = snd_pmac_awacs_get_master_amp, + .put = snd_pmac_awacs_put_master_amp, }, }; static snd_kcontrol_new_t snd_pmac_awacs_amp_hp_sw __initdata = { - iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Headphone Playback Switch", - info: snd_pmac_boolean_stereo_info, - get: snd_pmac_awacs_get_switch_amp, - put: snd_pmac_awacs_put_switch_amp, - private_value: AMP_CH_HD, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Switch", + .info = snd_pmac_boolean_stereo_info, + .get = snd_pmac_awacs_get_switch_amp, + .put = snd_pmac_awacs_put_switch_amp, + .private_value = AMP_CH_HD, }; static snd_kcontrol_new_t snd_pmac_awacs_amp_spk_sw __initdata = { - iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "PC Speaker Playback Switch", - info: snd_pmac_boolean_stereo_info, - get: snd_pmac_awacs_get_switch_amp, - put: snd_pmac_awacs_put_switch_amp, - private_value: AMP_CH_SPK, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PC Speaker Playback Switch", + .info = snd_pmac_boolean_stereo_info, + .get = snd_pmac_awacs_get_switch_amp, + .put = snd_pmac_awacs_put_switch_amp, + .private_value = AMP_CH_SPK, }; #endif /* PMAC_AMP_AVAIL */ @@ -556,11 +556,11 @@ }; static snd_kcontrol_new_t snd_pmac_screamer_mic_boost[] __initdata = { - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Mic Boost", - info: snd_pmac_screamer_mic_boost_info, - get: snd_pmac_screamer_mic_boost_get, - put: snd_pmac_screamer_mic_boost_put, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Boost", + .info = snd_pmac_screamer_mic_boost_info, + .get = snd_pmac_screamer_mic_boost_get, + .put = snd_pmac_screamer_mic_boost_put, }, }; diff -Nru a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c --- a/sound/ppc/burgundy.c Sat Aug 31 15:05:59 2002 +++ b/sound/ppc/burgundy.c Sat Aug 31 15:05:59 2002 @@ -196,10 +196,10 @@ } #define BURGUNDY_VOLUME(xname, xindex, addr, shift) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ - info: snd_pmac_burgundy_info_volume,\ - get: snd_pmac_burgundy_get_volume,\ - put: snd_pmac_burgundy_put_volume,\ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ + .info = snd_pmac_burgundy_info_volume,\ + .get = snd_pmac_burgundy_get_volume,\ + .put = snd_pmac_burgundy_put_volume,\ private_value: ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) } /* lineout/speaker */ @@ -245,10 +245,10 @@ } #define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ - info: snd_pmac_burgundy_info_switch_out,\ - get: snd_pmac_burgundy_get_switch_out,\ - put: snd_pmac_burgundy_put_switch_out,\ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ + .info = snd_pmac_burgundy_info_switch_out,\ + .get = snd_pmac_burgundy_get_switch_out,\ + .put = snd_pmac_burgundy_put_switch_out,\ private_value: ((lmask) | ((rmask) << 8) | ((stereo) << 24)) } /* line/speaker output volume */ @@ -295,10 +295,10 @@ } #define BURGUNDY_OUTPUT_VOLUME(xname, xindex, addr, stereo) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ - info: snd_pmac_burgundy_info_volume_out,\ - get: snd_pmac_burgundy_get_volume_out,\ - put: snd_pmac_burgundy_put_volume_out,\ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\ + .info = snd_pmac_burgundy_info_volume_out,\ + .get = snd_pmac_burgundy_get_volume_out,\ + .put = snd_pmac_burgundy_put_volume_out,\ private_value: (ADDR2BASE(addr) | ((stereo) << 24)) } static snd_kcontrol_new_t snd_pmac_burgundy_mixers[] __initdata = { diff -Nru a/sound/ppc/daca.c b/sound/ppc/daca.c --- a/sound/ppc/daca.c Sat Aug 31 15:05:54 2002 +++ b/sound/ppc/daca.c Sat Aug 31 15:05:54 2002 @@ -197,22 +197,22 @@ } static snd_kcontrol_new_t daca_mixers[] = { - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Deemphasis Switch", - info: daca_info_deemphasis, - get: daca_get_deemphasis, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Deemphasis Switch", + .info = daca_info_deemphasis, + .get = daca_get_deemphasis, put: daca_put_deemphasis }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Master Playback Volume", - info: daca_info_volume, - get: daca_get_volume, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = daca_info_volume, + .get = daca_get_volume, put: daca_put_volume }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Power Amplifier Switch", - info: daca_info_amp, - get: daca_get_amp, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Power Amplifier Switch", + .info = daca_info_amp, + .get = daca_get_amp, put: daca_put_amp }, }; diff -Nru a/sound/ppc/keywest.c b/sound/ppc/keywest.c --- a/sound/ppc/keywest.c Sat Aug 31 15:05:59 2002 +++ b/sound/ppc/keywest.c Sat Aug 31 15:05:59 2002 @@ -40,11 +40,11 @@ static int keywest_detach_client(struct i2c_client *client); struct i2c_driver keywest_driver = { - name: "PMac Keywest Audio", - id: I2C_DRIVERID_KEYWEST, - flags: I2C_DF_NOTIFY, - attach_adapter: &keywest_attach_adapter, - detach_client: &keywest_detach_client, + .name = "PMac Keywest Audio", + .id = I2C_DRIVERID_KEYWEST, + .flags = I2C_DF_NOTIFY, + .attach_adapter = &keywest_attach_adapter, + .detach_client = &keywest_detach_client, }; diff -Nru a/sound/ppc/pmac.c b/sound/ppc/pmac.c --- a/sound/ppc/pmac.c Sat Aug 31 15:06:00 2002 +++ b/sound/ppc/pmac.c Sat Aug 31 15:06:00 2002 @@ -442,17 +442,17 @@ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME), - formats: SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, - rates: SNDRV_PCM_RATE_8000_44100, - rate_min: 7350, - rate_max: 44100, - channels_min: 2, - channels_max: 2, - buffer_bytes_max: 32768, - period_bytes_min: 256, - period_bytes_max: 16384, - periods_min: 1, - periods_max: PMAC_MAX_FRAGS, + .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_44100, + .rate_min = 7350, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 256, + .period_bytes_max = 16384, + .periods_min = 1, + .periods_max = PMAC_MAX_FRAGS, }; static snd_pcm_hardware_t snd_pmac_capture = @@ -461,17 +461,17 @@ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME), - formats: SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, - rates: SNDRV_PCM_RATE_8000_44100, - rate_min: 7350, - rate_max: 44100, - channels_min: 2, - channels_max: 2, - buffer_bytes_max: 32768, - period_bytes_min: 256, - period_bytes_max: 16384, - periods_min: 1, - periods_max: PMAC_MAX_FRAGS, + .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_44100, + .rate_min = 7350, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 256, + .period_bytes_max = 16384, + .periods_min = 1, + .periods_max = PMAC_MAX_FRAGS, }; @@ -628,25 +628,25 @@ */ static snd_pcm_ops_t snd_pmac_playback_ops = { - open: snd_pmac_playback_open, - close: snd_pmac_playback_close, - ioctl: snd_pcm_lib_ioctl, - hw_params: snd_pmac_pcm_hw_params, - hw_free: snd_pmac_pcm_hw_free, - prepare: snd_pmac_playback_prepare, - trigger: snd_pmac_playback_trigger, - pointer: snd_pmac_playback_pointer, + .open = snd_pmac_playback_open, + .close = snd_pmac_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_pmac_pcm_hw_params, + .hw_free = snd_pmac_pcm_hw_free, + .prepare = snd_pmac_playback_prepare, + .trigger = snd_pmac_playback_trigger, + .pointer = snd_pmac_playback_pointer, }; static snd_pcm_ops_t snd_pmac_capture_ops = { - open: snd_pmac_capture_open, - close: snd_pmac_capture_close, - ioctl: snd_pcm_lib_ioctl, - hw_params: snd_pmac_pcm_hw_params, - hw_free: snd_pmac_pcm_hw_free, - prepare: snd_pmac_capture_prepare, - trigger: snd_pmac_capture_trigger, - pointer: snd_pmac_capture_pointer, + .open = snd_pmac_capture_open, + .close = snd_pmac_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_pmac_pcm_hw_params, + .hw_free = snd_pmac_pcm_hw_free, + .prepare = snd_pmac_capture_prepare, + .trigger = snd_pmac_capture_trigger, + .pointer = snd_pmac_capture_pointer, }; static void pmac_pcm_free(snd_pcm_t *pcm) @@ -871,12 +871,12 @@ } static snd_kcontrol_new_t snd_pmac_beep_mixer = { - iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Beep Playback Volume", - index: 0, - info: snd_pmac_info_beep, - get: snd_pmac_get_beep, - put: snd_pmac_put_beep, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Beep Playback Volume", + .index = 0, + .info = snd_pmac_info_beep, + .get = snd_pmac_get_beep, + .put = snd_pmac_put_beep, }; static void snd_pmac_beep_free(snd_kcontrol_t *control) @@ -1271,17 +1271,17 @@ } static snd_kcontrol_new_t auto_mute_controls[] __initdata = { - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Auto Mute Switch", - info: snd_pmac_boolean_mono_info, - get: pmac_auto_mute_get, - put: pmac_auto_mute_put, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto Mute Switch", + .info = snd_pmac_boolean_mono_info, + .get = pmac_auto_mute_get, + .put = pmac_auto_mute_put, }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Headphone Detection", - access: SNDRV_CTL_ELEM_ACCESS_READ, - info: snd_pmac_boolean_mono_info, - get: pmac_hp_detect_get, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Detection", + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_pmac_boolean_mono_info, + .get = pmac_hp_detect_get, }, }; @@ -1306,7 +1306,7 @@ struct device_node *np; int i, err; static snd_device_ops_t ops = { - dev_free: snd_pmac_dev_free, + .dev_free = snd_pmac_dev_free, }; snd_runtime_check(chip_return, return -EINVAL); diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c --- a/sound/ppc/tumbler.c Sat Aug 31 15:05:54 2002 +++ b/sound/ppc/tumbler.c Sat Aug 31 15:05:54 2002 @@ -410,46 +410,46 @@ } static struct tumbler_mono_vol tumbler_pcm_vol_info = { - index: VOL_IDX_PCM, - reg: TAS_REG_PCM, - bytes: 3, - max: number_of(mixer_volume_table), - table: mixer_volume_table, + .index = VOL_IDX_PCM, + .reg = TAS_REG_PCM, + .bytes = 3, + .max = number_of(mixer_volume_table), + .table = mixer_volume_table, }; #if 0 // for what? static struct tumbler_mono_vol tumbler_altpcm_vol_info = { - index: VOL_IDX_ALTPCM, - reg: TAS_REG_INPUT2, - bytes: 3, - max: number_of(mixer_volume_table), - table: mixer_volume_table, + .index = VOL_IDX_ALTPCM, + .reg = TAS_REG_INPUT2, + .bytes = 3, + .max = number_of(mixer_volume_table), + .table = mixer_volume_table, }; #endif static struct tumbler_mono_vol tumbler_bass_vol_info = { - index: VOL_IDX_BASS, - reg: TAS_REG_BASS, - bytes: 1, - max: number_of(bass_volume_table), - table: bass_volume_table, + .index = VOL_IDX_BASS, + .reg = TAS_REG_BASS, + .bytes = 1, + .max = number_of(bass_volume_table), + .table = bass_volume_table, }; static struct tumbler_mono_vol tumbler_treble_vol_info = { - index: VOL_IDX_TREBLE, - reg: TAS_REG_TREBLE, - bytes: 1, - max: number_of(treble_volume_table), - table: treble_volume_table, + .index = VOL_IDX_TREBLE, + .reg = TAS_REG_TREBLE, + .bytes = 1, + .max = number_of(treble_volume_table), + .table = treble_volume_table, }; #define DEFINE_MONO(xname,type) { \ - iface: SNDRV_CTL_ELEM_IFACE_MIXER,\ - name: xname, \ - info: tumbler_info_mono, \ - get: tumbler_get_mono, \ - put: tumbler_put_mono, \ - private_value: (unsigned long)(&tumbler_##type##_vol_info), \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ + .name = xname, \ + .info = tumbler_info_mono, \ + .get = tumbler_get_mono, \ + .put = tumbler_put_mono, \ + .private_value = (unsigned long)(&tumbler_##type##_vol_info), \ } /* @@ -491,51 +491,51 @@ /* */ static snd_kcontrol_new_t tumbler_mixers[] __initdata = { - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Master Playback Volume", - info: tumbler_info_master_volume, - get: tumbler_get_master_volume, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = tumbler_info_master_volume, + .get = tumbler_get_master_volume, put: tumbler_put_master_volume }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Master Playback Switch", - info: snd_pmac_boolean_stereo_info, - get: tumbler_get_master_switch, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_pmac_boolean_stereo_info, + .get = tumbler_get_master_switch, put: tumbler_put_master_switch }, DEFINE_MONO("Tone Control - Bass", bass), DEFINE_MONO("Tone Control - Treble", treble), DEFINE_MONO("PCM Playback Volume", pcm), // DEFINE_MONO("Mixer2 Playback Volume", altpcm), - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "DRC Switch", - info: snd_pmac_boolean_mono_info, - get: tumbler_get_drc_switch, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Switch", + .info = snd_pmac_boolean_mono_info, + .get = tumbler_get_drc_switch, put: tumbler_put_drc_switch }, - { iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "DRC Range", - info: tumbler_info_drc_value, - get: tumbler_get_drc_value, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Range", + .info = tumbler_info_drc_value, + .get = tumbler_get_drc_value, put: tumbler_put_drc_value }, }; static snd_kcontrol_new_t tumbler_hp_sw __initdata = { - iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "Headphone Playback Switch", - info: snd_pmac_boolean_mono_info, - get: tumbler_get_mute_switch, - put: tumbler_put_mute_switch, - private_value: TUMBLER_MUTE_HP, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Switch", + .info = snd_pmac_boolean_mono_info, + .get = tumbler_get_mute_switch, + .put = tumbler_put_mute_switch, + .private_value = TUMBLER_MUTE_HP, }; static snd_kcontrol_new_t tumbler_speaker_sw __initdata = { - iface: SNDRV_CTL_ELEM_IFACE_MIXER, - name: "PC Speaker Playback Switch", - info: snd_pmac_boolean_mono_info, - get: tumbler_get_mute_switch, - put: tumbler_put_mute_switch, - private_value: TUMBLER_MUTE_AMP, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PC Speaker Playback Switch", + .info = snd_pmac_boolean_mono_info, + .get = tumbler_get_mute_switch, + .put = tumbler_put_mute_switch, + .private_value = TUMBLER_MUTE_AMP, }; #ifdef PMAC_SUPPORT_AUTOMUTE