Merge branch 'upstream-linus' of git://oss.oracle.com/home/sourcebo/git/ocfs2
authorLinus Torvalds <torvalds@g5.osdl.org>
Fri, 3 Feb 2006 23:21:40 +0000 (15:21 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 3 Feb 2006 23:21:40 +0000 (15:21 -0800)
152 files changed:
Documentation/cputopology.txt [new file with mode: 0644]
Documentation/driver-model/overview.txt
Documentation/networking/ip-sysctl.txt
Documentation/parport-lowlevel.txt
Documentation/pci-error-recovery.txt
MAINTAINERS
arch/i386/oprofile/backtrace.c
arch/ia64/kernel/topology.c
arch/s390/kernel/compat_wrapper.S
arch/v850/kernel/simcons.c
arch/xtensa/platform-iss/console.c
drivers/base/Makefile
drivers/base/topology.c [new file with mode: 0644]
drivers/block/umem.c
drivers/char/cyclades.c
drivers/char/esp.c
drivers/char/ip2/i2cmd.c
drivers/char/ip2main.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/rio/cirrus.h
drivers/char/rio/defaults.h
drivers/char/rio/link.h
drivers/char/rio/list.h
drivers/char/rio/parmmap.h
drivers/char/rio/phb.h
drivers/char/rio/pkt.h
drivers/char/rio/qbuf.h
drivers/char/rio/riotypes.h
drivers/char/rio/rup.h
drivers/char/rio/sam.h
drivers/char/rocket.c
drivers/char/sx.c
drivers/char/tty_io.c
drivers/char/watchdog/sbc_epx_c3.c
drivers/edac/Kconfig
drivers/edac/e752x_edac.c
drivers/edac/edac_mc.c
drivers/ide/Kconfig
drivers/ide/ide-disk.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it821x.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/isdn/hisax/hisax.h
drivers/isdn/sc/ioctl.c
drivers/md/md.c
drivers/md/raid0.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6main.c
drivers/message/i2o/core.h
drivers/message/i2o/pci.c
drivers/mtd/maps/dc21285.c
drivers/net/3c59x.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/parport/Kconfig
drivers/parport/Makefile
drivers/parport/ieee1284.c
drivers/parport/parport_ip32.c [new file with mode: 0644]
drivers/parport/parport_serial.c
drivers/parport/probe.c
drivers/s390/block/Kconfig
drivers/s390/block/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c [new file with mode: 0644]
drivers/s390/block/dasd_int.h
drivers/s390/cio/chsc.h
drivers/serial/Kconfig
drivers/serial/jsm/jsm.h
drivers/serial/jsm/jsm_driver.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/mcfserial.c
drivers/telephony/ixj.c
fs/9p/conv.c
fs/9p/mux.c
fs/9p/vfs_inode.c
fs/buffer.c
fs/dcache.c
fs/direct-io.c
fs/ext2/acl.c
fs/ext2/ialloc.c
fs/ext2/super.c
fs/ext3/acl.c
fs/fat/file.c
fs/fat/misc.c
fs/fcntl.c
fs/jffs/intrep.c
fs/libfs.c
fs/proc/proc_misc.c
fs/quota_v2.c
fs/reiserfs/super.c
fs/udf/balloc.c
fs/udf/namei.c
fs/ufs/inode.c
fs/ufs/super.c
fs/ufs/truncate.c
include/asm-cris/bitops.h
include/asm-frv/bitops.h
include/asm-h8300/bitops.h
include/asm-i386/topology.h
include/asm-ia64/ide.h
include/asm-ia64/topology.h
include/asm-s390/dasd.h
include/asm-s390/io.h
include/asm-s390/timer.h
include/asm-v850/bitops.h
include/asm-x86_64/kexec.h
include/asm-x86_64/topology.h
include/linux/bitops.h
include/linux/dcache.h
include/linux/elfcore.h
include/linux/i2o.h
include/linux/ide.h
include/linux/kbd_kern.h
include/linux/list.h
include/linux/parport.h
include/linux/quotaops.h
include/linux/rcupdate.h
include/linux/suspend.h
include/linux/tty.h
include/linux/tty_flip.h
include/linux/ufs_fs.h
include/linux/ufs_fs_sb.h
include/net/sctp/structs.h
include/net/sock.h
init/Kconfig
kernel/cpuset.c
kernel/kprobes.c
kernel/module.c
kernel/signal.c
kernel/time.c
lib/int_sqrt.c
lib/ts_bm.c
net/802/psnap.c
net/Kconfig
net/ipv4/icmp.c
net/ipv4/multipath_wrandom.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/sctp/output.c
net/sctp/outqueue.c
security/keys/keyctl.c

diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
new file mode 100644 (file)
index 0000000..ff280e2
--- /dev/null
@@ -0,0 +1,41 @@
+
+Export cpu topology info by sysfs. Items (attributes) are similar
+to /proc/cpuinfo.
+
+1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:
+represent the physical package id of  cpu X;
+2) /sys/devices/system/cpu/cpuX/topology/core_id:
+represent the cpu core id to cpu X;
+3) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
+represent the thread siblings to cpu X in the same core;
+4) /sys/devices/system/cpu/cpuX/topology/core_siblings:
+represent the thread siblings to cpu X in the same physical package;
+
+To implement it in an architecture-neutral way, a new source file,
+driver/base/topology.c, is to export the 5 attributes.
+
+If one architecture wants to support this feature, it just needs to
+implement 4 defines, typically in file include/asm-XXX/topology.h.
+The 4 defines are:
+#define topology_physical_package_id(cpu)
+#define topology_core_id(cpu)
+#define topology_thread_siblings(cpu)
+#define topology_core_siblings(cpu)
+
+The type of **_id is int.
+The type of siblings is cpumask_t.
+
+To be consistent on all architectures, the 4 attributes should have
+deafult values if their values are unavailable. Below is the rule.
+1) physical_package_id: If cpu has no physical package id, -1 is the
+default value.
+2) core_id: If cpu doesn't support multi-core, its core id is 0.
+3) thread_siblings: Just include itself, if the cpu doesn't support
+HT/multi-thread.
+4) core_siblings: Just include itself, if the cpu doesn't support
+multi-core and HT/Multi-thread.
+
+So be careful when declaring the 4 defines in include/asm-XXX/topology.h.
+
+If an attribute isn't defined on an architecture, it won't be exported.
+
index 44662735cf81822a4387630b7317e98bdb3ab019..ac4a7a737e430207a22be59b2d817b309eefa828 100644 (file)
@@ -1,50 +1,43 @@
 The Linux Kernel Device Model
 
-Patrick Mochel <mochel@osdl.org>
+Patrick Mochel <mochel@digitalimplant.org>
 
-26 August 2002
+Drafted 26 August 2002
+Updated 31 January 2006
 
 
 Overview
 ~~~~~~~~
 
-This driver model is a unification of all the current, disparate driver models
-that are currently in the kernel. It is intended to augment the
+The Linux Kernel Driver Model is a unification of all the disparate driver
+models that were previously used in the kernel. It is intended to augment the
 bus-specific drivers for bridges and devices by consolidating a set of data
 and operations into globally accessible data structures.
 
-Current driver models implement some sort of tree-like structure (sometimes
-just a list) for the devices they control. But, there is no linkage between
-the different bus types.
+Traditional driver models implemented some sort of tree-like structure
+(sometimes just a list) for the devices they control. There wasn't any
+uniformity across the different bus types.
 
-A common data structure can provide this linkage with little overhead: when a
-bus driver discovers a particular device, it can insert it into the global
-tree as well as its local tree. In fact, the local tree becomes just a subset
-of the global tree.
-
-Common data fields can also be moved out of the local bus models into the
-global model. Some of the manipulations of these fields can also be
-consolidated. Most likely, manipulation functions will become a set
-of helper functions, which the bus drivers wrap around to include any
-bus-specific items.
-
-The common device and bridge interface currently reflects the goals of the
-modern PC: namely the ability to do seamless Plug and Play, power management,
-and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures
-us that any device in the system may fit any of these criteria.)
-
-In reality, not every bus will be able to support such operations. But, most
-buses will support a majority of those operations, and all future buses will.
-In other words, a bus that doesn't support an operation is the exception,
-instead of the other way around.
+The current driver model provides a comon, uniform data model for describing
+a bus and the devices that can appear under the bus. The unified bus
+model includes a set of common attributes which all busses carry, and a set
+of common callbacks, such as device discovery during bus probing, bus
+shutdown, bus power management, etc.
 
+The common device and bridge interface reflects the goals of the modern
+computer: namely the ability to do seamless device "plug and play", power
+management, and hot plug. In particular, the model dictated by Intel and
+Microsoft (namely ACPI) ensures that almost every device on almost any bus
+on an x86-compatible system can work within this paradigm.  Of course,
+not every bus is able to support all such operations, although most
+buses support a most of those operations.
 
 
 Downstream Access
 ~~~~~~~~~~~~~~~~~
 
 Common data fields have been moved out of individual bus layers into a common
-data structure. But, these fields must still be accessed by the bus layers,
+data structure. These fields must still be accessed by the bus layers,
 and sometimes by the device-specific drivers.
 
 Other bus layers are encouraged to do what has been done for the PCI layer.
@@ -53,7 +46,7 @@ struct pci_dev now looks like this:
 struct pci_dev {
        ...
 
-       struct device device;
+       struct device dev;
 };
 
 Note first that it is statically allocated. This means only one allocation on
@@ -64,9 +57,9 @@ the two.
 
 The PCI bus layer freely accesses the fields of struct device. It knows about
 the structure of struct pci_dev, and it should know the structure of struct
-device. PCI devices that have been converted generally do not touch the fields
-of struct device. More precisely, device-specific drivers should not touch
-fields of struct device unless there is a strong compelling reason to do so.
+device. Individual PCI device drivers that have been converted the the current
+driver model generally do not and should not touch the fields of struct device,
+unless there is a strong compelling reason to do so.
 
 This abstraction is prevention of unnecessary pain during transitional phases.
 If the name of the field changes or is removed, then every downstream driver
index 2b7cf19a06adc03435b84a04ae1dee46aae7e9a1..26364d06ae927f0262e4cbccda03d1ad2cca35ba 100644 (file)
@@ -427,6 +427,23 @@ icmp_ignore_bogus_error_responses - BOOLEAN
        will avoid log file clutter.
        Default: FALSE
 
+icmp_errors_use_inbound_ifaddr - BOOLEAN
+
+       If zero, icmp error messages are sent with the primary address of
+       the exiting interface.
+       If non-zero, the message will be sent with the primary address of
+       the interface that received the packet that caused the icmp error.
+       This is the behaviour network many administrators will expect from
+       a router. And it can make debugging complicated network layouts
+       much easier. 
+
+       Note that if no primary address exists for the interface selected,
+       then the primary address of the first non-loopback interface that
+       has one will be used regarldess of this setting.
+
+       Default: 0
+
 igmp_max_memberships - INTEGER
        Change the maximum number of multicast groups we can subscribe to.
        Default: 20
index 1d40008a1926f3ee112707476f2bb23fb4637120..8f2302415eff90b0df7aa655f132f9567ff9ccd7 100644 (file)
@@ -1068,7 +1068,7 @@ SYNOPSIS
 
 struct parport_operations {
        ...
-       void (*write_status) (struct parport *port, unsigned char s);
+       void (*write_control) (struct parport *port, unsigned char s);
        ...
 };
 
@@ -1097,9 +1097,9 @@ SYNOPSIS
 
 struct parport_operations {
        ...
-       void (*frob_control) (struct parport *port,
-                             unsigned char mask,
-                             unsigned char val);
+       unsigned char (*frob_control) (struct parport *port,
+                                      unsigned char mask,
+                                      unsigned char val);
        ...
 };
 
index d089967e4948b730b9f48084172018c2b1efb0f8..634d3e5b575691baaa55167c019cea3875c4920f 100644 (file)
 
                        PCI Error Recovery
                        ------------------
-                         May 31, 2005
-
-               Current document maintainer:
-           Linas Vepstas <linas@austin.ibm.com>
-
-
-Some PCI bus controllers are able to detect certain "hard" PCI errors
-on the bus, such as parity errors on the data and address busses, as
-well as SERR and PERR errors.  These chipsets are then able to disable
-I/O to/from the affected device, so that, for example, a bad DMA
-address doesn't end up corrupting system memory.  These same chipsets
-are also able to reset the affected PCI device, and return it to
-working condition.  This document describes a generic API form
-performing error recovery.
-
-The core idea is that after a PCI error has been detected, there must
-be a way for the kernel to coordinate with all affected device drivers
-so that the pci card can be made operational again, possibly after
-performing a full electrical #RST of the PCI card.  The API below
-provides a generic API for device drivers to be notified of PCI
-errors, and to be notified of, and respond to, a reset sequence.
-
-Preliminary sketch of API, cut-n-pasted-n-modified email from
-Ben Herrenschmidt, circa 5 april 2005
+                        February 2, 2006
+
+                 Current document maintainer:
+             Linas Vepstas <linas@austin.ibm.com>
+
+
+Many PCI bus controllers are able to detect a variety of hardware
+PCI errors on the bus, such as parity errors on the data and address
+busses, as well as SERR and PERR errors.  Some of the more advanced
+chipsets are able to deal with these errors; these include PCI-E chipsets,
+and the PCI-host bridges found on IBM Power4 and Power5-based pSeries
+boxes. A typical action taken is to disconnect the affected device,
+halting all I/O to it.  The goal of a disconnection is to avoid system
+corruption; for example, to halt system memory corruption due to DMA's
+to "wild" addresses. Typically, a reconnection mechanism is also
+offered, so that the affected PCI device(s) are reset and put back
+into working condition. The reset phase requires coordination
+between the affected device drivers and the PCI controller chip.
+This document describes a generic API for notifying device drivers
+of a bus disconnection, and then performing error recovery.
+This API is currently implemented in the 2.6.16 and later kernels.
+
+Reporting and recovery is performed in several steps. First, when
+a PCI hardware error has resulted in a bus disconnect, that event
+is reported as soon as possible to all affected device drivers,
+including multiple instances of a device driver on multi-function
+cards. This allows device drivers to avoid deadlocking in spinloops,
+waiting for some i/o-space register to change, when it never will.
+It also gives the drivers a chance to defer incoming I/O as
+needed.
+
+Next, recovery is performed in several stages. Most of the complexity
+is forced by the need to handle multi-function devices, that is,
+devices that have multiple device drivers associated with them.
+In the first stage, each driver is allowed to indicate what type
+of reset it desires, the choices being a simple re-enabling of I/O
+or requesting a hard reset (a full electrical #RST of the PCI card).
+If any driver requests a full reset, that is what will be done.
+
+After a full reset and/or a re-enabling of I/O, all drivers are
+again notified, so that they may then perform any device setup/config
+that may be required.  After these have all completed, a final
+"resume normal operations" event is sent out.
+
+The biggest reason for choosing a kernel-based implementation rather
+than a user-space implementation was the need to deal with bus
+disconnects of PCI devices attached to storage media, and, in particular,
+disconnects from devices holding the root file system.  If the root
+file system is disconnected, a user-space mechanism would have to go
+through a large number of contortions to complete recovery. Almost all
+of the current Linux file systems are not tolerant of disconnection
+from/reconnection to their underlying block device. By contrast,
+bus errors are easy to manage in the device driver. Indeed, most
+device drivers already handle very similar recovery procedures;
+for example, the SCSI-generic layer already provides significant
+mechanisms for dealing with SCSI bus errors and SCSI bus resets.
+
+
+Detailed Design
+---------------
+Design and implementation details below, based on a chain of
+public email discussions with Ben Herrenschmidt, circa 5 April 2005.
 
 The error recovery API support is exposed to the driver in the form of
 a structure of function pointers pointed to by a new field in struct
-pci_driver. The absence of this pointer in pci_driver denotes an
-"non-aware" driver, behaviour on these is platform dependant.
-Platforms like ppc64 can try to simulate pci hotplug remove/add.
-
-The definition of "pci_error_token" is not covered here. It is based on
-Seto's work on the synchronous error detection. We still need to define
-functions for extracting infos out of an opaque error token. This is
-separate from this API.
+pci_driver. A driver that fails to provide the structure is "non-aware",
+and the actual recovery steps taken are platform dependent.  The
+arch/powerpc implementation will simulate a PCI hotplug remove/add.
 
 This structure has the form:
-
 struct pci_error_handlers
 {
-       int (*error_detected)(struct pci_dev *dev, pci_error_token error);
+       int (*error_detected)(struct pci_dev *dev, enum pci_channel_state);
        int (*mmio_enabled)(struct pci_dev *dev);
-       int (*resume)(struct pci_dev *dev);
        int (*link_reset)(struct pci_dev *dev);
        int (*slot_reset)(struct pci_dev *dev);
+       void (*resume)(struct pci_dev *dev);
 };
 
-A driver doesn't have to implement all of these callbacks. The
-only mandatory one is error_detected(). If a callback is not
-implemented, the corresponding feature is considered unsupported.
-For example, if mmio_enabled() and resume() aren't there, then the
-driver is assumed as not doing any direct recovery and requires
+The possible channel states are:
+enum pci_channel_state {
+       pci_channel_io_normal,  /* I/O channel is in normal state */
+       pci_channel_io_frozen,  /* I/O to channel is blocked */
+       pci_channel_io_perm_failure, /* PCI card is dead */
+};
+
+Possible return values are:
+enum pci_ers_result {
+       PCI_ERS_RESULT_NONE,        /* no result/none/not supported in device driver */
+       PCI_ERS_RESULT_CAN_RECOVER, /* Device driver can recover without slot reset */
+       PCI_ERS_RESULT_NEED_RESET,  /* Device driver wants slot to be reset. */
+       PCI_ERS_RESULT_DISCONNECT,  /* Device has completely failed, is unrecoverable */
+       PCI_ERS_RESULT_RECOVERED,   /* Device driver is fully recovered and operational */
+};
+
+A driver does not have to implement all of these callbacks; however,
+if it implements any, it must implement error_detected(). If a callback
+is not implemented, the corresponding feature is considered unsupported.
+For example, if mmio_enabled() and resume() aren't there, then it
+is assumed that the driver is not doing any direct recovery and requires
 a reset. If link_reset() is not implemented, the card is assumed as
-not caring about link resets, in which case, if recover is supported,
-the core can try recover (but not slot_reset() unless it really did
-reset the slot). If slot_reset() is not supported, link_reset() can
-be called instead on a slot reset.
-
-At first, the call will always be :
-
-       1) error_detected()
-
-       Error detected. This is sent once after an error has been detected. At
-this point, the device might not be accessible anymore depending on the
-platform (the slot will be isolated on ppc64). The driver may already
-have "noticed" the error because of a failing IO, but this is the proper
-"synchronisation point", that is, it gives a chance to the driver to
-cleanup, waiting for pending stuff (timers, whatever, etc...) to
-complete; it can take semaphores, schedule, etc... everything but touch
-the device. Within this function and after it returns, the driver
+not care about link resets. Typically a driver will want to know about
+a slot_reset().
+
+The actual steps taken by a platform to recover from a PCI error
+event will be platform-dependent, but will follow the general
+sequence described below.
+
+STEP 0: Error Event
+-------------------
+PCI bus error is detect by the PCI hardware.  On powerpc, the slot
+is isolated, in that all I/O is blocked: all reads return 0xffffffff,
+all writes are ignored.
+
+
+STEP 1: Notification
+--------------------
+Platform calls the error_detected() callback on every instance of
+every driver affected by the error.
+
+At this point, the device might not be accessible anymore, depending on
+the platform (the slot will be isolated on powerpc). The driver may
+already have "noticed" the error because of a failing I/O, but this
+is the proper "synchronization point", that is, it gives the driver
+a chance to cleanup, waiting for pending stuff (timers, whatever, etc...)
+to complete; it can take semaphores, schedule, etc... everything but
+touch the device. Within this function and after it returns, the driver
 shouldn't do any new IOs. Called in task context. This is sort of a
 "quiesce" point. See note about interrupts at the end of this doc.
 
-       Result codes:
-               - PCIERR_RESULT_CAN_RECOVER:
-                 Driever returns this if it thinks it might be able to recover
+All drivers participating in this system must implement this call.
+The driver must return one of the following result codes:
+               - PCI_ERS_RESULT_CAN_RECOVER:
+                 Driver returns this if it thinks it might be able to recover
                  the HW by just banging IOs or if it wants to be given
-                 a chance to extract some diagnostic informations (see
-                 below).
-               - PCIERR_RESULT_NEED_RESET:
-                 Driver returns this if it thinks it can't recover unless the
-                 slot is reset.
-               - PCIERR_RESULT_DISCONNECT:
-                 Return this if driver thinks it won't recover at all,
-                 (this will detach the driver ? or just leave it
-                 dangling ? to be decided)
-
-So at this point, we have called error_detected() for all drivers
-on the segment that had the error. On ppc64, the slot is isolated. What
-happens now typically depends on the result from the drivers. If all
-drivers on the segment/slot return PCIERR_RESULT_CAN_RECOVER, we would
-re-enable IOs on the slot (or do nothing special if the platform doesn't
-isolate slots) and call 2). If not and we can reset slots, we go to 4),
-if neither, we have a dead slot. If it's an hotplug slot, we might
-"simulate" reset by triggering HW unplug/replug though.
-
->>> Current ppc64 implementation assumes that a device driver will
->>> *not* schedule or semaphore in this routine; the current ppc64
+                 a chance to extract some diagnostic information (see
+                 mmio_enable, below).
+               - PCI_ERS_RESULT_NEED_RESET:
+                 Driver returns this if it can't recover without a hard
+                 slot reset.
+               - PCI_ERS_RESULT_DISCONNECT:
+                 Driver returns this if it doesn't want to recover at all.
+
+The next step taken will depend on the result codes returned by the
+drivers.
+
+If all drivers on the segment/slot return PCI_ERS_RESULT_CAN_RECOVER,
+then the platform should re-enable IOs on the slot (or do nothing in
+particular, if the platform doesn't isolate slots), and recovery
+proceeds to STEP 2 (MMIO Enable).
+
+If any driver requested a slot reset (by returning PCI_ERS_RESULT_NEED_RESET),
+then recovery proceeds to STEP 4 (Slot Reset).
+
+If the platform is unable to recover the slot, the next step
+is STEP 6 (Permanent Failure).
+
+>>> The current powerpc implementation assumes that a device driver will
+>>> *not* schedule or semaphore in this routine; the current powerpc
 >>> implementation uses one kernel thread to notify all devices;
->>> thus, of one device sleeps/schedules, all devices are affected.
+>>> thus, if one device sleeps/schedules, all devices are affected.
 >>> Doing better requires complex multi-threaded logic in the error
 >>> recovery implementation (e.g. waiting for all notification threads
 >>> to "join" before proceeding with recovery.)  This seems excessively
 >>> complex and not worth implementing.
 
->>> The current ppc64 implementation doesn't much care if the device
->>> attempts i/o at this point, or not.  I/O's will fail, returning
+>>> The current powerpc implementation doesn't much care if the device
+>>> attempts I/O at this point, or not.  I/O's will fail, returning
 >>> a value of 0xff on read, and writes will be dropped. If the device
 >>> driver attempts more than 10K I/O's to a frozen adapter, it will
 >>> assume that the device driver has gone into an infinite loop, and
->>> it will panic the the kernel.
+>>> it will panic the the kernel. There doesn't seem to be any other
+>>> way of stopping a device driver that insists on spinning on I/O.
 
-       2) mmio_enabled()
+STEP 2: MMIO Enabled
+-------------------
+The platform re-enables MMIO to the device (but typically not the
+DMA), and then calls the mmio_enabled() callback on all affected
+device drivers.
 
-       This is the "early recovery" call. IOs are allowed again, but DMA is
+This is the "early recovery" call. IOs are allowed again, but DMA is
 not (hrm... to be discussed, I prefer not), with some restrictions. This
 is NOT a callback for the driver to start operations again, only to
 peek/poke at the device, extract diagnostic information, if any, and
 eventually do things like trigger a device local reset or some such,
-but not restart operations. This is sent if all drivers on a segment
-agree that they can try to recover and no automatic link reset was
-performed by the HW. If the platform can't just re-enable IOs without
-a slot reset or a link reset, it doesn't call this callback and goes
-directly to 3) or 4). All IOs should be done _synchronously_ from
-within this callback, errors triggered by them will be returned via
-the normal pci_check_whatever() api, no new error_detected() callback
-will be issued due to an error happening here. However, such an error
-might cause IOs to be re-blocked for the whole segment, and thus
-invalidate the recovery that other devices on the same segment might
-have done, forcing the whole segment into one of the next states,
-that is link reset or slot reset.
-
-       Result codes:
-               - PCIERR_RESULT_RECOVERED
+but not restart operations. This is callback is made if all drivers on
+a segment agree that they can try to recover and if no automatic link reset
+was performed by the HW. If the platform can't just re-enable IOs without
+a slot reset or a link reset, it wont call this callback, and instead
+will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset)
+
+>>> The following is proposed; no platform implements this yet:
+>>> Proposal: All I/O's should be done _synchronously_ from within
+>>> this callback, errors triggered by them will be returned via
+>>> the normal pci_check_whatever() API, no new error_detected()
+>>> callback will be issued due to an error happening here. However,
+>>> such an error might cause IOs to be re-blocked for the whole
+>>> segment, and thus invalidate the recovery that other devices
+>>> on the same segment might have done, forcing the whole segment
+>>> into one of the next states, that is, link reset or slot reset.
+
+The driver should return one of the following result codes:
+               - PCI_ERS_RESULT_RECOVERED
                  Driver returns this if it thinks the device is fully
-                 functionnal and thinks it is ready to start
+                 functional and thinks it is ready to start
                  normal driver operations again. There is no
                  guarantee that the driver will actually be
                  allowed to proceed, as another driver on the
                  same segment might have failed and thus triggered a
                  slot reset on platforms that support it.
 
-               - PCIERR_RESULT_NEED_RESET
+               - PCI_ERS_RESULT_NEED_RESET
                  Driver returns this if it thinks the device is not
                  recoverable in it's current state and it needs a slot
                  reset to proceed.
 
-               - PCIERR_RESULT_DISCONNECT
+               - PCI_ERS_RESULT_DISCONNECT
                  Same as above. Total failure, no recovery even after
                  reset driver dead. (To be defined more precisely)
 
->>> The current ppc64 implementation does not implement this callback.
+The next step taken depends on the results returned by the drivers.
+If all drivers returned PCI_ERS_RESULT_RECOVERED, then the platform
+proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations).
+
+If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform
+proceeds to STEP 4 (Slot Reset)
 
-       3) link_reset()
+>>> The current powerpc implementation does not implement this callback.
 
-       This is called after the link has been reset. This is typically
-a PCI Express specific state at this point and is done whenever a
-non-fatal error has been detected that can be "solved" by resetting
-the link. This call informs the driver of the reset and the driver
-should check if the device appears to be in working condition.
-This function acts a bit like 2) mmio_enabled(), in that the driver
-is not supposed to restart normal driver I/O operations right away.
-Instead, it should just "probe" the device to check it's recoverability
-status. If all is right, then the core will call resume() once all
-drivers have ack'd link_reset().
+
+STEP 3: Link Reset
+------------------
+The platform resets the link, and then calls the link_reset() callback
+on all affected device drivers.  This is a PCI-Express specific state
+and is done whenever a non-fatal error has been detected that can be
+"solved" by resetting the link. This call informs the driver of the
+reset and the driver should check to see if the device appears to be
+in working condition.
+
+The driver is not supposed to restart normal driver I/O operations
+at this point.  It should limit itself to "probing" the device to
+check it's recoverability status. If all is right, then the platform
+will call resume() once all drivers have ack'd link_reset().
 
        Result codes:
-               (identical to mmio_enabled)
+               (identical to STEP 3 (MMIO Enabled)
+
+The platform then proceeds to either STEP 4 (Slot Reset) or STEP 5
+(Resume Operations).
+
+>>> The current powerpc implementation does not implement this callback.
+
+
+STEP 4: Slot Reset
+------------------
+The platform performs a soft or hard reset of the device, and then
+calls the slot_reset() callback.
+
+A soft reset consists of asserting the adapter #RST line and then
+restoring the PCI BAR's and PCI configuration header to a state
+that is equivalent to what it would be after a fresh system
+power-on followed by power-on BIOS/system firmware initialization.
+If the platform supports PCI hotplug, then the reset might be
+performed by toggling the slot electrical power off/on.
 
->>> The current ppc64 implementation does not implement this callback.
+It is important for the platform to restore the PCI config space
+to the "fresh poweron" state, rather than the "last state". After
+a slot reset, the device driver will almost always use its standard
+device initialization routines, and an unusual config space setup
+may result in hung devices, kernel panics, or silent data corruption.
 
-       4) slot_reset()
+This call gives drivers the chance to re-initialize the hardware
+(re-download firmware, etc.).  At this point, the driver may assume
+that he card is in a fresh state and is fully functional. In
+particular, interrupt generation should work normally.
 
-       This is called after the slot has been soft or hard reset by the
-platform.  A soft reset consists of asserting the adapter #RST line
-and then restoring the PCI BARs and PCI configuration header. If the
-platform supports PCI hotplug, then it might instead perform a hard
-reset by toggling power on the slot off/on. This call gives drivers
-the chance to re-initialize the hardware (re-download firmware, etc.),
-but drivers shouldn't restart normal I/O processing operations at
-this point.  (See note about interrupts; interrupts aren't guaranteed
-to be delivered until the resume() callback has been called). If all
-device drivers report success on this callback, the patform will call
-resume() to complete the error handling and let the driver restart
-normal I/O processing.
+Drivers should not yet restart normal I/O processing operations
+at this point.  If all device drivers report success on this
+callback, the platform will call resume() to complete the sequence,
+and let the driver restart normal I/O processing.
 
 A driver can still return a critical failure for this function if
 it can't get the device operational after reset.  If the platform
-previously tried a soft reset, it migh now try a hard reset (power
+previously tried a soft reset, it might now try a hard reset (power
 cycle) and then call slot_reset() again.  It the device still can't
 be recovered, there is nothing more that can be done;  the platform
 will typically report a "permanent failure" in such a case.  The
 device will be considered "dead" in this case.
 
-       Result codes:
-               - PCIERR_RESULT_DISCONNECT
-               Same as above.
+Drivers for multi-function cards will need to coordinate among
+themselves as to which driver instance will perform any "one-shot"
+or global device initialization. For example, the Symbios sym53cxx2
+driver performs device init only from PCI function 0:
 
->>> The current ppc64 implementation does not try a power-cycle reset
->>> if the driver returned PCIERR_RESULT_DISCONNECT. However, it should.
++       if (PCI_FUNC(pdev->devfn) == 0)
++               sym_reset_scsi_bus(np, 0);
 
-       5) resume()
-
-       This is called if all drivers on the segment have returned
-PCIERR_RESULT_RECOVERED from one of the 3 prevous callbacks.
-That basically tells the driver to restart activity, tht everything
-is back and running. No result code is taken into account here. If
-a new error happens, it will restart a new error handling process.
+       Result codes:
+               - PCI_ERS_RESULT_DISCONNECT
+               Same as above.
 
-That's it. I think this covers all the possibilities. The way those
-callbacks are called is platform policy. A platform with no slot reset
-capability for example may want to just "ignore" drivers that can't
+Platform proceeds either to STEP 5 (Resume Operations) or STEP 6 (Permanent
+Failure).
+
+>>> The current powerpc implementation does not currently try a
+>>> power-cycle reset if the driver returned PCI_ERS_RESULT_DISCONNECT.
+>>> However, it probably should.
+
+
+STEP 5: Resume Operations
+-------------------------
+The platform will call the resume() callback on all affected device
+drivers if all drivers on the segment have returned
+PCI_ERS_RESULT_RECOVERED from one of the 3 previous callbacks.
+The goal of this callback is to tell the driver to restart activity,
+that everything is back and running. This callback does not return
+a result code.
+
+At this point, if a new error happens, the platform will restart
+a new error recovery sequence.
+
+STEP 6: Permanent Failure
+-------------------------
+A "permanent failure" has occurred, and the platform cannot recover
+the device.  The platform will call error_detected() with a
+pci_channel_state value of pci_channel_io_perm_failure.
+
+The device driver should, at this point, assume the worst. It should
+cancel all pending I/O, refuse all new I/O, returning -EIO to
+higher layers. The device driver should then clean up all of its
+memory and remove itself from kernel operations, much as it would
+during system shutdown.
+
+The platform will typically notify the system operator of the
+permanent failure in some way.  If the device is hotplug-capable,
+the operator will probably want to remove and replace the device.
+Note, however, not all failures are truly "permanent". Some are
+caused by over-heating, some by a poorly seated card. Many
+PCI error events are caused by software bugs, e.g. DMA's to
+wild addresses or bogus split transactions due to programming
+errors. See the discussion in powerpc/eeh-pci-error-recovery.txt
+for additional detail on real-life experience of the causes of
+software errors.
+
+
+Conclusion; General Remarks
+---------------------------
+The way those callbacks are called is platform policy. A platform with
+no slot reset capability may want to just "ignore" drivers that can't
 recover (disconnect them) and try to let other cards on the same segment
 recover. Keep in mind that in most real life cases, though, there will
 be only one driver per segment.
 
-Now, there is a note about interrupts. If you get an interrupt and your
+Now, a note about interrupts. If you get an interrupt and your
 device is dead or has been isolated, there is a problem :)
-
-After much thinking, I decided to leave that to the platform. That is,
-the recovery API only precies that:
+The current policy is to turn this into a platform policy.
+That is, the recovery API only requires that:
 
  - There is no guarantee that interrupt delivery can proceed from any
 device on the segment starting from the error detection and until the
-restart callback is sent, at which point interrupts are expected to be
+resume callback is sent, at which point interrupts are expected to be
 fully operational.
 
- - There is no guarantee that interrupt delivery is stopped, that is, ad
-river that gets an interrupts after detecting an error, or that detects
-and error within the interrupt handler such that it prevents proper
+ - There is no guarantee that interrupt delivery is stopped, that is,
+a driver that gets an interrupt after detecting an error, or that detects
+an error within the interrupt handler such that it prevents proper
 ack'ing of the interrupt (and thus removal of the source) should just
-return IRQ_NOTHANDLED. It's up to the platform to deal with taht
-condition, typically by masking the irq source during the duration of
+return IRQ_NOTHANDLED. It's up to the platform to deal with that
+condition, typically by masking the IRQ source during the duration of
 the error handling. It is expected that the platform "knows" which
 interrupts are routed to error-management capable slots and can deal
-with temporarily disabling that irq number during error processing (this
+with temporarily disabling that IRQ number during error processing (this
 isn't terribly complex). That means some IRQ latency for other devices
 sharing the interrupt, but there is simply no other way. High end
 platforms aren't supposed to share interrupts between many devices
 anyway :)
 
-
-Revised: 31 May 2005 Linas Vepstas <linas@austin.ibm.com>
+>>> Implementation details for the powerpc platform are discussed in
+>>> the file Documentation/powerpc/eeh-pci-error-recovery.txt
+
+>>> As of this writing, there are six device drivers with patches
+>>> implementing error recovery. Not all of these patches are in
+>>> mainline yet. These may be used as "examples":
+>>>
+>>> drivers/scsi/ipr.c
+>>> drivers/scsi/sym53cxx_2
+>>> drivers/next/e100.c
+>>> drivers/net/e1000
+>>> drivers/net/ixgb
+>>> drivers/net/s2io.c
+
+The End
+-------
index 81336702086f3289843c78b8d50255b381f9bf81..b6cbac5dbfd5ddf972857d85946428751ebe9065 100644 (file)
@@ -1985,7 +1985,6 @@ M:        philb@gnu.org
 P:     Tim Waugh
 M:     tim@cyberelk.net
 P:     David Campbell
-M:     campbell@torque.net
 P:     Andrea Arcangeli
 M:     andrea@suse.de
 L:     linux-parport@lists.infradead.org
index 21654be3f73f6409a6d33aa8de16b0a9f5f57244..acc18138fb2269de1f9fd7c29390f3c6b779b56c 100644 (file)
@@ -49,7 +49,9 @@ dump_backtrace(struct frame_head * head)
  * |    stack    |
  * --------------- saved regs->ebp value if valid (frame_head address)
  * .             .
- * --------------- struct pt_regs stored on stack (struct pt_regs *)
+ * --------------- saved regs->rsp value if x86_64
+ * |             |
+ * --------------- struct pt_regs * stored on stack if 32-bit
  * |             |
  * .             .
  * |             |
@@ -57,13 +59,26 @@ dump_backtrace(struct frame_head * head)
  * |             |
  * |             | \/ Lower addresses
  *
- * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
+ * Thus, regs (or regs->rsp for x86_64) <-> stack base restricts the
+ * valid(ish) ebp values. Note: (1) for x86_64, NMI and several other
+ * exceptions use special stacks, maintained by the interrupt stack table
+ * (IST). These stacks are set up in trap_init() in
+ * arch/x86_64/kernel/traps.c. Thus, for x86_64, regs now does not point
+ * to the kernel stack; instead, it points to some location on the NMI
+ * stack. On the other hand, regs->rsp is the stack pointer saved when the
+ * NMI occurred. (2) For 32-bit, regs->esp is not valid because the
+ * processor does not save %esp on the kernel stack when interrupts occur
+ * in the kernel mode.
  */
 #ifdef CONFIG_FRAME_POINTER
 static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
 {
        unsigned long headaddr = (unsigned long)head;
+#ifdef CONFIG_X86_64
+       unsigned long stack = (unsigned long)regs->rsp;
+#else
        unsigned long stack = (unsigned long)regs;
+#endif
        unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
 
        return headaddr > stack && headaddr < stack_base;
index 706b7734e191efbc51112ae4adea0bbeb4d93e19..6e5eea19fa672bb0199f997e0888fc91d98ad77c 100644 (file)
@@ -71,31 +71,33 @@ static int __init topology_init(void)
        int i, err = 0;
 
 #ifdef CONFIG_NUMA
-       sysfs_nodes = kmalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
+       sysfs_nodes = kzalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
        if (!sysfs_nodes) {
                err = -ENOMEM;
                goto out;
        }
-       memset(sysfs_nodes, 0, sizeof(struct node) * MAX_NUMNODES);
 
-       /* MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes? */
-       for_each_online_node(i)
+       /*
+        * MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes?
+        */
+       for_each_online_node(i) {
                if ((err = register_node(&sysfs_nodes[i], i, 0)))
                        goto out;
+       }
 #endif
 
-       sysfs_cpus = kmalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
+       sysfs_cpus = kzalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
        if (!sysfs_cpus) {
                err = -ENOMEM;
                goto out;
        }
-       memset(sysfs_cpus, 0, sizeof(struct ia64_cpu) * NR_CPUS);
 
-       for_each_present_cpu(i)
+       for_each_present_cpu(i) {
                if((err = arch_register_cpu(i)))
                        goto out;
+       }
 out:
        return err;
 }
 
-__initcall(topology_init);
+subsys_initcall(topology_init);
index 6e27ac68ec3f01060093a7fb98b3ff0899f7f0ca..83b33fe1923c0bbd53da91beadf66bdff8e964c4 100644 (file)
@@ -1486,7 +1486,7 @@ sys_inotify_rm_watch_wrapper:
 
        .globl compat_sys_openat_wrapper
 compat_sys_openat_wrapper:
-       lgfr    %r2,%r2                 # int
+       llgfr   %r2,%r2                 # unsigned int
        llgtr   %r3,%r3                 # const char *
        lgfr    %r4,%r4                 # int
        lgfr    %r5,%r5                 # int
@@ -1518,14 +1518,14 @@ sys_fchownat_wrapper:
 
        .globl compat_sys_futimesat_wrapper
 compat_sys_futimesat_wrapper:
-       lgfr    %r2,%r2                 # int
+       llgfr   %r2,%r2                 # unsigned int
        llgtr   %r3,%r3                 # char *
        llgtr   %r4,%r4                 # struct timeval *
        jg      compat_sys_futimesat
 
        .globl compat_sys_newfstatat_wrapper
 compat_sys_newfstatat_wrapper:
-       lgfr    %r2,%r2                 # int
+       llgfr   %r2,%r2                 # unsigned int
        llgtr   %r3,%r3                 # char *
        llgtr   %r4,%r4                 # struct stat *
        lgfr    %r5,%r5                 # int
index 7f0efaa025c9ba99fe2e130ac502824ae70ffcc5..3975aa02cef83df866a58085bb384715c87a3423 100644 (file)
@@ -117,6 +117,7 @@ late_initcall(simcons_tty_init);
    tty driver.  */
 void simcons_poll_tty (struct tty_struct *tty)
 {
+       char buf[32];   /* Not the nicest way to do it but I need it correct first */
        int flip = 0, send_break = 0;
        struct pollfd pfd;
        pfd.fd = 0;
@@ -124,21 +125,15 @@ void simcons_poll_tty (struct tty_struct *tty)
 
        if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) {
                if (pfd.revents & POLLIN) {
-                       int left = TTY_FLIPBUF_SIZE - tty->flip.count;
-
-                       if (left > 0) {
-                               unsigned char *buf = tty->flip.char_buf_ptr;
-                               int rd = V850_SIM_SYSCALL (read, 0, buf, left);
-
-                               if (rd > 0) {
-                                       tty->flip.count += rd;
-                                       tty->flip.char_buf_ptr += rd;
-                                       memset (tty->flip.flag_buf_ptr, 0, rd);
-                                       tty->flip.flag_buf_ptr += rd;
-                                       flip = 1;
-                               } else
-                                       send_break = 1;
-                       }
+                       /* Real block hardware knows the transfer size before
+                          transfer so the new tty buffering doesn't try to handle
+                          this rather weird simulator specific case well */
+                       int rd = V850_SIM_SYSCALL (read, 0, buf, 32);
+                       if (rd > 0) {
+                               tty_insert_flip_string(tty, buf, rd);
+                               flip = 1;
+                       } else
+                               send_break = 1;
                } else if (pfd.revents & POLLERR)
                        send_break = 1;
        }
index 4fbddf92a921e9d0c32b33e259c5a5f1026c72a2..94fdfe474ac1c1fe36284f0d4b6cced12bf3d520 100644 (file)
@@ -128,9 +128,7 @@ static void rs_poll(unsigned long priv)
 
        while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
                __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
-               tty->flip.count++;
-               *tty->flip.char_buf_ptr++ = c;
-               *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+               tty_insert_flip_char(tty, c, TTY_NORMAL);
                i++;
        }
 
index f12898d53078e9d4fbe21123e4283c8044387cc2..e99471d3232bb6d3fc70a33263986e2908d8751d 100644 (file)
@@ -8,6 +8,7 @@ obj-y                   += power/
 obj-$(CONFIG_FW_LOADER)        += firmware_class.o
 obj-$(CONFIG_NUMA)     += node.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
+obj-$(CONFIG_SMP)      += topology.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
new file mode 100644 (file)
index 0000000..915810f
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * driver/base/topology.c - Populate sysfs with cpu topology information
+ *
+ * Written by: Zhang Yanmin, Intel Corporation
+ *
+ * Copyright (C) 2006, Intel Corp.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/topology.h>
+
+#define define_one_ro(_name)           \
+static SYSDEV_ATTR(_name, 0444, show_##_name, NULL)
+
+#define define_id_show_func(name)                              \
+static ssize_t show_##name(struct sys_device *dev, char *buf)  \
+{                                                              \
+       unsigned int cpu = dev->id;                             \
+       return sprintf(buf, "%d\n", topology_##name(cpu));      \
+}
+
+#define define_siblings_show_func(name)                                        \
+static ssize_t show_##name(struct sys_device *dev, char *buf)          \
+{                                                                      \
+       ssize_t len = -1;                                               \
+       unsigned int cpu = dev->id;                                     \
+       len = cpumask_scnprintf(buf, NR_CPUS+1, topology_##name(cpu));  \
+       return (len + sprintf(buf + len, "\n"));                        \
+}
+
+#ifdef topology_physical_package_id
+define_id_show_func(physical_package_id);
+define_one_ro(physical_package_id);
+#define ref_physical_package_id_attr   &attr_physical_package_id.attr,
+#else
+#define ref_physical_package_id_attr
+#endif
+
+#ifdef topology_core_id
+define_id_show_func(core_id);
+define_one_ro(core_id);
+#define ref_core_id_attr               &attr_core_id.attr,
+#else
+#define ref_core_id_attr
+#endif
+
+#ifdef topology_thread_siblings
+define_siblings_show_func(thread_siblings);
+define_one_ro(thread_siblings);
+#define ref_thread_siblings_attr       &attr_thread_siblings.attr,
+#else
+#define ref_thread_siblings_attr
+#endif
+
+#ifdef topology_core_siblings
+define_siblings_show_func(core_siblings);
+define_one_ro(core_siblings);
+#define ref_core_siblings_attr         &attr_core_siblings.attr,
+#else
+#define ref_core_siblings_attr
+#endif
+
+static struct attribute *default_attrs[] = {
+       ref_physical_package_id_attr
+       ref_core_id_attr
+       ref_thread_siblings_attr
+       ref_core_siblings_attr
+       NULL
+};
+
+static struct attribute_group topology_attr_group = {
+       .attrs = default_attrs,
+       .name = "topology"
+};
+
+/* Add/Remove cpu_topology interface for CPU device */
+static int __cpuinit topology_add_dev(struct sys_device * sys_dev)
+{
+       sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
+       return 0;
+}
+
+static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
+{
+       sysfs_remove_group(&sys_dev->kobj, &topology_attr_group);
+       return 0;
+}
+
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
+               unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+       struct sys_device *sys_dev;
+
+       sys_dev = get_cpu_sysdev(cpu);
+       switch (action) {
+       case CPU_ONLINE:
+               topology_add_dev(sys_dev);
+               break;
+       case CPU_DEAD:
+               topology_remove_dev(sys_dev);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block topology_cpu_notifier =
+{
+       .notifier_call = topology_cpu_callback,
+};
+
+static int __cpuinit topology_sysfs_init(void)
+{
+       int i;
+
+       for_each_online_cpu(i) {
+               topology_cpu_callback(&topology_cpu_notifier, CPU_ONLINE,
+                               (void *)(long)i);
+       }
+
+       register_cpu_notifier(&topology_cpu_notifier);
+
+       return 0;
+}
+
+device_initcall(topology_sysfs_init);
+
index a3614e6a68d0b95e5c8c8904e3014af3f1b7db0c..4ada1268b40d1abda498b2eddf9ed6caa830a665 100644 (file)
@@ -882,7 +882,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
               card->card_number, dev->bus->number, dev->devfn);
 
        if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) &&
-           !pci_set_dma_mask(dev, 0xffffffffLL)) {
+           pci_set_dma_mask(dev, 0xffffffffLL)) {
                printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
                return  -ENOMEM;
        }
index 39c61a71176e0f0eec82a7cb432dba91cd965fdb..cc7acf877dc0ff92c4b55b1d2314ac4f0461e306 100644 (file)
@@ -1233,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                             }
                              info->idle_stats.recv_idle = jiffies;
                         }
-                        schedule_delayed_work(&tty->buf.work, 1);
+                       tty_schedule_flip(tty);
                     }
                     /* end of service */
                     cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
@@ -1606,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info,
            }
 #endif
            info->idle_stats.recv_idle = jiffies;
-           schedule_delayed_work(&tty->buf.work, 1);
+           tty_schedule_flip(tty);
        }
        /* Update rx_get */
        cy_writel(&buf_ctrl->rx_get, new_rx_get);
@@ -1809,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
        if(delta_count)
            cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
        if(special_count)
-           schedule_delayed_work(&tty->buf.work, 1);
+           tty_schedule_flip(tty);
     }
 }
 
index 3f3ac039f4d9a43eb5146b30b4731019ce697ff6..57539d8f9f7c861770c21843fbe38b1b7097151f 100644 (file)
@@ -359,7 +359,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
                }
        }
 
-       schedule_delayed_work(&tty->buf.work, 1);
+       tty_schedule_flip(tty);
 
        info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
        release_pio_buffer(pio_buf);
@@ -426,7 +426,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
                        }
                        tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
                }
-               schedule_delayed_work(&tty->buf.work, 1);
+               tty_schedule_flip(tty);
        }
 
        if (dma_bytes != num_bytes) {
index cb8f4198e9a34291b8cd67e41ee0f969741ac0ad..e7af647800b6e50d46a1f9c2479b00f2c1ea01cd 100644 (file)
@@ -139,7 +139,6 @@ static UCHAR ct79[] = { 2, BYP,     0x4F,0                   }; // XMIT_NOW
 //static UCHAR ct86[]={ 2, BTH,     0x56,0                   }; // RCV_ENABLE
 static UCHAR ct87[] = { 1, BYP,     0x57                     }; // HW_TEST
 //static UCHAR ct88[]={ 3, BTH,     0x58,0,0                 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 //static UCHAR ct90[]={ 3, BYP,     0x5A,0,0                 }; // Set SILO
 //static UCHAR ct91[]={ 2, BYP,     0x5B,0                   }; // timed break
 
index 56e93a5a1e2413fc8477aa354e436ee0d38df202..48fcfba37bfaafd5d0a44a772d8e0182225c07c7 100644 (file)
@@ -2906,65 +2906,16 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
                rc = -EINVAL;
                break;
        case 3:     // Trace device
-               if ( cmd == 1 ) {
-                       rc = put_user(iiSendPendingMail, pIndex++ );
-                       rc = put_user(i2InitChannels, pIndex++ );
-                       rc = put_user(i2QueueNeeds, pIndex++ );
-                       rc = put_user(i2QueueCommands, pIndex++ );
-                       rc = put_user(i2GetStatus, pIndex++ );
-                       rc = put_user(i2Input, pIndex++ );
-                       rc = put_user(i2InputFlush, pIndex++ );
-                       rc = put_user(i2Output, pIndex++ );
-                       rc = put_user(i2FlushOutput, pIndex++ );
-                       rc = put_user(i2DrainWakeup, pIndex++ );
-                       rc = put_user(i2DrainOutput, pIndex++ );
-                       rc = put_user(i2OutputFree, pIndex++ );
-                       rc = put_user(i2StripFifo, pIndex++ );
-                       rc = put_user(i2StuffFifoBypass, pIndex++ );
-                       rc = put_user(i2StuffFifoFlow, pIndex++ );
-                       rc = put_user(i2StuffFifoInline, pIndex++ );
-                       rc = put_user(i2ServiceBoard, pIndex++ );
-                       rc = put_user(serviceOutgoingFifo, pIndex++ );
-                       // rc = put_user(ip2_init, pIndex++ );
-                       rc = put_user(ip2_init_board, pIndex++ );
-                       rc = put_user(find_eisa_board, pIndex++ );
-                       rc = put_user(set_irq, pIndex++ );
-                       rc = put_user(ip2_interrupt, pIndex++ );
-                       rc = put_user(ip2_poll, pIndex++ );
-                       rc = put_user(service_all_boards, pIndex++ );
-                       rc = put_user(do_input, pIndex++ );
-                       rc = put_user(do_status, pIndex++ );
-#ifndef IP2DEBUG_OPEN
-                       rc = put_user(0, pIndex++ );
-#else
-                       rc = put_user(open_sanity_check, pIndex++ );
-#endif
-                       rc = put_user(ip2_open, pIndex++ );
-                       rc = put_user(ip2_close, pIndex++ );
-                       rc = put_user(ip2_hangup, pIndex++ );
-                       rc = put_user(ip2_write, pIndex++ );
-                       rc = put_user(ip2_putchar, pIndex++ );
-                       rc = put_user(ip2_flush_chars, pIndex++ );
-                       rc = put_user(ip2_write_room, pIndex++ );
-                       rc = put_user(ip2_chars_in_buf, pIndex++ );
-                       rc = put_user(ip2_flush_buffer, pIndex++ );
-
-                       //rc = put_user(ip2_wait_until_sent, pIndex++ );
-                       rc = put_user(0, pIndex++ );
-
-                       rc = put_user(ip2_throttle, pIndex++ );
-                       rc = put_user(ip2_unthrottle, pIndex++ );
-                       rc = put_user(ip2_ioctl, pIndex++ );
-                       rc = put_user(0, pIndex++ );
-                       rc = put_user(get_serial_info, pIndex++ );
-                       rc = put_user(set_serial_info, pIndex++ );
-                       rc = put_user(ip2_set_termios, pIndex++ );
-                       rc = put_user(ip2_set_line_discipline, pIndex++ );
-                       rc = put_user(set_params, pIndex++ );
-               } else {
+               /*
+                * akpm: This used to write a whole bunch of function addresses
+                * to userspace, which generated lots of put_user() warnings.
+                * I killed it all.  Just return "success" and don't do
+                * anything.
+                */
+               if (cmd == 1)
+                       rc = 0;
+               else
                        rc = -EINVAL;
-               }
-
                break;
 
        default:
index 0097f06fa67ba0af6852eb033597b7f0f1b08eb1..d745004281d08f372aaa0bdc87f0e231b946651e 100644 (file)
@@ -481,7 +481,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len)
        }
 
        if ((addr->channel == IPMI_BMC_CHANNEL)
-           || (addr->channel >= IPMI_NUM_CHANNELS)
+           || (addr->channel >= IPMI_MAX_CHANNELS)
            || (addr->channel < 0))
                return -EINVAL;
 
@@ -1321,7 +1321,7 @@ static int i_ipmi_request(ipmi_user_t          user,
                unsigned char         ipmb_seq;
                long                  seqid;
 
-               if (addr->channel >= IPMI_NUM_CHANNELS) {
+               if (addr->channel >= IPMI_MAX_CHANNELS) {
                        spin_lock_irqsave(&intf->counter_lock, flags);
                        intf->sent_invalid_commands++;
                        spin_unlock_irqrestore(&intf->counter_lock, flags);
index 6ed213bd702c2dc74c533cd29417a07ff79438ed..e59b638766ef5f02ac3bc6b454699d68c7d0d7af 100644 (file)
@@ -1270,36 +1270,36 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
        return 0;
 }
 
-static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset)
 {
        return readb((io->addr)+(offset * io->regspacing));
 }
 
-static void mem_outb(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outb(struct si_sm_io *io, unsigned int offset,
                     unsigned char b)
 {
        writeb(b, (io->addr)+(offset * io->regspacing));
 }
 
-static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset)
 {
        return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
                && 0xff;
 }
 
-static void mem_outw(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outw(struct si_sm_io *io, unsigned int offset,
                     unsigned char b)
 {
        writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
 }
 
-static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset)
 {
        return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
                && 0xff;
 }
 
-static void mem_outl(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outl(struct si_sm_io *io, unsigned int offset,
                     unsigned char b)
 {
        writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
@@ -1349,16 +1349,16 @@ static int mem_setup(struct smi_info *info)
           upon the register size. */
        switch (info->io.regsize) {
        case 1:
-               info->io.inputb = mem_inb;
-               info->io.outputb = mem_outb;
+               info->io.inputb = intf_mem_inb;
+               info->io.outputb = intf_mem_outb;
                break;
        case 2:
-               info->io.inputb = mem_inw;
-               info->io.outputb = mem_outw;
+               info->io.inputb = intf_mem_inw;
+               info->io.outputb = intf_mem_outw;
                break;
        case 4:
-               info->io.inputb = mem_inl;
-               info->io.outputb = mem_outl;
+               info->io.inputb = intf_mem_inl;
+               info->io.outputb = intf_mem_outl;
                break;
 #ifdef readq
        case 8:
index 217ff09f2fa1697e965082a36b6510894bd6e643..89bd94eb45be10c8962f98e2b26c86c837dfe250 100644 (file)
 #endif
 #define _cirrus_h 1
 
-#ifdef RTA
-#define        TO_UART RX
-#define TO_DRIVER TX
-#endif
-
-#ifdef HOST
-#define        TO_UART TX
-#define TO_DRIVER RX
-#endif
-#ifdef RTA
-/* Miscellaneous defines for CIRRUS addresses and related logic for
-   interrupts etc.
-*/
-#define        MAP(a)          ((short *)(cirrus_base + (a)))
-#define outp(a,b)      (*MAP (a) =(b))
-#define inp(a)         ((*MAP (a)) & 0xff)
-#define        CIRRUS_FIRST    (short*)0x7300
-#define        CIRRUS_SECOND   (short*)0x7200
-#define        CIRRUS_THIRD    (short*)0x7100
-#define        CIRRUS_FOURTH   (short*)0x7000
-#define        PORTS_ON_CIRRUS 4
-#define        CIRRUS_FIFO_SIZE        12
-#define        SPACE           0x20
-#define        TAB             0x09
-#define        LINE_FEED       0x0a
-#define        CARRIAGE_RETURN 0x0d
-#define        BACKSPACE       0x08
-#define        SPACES_IN_TABS  8
-#define        SEND_ESCAPE     0x00
-#define START_BREAK    0x81
-#define        TIMER_TICK      0x82
-#define STOP_BREAK     0x83
-#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH)))
-#define txack1 ((short *)0x7104)
-#define rxack1 ((short *)0x7102)
-#define mdack1  ((short *)0x7106)
-#define txack2  ((short *)0x7006)
-#define rxack2 ((short *)0x7004)
-#define mdack2  ((short *)0x7100)
-#define int_latch       ((short *) 0x7800)
-#define int_status      ((short *) 0x7c00)
-#define tx1_pending     0x20
-#define rx1_pending     0x10
-#define md1_pending     0x40
-#define tx2_pending     0x02
-#define rx2_pending     0x01
-#define md2_pending     0x40
-#define module1_bits   0x07
-#define module1_modern 0x08
-#define module2_bits   0x70
-#define module2_modern 0x80
-#define module_blank   0xf
-#define rs232_d25      0x0
-#define        rs232_rj45      0x1
-#define rs422_d25      0x3
-#define parallel       0x5
-
-#define        CLK0    0x00
-#define CLK1   0x01
-#define CLK2   0x02
-#define CLK3   0x03
-#define CLK4   0x04
-
-#define CIRRUS_REVC    0x42
-#define CIRRUS_REVE    0x44
-
-#define        TURNON  1
-#define TURNOFF 0
-
-/* The list of CIRRUS registers. 
-   NB. These registers are relative values on 8 bit boundaries whereas
-   on the RTA's the CIRRUS registers are on word boundaries. Use pointer
-   arithmetic (short *) to obtain the real addresses required */
-#define ccr    0x05            /* Channel Command Register     */
-#define ier    0x06            /* Interrupt Enable Register    */
-#define cor1   0x08            /* Channel Option Register 1    */
-#define cor2   0x09            /* Channel Option Register 2    */
-#define cor3   0x0a            /* Channel Option Register 3    */
-#define cor4   0x1e            /* Channel Option Register 4    */
-#define        cor5    0x1f            /* Channel Option Register 5    */
-
-#define ccsr   0x0b            /* Channel Control Status Register */
-#define rdcr   0x0e            /* Receive Data Count Register  */
-#define tdcr   0x12            /* Transmit Data Count Register */
-#define mcor1  0x15            /* Modem Change Option Register 1 */
-#define mcor2  0x16            /* Modem Change Option Regsiter 2 */
-
-#define livr   0x18            /* Local Interrupt Vector Register */
-#define schr1  0x1a            /* Special Character Register 1 */
-#define schr2  0x1b            /* Special Character Register 2 */
-#define schr3  0x1c            /* Special Character Register 3 */
-#define schr4  0x1d            /* Special Character Register 4 */
-
-#define rtr    0x20            /* Receive Timer Register */
-#define rtpr   0x21            /* Receive Timeout Period Register */
-#define lnc    0x24            /* Lnext character */
-
-#define rivr   0x43            /* Receive Interrupt Vector Register    */
-#define tivr   0x42            /* Transmit Interrupt Vector Register   */
-#define mivr   0x41            /* Modem Interrupt Vector Register      */
-#define gfrcr  0x40            /* Global Firmware Revision code Reg    */
-#define ricr   0x44            /* Receive Interrupting Channel Reg     */
-#define ticr   0x45            /* Transmit Interrupting Channel Reg    */
-#define micr   0x46            /* Modem Interrupting Channel Register  */
-
-#define gcr    0x4b            /* Global configuration register */
-#define misr    0x4c           /* Modem interrupt status register */
-
-#define rbusr  0x59
-#define tbusr  0x5a
-#define mbusr  0x5b
-
-#define eoir   0x60            /* End Of Interrupt Register */
-#define rdsr   0x62            /* Receive Data / Status Register */
-#define tdr    0x63            /* Transmit Data Register */
-#define svrr   0x67            /* Service Request Register */
-
-#define car    0x68            /* Channel Access Register */
-#define mir    0x69            /* Modem Interrupt Register */
-#define tir    0x6a            /* Transmit Interrupt Register */
-#define rir    0x6b            /* Receive Interrupt Register */
-#define msvr1  0x6c            /* Modem Signal Value Register 1 */
-#define msvr2  0x6d            /* Modem Signal Value Register 2 */
-#define psvr   0x6f            /* Printer Signal Value Register */
-
-#define tbpr   0x72            /* Transmit Baud Rate Period Register */
-#define tcor   0x76            /* Transmit Clock Option Register */
-
-#define rbpr   0x78            /* Receive Baud Rate Period Register */
-#define rber   0x7a            /* Receive Baud Rate Extension Register */
-#define rcor   0x7c            /* Receive Clock Option Register */
-#define ppr    0x7e            /* Prescalar Period Register    */
-
-/* Misc registers used for forcing the 1400 out of its reset woes */
-#define airl   0x6d
-#define airm   0x6e
-#define airh   0x6f
-#define btcr   0x66
-#define mtcr   0x6c
-#define tber   0x74
-
-#endif                         /* #ifdef RTA */
 
 
 /* Bit fields for particular registers */
index 5b600c32ac021a578fb32f75e6bdea2ed89b9a38..d55c2f6a9877ecf7cdb8d8e5f19ce1d61d38c66c 100644 (file)
@@ -45,13 +45,6 @@ static char *_rio_defaults_h_sccs = "@(#)defaults.h  1.1";
 #define MILLISECOND           (int) (1000/64)  /* 15.625 low ticks */
 #define SECOND                (int) 15625      /* Low priority ticks */
 
-#ifdef RTA
-#define RX_LIMIT       (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT       (ushort) 1
-#endif
-
 #define LINK_TIMEOUT          (int) (POLL_PERIOD / 2)
 
 
index bfba5b0c033e89f871dfe08b3ece5e6de6fba1f7..48d68ca7f825e15a6d390b1d5ef1924ec6d5f4f4 100644 (file)
 /*
 ** LED stuff
 */
-#if defined(RTA)
-#define LED_OFF            ((ushort) 0)        /* LED off */
-#define LED_RED            ((ushort) 1)        /* LED Red */
-#define LED_GREEN          ((ushort) 2)        /* LED Green */
-#define LED_ORANGE         ((ushort) 4)        /* LED Orange */
-#define LED_1TO8_OPEN      ((ushort) 1)        /* Port 1->8 LED on */
-#define LED_9TO16_OPEN     ((ushort) 2)        /* Port 9->16 LED on */
-#define LED_SET_COLOUR(colour) (link->led = (colour))
-#define LED_OR_COLOUR(colour)  (link->led |= (colour))
-#define LED_TIMEOUT(time)    (link->led_timeout = RioTimePlus(RioTime(),(time)))
-#else
 #define LED_SET_COLOUR(colour)
 #define LED_OR_COLOUR(colour)
 #define LED_TIMEOUT(time)
-#endif                         /* RTA */
 
 struct LPB {
        WORD link_number;       /* Link Number */
        Channel_ptr in_ch;      /* Link In Channel */
        Channel_ptr out_ch;     /* Link Out Channel */
-#ifdef RTA
-       uchar stat_led;         /* Port open leds */
-       uchar led;              /* True, light led! */
-#endif
        BYTE attached_serial[4];        /* Attached serial number */
        BYTE attached_host_serial[4];
        /* Serial number of Host who
@@ -144,30 +128,12 @@ struct LPB {
        WORD WaitNoBoot;        /* Secs to hold off booting */
        PKT_ptr add_packet_list;        /* Add packets to here */
        PKT_ptr remove_packet_list;     /* Send packets from here */
-#ifdef RTA
-#ifdef DCIRRUS
-#define    QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1)
-#else
-#define    QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1)
-#endif
-       PKT_ptr_ptr rd_add;     /* Add a new Packet here */
-       Q_BUF_ptr rd_add_qb;    /* Pointer to the add Q buf */
-       PKT_ptr_ptr rd_add_st_qbb;      /* Pointer to start of the Q's buf */
-       PKT_ptr_ptr rd_add_end_qbb;     /* Pointer to the end of the Q's buf */
-       PKT_ptr_ptr rd_remove;  /* Remove a Packet here */
-       Q_BUF_ptr rd_remove_qb; /* Pointer to the remove Q buf */
-       PKT_ptr_ptr rd_remove_st_qbb;   /* Pointer to the start of the Q buf */
-       PKT_ptr_ptr rd_remove_end_qbb;  /* Pointer to the end of the Q buf */
-       ushort pkts_in_q;       /* Packets in queue */
-#endif
 
        Channel_ptr lrt_fail_chan;      /* Lrt's failure channel */
        Channel_ptr ltt_fail_chan;      /* Ltt's failure channel */
 
-#if defined (HOST) || defined (INKERNEL)
        /* RUP structure for HOST to driver communications */
        struct RUP rup;
-#endif
        struct RUP link_rup;    /* RUP for the link (POLL,
                                   topology etc.) */
        WORD attached_link;     /* Number of attached link */
index 36aad4c9cb3a2539f85074873ca480c921f67262..79b853140ae55f7d04f2a85d9bbd1da4bc9eb204 100644 (file)
@@ -44,8 +44,6 @@ static char *_rio_list_h_sccs = "@(#)list.h   1.9";
 
 #define PKT_IN_USE    0x1
 
-#ifdef INKERNEL
-
 #define ZERO_PTR (ushort) 0x8000
 #define        CaD     PortP->Caddr
 
@@ -54,143 +52,5 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9";
 ** to by the TxAdd pointer has PKT_IN_USE clear in its address.
 */
 
-#ifndef linux
-#if defined( MIPS ) && !defined( MIPSEISA )
-/* May the shoes of the Devil dance on your grave for creating this */
-#define   can_add_transmit(PacketP,PortP) \
-          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
-          & (PKT_IN_USE<<2)))
-
-#elif  defined(MIPSEISA) || defined(nx6000) || \
-       defined(drs6000)  || defined(UWsparc)
-
-#define   can_add_transmit(PacketP,PortP) \
-          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
-         & PKT_IN_USE))
-
-#else
-#define   can_add_transmit(PacketP,PortP) \
-          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \
-         & PKT_IN_USE))
-#endif
-
-/*
-** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
-** and then move the TxAdd pointer along one position to point to the next
-** packet pointer. You must wrap the pointer from the end back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-#   define add_transmit(PortP)  \
-       WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\
-       if (PortP->TxAdd == PortP->TxEnd)\
-           PortP->TxAdd = PortP->TxStart;\
-       else\
-           PortP->TxAdd++;\
-       WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd));
-#elif defined(AIX)
-#   define add_transmit(PortP)  \
-       {\
-           register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\
-           WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\
-           if (PortP->TxAddO == PortP->TxEndO )\
-               PortP->TxAddO = PortP->TxStartO;\
-           else\
-               PortP->TxAddO += sizeof(ushort);\
-           WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\
-       }
-#else
-#   define add_transmit(PortP)  \
-       *PortP->TxAdd |= PKT_IN_USE;\
-       if (PortP->TxAdd == PortP->TxEnd)\
-           PortP->TxAdd = PortP->TxStart;\
-       else\
-           PortP->TxAdd++;\
-       PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd);
-#endif
-
-/*
-** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set
-** for the next packet on the queue. It will also set PacketP to point to the
-** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
-** then can_remove_receive() returns 0.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-#   define can_remove_receive(PacketP,PortP) \
-       ((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \
-       (PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0)
-#elif defined(AIX)
-#   define can_remove_receive(PacketP,PortP) \
-       ((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \
-       (PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0)
-#else
-#   define can_remove_receive(PacketP,PortP) \
-       ((*PortP->RxRemove & PKT_IN_USE) ? \
-       (PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0)
-#endif
-
-
-/*
-** Will God see it within his heart to forgive us for this thing that
-** we have created? To remove a packet from the receive queue you clear
-** its PKT_IN_USE bit, and then bump the pointers. Once the pointers
-** get to the end, they must be wrapped back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-#   define remove_receive(PortP) \
-       WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\
-       if (PortP->RxRemove == PortP->RxEnd)\
-           PortP->RxRemove = PortP->RxStart;\
-       else\
-           PortP->RxRemove++;\
-       WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove));
-#elif defined(AIX)
-#   define remove_receive(PortP) \
-    {\
-        register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\
-        WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\
-        if (PortP->RxRemoveO == PortP->RxEndO)\
-            PortP->RxRemoveO = PortP->RxStartO;\
-        else\
-            PortP->RxRemoveO += sizeof(ushort);\
-        WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\
-    }
-#else
-#   define remove_receive(PortP) \
-       *PortP->RxRemove &= ~PKT_IN_USE;\
-       if (PortP->RxRemove == PortP->RxEnd)\
-           PortP->RxRemove = PortP->RxStart;\
-       else\
-           PortP->RxRemove++;\
-       PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove);
-#endif
-#endif
-
-
-#else                          /* !IN_KERNEL */
-
-#define ZERO_PTR NULL
-
-
-#ifdef HOST
-/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE))   */
-#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\
-                             if (phb->tx_remove == phb->tx_end)\
-                                phb->tx_remove = phb->tx_start;\
-                             else\
-                                phb->tx_remove++;
-#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE)
-#define add_receive(pkt,phb) *phb->rx_add = pkt;\
-                             *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\
-                             if (phb->rx_add == phb->rx_end)\
-                                phb->rx_add = phb->rx_start;\
-                             else\
-                                phb->rx_add++;
-#endif
-#endif
-
-#ifdef RTA
-#define splx(oldspl)    if ((oldspl) == 0) spl0()
-#endif
-
 #endif                         /* ifndef _list.h */
 /*********** end of file ***********/
index fe4e00567065150d84e3aa3cb190caa936acdf21..e24acc1d18440d006b067fec23d06a97c738f5ff 100644 (file)
@@ -78,14 +78,9 @@ struct PARM_MAP {
        WORD idle_count;        /* Idle time counter */
        WORD busy_count;        /* Busy counter */
        WORD idle_control;      /* Control Idle Process */
-#if defined(HOST) || defined(INKERNEL)
        WORD tx_intr;           /* TX interrupt pending */
        WORD rx_intr;           /* RX interrupt pending */
        WORD rup_intr;          /* RUP interrupt pending */
-#endif
-#if defined(RTA)
-       WORD dying_count;       /* Count of processes dead */
-#endif
 };
 
 #endif
index 3baebf8513afe48d27c3803a868c116229a24df6..2663ca0306e2a0567f0d4fa2728e9e4ddb4a8df5 100644 (file)
 #endif
 
 
- /*************************************************
-  * Set the LIMIT values.
-  ************************************************/
-#ifdef RTA
-#define RX_LIMIT       (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT       (ushort) 1
-#endif
-
-
 /*************************************************
  * Handshake asserted. Deasserted by the LTT(s)
  ************************************************/
 /*************************************************
  * Maximum number of PHB's
  ************************************************/
-#if defined (HOST) || defined (INKERNEL)
 #define MAX_PHB               ((ushort) 128)   /* range 0-127 */
-#else
-#define MAX_PHB               ((ushort) 8)     /* range 0-7 */
-#endif
 
 /*************************************************
  * Defines for the mode fields
  * the start. The pointer tx_add points to a SPACE to put a Packet.
  * The pointer tx_remove points to the next Packet to remove
  *************************************************************************/
-#ifndef INKERNEL
-#define src_unit     u2.s2.unit
-#define src_port     u2.s2.port
-#define dest_unit    u1.s1.unit
-#define dest_port    u1.s1.port
-#endif
-#ifdef HOST
-#define tx_start     u3.s1.tx_start_ptr_ptr
-#define tx_add       u3.s1.tx_add_ptr_ptr
-#define tx_end       u3.s1.tx_end_ptr_ptr
-#define tx_remove    u3.s1.tx_remove_ptr_ptr
-#define rx_start     u4.s1.rx_start_ptr_ptr
-#define rx_add       u4.s1.rx_add_ptr_ptr
-#define rx_end       u4.s1.rx_end_ptr_ptr
-#define rx_remove    u4.s1.rx_remove_ptr_ptr
-#endif
 typedef struct PHB PHB;
 struct PHB {
-#ifdef RTA
-       ushort port;
-#endif
-#ifdef INKERNEL
        WORD source;
-#else
-       union {
-               ushort source;  /* Complete source */
-               struct {
-                       unsigned char unit;     /* Source unit */
-                       unsigned char port;     /* Source port */
-               } s2;
-       } u2;
-#endif
        WORD handshake;
        WORD status;
        NUMBER timeout;         /* Maximum of 1.9 seconds */
        WORD link;              /* Send down this link */
-#ifdef INKERNEL
        WORD destination;
-#else
-       union {
-               ushort destination;     /* Complete destination */
-               struct {
-                       unsigned char unit;     /* Destination unit */
-                       unsigned char port;     /* Destination port */
-               } s1;
-       } u1;
-#endif
-#ifdef RTA
-       ushort tx_pkts_added;
-       ushort tx_pkts_removed;
-       Q_BUF_ptr tx_q_start;   /* Start of the Q list chain */
-       short num_tx_q_bufs;    /* Number of Q buffers in the chain */
-       PKT_ptr_ptr tx_add;     /* Add a new Packet here */
-       Q_BUF_ptr tx_add_qb;    /* Pointer to the add Q buf */
-       PKT_ptr_ptr tx_add_st_qbb;      /* Pointer to start of the Q's buf */
-       PKT_ptr_ptr tx_add_end_qbb;     /* Pointer to the end of the Q's buf */
-       PKT_ptr_ptr tx_remove;  /* Remove a Packet here */
-       Q_BUF_ptr tx_remove_qb; /* Pointer to the remove Q buf */
-       PKT_ptr_ptr tx_remove_st_qbb;   /* Pointer to the start of the Q buf */
-       PKT_ptr_ptr tx_remove_end_qbb;  /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
        PKT_ptr_ptr tx_start;
        PKT_ptr_ptr tx_end;
        PKT_ptr_ptr tx_add;
        PKT_ptr_ptr tx_remove;
-#endif
-#ifdef HOST
-       union {
-               struct {
-                       PKT_ptr_ptr tx_start_ptr_ptr;
-                       PKT_ptr_ptr tx_end_ptr_ptr;
-                       PKT_ptr_ptr tx_add_ptr_ptr;
-                       PKT_ptr_ptr tx_remove_ptr_ptr;
-               } s1;
-               struct {
-                       ushort *tx_start_ptr;
-                       ushort *tx_end_ptr;
-                       ushort *tx_add_ptr;
-                       ushort *tx_remove_ptr;
-               } s2;
-       } u3;
-#endif
 
-#ifdef  RTA
-       ushort rx_pkts_added;
-       ushort rx_pkts_removed;
-       Q_BUF_ptr rx_q_start;   /* Start of the Q list chain */
-       short num_rx_q_bufs;    /* Number of Q buffers in the chain */
-       PKT_ptr_ptr rx_add;     /* Add a new Packet here */
-       Q_BUF_ptr rx_add_qb;    /* Pointer to the add Q buf */
-       PKT_ptr_ptr rx_add_st_qbb;      /* Pointer to start of the Q's buf */
-       PKT_ptr_ptr rx_add_end_qbb;     /* Pointer to the end of the Q's buf */
-       PKT_ptr_ptr rx_remove;  /* Remove a Packet here */
-       Q_BUF_ptr rx_remove_qb; /* Pointer to the remove Q buf */
-       PKT_ptr_ptr rx_remove_st_qbb;   /* Pointer to the start of the Q buf */
-       PKT_ptr_ptr rx_remove_end_qbb;  /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
        PKT_ptr_ptr rx_start;
        PKT_ptr_ptr rx_end;
        PKT_ptr_ptr rx_add;
        PKT_ptr_ptr rx_remove;
-#endif
-#ifdef HOST
-       union {
-               struct {
-                       PKT_ptr_ptr rx_start_ptr_ptr;
-                       PKT_ptr_ptr rx_end_ptr_ptr;
-                       PKT_ptr_ptr rx_add_ptr_ptr;
-                       PKT_ptr_ptr rx_remove_ptr_ptr;
-               } s1;
-               struct {
-                       ushort *rx_start_ptr;
-                       ushort *rx_end_ptr;
-                       ushort *rx_add_ptr;
-                       ushort *rx_remove_ptr;
-               } s2;
-       } u4;
-#endif
-
-#ifdef RTA                     /* some fields for the remotes */
-       ushort flush_count;     /* Count of write flushes */
-       ushort txmode;          /* Modes for tx */
-       ushort rxmode;          /* Modes for rx */
-       ushort portmode;        /* Generic modes */
-       ushort column;          /* TAB3 column count */
-       ushort tx_subscript;    /* (TX) Subscript into data field */
-       ushort rx_subscript;    /* (RX) Subscript into data field */
-       PKT_ptr rx_incomplete;  /* Hold an incomplete packet here */
-       ushort modem_bits;      /* Modem bits to mask */
-       ushort lastModem;       /* Modem control lines. */
-       ushort addr;            /* Address for sub commands */
-       ushort MonitorTstate;   /* TRUE if monitoring tstop */
-#endif
 
 };
 
index 882fd429ac2ef44494da9787cd0fff1b23db9f34..7011e52e82db51e2a005ece5c9f0363ab59f2b8c 100644 (file)
 #define CONTROL_DATA_WNDW  (DATA_WNDW << 8)
 
 struct PKT {
-#ifdef INKERNEL
        BYTE dest_unit;         /* Destination Unit Id */
        BYTE dest_port;         /* Destination POrt */
        BYTE src_unit;          /* Source Unit Id */
        BYTE src_port;          /* Source POrt */
-#else
-       union {
-               ushort destination;     /* Complete destination */
-               struct {
-                       unsigned char unit;     /* Destination unit */
-                       unsigned char port;     /* Destination port */
-               } s1;
-       } u1;
-       union {
-               ushort source;  /* Complete source */
-               struct {
-                       unsigned char unit;     /* Source unit */
-                       unsigned char port;     /* Source port */
-               } s2;
-       } u2;
-#endif
-#ifdef INKERNEL
        BYTE len;
        BYTE control;
-#else
-       union {
-               ushort control;
-               struct {
-                       unsigned char len;
-                       unsigned char control;
-               } s3;
-       } u3;
-#endif
        BYTE data[PKT_MAX_DATA_LEN];
        /* Actual data :-) */
        WORD csum;              /* C-SUM */
index acd9e8e5307de628a2282aeaf4603aa90a48bda3..391ffc335535f37b6a2b51ec69b0a946278b8c34 100644 (file)
@@ -46,11 +46,7 @@ static char *_rio_qbuf_h_sccs = "@(#)qbuf.h  1.1";
 
 
 
-#ifdef HOST
-#define PKTS_PER_BUFFER    1
-#else
 #define PKTS_PER_BUFFER    (220 / PKT_LENGTH)
-#endif
 
 typedef struct Q_BUF Q_BUF;
 struct Q_BUF {
index 9b67e2468becd51a280d4c3637d656c56b8f991c..46084d5c7e983e21f1068255ddea077ad8584aba 100644 (file)
@@ -43,9 +43,6 @@
 #endif
 #endif
 
-#ifdef INKERNEL
-
-#if !defined(MIPSAT)
 typedef unsigned short NUMBER_ptr;
 typedef unsigned short WORD_ptr;
 typedef unsigned short BYTE_ptr;
@@ -65,69 +62,6 @@ typedef unsigned short RUP_ptr;
 typedef unsigned short short_ptr;
 typedef unsigned short u_short_ptr;
 typedef unsigned short ushort_ptr;
-#else
-/* MIPSAT types */
-typedef char RIO_POINTER[8];
-typedef RIO_POINTER NUMBER_ptr;
-typedef RIO_POINTER WORD_ptr;
-typedef RIO_POINTER BYTE_ptr;
-typedef RIO_POINTER char_ptr;
-typedef RIO_POINTER Channel_ptr;
-typedef RIO_POINTER FREE_LIST_ptr_ptr;
-typedef RIO_POINTER FREE_LIST_ptr;
-typedef RIO_POINTER LPB_ptr;
-typedef RIO_POINTER Process_ptr;
-typedef RIO_POINTER PHB_ptr;
-typedef RIO_POINTER PKT_ptr;
-typedef RIO_POINTER PKT_ptr_ptr;
-typedef RIO_POINTER Q_BUF_ptr;
-typedef RIO_POINTER Q_BUF_ptr_ptr;
-typedef RIO_POINTER ROUTE_STR_ptr;
-typedef RIO_POINTER RUP_ptr;
-typedef RIO_POINTER short_ptr;
-typedef RIO_POINTER u_short_ptr;
-typedef RIO_POINTER ushort_ptr;
-#endif
-
-#else                          /* not INKERNEL */
-typedef unsigned char BYTE;
-typedef unsigned short WORD;
-typedef unsigned long DWORD;
-typedef short NUMBER;
-typedef short *NUMBER_ptr;
-typedef unsigned short *WORD_ptr;
-typedef unsigned char *BYTE_ptr;
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned char u_char;
-typedef unsigned short u_short;
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short ERROR;
-typedef unsigned long ID;
-typedef char *char_ptr;
-typedef Channel *Channel_ptr;
-typedef struct FREE_LIST *FREE_LIST_ptr;
-typedef struct FREE_LIST **FREE_LIST_ptr_ptr;
-typedef struct LPB *LPB_ptr;
-typedef struct Process *Process_ptr;
-typedef struct PHB *PHB_ptr;
-typedef struct PKT *PKT_ptr;
-typedef struct PKT **PKT_ptr_ptr;
-typedef struct Q_BUF *Q_BUF_ptr;
-typedef struct Q_BUF **Q_BUF_ptr_ptr;
-typedef struct ROUTE_STR *ROUTE_STR_ptr;
-typedef struct RUP *RUP_ptr;
-typedef short *short_ptr;
-typedef u_short *u_short_ptr;
-typedef ushort *ushort_ptr;
-typedef struct PKT PKT;
-typedef struct LPB LPB;
-typedef struct RUP RUP;
-#endif
-
 
 #endif                         /* __riotypes__ */
 
index 8d44fec91dd5212a1f588c4cc7752865a847d990..f74f67c6f702a72a4c99832c61a267e43feb2636 100644 (file)
 #endif
 #endif
 
-#if defined( HOST ) || defined( INKERNEL )
 #define MAX_RUP          ((short) 16)
-#endif
-#ifdef RTA
-#define MAX_RUP          ((short) 1)
-#endif
 
 #define PKTS_PER_RUP     ((short) 2)   /* They are always used in pairs */
 
index 31494054b21380875a89f42c557bb05c573cf09d..6f754e19015d573432af716360084acc0447c189 100644 (file)
 #endif
 
 
-#if !defined( HOST ) && !defined( INKERNEL )
-#define RTA 1
-#endif
-
 #define NUM_FREE_LIST_UNITS     500
 
 #ifndef FALSE
index 0949dcef06976d8f78a250a0a725f99ce06f8f11..7edc6a4dbdc43f371df3064f68930284889a66a0 100644 (file)
@@ -433,7 +433,7 @@ static void rp_do_receive(struct r_port *info,
                count += ToRecv;
        }
        /*  Push the data up to the tty layer */
-       ld->receive_buf(tty, cbuf, fbuf, count);
+       ld->receive_buf(tty, chead, fhead, count);
 done:
        tty_ldisc_deref(ld);
 }
index 64bf89cb574f75d105dd4283a8c8c711fc22ae4e..c2490e270f1fc92b280b477eaff5605bbb4b79e6 100644 (file)
@@ -931,7 +931,7 @@ static int sx_set_real_termios (void *ptr)
        case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
        case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
        default:
-               printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+               printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
                break;
        }
 
@@ -958,7 +958,7 @@ static int sx_set_real_termios (void *ptr)
        } else {
                set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
        }
-       sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", 
+       sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
                    port->gs.tty->termios->c_iflag, 
                    I_OTHER(port->gs.tty));
 
@@ -973,7 +973,7 @@ static int sx_set_real_termios (void *ptr)
        } else {
                clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
        }
-       sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", 
+       sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
                    port->gs.tty->termios->c_oflag, 
                    O_OTHER(port->gs.tty));
        /* port->c_dcd = sx_get_CD (port); */
index eb8b5be4e2494c318e9f4af4195d8cd0b63cede7..076e07c1da38dc441592d8a98d83804d4ff8afea 100644 (file)
@@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty)
 
 static void tty_buffer_init(struct tty_struct *tty)
 {
+       spin_lock_init(&tty->buf.lock);
        tty->buf.head = NULL;
        tty->buf.tail = NULL;
        tty->buf.free = NULL;
@@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
        p->used = 0;
        p->size = size;
        p->next = NULL;
+       p->active = 0;
        p->char_buf_ptr = (char *)(p->data);
        p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
 /*     printk("Flip create %p\n", p); */
@@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
 
 int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
-       struct tty_buffer *b = tty->buf.tail, *n;
-       int left = 0;
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
 
        /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
           remove this conditional if its worth it. This would be invisible
           to the callers */
-       if(b != NULL)
+       if ((b = tty->buf.tail) != NULL) {
                left = b->size - b->used;
-       if(left >= size)
-               return size;
-       /* This is the slow path - looking for new buffers to use */
-       n = tty_buffer_find(tty, size);
-       if(n == NULL)
-               return left;
-       if(b != NULL)
-               b->next = n;
-       else
-               tty->buf.head = n;
-       tty->buf.tail = n;
+               b->active = 1;
+       } else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->active = 0;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+                       n->active = 1;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
        return size;
 }
 
@@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
 {
        int space = tty_buffer_request_room(tty, size);
-       struct tty_buffer *tb = tty->buf.tail;
-       *chars = tb->char_buf_ptr + tb->used;
-       memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-       tb->used += space;
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
        return space;
 }
 
@@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
 int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
 {
        int space = tty_buffer_request_room(tty, size);
-       struct tty_buffer *tb = tty->buf.tail;
-       *chars = tb->char_buf_ptr + tb->used;
-       *flags = tb->flag_buf_ptr + tb->used;
-       tb->used += space;
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
        return space;
 }
 
@@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_)
                schedule_delayed_work(&tty->buf.work, 1);
                goto out;
        }
-       spin_lock_irqsave(&tty->read_lock, flags);
-       while((tbuf = tty->buf.head) != NULL) {
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       while((tbuf = tty->buf.head) != NULL && !tbuf->active) {
                tty->buf.head = tbuf->next;
                if (tty->buf.head == NULL)
                        tty->buf.tail = NULL;
-               spin_unlock_irqrestore(&tty->read_lock, flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
                /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
                disc->receive_buf(tty, tbuf->char_buf_ptr,
                                       tbuf->flag_buf_ptr,
                                       tbuf->used);
-               spin_lock_irqsave(&tty->read_lock, flags);
+               spin_lock_irqsave(&tty->buf.lock, flags);
                tty_buffer_free(tty, tbuf);
        }
-       spin_unlock_irqrestore(&tty->read_lock, flags);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
 out:
        tty_ldisc_deref(disc);
 }
@@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate);
 
 void tty_flip_buffer_push(struct tty_struct *tty)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->active = 0;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
        if (tty->low_latency)
                flush_to_ldisc((void *) tty);
        else
index 951764614ebf66ba4c309f1c978080c57710e9a8..7a4dfb95d08770f8e244ce01ce6c6e7fc4863df0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -181,11 +182,14 @@ static int __init watchdog_init(void)
 {
        int ret;
 
+       if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog"))
+               return -EBUSY;
+
        ret = register_reboot_notifier(&epx_c3_notifier);
        if (ret) {
                printk(KERN_ERR PFX "cannot register reboot notifier "
                        "(err=%d)\n", ret);
-               return ret;
+               goto out;
        }
 
        ret = misc_register(&epx_c3_miscdev);
@@ -193,18 +197,23 @@ static int __init watchdog_init(void)
                printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
                        "(err=%d)\n", WATCHDOG_MINOR, ret);
                unregister_reboot_notifier(&epx_c3_notifier);
-               return ret;
+               goto out;
        }
 
        printk(banner);
 
        return 0;
+
+out:
+       release_region(EPXC3_WATCHDOG_CTL_REG, 2);
+       return ret;
 }
 
 static void __exit watchdog_exit(void)
 {
        misc_deregister(&epx_c3_miscdev);
        unregister_reboot_notifier(&epx_c3_notifier);
+       release_region(EPXC3_WATCHDOG_CTL_REG, 2);
 }
 
 module_init(watchdog_init);
index 4819e7fc00ddf1467cc3e61b8835e01c531b6fd0..d94331c1e5b042a7ab80fa4c265d7db2f5a59716 100644 (file)
@@ -46,7 +46,7 @@ config EDAC_MM_EDAC
 
 config EDAC_AMD76X
        tristate "AMD 76x (760, 762, 768)"
-       depends on EDAC_MM_EDAC  && PCI
+       depends on EDAC_MM_EDAC && PCI && X86_32
        help
          Support for error detection and correction on the AMD 76x
          series of chipsets used with the Athlon processor.
index 770a5a6330798c33873a2d992d29d8d7cb03c138..c454ded2b0600974ad035cece99f5422a5e411a9 100644 (file)
@@ -1039,10 +1039,10 @@ MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
 
 
 static struct pci_driver e752x_driver = {
-      name: BS_MOD_STR,
-      probe: e752x_init_one,
-      remove: __devexit_p(e752x_remove_one),
-      id_table: e752x_pci_tbl,
+       .name = BS_MOD_STR,
+       .probe = e752x_init_one,
+       .remove = __devexit_p(e752x_remove_one),
+       .id_table = e752x_pci_tbl,
 };
 
 
index 4be9bd0a1267890604b815785a5bf425cd6154fa..b10ee4698b1db95f8b3045fd7fd814648cedfed0 100644 (file)
@@ -14,7 +14,6 @@
 
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
index 1c81174595b3ce12db4ee9d8194d29b61d92c67b..d633081fa4c58123bc8769e7439af651039cb415 100644 (file)
@@ -52,9 +52,9 @@ config IDE
 
 if IDE
 
-config IDE_MAX_HWIFS 
+config IDE_MAX_HWIFS
        int "Max IDE interfaces"
-       depends on ALPHA || SUPERH
+       depends on ALPHA || SUPERH || IA64
        default 4
        help
          This is the maximum number of IDE hardware interfaces that will
@@ -162,8 +162,8 @@ config BLK_DEV_IDECS
        tristate "PCMCIA IDE support"
        depends on PCMCIA
        help
-         Support for outboard IDE disks, tape drives, and CD-ROM drives
-         connected through a  PCMCIA card.
+         Support for Compact Flash cards, outboard IDE disks, tape drives,
+         and CD-ROM drives connected through a PCMCIA card.
 
 config BLK_DEV_IDECD
        tristate "Include IDE/ATAPI CDROM support"
@@ -267,7 +267,7 @@ config IDE_TASK_IOCTL
        help
          This is a direct raw access to the media.  It is a complex but
          elegant solution to test and validate the domain of the hardware and
-         perform below the driver data recover if needed.  This is the most
+         perform below the driver data recovery if needed.  This is the most
          basic form of media-forensics.
 
          If you are unsure, say N here.
@@ -525,7 +525,7 @@ config BLK_DEV_CS5520
        tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
-         Include support for PIO tuning an virtual DMA on the Cyrix MediaGX 
+         Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
          5510/5520 chipset. This will automatically be detected and
          configured if found.
 
@@ -662,7 +662,7 @@ config PDC202XX_BURST
 
          It was originally designed for the PDC20246/Ultra33, whose BIOS will
          only setup UDMA on the first two PDC20246 cards.  It has also been
-         used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes
+         used successfully on a PDC20265/Ultra100, allowing use of UDMA modes
          when the PDC20265 BIOS has been disabled (for faster boot up).
 
          Please read the comments at the top of
@@ -673,13 +673,6 @@ config PDC202XX_BURST
 config BLK_DEV_PDC202XX_NEW
        tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
 
-# FIXME - probably wants to be one for old and for new
-config PDC202XX_FORCE
-       bool "Enable controller even if disabled by BIOS"
-       depends on BLK_DEV_PDC202XX_NEW
-       help
-         Enable the PDC202xx controller even if it has been disabled in the BIOS setup.
-
 config BLK_DEV_SVWKS
        tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
        help
@@ -722,7 +715,7 @@ config BLK_DEV_SIS5513
 config BLK_DEV_SLC90E66
        tristate "SLC90E66 chipset support"
        help
-         This driver ensures (U)DMA support for Victroy66 SouthBridges for
+         This driver ensures (U)DMA support for Victory66 SouthBridges for
          SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
          The nice thing about it is that you can mix Ultra/DMA/PIO devices
          and it will handle timing cycles.  Since this is an improved
@@ -1060,7 +1053,7 @@ config IDEDMA_IVB
          in that mode with an 80c ribbon.
 
          If you are experiencing compatibility or performance problems, you
-         MAY try to answering Y here. However, it does not necessarily solve
+         MAY try to answer Y here. However, it does not necessarily solve
          any of your problems, it could even cause more of them.
 
          It is normally safe to answer Y; however, the default is N.
index ca25f9e3d0f4e6816f6155d0cd00f79dd07509d1..6c60a9d2afd81e68b2c2170dfd3326f7902b2006 100644 (file)
@@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive)
                         ide_id_has_flush_cache_ext(id));
 
                printk(KERN_INFO "%s: cache flushes %ssupported\n",
-                      drive->name, barrier ? "" : "not");
+                      drive->name, barrier ? "" : "not ");
 
                if (barrier) {
                        ordered = QUEUE_ORDERED_DRAIN_FLUSH;
@@ -889,11 +889,7 @@ static void idedisk_setup (ide_drive_t *drive)
        if (drive->id_read == 0)
                return;
 
-       /*
-        * CompactFlash cards and their brethern look just like hard drives
-        * to us, but they are removable and don't have a doorlock mechanism.
-        */
-       if (drive->removable && !(drive->is_flash)) {
+       if (drive->removable) {
                /*
                 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
                 */
index 8d50df4526a4ec85cf05627e396902af84cf1f57..c01615dec2024f84efba781769a78d341d69a69d 100644 (file)
@@ -55,8 +55,8 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
-                     int nr_sectors)
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+                            int uptodate, int nr_sectors)
 {
        int ret = 1;
 
@@ -91,7 +91,6 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
 
        return ret;
 }
-EXPORT_SYMBOL(__ide_end_request);
 
 /**
  *     ide_end_request         -       complete an IDE I/O
index af7af958ab3e4f83d5df42d8fd783b4bc48e674f..b72dde70840a797f3279021aecd4b080491e2663 100644 (file)
@@ -1243,6 +1243,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
                 */
                if (stat == 0xff)
                        return -ENODEV;
+               touch_softlockup_watchdog();
        }
        return -EBUSY;
 }
index e7425546b4b1786feb0333f71b0aa43b570d1e43..427d1c204174ec39434b15a6fb5bebcbbe40ec06 100644 (file)
@@ -124,45 +124,6 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
        }
 }
 
-/**
- *     drive_is_flashcard      -       check for compact flash
- *     @drive: drive to check
- *
- *     CompactFlash cards and their brethern pretend to be removable
- *     hard disks, except:
- *             (1) they never have a slave unit, and
- *             (2) they don't have doorlock mechanisms.
- *     This test catches them, and is invoked elsewhere when setting
- *     appropriate config bits.
- *
- *     FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
- *     devices, so in linux 2.3.x we should change this to just treat all
- *     PCMCIA  drives this way, and get rid of the model-name tests below
- *     (too big of an interface change for 2.4.x).
- *     At that time, we might also consider parameterizing the timeouts and
- *     retries, since these are MUCH faster than mechanical drives. -M.Lord
- */
-static inline int drive_is_flashcard (ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-
-       if (drive->removable) {
-               if (id->config == 0x848a) return 1;     /* CompactFlash */
-               if (!strncmp(id->model, "KODAK ATA_FLASH", 15)  /* Kodak */
-                || !strncmp(id->model, "Hitachi CV", 10)       /* Hitachi */
-                || !strncmp(id->model, "SunDisk SDCFB", 13)    /* old SanDisk */
-                || !strncmp(id->model, "SanDisk SDCFB", 13)    /* SanDisk */
-                || !strncmp(id->model, "HAGIWARA HPC", 12)     /* Hagiwara */
-                || !strncmp(id->model, "LEXAR ATA_FLASH", 15)  /* Lexar */
-                || !strncmp(id->model, "ATA_FLASH", 9))        /* Simple Tech */
-               {
-                       return 1;       /* yes, it is a flash memory card */
-               }
-       }
-       return 0;       /* no, it is not a flash memory card */
-}
-
 /**
  *     do_identify     -       identify a drive
  *     @drive: drive to identify 
@@ -278,13 +239,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
        /*
         * Not an ATAPI device: looks like a "regular" hard disk
         */
-       if (id->config & (1<<7))
+
+       /*
+        * 0x848a = CompactFlash device
+        * These are *not* removable in Linux definition of the term
+        */
+
+       if ((id->config != 0x848a) && (id->config & (1<<7)))
                drive->removable = 1;
 
-       if (drive_is_flashcard(drive))
-               drive->is_flash = 1;
        drive->media = ide_disk;
-       printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+       printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
        QUIRK_LIST(drive);
        return;
 
index afeb02bbb72210b4ee45bbcf6c6ed5e4a0cd416c..b2cc43702f65ab5738e533c4152ba3aa9f90f3e7 100644 (file)
@@ -242,7 +242,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
                drive->name[2]                  = 'a' + (index * MAX_DRIVES) + unit;
                drive->max_failures             = IDE_DEFAULT_MAX_FAILURES;
                drive->using_dma                = 0;
-               drive->is_flash                 = 0;
                drive->vdma                     = 0;
                INIT_LIST_HEAD(&drive->list);
                init_completion(&drive->gendev_rel_comp);
index a21b1e11eef4e5fe0ca849847695b049106fd943..c743e68c33aadca3894017ed2ba1c82cde5cff52 100644 (file)
@@ -262,6 +262,21 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
        else
                pci_set_drvdata(dev, (void *) aec6xxx_34_base);
 
+       /* These are necessary to get AEC6280 Macintosh cards to work */
+       if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
+           (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
+               u8 reg49h = 0, reg4ah = 0;
+               /* Clear reset and test bits.  */
+               pci_read_config_byte(dev, 0x49, &reg49h);
+               pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
+               /* Enable chip interrupt output.  */
+               pci_read_config_byte(dev, 0x4a, &reg4ah);
+               pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
+               /* Enable burst mode. */
+               pci_read_config_byte(dev, 0x4a, &reg4ah);
+               pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
+       }
+
        return dev->irq;
 }
 
index 7b589d948bf98bce6405196a55444787d4eff920..940bdd4c5784bf80092bac207c75df2352f5c32b 100644 (file)
@@ -1288,6 +1288,10 @@ static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
                                goto init_hpt37X_done;
                        }
                }
+               if (!pci_get_drvdata(dev)) {
+                       printk("No Clock Stabilization!!!\n");
+                       return;
+               }
 pll_recal:
                if (adjust & 1)
                        pll -= (adjust >> 1);
index 108fda83fea476bc2ab4d13e96ac3c09e847cd22..38f41b377ff6f322d1ba5a1276ba00d5024fd518 100644 (file)
@@ -733,7 +733,7 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev)
 
        pci_write_config_dword(dev,0x4C, 0x02040204);
        pci_write_config_byte(dev, 0x42, 0x36);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 }
 
 static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
index fe06ebb0e5bfdd012227f264c636178d30ed8569..acd63173199bbf17acd1a306da2160cda563c511 100644 (file)
@@ -420,9 +420,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .init_hwif      = init_hwif_pdc202new,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
        },{     /* 3 */
                .name           = "PDC20271",
@@ -447,9 +444,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .init_hwif      = init_hwif_pdc202new,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
        },{     /* 6 */
                .name           = "PDC20277",
index ad9d95817f95ec15415bd4f00cd9f3381c9edb88..6f8f8645b02c5666ad4cc336b0a93d8ba6aa7447 100644 (file)
@@ -786,9 +786,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_dma       = init_dma_pdc202xx,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
                .extra          = 16,
        },{     /* 1 */
@@ -799,9 +796,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_dma       = init_dma_pdc202xx,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
                .extra          = 48,
                .flags          = IDEPCI_FLAG_FORCE_PDC,
@@ -813,9 +807,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_dma       = init_dma_pdc202xx,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
                .extra          = 48,
        },{     /* 3 */
@@ -826,9 +817,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_dma       = init_dma_pdc202xx,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
                .extra          = 48,
                .flags          = IDEPCI_FLAG_FORCE_PDC,
@@ -840,9 +828,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_dma       = init_dma_pdc202xx,
                .channels       = 2,
                .autodma        = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
                .bootable       = OFF_BOARD,
                .extra          = 48,
        }
index b3e77df63cef9ab613e97cf3c2a10c743b8179b8..e9b83e1a30287adf49475ab729b95c7b3d4c380c 100644 (file)
@@ -135,6 +135,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
                case PCI_DEVICE_ID_INTEL_ICH6_19:
                case PCI_DEVICE_ID_INTEL_ICH7_21:
                case PCI_DEVICE_ID_INTEL_ESB2_18:
+               case PCI_DEVICE_ID_INTEL_ICH8_6:
                        mode = 3;
                        break;
                /* UDMA 66 capable */
@@ -449,6 +450,7 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
                case PCI_DEVICE_ID_INTEL_ICH6_19:
                case PCI_DEVICE_ID_INTEL_ICH7_21:
                case PCI_DEVICE_ID_INTEL_ESB2_18:
+               case PCI_DEVICE_ID_INTEL_ICH8_6:
                {
                        unsigned int extra = 0;
                        pci_read_config_dword(dev, 0x54, &extra);
@@ -575,6 +577,7 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
        /* 21 */ DECLARE_PIIX_DEV("ICH7"),
        /* 22 */ DECLARE_PIIX_DEV("ICH4"),
        /* 23 */ DECLARE_PIIX_DEV("ESB2"),
+       /* 24 */ DECLARE_PIIX_DEV("ICH8M"),
 };
 
 /**
@@ -651,6 +654,7 @@ static struct pci_device_id piix_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23},
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
index 1b85ce166af8c48b13fe74930d45a66555b7ca63..11fe537e2f6f00b1aaf0d1f5bf0d87894df35fd2 100644 (file)
@@ -216,7 +216,7 @@ struct Layer1 {
 #define GROUP_TEI      127
 #define TEI_SAPI       63
 #define CTRL_SAPI      0
-#define PACKET_NOACK   250
+#define PACKET_NOACK   7
 
 /* Layer2 Flags */
 
index 3314a5a19854239f2bf335102c4e6f1c6dabfa97..94c9afb7017c66791b1eb154bcdf5d53f350b77c 100644 (file)
@@ -71,14 +71,14 @@ int sc_ioctl(int card, scs_ioctl *data)
                /*
                 * Get the SRec from user space
                 */
-               if (copy_from_user(srec, data->dataptr, sizeof(srec))) {
+               if (copy_from_user(srec, data->dataptr, SCIOC_SRECSIZE)) {
                        kfree(rcvmsg);
                        kfree(srec);
                        return -EFAULT;
                }
 
                status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
-                               0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT);
+                               0, SCIOC_SRECSIZE, srec, rcvmsg, SAR_TIMEOUT);
                kfree(rcvmsg);
                kfree(srec);
 
index 653d4dcbee23e7e78b4da9c44cf648f17806ee0a..d05e3125d298bd5c7083204d6f24d098e002c66e 100644 (file)
@@ -1024,7 +1024,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                rdev-> sb_size = (rdev->sb_size | bmask)+1;
 
        if (refdev == 0)
-               return 1;
+               ret = 1;
        else {
                __u64 ev1, ev2;
                struct mdp_superblock_1 *refsb = 
@@ -1044,7 +1044,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                ev2 = le64_to_cpu(refsb->events);
 
                if (ev1 > ev2)
-                       return 1;
+                       ret = 1;
+               else
+                       ret = 0;
        }
        if (minor_version) 
                rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;
@@ -1058,7 +1060,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
 
        if (le32_to_cpu(sb->size) > rdev->size*2)
                return -EINVAL;
-       return 0;
+       return ret;
 }
 
 static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -1081,7 +1083,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->size = le64_to_cpu(sb->size)/2;
                mddev->events = le64_to_cpu(sb->events);
                mddev->bitmap_offset = 0;
-               mddev->default_bitmap_offset = 1024;
+               mddev->default_bitmap_offset = 1024 >> 9;
                
                mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
                memcpy(mddev->uuid, sb->set_uuid, 16);
@@ -1162,7 +1164,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
 
        sb->raid_disks = cpu_to_le32(mddev->raid_disks);
-       sb->size = cpu_to_le64(mddev->size);
+       sb->size = cpu_to_le64(mddev->size<<1);
 
        if (mddev->bitmap && mddev->bitmap_file == NULL) {
                sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
@@ -2942,6 +2944,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        info.ctime         = mddev->ctime;
        info.level         = mddev->level;
        info.size          = mddev->size;
+       if (info.size != mddev->size) /* overflow */
+               info.size = -1;
        info.nr_disks      = nr;
        info.raid_disks    = mddev->raid_disks;
        info.md_minor      = mddev->md_minor;
@@ -3523,7 +3527,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                )
                return -EINVAL;
        /* Check there is only one change */
-       if (mddev->size != info->size) cnt++;
+       if (info->size >= 0 && mddev->size != info->size) cnt++;
        if (mddev->raid_disks != info->raid_disks) cnt++;
        if (mddev->layout != info->layout) cnt++;
        if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++;
@@ -3540,7 +3544,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                else
                        return mddev->pers->reconfig(mddev, info->layout, -1);
        }
-       if (mddev->size != info->size)
+       if (info->size >= 0 && mddev->size != info->size)
                rv = update_size(mddev, info->size);
 
        if (mddev->raid_disks    != info->raid_disks)
index d03f99cf4b7dfa936af326eef8ceb0586709fd5a..678f4dbbea1d5c22082d13fb1afd321465b61f28 100644 (file)
@@ -372,7 +372,7 @@ out_free_conf:
        kfree(conf);
        mddev->private = NULL;
 out:
-       return 1;
+       return -ENOMEM;
 }
 
 static int raid0_stop (mddev_t *mddev)
index 9130d051b474d64c4816644be4bc89d3b397f37a..ab90a6d1202043f7d332fe5f613be414845f1107 100644 (file)
@@ -565,6 +565,8 @@ rb_out:
 
        if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
                atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+       else
+               disk = -1;
        rcu_read_unlock();
 
        return disk;
index 25976bfb6f9c19b841aa432dff67c0c24a425435..2dba305daf3c887799453caefae8d5a36535de4b 100644 (file)
@@ -350,7 +350,8 @@ static void shrink_stripes(raid5_conf_t *conf)
        while (drop_one_stripe(conf))
                ;
 
-       kmem_cache_destroy(conf->slab_cache);
+       if (conf->slab_cache)
+               kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
index ed2abb2e2e2d43a5f22b2a5b51c3ebdd093cbf69..cd477ebf2ee44d8b963ec3157a5674300e1e85f5 100644 (file)
@@ -366,7 +366,8 @@ static void shrink_stripes(raid6_conf_t *conf)
        while (drop_one_stripe(conf))
                ;
 
-       kmem_cache_destroy(conf->slab_cache);
+       if (conf->slab_cache)
+               kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
index 90628562851ed70dd5ee4dcf99aac4c6bdaa20fc..184974cc734de25f852d971d0983fcbc20219c10 100644 (file)
@@ -60,4 +60,7 @@ extern void i2o_iop_remove(struct i2o_controller *);
 #define I2O_IN_PORT    0x40
 #define I2O_OUT_PORT   0x44
 
+/* Motorola/Freescale specific register offset */
+#define I2O_MOTOROLA_PORT_OFFSET       0x10400
+
 #define I2O_IRQ_OUTBOUND_POST  0x00000008
index d698d7709c31c8d6073a58e3893de2c723f760f5..4f1515cae5dc94ceb589d74f3c58a3327823efe5 100644 (file)
@@ -88,6 +88,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
        struct device *dev = &pdev->dev;
        int i;
 
+       if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+               printk(KERN_ERR "%s: device already claimed\n", c->name);
+               return -ENODEV;
+       }
+
        for (i = 0; i < 6; i++) {
                /* Skip I/O spaces */
                if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
@@ -163,6 +168,24 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
        c->in_port = c->base.virt + I2O_IN_PORT;
        c->out_port = c->base.virt + I2O_OUT_PORT;
 
+       /* Motorola/Freescale chip does not follow spec */
+       if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
+               /* Check if CPU is enabled */
+               if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
+                       printk(KERN_INFO "%s: MPC82XX needs CPU running to "
+                              "service I2O.\n", c->name);
+                       i2o_pci_free(c);
+                       return -ENODEV;
+               } else {
+                       c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
+                       c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
+                       c->in_port += I2O_MOTOROLA_PORT_OFFSET;
+                       c->out_port += I2O_MOTOROLA_PORT_OFFSET;
+                       printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
+                              c->name);
+               }
+       }
+
        if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
                i2o_pci_free(c);
                return -ENOMEM;
@@ -298,7 +321,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
        struct i2o_controller *c;
        int rc;
        struct pci_dev *i960 = NULL;
-       int pci_dev_busy = 0;
+       int enabled = pdev->is_enabled;
 
        printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
 
@@ -308,16 +331,12 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       if ((rc = pci_enable_device(pdev))) {
-               printk(KERN_WARNING "i2o: couldn't enable device %s\n",
-                      pci_name(pdev));
-               return rc;
-       }
-
-       if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
-               printk(KERN_ERR "i2o: device already claimed\n");
-               return -ENODEV;
-       }
+       if (!enabled)
+               if ((rc = pci_enable_device(pdev))) {
+                       printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+                              pci_name(pdev));
+                       return rc;
+               }
 
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
@@ -395,9 +414,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
 
        if ((rc = i2o_pci_alloc(c))) {
                printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
-                      " failed\n", c->name);
-               if (rc == -ENODEV)
-                       pci_dev_busy = 1;
+                      "failed\n", c->name);
                goto free_controller;
        }
 
@@ -425,7 +442,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
        i2o_iop_free(c);
 
       disable:
-       if (!pci_dev_busy)
+       if (!enabled)
                pci_disable_device(pdev);
 
        return rc;
index 701620b6baede850569e5516a1d2683a86323d6f..8b3784e2de891d0f0f8b3b2d6c84b6d3ed3019cf 100644 (file)
@@ -110,8 +110,9 @@ static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const voi
 {
        while (len > 0) {
                map_word d;
-               d.x[0] = *((uint32_t*)from)++;
+               d.x[0] = *((uint32_t*)from);
                dc21285_write32(map, d, to);
+               from += 4;
                to += 4;
                len -= 4;
        }
@@ -121,8 +122,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
 {
        while (len > 0) {
                map_word d;
-               d.x[0] = *((uint16_t*)from)++;
+               d.x[0] = *((uint16_t*)from);
                dc21285_write16(map, d, to);
+               from += 2;
                to += 2;
                len -= 2;
        }
@@ -131,8 +133,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
 static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
        map_word d;
-       d.x[0] = *((uint8_t*)from)++;
+       d.x[0] = *((uint8_t*)from);
        dc21285_write8(map, d, to);
+       from++;
        to++;
        len--;
 }
index 7488ee7f7cafa1075c6079b0f20081a614eeccb0..7f47124f118d37021cb84b467ac26d873b0d2cb4 100644 (file)
@@ -753,9 +753,11 @@ enum tx_desc_status {
 enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_extra_stats {
-        unsigned long tx_deferred;
-        unsigned long tx_multiple_collisions;
-        unsigned long rx_bad_ssd;
+       unsigned long tx_deferred;
+       unsigned long tx_max_collisions;
+       unsigned long tx_multiple_collisions;
+       unsigned long tx_single_collisions;
+       unsigned long rx_bad_ssd;
 };
 
 struct vortex_private {
@@ -863,12 +865,14 @@ static struct {
        const char str[ETH_GSTRING_LEN];
 } ethtool_stats_keys[] = {
        { "tx_deferred" },
+       { "tx_max_collisions" },
        { "tx_multiple_collisions" },
+       { "tx_single_collisions" },
        { "rx_bad_ssd" },
 };
 
 /* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS     3
+#define VORTEX_NUM_STATS    5
 
 static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
                                   int chip_idx, int card_idx);
@@ -2108,9 +2112,12 @@ vortex_error(struct net_device *dev, int status)
                iowrite8(0, ioaddr + TxStatus);
                if (tx_status & 0x30) {                 /* txJabber or txUnderrun */
                        do_tx_reset = 1;
-               } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) {       /* maxCollisions */
-                       do_tx_reset = 1;
-                       reset_mask = 0x0108;            /* Reset interface logic, but not download logic */
+               } else if (tx_status & 0x08) {  /* maxCollisions */
+                       vp->xstats.tx_max_collisions++;
+                       if (vp->drv_flags & MAX_COLLISION_RESET) {
+                               do_tx_reset = 1;
+                               reset_mask = 0x0108;            /* Reset interface logic, but not download logic */
+                       }
                } else {                                                /* Merely re-enable the transmitter. */
                        iowrite16(TxEnable, ioaddr + EL3_CMD);
                }
@@ -2926,7 +2933,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
        EL3WINDOW(6);
        vp->stats.tx_carrier_errors             += ioread8(ioaddr + 0);
        vp->stats.tx_heartbeat_errors           += ioread8(ioaddr + 1);
-       vp->stats.collisions                    += ioread8(ioaddr + 3);
        vp->stats.tx_window_errors              += ioread8(ioaddr + 4);
        vp->stats.rx_fifo_errors                += ioread8(ioaddr + 5);
        vp->stats.tx_packets                    += ioread8(ioaddr + 6);
@@ -2939,10 +2945,15 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
        vp->stats.tx_bytes                      += ioread16(ioaddr + 12);
        /* Extra stats for get_ethtool_stats() */
        vp->xstats.tx_multiple_collisions       += ioread8(ioaddr + 2);
+       vp->xstats.tx_single_collisions         += ioread8(ioaddr + 3);
        vp->xstats.tx_deferred                  += ioread8(ioaddr + 8);
        EL3WINDOW(4);
        vp->xstats.rx_bad_ssd                   += ioread8(ioaddr + 12);
 
+       vp->stats.collisions = vp->xstats.tx_multiple_collisions
+               + vp->xstats.tx_single_collisions
+               + vp->xstats.tx_max_collisions;
+
        {
                u8 up = ioread8(ioaddr + 13);
                vp->stats.rx_bytes += (up & 0x0f) << 16;
@@ -3036,8 +3047,10 @@ static void vortex_get_ethtool_stats(struct net_device *dev,
        spin_unlock_irqrestore(&vp->lock, flags);
 
        data[0] = vp->xstats.tx_deferred;
-       data[1] = vp->xstats.tx_multiple_collisions;
-       data[2] = vp->xstats.rx_bad_ssd;
+       data[1] = vp->xstats.tx_max_collisions;
+       data[2] = vp->xstats.tx_multiple_collisions;
+       data[3] = vp->xstats.tx_single_collisions;
+       data[4] = vp->xstats.rx_bad_ssd;
 }
 
 
index f2d1dafde08773ad74107309b5e74ed9a0b60f16..e7dc653d5bd673ff10fb56970c25bc29a50a9815 100644 (file)
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.48"
-#define DRV_MODULE_RELDATE     "Jan 16, 2006"
+#define DRV_MODULE_VERSION     "3.49"
+#define DRV_MODULE_RELDATE     "Feb 2, 2006"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data)
        struct tg3 *tp = _data;
        unsigned int restart_timer;
 
+       tg3_full_lock(tp, 0);
+       tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
+
+       if (!netif_running(tp->dev)) {
+               tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+               tg3_full_unlock(tp);
+               return;
+       }
+
+       tg3_full_unlock(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data)
 
        tg3_netif_start(tp);
 
-       tg3_full_unlock(tp);
-
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
+
+       tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+
+       tg3_full_unlock(tp);
 }
 
 static void tg3_tx_timeout(struct net_device *dev)
@@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       /* Calling flush_scheduled_work() may deadlock because
+        * linkwatch_event() may be on the workqueue and it will try to get
+        * the rtnl_lock which we are holding.
+        */
+       while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
+               msleep(1);
+
        netif_stop_queue(dev);
 
        del_timer_sync(&tp->timer);
@@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
        if (dev) {
                struct tg3 *tp = netdev_priv(dev);
 
+               flush_scheduled_work();
                unregister_netdev(dev);
                if (tp->regs) {
                        iounmap(tp->regs);
@@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!netif_running(dev))
                return 0;
 
+       flush_scheduled_work();
        tg3_netif_stop(tp);
 
        del_timer_sync(&tp->timer);
index e8243305f0e807a9433ac9e0762dc5266ff116aa..7f4b7f6ac40dec8085ac567457ce50ddb83038d3 100644 (file)
@@ -2162,6 +2162,7 @@ struct tg3 {
 #define TG3_FLAG_JUMBO_RING_ENABLE     0x00800000
 #define TG3_FLAG_10_100_ONLY           0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG         0x02000000
+#define TG3_FLAG_IN_RESET_TASK         0x04000000
 #define TG3_FLAG_BROKEN_CHECKSUMS      0x10000000
 #define TG3_FLAG_GOT_SERDES_FLOWCTL    0x20000000
 #define TG3_FLAG_SPLIT_MODE            0x40000000
index f605dea57224ca23e5f1159c670f554104de1c21..f63c387976cf378a6f8ce78491a3d8de0f9a1c7c 100644 (file)
@@ -90,6 +90,15 @@ config PARPORT_ARC
        depends on ARM && PARPORT
        select PARPORT_NOT_PC
 
+config PARPORT_IP32
+       tristate "SGI IP32 builtin port (EXPERIMENTAL)"
+       depends on SGI_IP32 && PARPORT && EXPERIMENTAL
+       select PARPORT_NOT_PC
+       help
+         Say Y here if you need support for the parallel port on
+         SGI O2 machines. This code is also available as a module (say M),
+         called parport_ip32.  If in doubt, saying N is the safe plan.
+
 config PARPORT_AMIGA
        tristate "Amiga builtin port"
        depends on AMIGA && PARPORT
index 5372212bb9d901a77f9bd6bbba6543d28f607760..a19de35f8de262b6ca04ef9ba19c4480c9e364dd 100644 (file)
@@ -17,3 +17,4 @@ obj-$(CONFIG_PARPORT_MFC3)    += parport_mfc3.o
 obj-$(CONFIG_PARPORT_ATARI)    += parport_atari.o
 obj-$(CONFIG_PARPORT_SUNBPP)   += parport_sunbpp.o
 obj-$(CONFIG_PARPORT_GSC)      += parport_gsc.o
+obj-$(CONFIG_PARPORT_IP32)     += parport_ip32.o
index 5b887ba5aaf9e613c39939afd62c6f82febef660..690b239ad3a7c3fe5b0b7763fb3856b0d64a052e 100644 (file)
@@ -61,10 +61,10 @@ static void timeout_waiting_on_port (unsigned long cookie)
  *     set to zero, it returns immediately.
  *
  *     If an interrupt occurs before the timeout period elapses, this
- *     function returns one immediately.  If it times out, it returns
- *     a value greater than zero.  An error code less than zero
- *     indicates an error (most likely a pending signal), and the
- *     calling code should finish what it's doing as soon as it can.
+ *     function returns zero immediately.  If it times out, it returns
+ *     one.  An error code less than zero indicates an error (most
+ *     likely a pending signal), and the calling code should finish
+ *     what it's doing as soon as it can.
  */
 
 int parport_wait_event (struct parport *port, signed long timeout)
@@ -110,7 +110,7 @@ int parport_wait_event (struct parport *port, signed long timeout)
  *
  *     If the status lines take on the desired values before the
  *     timeout period elapses, parport_poll_peripheral() returns zero
- *     immediately.  A zero return value greater than zero indicates
+ *     immediately.  A return value greater than zero indicates
  *     a timeout.  An error code (less than zero) indicates an error,
  *     most likely a signal that arrived, and the caller should
  *     finish what it is doing as soon as possible.
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
new file mode 100644 (file)
index 0000000..46e06e5
--- /dev/null
@@ -0,0 +1,2253 @@
+/* Low-level parallel port routines for built-in port on SGI IP32
+ *
+ * Author: Arnaud Giersch <arnaud.giersch@free.fr>
+ *
+ * Based on parport_pc.c by
+ *     Phil Blundell, Tim Waugh, Jose Renau, David Campbell,
+ *     Andrea Arcangeli, et al.
+ *
+ * Thanks to Ilya A. Volynets-Evenbakh for his help.
+ *
+ * Copyright (C) 2005, 2006 Arnaud Giersch.
+ *
+ * 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.
+ */
+
+/* Current status:
+ *
+ *     Basic SPP and PS2 modes are supported.
+ *     Support for parallel port IRQ is present.
+ *     Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are
+ *     supported.
+ *     SPP/ECP FIFO can be driven in PIO or DMA mode.  PIO mode can work with
+ *     or without interrupt support.
+ *
+ *     Hardware ECP mode is not fully implemented (ecp_read_data and
+ *     ecp_write_addr are actually missing).
+ *
+ * To do:
+ *
+ *     Fully implement ECP mode.
+ *     EPP and ECP mode need to be tested.  I currently do not own any
+ *     peripheral supporting these extended mode, and cannot test them.
+ *     If DMA mode works well, decide if support for PIO FIFO modes should be
+ *     dropped.
+ *     Use the io{read,write} family functions when they become available in
+ *     the linux-mips.org tree.  Note: the MIPS specific functions readsb()
+ *     and writesb() are to be translated by ioread8_rep() and iowrite8_rep()
+ *     respectively.
+ */
+
+/* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an
+ * IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1].
+ * This chip supports SPP, bidirectional, EPP and ECP modes.  It has a 16 byte
+ * FIFO buffer and supports DMA transfers.
+ *
+ * [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html
+ *
+ * Theoretically, we could simply use the parport_pc module.  It is however
+ * not so simple.  The parport_pc code assumes that the parallel port
+ * registers are port-mapped.  On the O2, they are memory-mapped.
+ * Furthermore, each register is replicated on 256 consecutive addresses (as
+ * it is for the built-in serial ports on the same chip).
+ */
+
+/*--- Some configuration defines ---------------------------------------*/
+
+/* DEBUG_PARPORT_IP32
+ *     0       disable debug
+ *     1       standard level: pr_debug1 is enabled
+ *     2       parport_ip32_dump_state is enabled
+ *     >=3     verbose level: pr_debug is enabled
+ */
+#if !defined(DEBUG_PARPORT_IP32)
+#      define DEBUG_PARPORT_IP32  0    /* 0 (disabled) for production */
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/* Setup DEBUG macros.  This is done before any includes, just in case we
+ * activate pr_debug() with DEBUG_PARPORT_IP32 >= 3.
+ */
+#if DEBUG_PARPORT_IP32 == 1
+#      warning DEBUG_PARPORT_IP32 == 1
+#elif DEBUG_PARPORT_IP32 == 2
+#      warning DEBUG_PARPORT_IP32 == 2
+#elif DEBUG_PARPORT_IP32 >= 3
+#      warning DEBUG_PARPORT_IP32 >= 3
+#      if !defined(DEBUG)
+#              define DEBUG /* enable pr_debug() in kernel.h */
+#      endif
+#endif
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/ip32/mace.h>
+
+/*--- Global variables -------------------------------------------------*/
+
+/* Verbose probing on by default for debugging. */
+#if DEBUG_PARPORT_IP32 >= 1
+#      define DEFAULT_VERBOSE_PROBING  1
+#else
+#      define DEFAULT_VERBOSE_PROBING  0
+#endif
+
+/* Default prefix for printk */
+#define PPIP32 "parport_ip32: "
+
+/*
+ * These are the module parameters:
+ * @features:          bit mask of features to enable/disable
+ *                     (all enabled by default)
+ * @verbose_probing:   log chit-chat during initialization
+ */
+#define PARPORT_IP32_ENABLE_IRQ        (1U << 0)
+#define PARPORT_IP32_ENABLE_DMA        (1U << 1)
+#define PARPORT_IP32_ENABLE_SPP        (1U << 2)
+#define PARPORT_IP32_ENABLE_EPP        (1U << 3)
+#define PARPORT_IP32_ENABLE_ECP        (1U << 4)
+static unsigned int features = ~0U;
+static int verbose_probing =   DEFAULT_VERBOSE_PROBING;
+
+/* We do not support more than one port. */
+static struct parport *this_port = NULL;
+
+/* Timing constants for FIFO modes.  */
+#define FIFO_NFAULT_TIMEOUT    100     /* milliseconds */
+#define FIFO_POLLING_INTERVAL  50      /* microseconds */
+
+/*--- I/O register definitions -----------------------------------------*/
+
+/**
+ * struct parport_ip32_regs - virtual addresses of parallel port registers
+ * @data:      Data Register
+ * @dsr:       Device Status Register
+ * @dcr:       Device Control Register
+ * @eppAddr:   EPP Address Register
+ * @eppData0:  EPP Data Register 0
+ * @eppData1:  EPP Data Register 1
+ * @eppData2:  EPP Data Register 2
+ * @eppData3:  EPP Data Register 3
+ * @ecpAFifo:  ECP Address FIFO
+ * @fifo:      General FIFO register.  The same address is used for:
+ *             - cFifo, the Parallel Port DATA FIFO
+ *             - ecpDFifo, the ECP Data FIFO
+ *             - tFifo, the ECP Test FIFO
+ * @cnfgA:     Configuration Register A
+ * @cnfgB:     Configuration Register B
+ * @ecr:       Extended Control Register
+ */
+struct parport_ip32_regs {
+       void __iomem *data;
+       void __iomem *dsr;
+       void __iomem *dcr;
+       void __iomem *eppAddr;
+       void __iomem *eppData0;
+       void __iomem *eppData1;
+       void __iomem *eppData2;
+       void __iomem *eppData3;
+       void __iomem *ecpAFifo;
+       void __iomem *fifo;
+       void __iomem *cnfgA;
+       void __iomem *cnfgB;
+       void __iomem *ecr;
+};
+
+/* Device Status Register */
+#define DSR_nBUSY              (1U << 7)       /* PARPORT_STATUS_BUSY */
+#define DSR_nACK               (1U << 6)       /* PARPORT_STATUS_ACK */
+#define DSR_PERROR             (1U << 5)       /* PARPORT_STATUS_PAPEROUT */
+#define DSR_SELECT             (1U << 4)       /* PARPORT_STATUS_SELECT */
+#define DSR_nFAULT             (1U << 3)       /* PARPORT_STATUS_ERROR */
+#define DSR_nPRINT             (1U << 2)       /* specific to TL16PIR552 */
+/* #define DSR_reserved                (1U << 1) */
+#define DSR_TIMEOUT            (1U << 0)       /* EPP timeout */
+
+/* Device Control Register */
+/* #define DCR_reserved                (1U << 7) | (1U <<  6) */
+#define DCR_DIR                        (1U << 5)       /* direction */
+#define DCR_IRQ                        (1U << 4)       /* interrupt on nAck */
+#define DCR_SELECT             (1U << 3)       /* PARPORT_CONTROL_SELECT */
+#define DCR_nINIT              (1U << 2)       /* PARPORT_CONTROL_INIT */
+#define DCR_AUTOFD             (1U << 1)       /* PARPORT_CONTROL_AUTOFD */
+#define DCR_STROBE             (1U << 0)       /* PARPORT_CONTROL_STROBE */
+
+/* ECP Configuration Register A */
+#define CNFGA_IRQ              (1U << 7)
+#define CNFGA_ID_MASK          ((1U << 6) | (1U << 5) | (1U << 4))
+#define CNFGA_ID_SHIFT         4
+#define CNFGA_ID_16            (00U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_8             (01U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_32            (02U << CNFGA_ID_SHIFT)
+/* #define CNFGA_reserved      (1U << 3) */
+#define CNFGA_nBYTEINTRANS     (1U << 2)
+#define CNFGA_PWORDLEFT                ((1U << 1) | (1U << 0))
+
+/* ECP Configuration Register B */
+#define CNFGB_COMPRESS         (1U << 7)
+#define CNFGB_INTRVAL          (1U << 6)
+#define CNFGB_IRQ_MASK         ((1U << 5) | (1U << 4) | (1U << 3))
+#define CNFGB_IRQ_SHIFT                3
+#define CNFGB_DMA_MASK         ((1U << 2) | (1U << 1) | (1U << 0))
+#define CNFGB_DMA_SHIFT                0
+
+/* Extended Control Register */
+#define ECR_MODE_MASK          ((1U << 7) | (1U << 6) | (1U << 5))
+#define ECR_MODE_SHIFT         5
+#define ECR_MODE_SPP           (00U << ECR_MODE_SHIFT)
+#define ECR_MODE_PS2           (01U << ECR_MODE_SHIFT)
+#define ECR_MODE_PPF           (02U << ECR_MODE_SHIFT)
+#define ECR_MODE_ECP           (03U << ECR_MODE_SHIFT)
+#define ECR_MODE_EPP           (04U << ECR_MODE_SHIFT)
+/* #define ECR_MODE_reserved   (05U << ECR_MODE_SHIFT) */
+#define ECR_MODE_TST           (06U << ECR_MODE_SHIFT)
+#define ECR_MODE_CFG           (07U << ECR_MODE_SHIFT)
+#define ECR_nERRINTR           (1U << 4)
+#define ECR_DMAEN              (1U << 3)
+#define ECR_SERVINTR           (1U << 2)
+#define ECR_F_FULL             (1U << 1)
+#define ECR_F_EMPTY            (1U << 0)
+
+/*--- Private data -----------------------------------------------------*/
+
+/**
+ * enum parport_ip32_irq_mode - operation mode of interrupt handler
+ * @PARPORT_IP32_IRQ_FWD:      forward interrupt to the upper parport layer
+ * @PARPORT_IP32_IRQ_HERE:     interrupt is handled locally
+ */
+enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE };
+
+/**
+ * struct parport_ip32_private - private stuff for &struct parport
+ * @regs:              register addresses
+ * @dcr_cache:         cached contents of DCR
+ * @dcr_writable:      bit mask of writable DCR bits
+ * @pword:             number of bytes per PWord
+ * @fifo_depth:                number of PWords that FIFO will hold
+ * @readIntrThreshold: minimum number of PWords we can read
+ *                     if we get an interrupt
+ * @writeIntrThreshold:        minimum number of PWords we can write
+ *                     if we get an interrupt
+ * @irq_mode:          operation mode of interrupt handler for this port
+ * @irq_complete:      mutex used to wait for an interrupt to occur
+ */
+struct parport_ip32_private {
+       struct parport_ip32_regs        regs;
+       unsigned int                    dcr_cache;
+       unsigned int                    dcr_writable;
+       unsigned int                    pword;
+       unsigned int                    fifo_depth;
+       unsigned int                    readIntrThreshold;
+       unsigned int                    writeIntrThreshold;
+       enum parport_ip32_irq_mode      irq_mode;
+       struct completion               irq_complete;
+};
+
+/*--- Debug code -------------------------------------------------------*/
+
+/*
+ * pr_debug1 - print debug messages
+ *
+ * This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+#      define pr_debug1(...)   printk(KERN_DEBUG __VA_ARGS__)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+#      define pr_debug1(...)   do { } while (0)
+#endif
+
+/*
+ * pr_trace, pr_trace1 - trace function calls
+ * @p:         pointer to &struct parport
+ * @fmt:       printk format string
+ * @...:       parameters for format string
+ *
+ * Macros used to trace function calls.  The given string is formatted after
+ * function name.  pr_trace() uses pr_debug(), and pr_trace1() uses
+ * pr_debug1().  __pr_trace() is the low-level macro and is not to be used
+ * directly.
+ */
+#define __pr_trace(pr, p, fmt, ...)                                    \
+       pr("%s: %s" fmt "\n",                                           \
+          ({ const struct parport *__p = (p);                          \
+                  __p ? __p->name : "parport_ip32"; }),                \
+          __func__ , ##__VA_ARGS__)
+#define pr_trace(p, fmt, ...)  __pr_trace(pr_debug, p, fmt , ##__VA_ARGS__)
+#define pr_trace1(p, fmt, ...) __pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__)
+
+/*
+ * __pr_probe, pr_probe - print message if @verbose_probing is true
+ * @p:         pointer to &struct parport
+ * @fmt:       printk format string
+ * @...:       parameters for format string
+ *
+ * For new lines, use pr_probe().  Use __pr_probe() for continued lines.
+ */
+#define __pr_probe(...)                                                        \
+       do { if (verbose_probing) printk(__VA_ARGS__); } while (0)
+#define pr_probe(p, fmt, ...)                                          \
+       __pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__)
+
+/*
+ * parport_ip32_dump_state - print register status of parport
+ * @p:         pointer to &struct parport
+ * @str:       string to add in message
+ * @show_ecp_config:   shall we dump ECP configuration registers too?
+ *
+ * This function is only here for debugging purpose, and should be used with
+ * care.  Reading the parallel port registers may have undesired side effects.
+ * Especially if @show_ecp_config is true, the parallel port is resetted.
+ * This function is only defined if %DEBUG_PARPORT_IP32 >= 2.
+ */
+#if DEBUG_PARPORT_IP32 >= 2
+static void parport_ip32_dump_state(struct parport *p, char *str,
+                                   unsigned int show_ecp_config)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       unsigned int i;
+
+       printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str);
+       {
+               static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF",
+                                                    "ECP", "EPP", "???",
+                                                    "TST", "CFG"};
+               unsigned int ecr = readb(priv->regs.ecr);
+               printk(KERN_DEBUG PPIP32 "    ecr=0x%02x", ecr);
+               printk(" %s",
+                      ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]);
+               if (ecr & ECR_nERRINTR)
+                       printk(",nErrIntrEn");
+               if (ecr & ECR_DMAEN)
+                       printk(",dmaEn");
+               if (ecr & ECR_SERVINTR)
+                       printk(",serviceIntr");
+               if (ecr & ECR_F_FULL)
+                       printk(",f_full");
+               if (ecr & ECR_F_EMPTY)
+                       printk(",f_empty");
+               printk("\n");
+       }
+       if (show_ecp_config) {
+               unsigned int oecr, cnfgA, cnfgB;
+               oecr = readb(priv->regs.ecr);
+               writeb(ECR_MODE_PS2, priv->regs.ecr);
+               writeb(ECR_MODE_CFG, priv->regs.ecr);
+               cnfgA = readb(priv->regs.cnfgA);
+               cnfgB = readb(priv->regs.cnfgB);
+               writeb(ECR_MODE_PS2, priv->regs.ecr);
+               writeb(oecr, priv->regs.ecr);
+               printk(KERN_DEBUG PPIP32 "    cnfgA=0x%02x", cnfgA);
+               printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses");
+               switch (cnfgA & CNFGA_ID_MASK) {
+               case CNFGA_ID_8:
+                       printk(",8 bits");
+                       break;
+               case CNFGA_ID_16:
+                       printk(",16 bits");
+                       break;
+               case CNFGA_ID_32:
+                       printk(",32 bits");
+                       break;
+               default:
+                       printk(",unknown ID");
+                       break;
+               }
+               if (!(cnfgA & CNFGA_nBYTEINTRANS))
+                       printk(",ByteInTrans");
+               if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8)
+                       printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT,
+                              ((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : "");
+               printk("\n");
+               printk(KERN_DEBUG PPIP32 "    cnfgB=0x%02x", cnfgB);
+               printk(" irq=%u,dma=%u",
+                      (cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT,
+                      (cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT);
+               printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL));
+               if (cnfgB & CNFGB_COMPRESS)
+                       printk(",compress");
+               printk("\n");
+       }
+       for (i = 0; i < 2; i++) {
+               unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr);
+               printk(KERN_DEBUG PPIP32 "    dcr(%s)=0x%02x",
+                      i ? "soft" : "hard", dcr);
+               printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd");
+               if (dcr & DCR_IRQ)
+                       printk(",ackIntEn");
+               if (!(dcr & DCR_SELECT))
+                       printk(",nSelectIn");
+               if (dcr & DCR_nINIT)
+                       printk(",nInit");
+               if (!(dcr & DCR_AUTOFD))
+                       printk(",nAutoFD");
+               if (!(dcr & DCR_STROBE))
+                       printk(",nStrobe");
+               printk("\n");
+       }
+#define sep (f++ ? ',' : ' ')
+       {
+               unsigned int f = 0;
+               unsigned int dsr = readb(priv->regs.dsr);
+               printk(KERN_DEBUG PPIP32 "    dsr=0x%02x", dsr);
+               if (!(dsr & DSR_nBUSY))
+                       printk("%cBusy", sep);
+               if (dsr & DSR_nACK)
+                       printk("%cnAck", sep);
+               if (dsr & DSR_PERROR)
+                       printk("%cPError", sep);
+               if (dsr & DSR_SELECT)
+                       printk("%cSelect", sep);
+               if (dsr & DSR_nFAULT)
+                       printk("%cnFault", sep);
+               if (!(dsr & DSR_nPRINT))
+                       printk("%c(Print)", sep);
+               if (dsr & DSR_TIMEOUT)
+                       printk("%cTimeout", sep);
+               printk("\n");
+       }
+#undef sep
+}
+#else /* DEBUG_PARPORT_IP32 < 2 */
+#define parport_ip32_dump_state(...)   do { } while (0)
+#endif
+
+/*
+ * CHECK_EXTRA_BITS - track and log extra bits
+ * @p:         pointer to &struct parport
+ * @b:         byte to inspect
+ * @m:         bit mask of authorized bits
+ *
+ * This is used to track and log extra bits that should not be there in
+ * parport_ip32_write_control() and parport_ip32_frob_control().  It is only
+ * defined if %DEBUG_PARPORT_IP32 >= 1.
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+#define CHECK_EXTRA_BITS(p, b, m)                                      \
+       do {                                                            \
+               unsigned int __b = (b), __m = (m);                      \
+               if (__b & ~__m)                                         \
+                       pr_debug1(PPIP32 "%s: extra bits in %s(%s): "   \
+                                 "0x%02x/0x%02x\n",                    \
+                                 (p)->name, __func__, #b, __b, __m);   \
+       } while (0)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+#define CHECK_EXTRA_BITS(...)  do { } while (0)
+#endif
+
+/*--- IP32 parallel port DMA operations --------------------------------*/
+
+/**
+ * struct parport_ip32_dma_data - private data needed for DMA operation
+ * @dir:       DMA direction (from or to device)
+ * @buf:       buffer physical address
+ * @len:       buffer length
+ * @next:      address of next bytes to DMA transfer
+ * @left:      number of bytes remaining
+ * @ctx:       next context to write (0: context_a; 1: context_b)
+ * @irq_on:    are the DMA IRQs currently enabled?
+ * @lock:      spinlock to protect access to the structure
+ */
+struct parport_ip32_dma_data {
+       enum dma_data_direction         dir;
+       dma_addr_t                      buf;
+       dma_addr_t                      next;
+       size_t                          len;
+       size_t                          left;
+       unsigned int                    ctx;
+       unsigned int                    irq_on;
+       spinlock_t                      lock;
+};
+static struct parport_ip32_dma_data parport_ip32_dma;
+
+/**
+ * parport_ip32_dma_setup_context - setup next DMA context
+ * @limit:     maximum data size for the context
+ *
+ * The alignment constraints must be verified in caller function, and the
+ * parameter @limit must be set accordingly.
+ */
+static void parport_ip32_dma_setup_context(unsigned int limit)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&parport_ip32_dma.lock, flags);
+       if (parport_ip32_dma.left > 0) {
+               /* Note: ctxreg is "volatile" here only because
+                * mace->perif.ctrl.parport.context_a and context_b are
+                * "volatile".  */
+               volatile u64 __iomem *ctxreg = (parport_ip32_dma.ctx == 0) ?
+                       &mace->perif.ctrl.parport.context_a :
+                       &mace->perif.ctrl.parport.context_b;
+               u64 count;
+               u64 ctxval;
+               if (parport_ip32_dma.left <= limit) {
+                       count = parport_ip32_dma.left;
+                       ctxval = MACEPAR_CONTEXT_LASTFLAG;
+               } else {
+                       count = limit;
+                       ctxval = 0;
+               }
+
+               pr_trace(NULL,
+                        "(%u): 0x%04x:0x%04x, %u -> %u%s",
+                        limit,
+                        (unsigned int)parport_ip32_dma.buf,
+                        (unsigned int)parport_ip32_dma.next,
+                        (unsigned int)count,
+                        parport_ip32_dma.ctx, ctxval ? "*" : "");
+
+               ctxval |= parport_ip32_dma.next &
+                       MACEPAR_CONTEXT_BASEADDR_MASK;
+               ctxval |= ((count - 1) << MACEPAR_CONTEXT_DATALEN_SHIFT) &
+                       MACEPAR_CONTEXT_DATALEN_MASK;
+               writeq(ctxval, ctxreg);
+               parport_ip32_dma.next += count;
+               parport_ip32_dma.left -= count;
+               parport_ip32_dma.ctx ^= 1U;
+       }
+       /* If there is nothing more to send, disable IRQs to avoid to
+        * face an IRQ storm which can lock the machine.  Disable them
+        * only once. */
+       if (parport_ip32_dma.left == 0 && parport_ip32_dma.irq_on) {
+               pr_debug(PPIP32 "IRQ off (ctx)\n");
+               disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+               disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+               parport_ip32_dma.irq_on = 0;
+       }
+       spin_unlock_irqrestore(&parport_ip32_dma.lock, flags);
+}
+
+/**
+ * parport_ip32_dma_interrupt - DMA interrupt handler
+ * @irq:       interrupt number
+ * @dev_id:    unused
+ * @regs:      pointer to &struct pt_regs
+ */
+static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
+                                             struct pt_regs *regs)
+{
+       if (parport_ip32_dma.left)
+               pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
+       parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+       return IRQ_HANDLED;
+}
+
+#if DEBUG_PARPORT_IP32
+static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id,
+                                              struct pt_regs *regs)
+{
+       pr_trace1(NULL, "(%d)", irq);
+       return IRQ_HANDLED;
+}
+#endif
+
+/**
+ * parport_ip32_dma_start - begins a DMA transfer
+ * @dir:       DMA direction: DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @addr:      pointer to data buffer
+ * @count:     buffer size
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static int parport_ip32_dma_start(enum dma_data_direction dir,
+                                 void *addr, size_t count)
+{
+       unsigned int limit;
+       u64 ctrl;
+
+       pr_trace(NULL, "(%d, %lu)", dir, (unsigned long)count);
+
+       /* FIXME - add support for DMA_FROM_DEVICE.  In this case, buffer must
+        * be 64 bytes aligned. */
+       BUG_ON(dir != DMA_TO_DEVICE);
+
+       /* Reset DMA controller */
+       ctrl = MACEPAR_CTLSTAT_RESET;
+       writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+       /* DMA IRQs should normally be enabled */
+       if (!parport_ip32_dma.irq_on) {
+               WARN_ON(1);
+               enable_irq(MACEISA_PAR_CTXA_IRQ);
+               enable_irq(MACEISA_PAR_CTXB_IRQ);
+               parport_ip32_dma.irq_on = 1;
+       }
+
+       /* Prepare DMA pointers */
+       parport_ip32_dma.dir = dir;
+       parport_ip32_dma.buf = dma_map_single(NULL, addr, count, dir);
+       parport_ip32_dma.len = count;
+       parport_ip32_dma.next = parport_ip32_dma.buf;
+       parport_ip32_dma.left = parport_ip32_dma.len;
+       parport_ip32_dma.ctx = 0;
+
+       /* Setup DMA direction and first two contexts */
+       ctrl = (dir == DMA_TO_DEVICE) ? 0 : MACEPAR_CTLSTAT_DIRECTION;
+       writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+       /* Single transfer should not cross a 4K page boundary */
+       limit = MACEPAR_CONTEXT_DATA_BOUND -
+               (parport_ip32_dma.next & (MACEPAR_CONTEXT_DATA_BOUND - 1));
+       parport_ip32_dma_setup_context(limit);
+       parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+
+       /* Real start of DMA transfer */
+       ctrl |= MACEPAR_CTLSTAT_ENABLE;
+       writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+       return 0;
+}
+
+/**
+ * parport_ip32_dma_stop - ends a running DMA transfer
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static void parport_ip32_dma_stop(void)
+{
+       u64 ctx_a;
+       u64 ctx_b;
+       u64 ctrl;
+       u64 diag;
+       size_t res[2];  /* {[0] = res_a, [1] = res_b} */
+
+       pr_trace(NULL, "()");
+
+       /* Disable IRQs */
+       spin_lock_irq(&parport_ip32_dma.lock);
+       if (parport_ip32_dma.irq_on) {
+               pr_debug(PPIP32 "IRQ off (stop)\n");
+               disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+               disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+               parport_ip32_dma.irq_on = 0;
+       }
+       spin_unlock_irq(&parport_ip32_dma.lock);
+       /* Force IRQ synchronization, even if the IRQs were disabled
+        * elsewhere. */
+       synchronize_irq(MACEISA_PAR_CTXA_IRQ);
+       synchronize_irq(MACEISA_PAR_CTXB_IRQ);
+
+       /* Stop DMA transfer */
+       ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+       ctrl &= ~MACEPAR_CTLSTAT_ENABLE;
+       writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+       /* Adjust residue (parport_ip32_dma.left) */
+       ctx_a = readq(&mace->perif.ctrl.parport.context_a);
+       ctx_b = readq(&mace->perif.ctrl.parport.context_b);
+       ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+       diag = readq(&mace->perif.ctrl.parport.diagnostic);
+       res[0] = (ctrl & MACEPAR_CTLSTAT_CTXA_VALID) ?
+               1 + ((ctx_a & MACEPAR_CONTEXT_DATALEN_MASK) >>
+                    MACEPAR_CONTEXT_DATALEN_SHIFT) :
+               0;
+       res[1] = (ctrl & MACEPAR_CTLSTAT_CTXB_VALID) ?
+               1 + ((ctx_b & MACEPAR_CONTEXT_DATALEN_MASK) >>
+                    MACEPAR_CONTEXT_DATALEN_SHIFT) :
+               0;
+       if (diag & MACEPAR_DIAG_DMACTIVE)
+               res[(diag & MACEPAR_DIAG_CTXINUSE) != 0] =
+                       1 + ((diag & MACEPAR_DIAG_CTRMASK) >>
+                            MACEPAR_DIAG_CTRSHIFT);
+       parport_ip32_dma.left += res[0] + res[1];
+
+       /* Reset DMA controller, and re-enable IRQs */
+       ctrl = MACEPAR_CTLSTAT_RESET;
+       writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+       pr_debug(PPIP32 "IRQ on (stop)\n");
+       enable_irq(MACEISA_PAR_CTXA_IRQ);
+       enable_irq(MACEISA_PAR_CTXB_IRQ);
+       parport_ip32_dma.irq_on = 1;
+
+       dma_unmap_single(NULL, parport_ip32_dma.buf, parport_ip32_dma.len,
+                        parport_ip32_dma.dir);
+}
+
+/**
+ * parport_ip32_dma_get_residue - get residue from last DMA transfer
+ *
+ * Returns the number of bytes remaining from last DMA transfer.
+ */
+static inline size_t parport_ip32_dma_get_residue(void)
+{
+       return parport_ip32_dma.left;
+}
+
+/**
+ * parport_ip32_dma_register - initialize DMA engine
+ *
+ * Returns zero for success.
+ */
+static int parport_ip32_dma_register(void)
+{
+       int err;
+
+       spin_lock_init(&parport_ip32_dma.lock);
+       parport_ip32_dma.irq_on = 1;
+
+       /* Reset DMA controller */
+       writeq(MACEPAR_CTLSTAT_RESET, &mace->perif.ctrl.parport.cntlstat);
+
+       /* Request IRQs */
+       err = request_irq(MACEISA_PAR_CTXA_IRQ, parport_ip32_dma_interrupt,
+                         0, "parport_ip32", NULL);
+       if (err)
+               goto fail_a;
+       err = request_irq(MACEISA_PAR_CTXB_IRQ, parport_ip32_dma_interrupt,
+                         0, "parport_ip32", NULL);
+       if (err)
+               goto fail_b;
+#if DEBUG_PARPORT_IP32
+       /* FIXME - what is this IRQ for? */
+       err = request_irq(MACEISA_PAR_MERR_IRQ, parport_ip32_merr_interrupt,
+                         0, "parport_ip32", NULL);
+       if (err)
+               goto fail_merr;
+#endif
+       return 0;
+
+#if DEBUG_PARPORT_IP32
+fail_merr:
+       free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+#endif
+fail_b:
+       free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+fail_a:
+       return err;
+}
+
+/**
+ * parport_ip32_dma_unregister - release and free resources for DMA engine
+ */
+static void parport_ip32_dma_unregister(void)
+{
+#if DEBUG_PARPORT_IP32
+       free_irq(MACEISA_PAR_MERR_IRQ, NULL);
+#endif
+       free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+       free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+}
+
+/*--- Interrupt handlers and associates --------------------------------*/
+
+/**
+ * parport_ip32_wakeup - wakes up code waiting for an interrupt
+ * @p:         pointer to &struct parport
+ */
+static inline void parport_ip32_wakeup(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       complete(&priv->irq_complete);
+}
+
+/**
+ * parport_ip32_interrupt - interrupt handler
+ * @irq:       interrupt number
+ * @dev_id:    pointer to &struct parport
+ * @regs:      pointer to &struct pt_regs
+ *
+ * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
+ * %PARPORT_IP32_IRQ_FWD.
+ */
+static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id,
+                                         struct pt_regs *regs)
+{
+       struct parport * const p = dev_id;
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       enum parport_ip32_irq_mode irq_mode = priv->irq_mode;
+       switch (irq_mode) {
+       case PARPORT_IP32_IRQ_FWD:
+               parport_generic_irq(irq, p, regs);
+               break;
+       case PARPORT_IP32_IRQ_HERE:
+               parport_ip32_wakeup(p);
+               break;
+       }
+       return IRQ_HANDLED;
+}
+
+/*--- Some utility function to manipulate ECR register -----------------*/
+
+/**
+ * parport_ip32_read_econtrol - read contents of the ECR register
+ * @p:         pointer to &struct parport
+ */
+static inline unsigned int parport_ip32_read_econtrol(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return readb(priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_write_econtrol - write new contents to the ECR register
+ * @p:         pointer to &struct parport
+ * @c:         new value to write
+ */
+static inline void parport_ip32_write_econtrol(struct parport *p,
+                                              unsigned int c)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       writeb(c, priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_frob_econtrol - change bits from the ECR register
+ * @p:         pointer to &struct parport
+ * @mask:      bit mask of bits to change
+ * @val:       new value for changed bits
+ *
+ * Read from the ECR, mask out the bits in @mask, exclusive-or with the bits
+ * in @val, and write the result to the ECR.
+ */
+static inline void parport_ip32_frob_econtrol(struct parport *p,
+                                             unsigned int mask,
+                                             unsigned int val)
+{
+       unsigned int c;
+       c = (parport_ip32_read_econtrol(p) & ~mask) ^ val;
+       parport_ip32_write_econtrol(p, c);
+}
+
+/**
+ * parport_ip32_set_mode - change mode of ECP port
+ * @p:         pointer to &struct parport
+ * @mode:      new mode to write in ECR
+ *
+ * ECR is reset in a sane state (interrupts and DMA disabled), and placed in
+ * mode @mode.  Go through PS2 mode if needed.
+ */
+static void parport_ip32_set_mode(struct parport *p, unsigned int mode)
+{
+       unsigned int omode;
+
+       mode &= ECR_MODE_MASK;
+       omode = parport_ip32_read_econtrol(p) & ECR_MODE_MASK;
+
+       if (!(mode == ECR_MODE_SPP || mode == ECR_MODE_PS2
+             || omode == ECR_MODE_SPP || omode == ECR_MODE_PS2)) {
+               /* We have to go through PS2 mode */
+               unsigned int ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+               parport_ip32_write_econtrol(p, ecr);
+       }
+       parport_ip32_write_econtrol(p, mode | ECR_nERRINTR | ECR_SERVINTR);
+}
+
+/*--- Basic functions needed for parport -------------------------------*/
+
+/**
+ * parport_ip32_read_data - return current contents of the DATA register
+ * @p:         pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_data(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return readb(priv->regs.data);
+}
+
+/**
+ * parport_ip32_write_data - set new contents for the DATA register
+ * @p:         pointer to &struct parport
+ * @d:         new value to write
+ */
+static inline void parport_ip32_write_data(struct parport *p, unsigned char d)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       writeb(d, priv->regs.data);
+}
+
+/**
+ * parport_ip32_read_status - return current contents of the DSR register
+ * @p:         pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_status(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return readb(priv->regs.dsr);
+}
+
+/**
+ * __parport_ip32_read_control - return cached contents of the DCR register
+ * @p:         pointer to &struct parport
+ */
+static inline unsigned int __parport_ip32_read_control(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return priv->dcr_cache; /* use soft copy */
+}
+
+/**
+ * __parport_ip32_write_control - set new contents for the DCR register
+ * @p:         pointer to &struct parport
+ * @c:         new value to write
+ */
+static inline void __parport_ip32_write_control(struct parport *p,
+                                               unsigned int c)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       CHECK_EXTRA_BITS(p, c, priv->dcr_writable);
+       c &= priv->dcr_writable; /* only writable bits */
+       writeb(c, priv->regs.dcr);
+       priv->dcr_cache = c;            /* update soft copy */
+}
+
+/**
+ * __parport_ip32_frob_control - change bits from the DCR register
+ * @p:         pointer to &struct parport
+ * @mask:      bit mask of bits to change
+ * @val:       new value for changed bits
+ *
+ * This is equivalent to read from the DCR, mask out the bits in @mask,
+ * exclusive-or with the bits in @val, and write the result to the DCR.
+ * Actually, the cached contents of the DCR is used.
+ */
+static inline void __parport_ip32_frob_control(struct parport *p,
+                                              unsigned int mask,
+                                              unsigned int val)
+{
+       unsigned int c;
+       c = (__parport_ip32_read_control(p) & ~mask) ^ val;
+       __parport_ip32_write_control(p, c);
+}
+
+/**
+ * parport_ip32_read_control - return cached contents of the DCR register
+ * @p:         pointer to &struct parport
+ *
+ * The return value is masked so as to only return the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_read_control(struct parport *p)
+{
+       const unsigned int rm =
+               DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+       return __parport_ip32_read_control(p) & rm;
+}
+
+/**
+ * parport_ip32_write_control - set new contents for the DCR register
+ * @p:         pointer to &struct parport
+ * @c:         new value to write
+ *
+ * The value is masked so as to only change the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline void parport_ip32_write_control(struct parport *p,
+                                             unsigned char c)
+{
+       const unsigned int wm =
+               DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+       CHECK_EXTRA_BITS(p, c, wm);
+       __parport_ip32_frob_control(p, wm, c & wm);
+}
+
+/**
+ * parport_ip32_frob_control - change bits from the DCR register
+ * @p:         pointer to &struct parport
+ * @mask:      bit mask of bits to change
+ * @val:       new value for changed bits
+ *
+ * This differs from __parport_ip32_frob_control() in that it only allows to
+ * change the value of %DCR_STROBE, %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_frob_control(struct parport *p,
+                                                     unsigned char mask,
+                                                     unsigned char val)
+{
+       const unsigned int wm =
+               DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+       CHECK_EXTRA_BITS(p, mask, wm);
+       CHECK_EXTRA_BITS(p, val, wm);
+       __parport_ip32_frob_control(p, mask & wm, val & wm);
+       return parport_ip32_read_control(p);
+}
+
+/**
+ * parport_ip32_disable_irq - disable interrupts on the rising edge of nACK
+ * @p:         pointer to &struct parport
+ */
+static inline void parport_ip32_disable_irq(struct parport *p)
+{
+       __parport_ip32_frob_control(p, DCR_IRQ, 0);
+}
+
+/**
+ * parport_ip32_enable_irq - enable interrupts on the rising edge of nACK
+ * @p:         pointer to &struct parport
+ */
+static inline void parport_ip32_enable_irq(struct parport *p)
+{
+       __parport_ip32_frob_control(p, DCR_IRQ, DCR_IRQ);
+}
+
+/**
+ * parport_ip32_data_forward - enable host-to-peripheral communications
+ * @p:         pointer to &struct parport
+ *
+ * Enable the data line drivers, for 8-bit host-to-peripheral communications.
+ */
+static inline void parport_ip32_data_forward(struct parport *p)
+{
+       __parport_ip32_frob_control(p, DCR_DIR, 0);
+}
+
+/**
+ * parport_ip32_data_reverse - enable peripheral-to-host communications
+ * @p:         pointer to &struct parport
+ *
+ * Place the data bus in a high impedance state, if @p->modes has the
+ * PARPORT_MODE_TRISTATE bit set.
+ */
+static inline void parport_ip32_data_reverse(struct parport *p)
+{
+       __parport_ip32_frob_control(p, DCR_DIR, DCR_DIR);
+}
+
+/**
+ * parport_ip32_init_state - for core parport code
+ * @dev:       pointer to &struct pardevice
+ * @s:         pointer to &struct parport_state to initialize
+ */
+static void parport_ip32_init_state(struct pardevice *dev,
+                                   struct parport_state *s)
+{
+       s->u.ip32.dcr = DCR_SELECT | DCR_nINIT;
+       s->u.ip32.ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+}
+
+/**
+ * parport_ip32_save_state - for core parport code
+ * @p:         pointer to &struct parport
+ * @s:         pointer to &struct parport_state to save state to
+ */
+static void parport_ip32_save_state(struct parport *p,
+                                   struct parport_state *s)
+{
+       s->u.ip32.dcr = __parport_ip32_read_control(p);
+       s->u.ip32.ecr = parport_ip32_read_econtrol(p);
+}
+
+/**
+ * parport_ip32_restore_state - for core parport code
+ * @p:         pointer to &struct parport
+ * @s:         pointer to &struct parport_state to restore state from
+ */
+static void parport_ip32_restore_state(struct parport *p,
+                                      struct parport_state *s)
+{
+       parport_ip32_set_mode(p, s->u.ip32.ecr & ECR_MODE_MASK);
+       parport_ip32_write_econtrol(p, s->u.ip32.ecr);
+       __parport_ip32_write_control(p, s->u.ip32.dcr);
+}
+
+/*--- EPP mode functions -----------------------------------------------*/
+
+/**
+ * parport_ip32_clear_epp_timeout - clear Timeout bit in EPP mode
+ * @p:         pointer to &struct parport
+ *
+ * Returns 1 if the Timeout bit is clear, and 0 otherwise.
+ */
+static unsigned int parport_ip32_clear_epp_timeout(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       unsigned int cleared;
+
+       if (!(parport_ip32_read_status(p) & DSR_TIMEOUT))
+               cleared = 1;
+       else {
+               unsigned int r;
+               /* To clear timeout some chips require double read */
+               parport_ip32_read_status(p);
+               r = parport_ip32_read_status(p);
+               /* Some reset by writing 1 */
+               writeb(r | DSR_TIMEOUT, priv->regs.dsr);
+               /* Others by writing 0 */
+               writeb(r & ~DSR_TIMEOUT, priv->regs.dsr);
+
+               r = parport_ip32_read_status(p);
+               cleared = !(r & DSR_TIMEOUT);
+       }
+
+       pr_trace(p, "(): %s", cleared ? "cleared" : "failed");
+       return cleared;
+}
+
+/**
+ * parport_ip32_epp_read - generic EPP read function
+ * @eppreg:    I/O register to read from
+ * @p:         pointer to &struct parport
+ * @buf:       buffer to store read data
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read(void __iomem *eppreg,
+                                   struct parport *p, void *buf,
+                                   size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       size_t got;
+       parport_ip32_set_mode(p, ECR_MODE_EPP);
+       parport_ip32_data_reverse(p);
+       parport_ip32_write_control(p, DCR_nINIT);
+       if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+               readsb(eppreg, buf, len);
+               if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+                       parport_ip32_clear_epp_timeout(p);
+                       return -EIO;
+               }
+               got = len;
+       } else {
+               u8 *bufp = buf;
+               for (got = 0; got < len; got++) {
+                       *bufp++ = readb(eppreg);
+                       if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+                               parport_ip32_clear_epp_timeout(p);
+                               break;
+                       }
+               }
+       }
+       parport_ip32_data_forward(p);
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       return got;
+}
+
+/**
+ * parport_ip32_epp_write - generic EPP write function
+ * @eppreg:    I/O register to write to
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write(void __iomem *eppreg,
+                                    struct parport *p, const void *buf,
+                                    size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       size_t written;
+       parport_ip32_set_mode(p, ECR_MODE_EPP);
+       parport_ip32_data_forward(p);
+       parport_ip32_write_control(p, DCR_nINIT);
+       if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+               writesb(eppreg, buf, len);
+               if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+                       parport_ip32_clear_epp_timeout(p);
+                       return -EIO;
+               }
+               written = len;
+       } else {
+               const u8 *bufp = buf;
+               for (written = 0; written < len; written++) {
+                       writeb(*bufp++, eppreg);
+                       if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+                               parport_ip32_clear_epp_timeout(p);
+                               break;
+                       }
+               }
+       }
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       return written;
+}
+
+/**
+ * parport_ip32_epp_read_data - read a block of data in EPP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer to store read data
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_data(struct parport *p, void *buf,
+                                        size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return parport_ip32_epp_read(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_data - write a block of data in EPP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_data(struct parport *p, const void *buf,
+                                         size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return parport_ip32_epp_write(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_read_addr - read a block of addresses in EPP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer to store read data
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_addr(struct parport *p, void *buf,
+                                        size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return parport_ip32_epp_read(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_addr - write a block of addresses in EPP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ * @flags:     may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_addr(struct parport *p, const void *buf,
+                                         size_t len, int flags)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       return parport_ip32_epp_write(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/*--- ECP mode functions (FIFO) ----------------------------------------*/
+
+/**
+ * parport_ip32_fifo_wait_break - check if the waiting function should return
+ * @p:         pointer to &struct parport
+ * @expire:    timeout expiring date, in jiffies
+ *
+ * parport_ip32_fifo_wait_break() checks if the waiting function should return
+ * immediately or not.  The break conditions are:
+ *     - expired timeout;
+ *     - a pending signal;
+ *     - nFault asserted low.
+ * This function also calls cond_resched().
+ */
+static unsigned int parport_ip32_fifo_wait_break(struct parport *p,
+                                                unsigned long expire)
+{
+       cond_resched();
+       if (time_after(jiffies, expire)) {
+               pr_debug1(PPIP32 "%s: FIFO write timed out\n", p->name);
+               return 1;
+       }
+       if (signal_pending(current)) {
+               pr_debug1(PPIP32 "%s: Signal pending\n", p->name);
+               return 1;
+       }
+       if (!(parport_ip32_read_status(p) & DSR_nFAULT)) {
+               pr_debug1(PPIP32 "%s: nFault asserted low\n", p->name);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * parport_ip32_fwp_wait_polling - wait for FIFO to empty (polling)
+ * @p:         pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO.  A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_polling(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport * const physport = p->physport;
+       unsigned long expire;
+       unsigned int count;
+       unsigned int ecr;
+
+       expire = jiffies + physport->cad->timeout;
+       count = 0;
+       while (1) {
+               if (parport_ip32_fifo_wait_break(p, expire))
+                       break;
+
+               /* Check FIFO state.  We do nothing when the FIFO is nor full,
+                * nor empty.  It appears that the FIFO full bit is not always
+                * reliable, the FIFO state is sometimes wrongly reported, and
+                * the chip gets confused if we give it another byte. */
+               ecr = parport_ip32_read_econtrol(p);
+               if (ecr & ECR_F_EMPTY) {
+                       /* FIFO is empty, fill it up */
+                       count = priv->fifo_depth;
+                       break;
+               }
+
+               /* Wait a moment... */
+               udelay(FIFO_POLLING_INTERVAL);
+       } /* while (1) */
+
+       return count;
+}
+
+/**
+ * parport_ip32_fwp_wait_interrupt - wait for FIFO to empty (interrupt-driven)
+ * @p:         pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO.  A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_interrupt(struct parport *p)
+{
+       static unsigned int lost_interrupt = 0;
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport * const physport = p->physport;
+       unsigned long nfault_timeout;
+       unsigned long expire;
+       unsigned int count;
+       unsigned int ecr;
+
+       nfault_timeout = min((unsigned long)physport->cad->timeout,
+                            msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+       expire = jiffies + physport->cad->timeout;
+       count = 0;
+       while (1) {
+               if (parport_ip32_fifo_wait_break(p, expire))
+                       break;
+
+               /* Initialize mutex used to take interrupts into account */
+               INIT_COMPLETION(priv->irq_complete);
+
+               /* Enable serviceIntr */
+               parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+               /* Enabling serviceIntr while the FIFO is empty does not
+                * always generate an interrupt, so check for emptiness
+                * now. */
+               ecr = parport_ip32_read_econtrol(p);
+               if (!(ecr & ECR_F_EMPTY)) {
+                       /* FIFO is not empty: wait for an interrupt or a
+                        * timeout to occur */
+                       wait_for_completion_interruptible_timeout(
+                               &priv->irq_complete, nfault_timeout);
+                       ecr = parport_ip32_read_econtrol(p);
+                       if ((ecr & ECR_F_EMPTY) && !(ecr & ECR_SERVINTR)
+                           && !lost_interrupt) {
+                               printk(KERN_WARNING PPIP32
+                                      "%s: lost interrupt in %s\n",
+                                      p->name, __func__);
+                               lost_interrupt = 1;
+                       }
+               }
+
+               /* Disable serviceIntr */
+               parport_ip32_frob_econtrol(p, ECR_SERVINTR, ECR_SERVINTR);
+
+               /* Check FIFO state */
+               if (ecr & ECR_F_EMPTY) {
+                       /* FIFO is empty, fill it up */
+                       count = priv->fifo_depth;
+                       break;
+               } else if (ecr & ECR_SERVINTR) {
+                       /* FIFO is not empty, but we know that can safely push
+                        * writeIntrThreshold bytes into it */
+                       count = priv->writeIntrThreshold;
+                       break;
+               }
+               /* FIFO is not empty, and we did not get any interrupt.
+                * Either it's time to check for nFault, or a signal is
+                * pending.  This is verified in
+                * parport_ip32_fifo_wait_break(), so we continue the loop. */
+       } /* while (1) */
+
+       return count;
+}
+
+/**
+ * parport_ip32_fifo_write_block_pio - write a block of data (PIO mode)
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ *
+ * Uses PIO to write the contents of the buffer @buf into the parallel port
+ * FIFO.  Returns the number of bytes that were actually written.  It can work
+ * with or without the help of interrupts.  The parallel port must be
+ * correctly initialized before calling parport_ip32_fifo_write_block_pio().
+ */
+static size_t parport_ip32_fifo_write_block_pio(struct parport *p,
+                                               const void *buf, size_t len)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       const u8 *bufp = buf;
+       size_t left = len;
+
+       priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+       while (left > 0) {
+               unsigned int count;
+
+               count = (p->irq == PARPORT_IRQ_NONE) ?
+                       parport_ip32_fwp_wait_polling(p) :
+                       parport_ip32_fwp_wait_interrupt(p);
+               if (count == 0)
+                       break;  /* Transmission should be stopped */
+               if (count > left)
+                       count = left;
+               if (count == 1) {
+                       writeb(*bufp, priv->regs.fifo);
+                       bufp++, left--;
+               } else {
+                       writesb(priv->regs.fifo, bufp, count);
+                       bufp += count, left -= count;
+               }
+       }
+
+       priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+       return len - left;
+}
+
+/**
+ * parport_ip32_fifo_write_block_dma - write a block of data (DMA mode)
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ *
+ * Uses DMA to write the contents of the buffer @buf into the parallel port
+ * FIFO.  Returns the number of bytes that were actually written.  The
+ * parallel port must be correctly initialized before calling
+ * parport_ip32_fifo_write_block_dma().
+ */
+static size_t parport_ip32_fifo_write_block_dma(struct parport *p,
+                                               const void *buf, size_t len)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport * const physport = p->physport;
+       unsigned long nfault_timeout;
+       unsigned long expire;
+       size_t written;
+       unsigned int ecr;
+
+       priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+       parport_ip32_dma_start(DMA_TO_DEVICE, (void *)buf, len);
+       INIT_COMPLETION(priv->irq_complete);
+       parport_ip32_frob_econtrol(p, ECR_DMAEN | ECR_SERVINTR, ECR_DMAEN);
+
+       nfault_timeout = min((unsigned long)physport->cad->timeout,
+                            msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+       expire = jiffies + physport->cad->timeout;
+       while (1) {
+               if (parport_ip32_fifo_wait_break(p, expire))
+                       break;
+               wait_for_completion_interruptible_timeout(&priv->irq_complete,
+                                                         nfault_timeout);
+               ecr = parport_ip32_read_econtrol(p);
+               if (ecr & ECR_SERVINTR)
+                       break;  /* DMA transfer just finished */
+       }
+       parport_ip32_dma_stop();
+       written = len - parport_ip32_dma_get_residue();
+
+       priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+       return written;
+}
+
+/**
+ * parport_ip32_fifo_write_block - write a block of data
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ *
+ * Uses PIO or DMA to write the contents of the buffer @buf into the parallel
+ * p FIFO.  Returns the number of bytes that were actually written.
+ */
+static size_t parport_ip32_fifo_write_block(struct parport *p,
+                                           const void *buf, size_t len)
+{
+       size_t written = 0;
+       if (len)
+               /* FIXME - Maybe some threshold value should be set for @len
+                * under which we revert to PIO mode? */
+               written = (p->modes & PARPORT_MODE_DMA) ?
+                       parport_ip32_fifo_write_block_dma(p, buf, len) :
+                       parport_ip32_fifo_write_block_pio(p, buf, len);
+       return written;
+}
+
+/**
+ * parport_ip32_drain_fifo - wait for FIFO to empty
+ * @p:         pointer to &struct parport
+ * @timeout:   timeout, in jiffies
+ *
+ * This function waits for FIFO to empty.  It returns 1 when FIFO is empty, or
+ * 0 if the timeout @timeout is reached before, or if a signal is pending.
+ */
+static unsigned int parport_ip32_drain_fifo(struct parport *p,
+                                           unsigned long timeout)
+{
+       unsigned long expire = jiffies + timeout;
+       unsigned int polling_interval;
+       unsigned int counter;
+
+       /* Busy wait for approx. 200us */
+       for (counter = 0; counter < 40; counter++) {
+               if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+                       break;
+               if (time_after(jiffies, expire))
+                       break;
+               if (signal_pending(current))
+                       break;
+               udelay(5);
+       }
+       /* Poll slowly.  Polling interval starts with 1 millisecond, and is
+        * increased exponentially until 128.  */
+       polling_interval = 1; /* msecs */
+       while (!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY)) {
+               if (time_after_eq(jiffies, expire))
+                       break;
+               msleep_interruptible(polling_interval);
+               if (signal_pending(current))
+                       break;
+               if (polling_interval < 128)
+                       polling_interval *= 2;
+       }
+
+       return !!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY);
+}
+
+/**
+ * parport_ip32_get_fifo_residue - reset FIFO
+ * @p:         pointer to &struct parport
+ * @mode:      current operation mode (ECR_MODE_PPF or ECR_MODE_ECP)
+ *
+ * This function resets FIFO, and returns the number of bytes remaining in it.
+ */
+static unsigned int parport_ip32_get_fifo_residue(struct parport *p,
+                                                 unsigned int mode)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       unsigned int residue;
+       unsigned int cnfga;
+
+       /* FIXME - We are missing one byte if the printer is off-line.  I
+        * don't know how to detect this.  It looks that the full bit is not
+        * always reliable.  For the moment, the problem is avoided in most
+        * cases by testing for BUSY in parport_ip32_compat_write_data().
+        */
+       if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+               residue = 0;
+       else {
+               pr_debug1(PPIP32 "%s: FIFO is stuck\n", p->name);
+
+               /* Stop all transfers.
+                *
+                * Microsoft's document instructs to drive DCR_STROBE to 0,
+                * but it doesn't work (at least in Compatibility mode, not
+                * tested in ECP mode).  Switching directly to Test mode (as
+                * in parport_pc) is not an option: it does confuse the port,
+                * ECP service interrupts are no more working after that.  A
+                * hard reset is then needed to revert to a sane state.
+                *
+                * Let's hope that the FIFO is really stuck and that the
+                * peripheral doesn't wake up now.
+                */
+               parport_ip32_frob_control(p, DCR_STROBE, 0);
+
+               /* Fill up FIFO */
+               for (residue = priv->fifo_depth; residue > 0; residue--) {
+                       if (parport_ip32_read_econtrol(p) & ECR_F_FULL)
+                               break;
+                       writeb(0x00, priv->regs.fifo);
+               }
+       }
+       if (residue)
+               pr_debug1(PPIP32 "%s: %d PWord%s left in FIFO\n",
+                         p->name, residue,
+                         (residue == 1) ? " was" : "s were");
+
+       /* Now reset the FIFO */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+
+       /* Host recovery for ECP mode */
+       if (mode == ECR_MODE_ECP) {
+               parport_ip32_data_reverse(p);
+               parport_ip32_frob_control(p, DCR_nINIT, 0);
+               if (parport_wait_peripheral(p, DSR_PERROR, 0))
+                       pr_debug1(PPIP32 "%s: PEerror timeout 1 in %s\n",
+                                 p->name, __func__);
+               parport_ip32_frob_control(p, DCR_STROBE, DCR_STROBE);
+               parport_ip32_frob_control(p, DCR_nINIT, DCR_nINIT);
+               if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR))
+                       pr_debug1(PPIP32 "%s: PEerror timeout 2 in %s\n",
+                                 p->name, __func__);
+       }
+
+       /* Adjust residue if needed */
+       parport_ip32_set_mode(p, ECR_MODE_CFG);
+       cnfga = readb(priv->regs.cnfgA);
+       if (!(cnfga & CNFGA_nBYTEINTRANS)) {
+               pr_debug1(PPIP32 "%s: cnfgA contains 0x%02x\n",
+                         p->name, cnfga);
+               pr_debug1(PPIP32 "%s: Accounting for extra byte\n",
+                         p->name);
+               residue++;
+       }
+
+       /* Don't care about partial PWords since we do not support
+        * PWord != 1 byte. */
+
+       /* Back to forward PS2 mode. */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       parport_ip32_data_forward(p);
+
+       return residue;
+}
+
+/**
+ * parport_ip32_compat_write_data - write a block of data in SPP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ * @flags:     ignored
+ */
+static size_t parport_ip32_compat_write_data(struct parport *p,
+                                            const void *buf, size_t len,
+                                            int flags)
+{
+       static unsigned int ready_before = 1;
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport * const physport = p->physport;
+       size_t written = 0;
+
+       /* Special case: a timeout of zero means we cannot call schedule().
+        * Also if O_NONBLOCK is set then use the default implementation. */
+       if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+               return parport_ieee1284_write_compat(p, buf, len, flags);
+
+       /* Reset FIFO, go in forward mode, and disable ackIntEn */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+       parport_ip32_data_forward(p);
+       parport_ip32_disable_irq(p);
+       parport_ip32_set_mode(p, ECR_MODE_PPF);
+       physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* Wait for peripheral to become ready */
+       if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+                                      DSR_nBUSY | DSR_nFAULT)) {
+               /* Avoid to flood the logs */
+               if (ready_before)
+                       printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+                              p->name, __func__);
+               ready_before = 0;
+               goto stop;
+       }
+       ready_before = 1;
+
+       written = parport_ip32_fifo_write_block(p, buf, len);
+
+       /* Wait FIFO to empty.  Timeout is proportional to FIFO_depth.  */
+       parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+       /* Check for a potential residue */
+       written -= parport_ip32_get_fifo_residue(p, ECR_MODE_PPF);
+
+       /* Then, wait for BUSY to get low. */
+       if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+               printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+                      p->name, __func__);
+
+stop:
+       /* Reset FIFO */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_read_data().
+ */
+
+/**
+ * parport_ip32_ecp_write_data - write a block of data in ECP mode
+ * @p:         pointer to &struct parport
+ * @buf:       buffer of data to write
+ * @len:       length of buffer @buf
+ * @flags:     ignored
+ */
+static size_t parport_ip32_ecp_write_data(struct parport *p,
+                                         const void *buf, size_t len,
+                                         int flags)
+{
+       static unsigned int ready_before = 1;
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport * const physport = p->physport;
+       size_t written = 0;
+
+       /* Special case: a timeout of zero means we cannot call schedule().
+        * Also if O_NONBLOCK is set then use the default implementation. */
+       if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+               return parport_ieee1284_ecp_write_data(p, buf, len, flags);
+
+       /* Negotiate to forward mode if necessary. */
+       if (physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+               /* Event 47: Set nInit high. */
+               parport_ip32_frob_control(p, DCR_nINIT | DCR_AUTOFD,
+                                            DCR_nINIT | DCR_AUTOFD);
+
+               /* Event 49: PError goes high. */
+               if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) {
+                       printk(KERN_DEBUG PPIP32 "%s: PError timeout in %s",
+                              p->name, __func__);
+                       physport->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
+                       return 0;
+               }
+       }
+
+       /* Reset FIFO, go in forward mode, and disable ackIntEn */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+       parport_ip32_data_forward(p);
+       parport_ip32_disable_irq(p);
+       parport_ip32_set_mode(p, ECR_MODE_ECP);
+       physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* Wait for peripheral to become ready */
+       if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+                                      DSR_nBUSY | DSR_nFAULT)) {
+               /* Avoid to flood the logs */
+               if (ready_before)
+                       printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+                              p->name, __func__);
+               ready_before = 0;
+               goto stop;
+       }
+       ready_before = 1;
+
+       written = parport_ip32_fifo_write_block(p, buf, len);
+
+       /* Wait FIFO to empty.  Timeout is proportional to FIFO_depth.  */
+       parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+       /* Check for a potential residue */
+       written -= parport_ip32_get_fifo_residue(p, ECR_MODE_ECP);
+
+       /* Then, wait for BUSY to get low. */
+       if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+               printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+                      p->name, __func__);
+
+stop:
+       /* Reset FIFO */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_write_addr().
+ */
+
+/*--- Default parport operations ---------------------------------------*/
+
+static __initdata struct parport_operations parport_ip32_ops = {
+       .write_data             = parport_ip32_write_data,
+       .read_data              = parport_ip32_read_data,
+
+       .write_control          = parport_ip32_write_control,
+       .read_control           = parport_ip32_read_control,
+       .frob_control           = parport_ip32_frob_control,
+
+       .read_status            = parport_ip32_read_status,
+
+       .enable_irq             = parport_ip32_enable_irq,
+       .disable_irq            = parport_ip32_disable_irq,
+
+       .data_forward           = parport_ip32_data_forward,
+       .data_reverse           = parport_ip32_data_reverse,
+
+       .init_state             = parport_ip32_init_state,
+       .save_state             = parport_ip32_save_state,
+       .restore_state          = parport_ip32_restore_state,
+
+       .epp_write_data         = parport_ieee1284_epp_write_data,
+       .epp_read_data          = parport_ieee1284_epp_read_data,
+       .epp_write_addr         = parport_ieee1284_epp_write_addr,
+       .epp_read_addr          = parport_ieee1284_epp_read_addr,
+
+       .ecp_write_data         = parport_ieee1284_ecp_write_data,
+       .ecp_read_data          = parport_ieee1284_ecp_read_data,
+       .ecp_write_addr         = parport_ieee1284_ecp_write_addr,
+
+       .compat_write_data      = parport_ieee1284_write_compat,
+       .nibble_read_data       = parport_ieee1284_read_nibble,
+       .byte_read_data         = parport_ieee1284_read_byte,
+
+       .owner                  = THIS_MODULE,
+};
+
+/*--- Device detection -------------------------------------------------*/
+
+/**
+ * parport_ip32_ecp_supported - check for an ECP port
+ * @p:         pointer to the &parport structure
+ *
+ * Returns 1 if an ECP port is found, and 0 otherwise.  This function actually
+ * checks if an Extended Control Register seems to be present.  On successful
+ * return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_ecp_supported(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       unsigned int ecr;
+
+       ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+       writeb(ecr, priv->regs.ecr);
+       if (readb(priv->regs.ecr) != (ecr | ECR_F_EMPTY))
+               goto fail;
+
+       pr_probe(p, "Found working ECR register\n");
+       parport_ip32_set_mode(p, ECR_MODE_SPP);
+       parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+       return 1;
+
+fail:
+       pr_probe(p, "ECR register not found\n");
+       return 0;
+}
+
+/**
+ * parport_ip32_fifo_supported - check for FIFO parameters
+ * @p:         pointer to the &parport structure
+ *
+ * Check for FIFO parameters of an Extended Capabilities Port.  Returns 1 on
+ * success, and 0 otherwise.  Adjust FIFO parameters in the parport structure.
+ * On return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_fifo_supported(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       unsigned int configa, configb;
+       unsigned int pword;
+       unsigned int i;
+
+       /* Configuration mode */
+       parport_ip32_set_mode(p, ECR_MODE_CFG);
+       configa = readb(priv->regs.cnfgA);
+       configb = readb(priv->regs.cnfgB);
+
+       /* Find out PWord size */
+       switch (configa & CNFGA_ID_MASK) {
+       case CNFGA_ID_8:
+               pword = 1;
+               break;
+       case CNFGA_ID_16:
+               pword = 2;
+               break;
+       case CNFGA_ID_32:
+               pword = 4;
+               break;
+       default:
+               pr_probe(p, "Unknown implementation ID: 0x%0x\n",
+                        (configa & CNFGA_ID_MASK) >> CNFGA_ID_SHIFT);
+               goto fail;
+               break;
+       }
+       if (pword != 1) {
+               pr_probe(p, "Unsupported PWord size: %u\n", pword);
+               goto fail;
+       }
+       priv->pword = pword;
+       pr_probe(p, "PWord is %u bits\n", 8 * priv->pword);
+
+       /* Check for compression support */
+       writeb(configb | CNFGB_COMPRESS, priv->regs.cnfgB);
+       if (readb(priv->regs.cnfgB) & CNFGB_COMPRESS)
+               pr_probe(p, "Hardware compression detected (unsupported)\n");
+       writeb(configb & ~CNFGB_COMPRESS, priv->regs.cnfgB);
+
+       /* Reset FIFO and go in test mode (no interrupt, no DMA) */
+       parport_ip32_set_mode(p, ECR_MODE_TST);
+
+       /* FIFO must be empty now */
+       if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+               pr_probe(p, "FIFO not reset\n");
+               goto fail;
+       }
+
+       /* Find out FIFO depth. */
+       priv->fifo_depth = 0;
+       for (i = 0; i < 1024; i++) {
+               if (readb(priv->regs.ecr) & ECR_F_FULL) {
+                       /* FIFO full */
+                       priv->fifo_depth = i;
+                       break;
+               }
+               writeb((u8)i, priv->regs.fifo);
+       }
+       if (i >= 1024) {
+               pr_probe(p, "Can't fill FIFO\n");
+               goto fail;
+       }
+       if (!priv->fifo_depth) {
+               pr_probe(p, "Can't get FIFO depth\n");
+               goto fail;
+       }
+       pr_probe(p, "FIFO is %u PWords deep\n", priv->fifo_depth);
+
+       /* Enable interrupts */
+       parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+       /* Find out writeIntrThreshold: number of PWords we know we can write
+        * if we get an interrupt. */
+       priv->writeIntrThreshold = 0;
+       for (i = 0; i < priv->fifo_depth; i++) {
+               if (readb(priv->regs.fifo) != (u8)i) {
+                       pr_probe(p, "Invalid data in FIFO\n");
+                       goto fail;
+               }
+               if (!priv->writeIntrThreshold
+                   && readb(priv->regs.ecr) & ECR_SERVINTR)
+                       /* writeIntrThreshold reached */
+                       priv->writeIntrThreshold = i + 1;
+               if (i + 1 < priv->fifo_depth
+                   && readb(priv->regs.ecr) & ECR_F_EMPTY) {
+                       /* FIFO empty before the last byte? */
+                       pr_probe(p, "Data lost in FIFO\n");
+                       goto fail;
+               }
+       }
+       if (!priv->writeIntrThreshold) {
+               pr_probe(p, "Can't get writeIntrThreshold\n");
+               goto fail;
+       }
+       pr_probe(p, "writeIntrThreshold is %u\n", priv->writeIntrThreshold);
+
+       /* FIFO must be empty now */
+       if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+               pr_probe(p, "Can't empty FIFO\n");
+               goto fail;
+       }
+
+       /* Reset FIFO */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       /* Set reverse direction (must be in PS2 mode) */
+       parport_ip32_data_reverse(p);
+       /* Test FIFO, no interrupt, no DMA */
+       parport_ip32_set_mode(p, ECR_MODE_TST);
+       /* Enable interrupts */
+       parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+       /* Find out readIntrThreshold: number of PWords we can read if we get
+        * an interrupt. */
+       priv->readIntrThreshold = 0;
+       for (i = 0; i < priv->fifo_depth; i++) {
+               writeb(0xaa, priv->regs.fifo);
+               if (readb(priv->regs.ecr) & ECR_SERVINTR) {
+                       /* readIntrThreshold reached */
+                       priv->readIntrThreshold = i + 1;
+                       break;
+               }
+       }
+       if (!priv->readIntrThreshold) {
+               pr_probe(p, "Can't get readIntrThreshold\n");
+               goto fail;
+       }
+       pr_probe(p, "readIntrThreshold is %u\n", priv->readIntrThreshold);
+
+       /* Reset ECR */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       parport_ip32_data_forward(p);
+       parport_ip32_set_mode(p, ECR_MODE_SPP);
+       return 1;
+
+fail:
+       priv->fifo_depth = 0;
+       parport_ip32_set_mode(p, ECR_MODE_SPP);
+       return 0;
+}
+
+/*--- Initialization code ----------------------------------------------*/
+
+/**
+ * parport_ip32_make_isa_registers - compute (ISA) register addresses
+ * @regs:      pointer to &struct parport_ip32_regs to fill
+ * @base:      base address of standard and EPP registers
+ * @base_hi:   base address of ECP registers
+ * @regshift:  how much to shift register offset by
+ *
+ * Compute register addresses, according to the ISA standard.  The addresses
+ * of the standard and EPP registers are computed from address @base.  The
+ * addresses of the ECP registers are computed from address @base_hi.
+ */
+static void __init
+parport_ip32_make_isa_registers(struct parport_ip32_regs *regs,
+                               void __iomem *base, void __iomem *base_hi,
+                               unsigned int regshift)
+{
+#define r_base(offset)    ((u8 __iomem *)base    + ((offset) << regshift))
+#define r_base_hi(offset) ((u8 __iomem *)base_hi + ((offset) << regshift))
+       *regs = (struct parport_ip32_regs){
+               .data           = r_base(0),
+               .dsr            = r_base(1),
+               .dcr            = r_base(2),
+               .eppAddr        = r_base(3),
+               .eppData0       = r_base(4),
+               .eppData1       = r_base(5),
+               .eppData2       = r_base(6),
+               .eppData3       = r_base(7),
+               .ecpAFifo       = r_base(0),
+               .fifo           = r_base_hi(0),
+               .cnfgA          = r_base_hi(0),
+               .cnfgB          = r_base_hi(1),
+               .ecr            = r_base_hi(2)
+       };
+#undef r_base_hi
+#undef r_base
+}
+
+/**
+ * parport_ip32_probe_port - probe and register IP32 built-in parallel port
+ *
+ * Returns the new allocated &parport structure.  On error, an error code is
+ * encoded in return value with the ERR_PTR function.
+ */
+static __init struct parport *parport_ip32_probe_port(void)
+{
+       struct parport_ip32_regs regs;
+       struct parport_ip32_private *priv = NULL;
+       struct parport_operations *ops = NULL;
+       struct parport *p = NULL;
+       int err;
+
+       parport_ip32_make_isa_registers(&regs, &mace->isa.parallel,
+                                       &mace->isa.ecp1284, 8 /* regshift */);
+
+       ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
+       priv = kmalloc(sizeof(struct parport_ip32_private), GFP_KERNEL);
+       p = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops);
+       if (ops == NULL || priv == NULL || p == NULL) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       p->base = MACE_BASE + offsetof(struct sgi_mace, isa.parallel);
+       p->base_hi = MACE_BASE + offsetof(struct sgi_mace, isa.ecp1284);
+       p->private_data = priv;
+
+       *ops = parport_ip32_ops;
+       *priv = (struct parport_ip32_private){
+               .regs                   = regs,
+               .dcr_writable           = DCR_DIR | DCR_SELECT | DCR_nINIT |
+                                         DCR_AUTOFD | DCR_STROBE,
+               .irq_mode               = PARPORT_IP32_IRQ_FWD,
+       };
+       init_completion(&priv->irq_complete);
+
+       /* Probe port. */
+       if (!parport_ip32_ecp_supported(p)) {
+               err = -ENODEV;
+               goto fail;
+       }
+       parport_ip32_dump_state(p, "begin init", 0);
+
+       /* We found what looks like a working ECR register.  Simply assume
+        * that all modes are correctly supported.  Enable basic modes. */
+       p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
+       p->modes |= PARPORT_MODE_TRISTATE;
+
+       if (!parport_ip32_fifo_supported(p)) {
+               printk(KERN_WARNING PPIP32
+                      "%s: error: FIFO disabled\n", p->name);
+               /* Disable hardware modes depending on a working FIFO. */
+               features &= ~PARPORT_IP32_ENABLE_SPP;
+               features &= ~PARPORT_IP32_ENABLE_ECP;
+               /* DMA is not needed if FIFO is not supported.  */
+               features &= ~PARPORT_IP32_ENABLE_DMA;
+       }
+
+       /* Request IRQ */
+       if (features & PARPORT_IP32_ENABLE_IRQ) {
+               int irq = MACEISA_PARALLEL_IRQ;
+               if (request_irq(irq, parport_ip32_interrupt, 0, p->name, p)) {
+                       printk(KERN_WARNING PPIP32
+                              "%s: error: IRQ disabled\n", p->name);
+                       /* DMA cannot work without interrupts. */
+                       features &= ~PARPORT_IP32_ENABLE_DMA;
+               } else {
+                       pr_probe(p, "Interrupt support enabled\n");
+                       p->irq = irq;
+                       priv->dcr_writable |= DCR_IRQ;
+               }
+       }
+
+       /* Allocate DMA resources */
+       if (features & PARPORT_IP32_ENABLE_DMA) {
+               if (parport_ip32_dma_register())
+                       printk(KERN_WARNING PPIP32
+                              "%s: error: DMA disabled\n", p->name);
+               else {
+                       pr_probe(p, "DMA support enabled\n");
+                       p->dma = 0; /* arbitrary value != PARPORT_DMA_NONE */
+                       p->modes |= PARPORT_MODE_DMA;
+               }
+       }
+
+       if (features & PARPORT_IP32_ENABLE_SPP) {
+               /* Enable compatibility FIFO mode */
+               p->ops->compat_write_data = parport_ip32_compat_write_data;
+               p->modes |= PARPORT_MODE_COMPAT;
+               pr_probe(p, "Hardware support for SPP mode enabled\n");
+       }
+       if (features & PARPORT_IP32_ENABLE_EPP) {
+               /* Set up access functions to use EPP hardware. */
+               p->ops->epp_read_data = parport_ip32_epp_read_data;
+               p->ops->epp_write_data = parport_ip32_epp_write_data;
+               p->ops->epp_read_addr = parport_ip32_epp_read_addr;
+               p->ops->epp_write_addr = parport_ip32_epp_write_addr;
+               p->modes |= PARPORT_MODE_EPP;
+               pr_probe(p, "Hardware support for EPP mode enabled\n");
+       }
+       if (features & PARPORT_IP32_ENABLE_ECP) {
+               /* Enable ECP FIFO mode */
+               p->ops->ecp_write_data = parport_ip32_ecp_write_data;
+               /* FIXME - not implemented */
+/*             p->ops->ecp_read_data  = parport_ip32_ecp_read_data; */
+/*             p->ops->ecp_write_addr = parport_ip32_ecp_write_addr; */
+               p->modes |= PARPORT_MODE_ECP;
+               pr_probe(p, "Hardware support for ECP mode enabled\n");
+       }
+
+       /* Initialize the port with sensible values */
+       parport_ip32_set_mode(p, ECR_MODE_PS2);
+       parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+       parport_ip32_data_forward(p);
+       parport_ip32_disable_irq(p);
+       parport_ip32_write_data(p, 0x00);
+       parport_ip32_dump_state(p, "end init", 0);
+
+       /* Print out what we found */
+       printk(KERN_INFO "%s: SGI IP32 at 0x%lx (0x%lx)",
+              p->name, p->base, p->base_hi);
+       if (p->irq != PARPORT_IRQ_NONE)
+               printk(", irq %d", p->irq);
+       printk(" [");
+#define printmode(x)   if (p->modes & PARPORT_MODE_##x)                \
+                               printk("%s%s", f++ ? "," : "", #x)
+       {
+               unsigned int f = 0;
+               printmode(PCSPP);
+               printmode(TRISTATE);
+               printmode(COMPAT);
+               printmode(EPP);
+               printmode(ECP);
+               printmode(DMA);
+       }
+#undef printmode
+       printk("]\n");
+
+       parport_announce_port(p);
+       return p;
+
+fail:
+       if (p)
+               parport_put_port(p);
+       kfree(priv);
+       kfree(ops);
+       return ERR_PTR(err);
+}
+
+/**
+ * parport_ip32_unregister_port - unregister a parallel port
+ * @p:         pointer to the &struct parport
+ *
+ * Unregisters a parallel port and free previously allocated resources
+ * (memory, IRQ, ...).
+ */
+static __exit void parport_ip32_unregister_port(struct parport *p)
+{
+       struct parport_ip32_private * const priv = p->physport->private_data;
+       struct parport_operations *ops = p->ops;
+
+       parport_remove_port(p);
+       if (p->modes & PARPORT_MODE_DMA)
+               parport_ip32_dma_unregister();
+       if (p->irq != PARPORT_IRQ_NONE)
+               free_irq(p->irq, p);
+       parport_put_port(p);
+       kfree(priv);
+       kfree(ops);
+}
+
+/**
+ * parport_ip32_init - module initialization function
+ */
+static int __init parport_ip32_init(void)
+{
+       pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n");
+       pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__);
+       this_port = parport_ip32_probe_port();
+       return IS_ERR(this_port) ? PTR_ERR(this_port) : 0;
+}
+
+/**
+ * parport_ip32_exit - module termination function
+ */
+static void __exit parport_ip32_exit(void)
+{
+       parport_ip32_unregister_port(this_port);
+}
+
+/*--- Module stuff -----------------------------------------------------*/
+
+MODULE_AUTHOR("Arnaud Giersch <arnaud.giersch@free.fr>");
+MODULE_DESCRIPTION("SGI IP32 built-in parallel port driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6");         /* update in parport_ip32_init() too */
+
+module_init(parport_ip32_init);
+module_exit(parport_ip32_exit);
+
+module_param(verbose_probing, bool, S_IRUGO);
+MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialization");
+
+module_param(features, uint, S_IRUGO);
+MODULE_PARM_DESC(features,
+                "Bit mask of features to enable"
+                ", bit 0: IRQ support"
+                ", bit 1: DMA support"
+                ", bit 2: hardware SPP mode"
+                ", bit 3: hardware EPP mode"
+                ", bit 4: hardware ECP mode");
+
+/*--- Inform (X)Emacs about preferred coding style ---------------------*/
+/*
+ * Local Variables:
+ * mode: c
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * tab-width: 8
+ * fill-column: 78
+ * ispell-local-dictionary: "american"
+ * End:
+ */
index 76dd077e3184f7ed85f3a78de3c8c66a29753199..166de3507780f65c7354ebf4c9548c558baf3d00 100644 (file)
@@ -329,9 +329,9 @@ static int __devinit parport_register (struct pci_dev *dev,
 
                if (priv->num_par == ARRAY_SIZE (priv->port)) {
                        printk (KERN_WARNING
-                               "parport_serial: %s: only %u parallel ports "
+                               "parport_serial: %s: only %zu parallel ports "
                                "supported (%d reported)\n", pci_name (dev),
-                               ARRAY_SIZE (priv->port), card->numports);
+                               ARRAY_SIZE(priv->port), card->numports);
                        break;
                }
 
index b62aee8de3cba0aeddae8f659b1dcadc99e1fdde..ea83b70e0de2ccf5bf03b49ea27875a5b46e1a85 100644 (file)
@@ -199,7 +199,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
 
                if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) {
                        if (belen != len) {
-                               printk (KERN_DEBUG "%s: Device ID was %d bytes"
+                               printk (KERN_DEBUG "%s: Device ID was %zd bytes"
                                        " while device told it would be %d"
                                        " bytes\n",
                                        port->name, len, belen);
@@ -214,7 +214,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
                if (buffer[len-1] == ';') {
                        printk (KERN_DEBUG "%s: Device ID reading stopped"
                                " before device told data not available. "
-                               "Current idlen %d of %d, len bytes %02X %02X\n",
+                               "Current idlen %u of %u, len bytes %02X %02X\n",
                                port->name, current_idlen, numidlens,
                                length[0], length[1]);
                        goto done;
index 6f50cc9323d9590093ae70fb986f519aceafb642..6912399d0937099c89d08d9caea2850b0b0d1337 100644 (file)
@@ -55,13 +55,21 @@ config DASD_DIAG
          Disks under VM.  If you are not running under VM or unsure what it is,
          say "N".
 
+config DASD_EER
+       tristate "Extended error reporting (EER)"
+       depends on DASD
+       help
+         This driver provides a character device interface to the
+          DASD extended error reporting. This is only needed if you want to
+          use applications written for the EER facility.
+
 config DASD_CMB
        tristate "Compatibility interface for DASD channel measurement blocks"
        depends on DASD
        help
-         This driver provides an additional interface to the channel measurement
-         facility, which is normally accessed though sysfs, with a set of
-         ioctl functions specific to the dasd driver.
+         This driver provides an additional interface to the channel
+          measurement facility, which is normally accessed though sysfs, with
+          a set of ioctl functions specific to the dasd driver.
          This is only needed if you want to use applications written for
          linux-2.4 dasd channel measurement facility interface.
 
index 58c6780134f7487dc8ba65819d0dbd476f580494..0c0d871e8f512f9a4e38acd1a813d25b321df48a 100644 (file)
@@ -5,6 +5,7 @@
 dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
 dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
 dasd_diag_mod-objs := dasd_diag.o
+dasd_eer_mod-objs := dasd_eer.o
 dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
                        dasd_genhd.o dasd_erp.o
 
@@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
 obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
 obj-$(CONFIG_DASD_FBA)  += dasd_fba_mod.o
 obj-$(CONFIG_DASD_CMB)  += dasd_cmb.o
+obj-$(CONFIG_DASD_EER)  += dasd_eer.o
 obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
 obj-$(CONFIG_DCSSBLK) += dcssblk.o
index abdf1ee633e7ecf3dced11ca4850237e3b2fc807..08c88fcd896339eeb8c9700535c5aa0f620d313b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 #include <linux/hdreg.h>
+#include <linux/notifier.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
@@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 static void dasd_flush_ccw_queue(struct dasd_device *, int);
 static void dasd_tasklet(struct dasd_device *);
 static void do_kick_device(void *data);
+static void dasd_disable_eer(struct dasd_device *device);
 
 /*
  * SECTION: Operations on the device structure.
@@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device)
 static inline void
 dasd_state_known_to_new(struct dasd_device * device)
 {
+       /* disable extended error reporting for this device */
+       dasd_disable_eer(device);
        /* Forget the discipline information. */
        device->discipline = NULL;
        device->state = DASD_STATE_NEW;
@@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device)
        struct dasd_ccw_req *cqr;
        struct list_head *l, *n;
 
+       /* first of all call extended error reporting */
+       dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
+
        device->stopped &= ~DASD_STOPPED_PENDING;
 
         /* restart all 'running' IO on queue */
@@ -1086,6 +1093,19 @@ restart:
                        }
                        goto restart;
                }
+
+               /* first of all call extended error reporting */
+               if (device->eer && cqr->status == DASD_CQR_FAILED) {
+                       dasd_write_eer_trigger(DASD_EER_FATALERROR,
+                                              device, cqr);
+
+                       /* restart request  */
+                       cqr->status = DASD_CQR_QUEUED;
+                       cqr->retries = 255;
+                       device->stopped |= DASD_STOPPED_QUIESCE;
+                       goto restart;
+               }
+
                /* Process finished ERP request. */
                if (cqr->refers) {
                        __dasd_process_erp(device, cqr);
@@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device)
        cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
         /* check FAILFAST */
        if (device->stopped & ~DASD_STOPPED_PENDING &&
-           test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) {
+           test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+           (!device->eer)) {
                cqr->status = DASD_CQR_FAILED;
                dasd_schedule_bh(device);
        }
@@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
        switch (event) {
        case CIO_GONE:
        case CIO_NO_PATH:
+               /* first of all call extended error reporting */
+               dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
+
                if (device->state < DASD_STATE_BASIC)
                        break;
                /* Device is active. We want to keep it. */
@@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
        put_driver(drv);
 }
 
+/*
+ * notifications for extended error reports
+ */
+static struct notifier_block *dasd_eer_chain;
+
+int
+dasd_register_eer_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_register(&dasd_eer_chain, nb);
+}
+
+int
+dasd_unregister_eer_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_unregister(&dasd_eer_chain, nb);
+}
+
+/*
+ * Notify the registered error reporting module of a problem
+ */
+void
+dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
+                      struct dasd_ccw_req *cqr)
+{
+       if (device->eer) {
+               struct dasd_eer_trigger temp;
+               temp.id = id;
+               temp.device = device;
+               temp.cqr = cqr;
+               notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
+                                   (void *)&temp);
+       }
+}
+
+/*
+ * Tell the registered error reporting module to disable error reporting for
+ * a given device and to cleanup any private data structures on that device.
+ */
+static void
+dasd_disable_eer(struct dasd_device *device)
+{
+       notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
+}
+
+
 static int __init
 dasd_init(void)
 {
@@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
 EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
 
+EXPORT_SYMBOL(dasd_register_eer_notifier);
+EXPORT_SYMBOL(dasd_unregister_eer_notifier);
+EXPORT_SYMBOL(dasd_write_eer_trigger);
+
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
index 4ee0f934e325388c779e20c05e32098b55ebe1ce..c811380b90796752e5d2fea8d98f04c6953e6a24 100644 (file)
@@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
                case 0x0B:
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                    "FORMAT F - Volume is suspended duplex");
+                       /* call extended error reporting (EER) */
+                       dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device,
+                                              erp->refers);
                        break;
                case 0x0C:
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
index bc3823d35223362d97a0b939f59ca687b1345759..e15dd79780509dc87eaa789beb05863efaf5cc64 100644 (file)
@@ -29,6 +29,7 @@
 #define DASD_ECKD_CCW_PSF               0x27
 #define DASD_ECKD_CCW_RSSD              0x3e
 #define DASD_ECKD_CCW_LOCATE_RECORD     0x47
+#define DASD_ECKD_CCW_SNSS               0x54
 #define DASD_ECKD_CCW_DEFINE_EXTENT     0x63
 #define DASD_ECKD_CCW_WRITE_MT          0x85
 #define DASD_ECKD_CCW_READ_MT           0x86
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
new file mode 100644 (file)
index 0000000..f70cd77
--- /dev/null
@@ -0,0 +1,1090 @@
+/*
+ *     character device driver for extended error reporting
+ *
+ *
+ *     Copyright (C) 2005 IBM Corporation
+ *     extended error reporting for DASD ECKD devices
+ *     Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+#include <asm/ebcdic.h>
+
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Stefan Weinhuber <wein@de.ibm.com>");
+MODULE_DESCRIPTION("DASD extended error reporting module");
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif                         /* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eer):"
+
+
+
+
+
+/*****************************************************************************/
+/*      the internal buffer                                                  */
+/*****************************************************************************/
+
+/*
+ * The internal buffer is meant to store obaque blobs of data, so it doesn't
+ * know of higher level concepts like triggers.
+ * It consists of a number of pages that are used as a ringbuffer. Each data
+ * blob is stored in a simple record that consists of an integer, which
+ * contains the size of the following data, and the data bytes themselfes.
+ *
+ * To allow for multiple independent readers we create one internal buffer
+ * each time the device is opened and destroy the buffer when the file is
+ * closed again.
+ *
+ * One record can be written to a buffer by using the functions
+ * - dasd_eer_start_record (one time per record to write the size to the buffer
+ *                          and reserve the space for the data)
+ * - dasd_eer_write_buffer (one or more times per record to write the data)
+ * The data can be written in several steps but you will have to compute
+ * the total size up front for the invocation of dasd_eer_start_record.
+ * If the ringbuffer is full, dasd_eer_start_record will remove the required
+ * number of old records.
+ *
+ * A record is typically read in two steps, first read the integer that
+ * specifies the size of the following data, then read the data.
+ * Both can be done by
+ * - dasd_eer_read_buffer
+ *
+ * For all mentioned functions you need to get the bufferlock first and keep it
+ * until a complete record is written or read.
+ */
+
+
+/*
+ * Alle information necessary to keep track of an internal buffer is kept in
+ * a struct eerbuffer. The buffer specific to a file pointer is strored in
+ * the private_data field of that file. To be able to write data to all
+ * existing buffers, each buffer is also added to the bufferlist.
+ * If the user doesn't want to read a complete record in one go, we have to
+ * keep track of the rest of the record. residual stores the number of bytes
+ * that are still to deliver. If the rest of the record is invalidated between
+ * two reads then residual will be set to -1 so that the next read will fail.
+ * All entries in the eerbuffer structure are protected with the bufferlock.
+ * To avoid races between writing to a buffer on the one side and creating
+ * and destroying buffers on the other side, the bufferlock must also be used
+ * to protect the bufferlist.
+ */
+
+struct eerbuffer {
+       struct list_head list;
+       char **buffer;
+       int buffersize;
+       int buffer_page_count;
+       int head;
+        int tail;
+       int residual;
+};
+
+LIST_HEAD(bufferlist);
+
+static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+
+DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
+
+/*
+ * How many free bytes are available on the buffer.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_free_bytes(struct eerbuffer *eerb)
+{
+       if (eerb->head < eerb->tail) {
+               return eerb->tail - eerb->head - 1;
+       } else
+               return eerb->buffersize - eerb->head + eerb->tail -1;
+}
+
+/*
+ * How many bytes of buffer space are used.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_filled_bytes(struct eerbuffer *eerb)
+{
+
+       if (eerb->head >= eerb->tail) {
+               return eerb->head - eerb->tail;
+       } else
+               return eerb->buffersize - eerb->tail + eerb->head;
+}
+
+/*
+ * The dasd_eer_write_buffer function just copies count bytes of data
+ * to the buffer. Make sure to call dasd_eer_start_record first, to
+ * make sure that enough free space is available.
+ * needs to be called with bufferlock held
+ */
+static void
+dasd_eer_write_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+       unsigned long headindex,localhead;
+       unsigned long rest, len;
+       char *nextdata;
+
+       nextdata = data;
+       rest = count;
+       while (rest > 0) {
+               headindex = eerb->head / PAGE_SIZE;
+               localhead = eerb->head % PAGE_SIZE;
+               len = min(rest, (PAGE_SIZE - localhead));
+               memcpy(eerb->buffer[headindex]+localhead, nextdata, len);
+               nextdata += len;
+               rest -= len;
+               eerb->head += len;
+               if ( eerb->head == eerb->buffersize )
+                       eerb->head = 0; /* wrap around */
+               if (eerb->head > eerb->buffersize) {
+                       MESSAGE(KERN_ERR, "%s", "runaway buffer head.");
+                       BUG();
+               }
+       }
+}
+
+/*
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_read_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+       unsigned long tailindex,localtail;
+       unsigned long rest, len, finalcount;
+       char *nextdata;
+
+       finalcount = min(count, dasd_eer_get_filled_bytes(eerb));
+       nextdata = data;
+       rest = finalcount;
+       while (rest > 0) {
+               tailindex = eerb->tail / PAGE_SIZE;
+               localtail = eerb->tail % PAGE_SIZE;
+               len = min(rest, (PAGE_SIZE - localtail));
+               memcpy(nextdata, eerb->buffer[tailindex]+localtail, len);
+               nextdata += len;
+               rest -= len;
+               eerb->tail += len;
+               if ( eerb->tail == eerb->buffersize )
+                       eerb->tail = 0; /* wrap around */
+               if (eerb->tail > eerb->buffersize) {
+                       MESSAGE(KERN_ERR, "%s", "runaway buffer tail.");
+                       BUG();
+               }
+       }
+       return finalcount;
+}
+
+/*
+ * Whenever you want to write a blob of data to the internal buffer you
+ * have to start by using this function first. It will write the number
+ * of bytes that will be written to the buffer. If necessary it will remove
+ * old records to make room for the new one.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_start_record(struct eerbuffer *eerb, int count)
+{
+       int tailcount;
+       if (count + sizeof(count) > eerb->buffersize)
+               return -ENOMEM;
+       while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) {
+               if (eerb->residual > 0) {
+                       eerb->tail += eerb->residual;
+                       if (eerb->tail >= eerb->buffersize)
+                               eerb->tail -= eerb->buffersize;
+                       eerb->residual = -1;
+               }
+               dasd_eer_read_buffer(eerb, sizeof(tailcount),
+                                    (char*)(&tailcount));
+               eerb->tail += tailcount;
+               if (eerb->tail >= eerb->buffersize)
+                       eerb->tail -= eerb->buffersize;
+       }
+       dasd_eer_write_buffer(eerb, sizeof(count), (char*)(&count));
+
+       return 0;
+};
+
+/*
+ * release pages that are not used anymore
+ */
+static void
+dasd_eer_free_buffer_pages(char **buf, int no_pages)
+{
+       int i;
+
+       for (i = 0; i < no_pages; ++i) {
+               free_page((unsigned long)buf[i]);
+       }
+}
+
+/*
+ * allocate a new set of memory pages
+ */
+static int
+dasd_eer_allocate_buffer_pages(char **buf, int no_pages)
+{
+       int i;
+
+       for (i = 0; i < no_pages; ++i) {
+               buf[i] = (char *) get_zeroed_page(GFP_KERNEL);
+               if (!buf[i]) {
+                       dasd_eer_free_buffer_pages(buf, i);
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+/*
+ * empty the buffer by resetting head and tail
+ * In case there is a half read data blob in the buffer, we set residual
+ * to -1 to indicate that the remainder of the blob is lost.
+ */
+static void
+dasd_eer_purge_buffer(struct eerbuffer *eerb)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&bufferlock, flags);
+       if (eerb->residual > 0)
+               eerb->residual = -1;
+       eerb->tail=0;
+       eerb->head=0;
+       spin_unlock_irqrestore(&bufferlock, flags);
+}
+
+/*
+ * set the size of the buffer, newsize is the new number of pages to be used
+ * we don't try to copy any data back an forth, so any resize will also purge
+ * the buffer
+ */
+static int
+dasd_eer_resize_buffer(struct eerbuffer *eerb, int newsize)
+{
+       int i, oldcount, reuse;
+       char **new;
+       char **old;
+       unsigned long flags;
+
+       if (newsize < 1)
+               return -EINVAL;
+       if (eerb->buffer_page_count == newsize) {
+               /* documented behaviour is that any successfull invocation
+                 * will purge all records */
+               dasd_eer_purge_buffer(eerb);
+               return 0;
+       }
+       new = kmalloc(newsize*sizeof(char*), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       reuse=min(eerb->buffer_page_count, newsize);
+       for (i = 0; i < reuse; ++i) {
+               new[i] = eerb->buffer[i];
+       }
+       if (eerb->buffer_page_count < newsize) {
+               if (dasd_eer_allocate_buffer_pages(
+                           &new[eerb->buffer_page_count],
+                           newsize - eerb->buffer_page_count)) {
+                       kfree(new);
+                       return -ENOMEM;
+               }
+       }
+
+       spin_lock_irqsave(&bufferlock, flags);
+       old = eerb->buffer;
+       eerb->buffer = new;
+       if (eerb->residual > 0)
+               eerb->residual = -1;
+       eerb->tail = 0;
+       eerb->head = 0;
+       oldcount = eerb->buffer_page_count;
+       eerb->buffer_page_count = newsize;
+       spin_unlock_irqrestore(&bufferlock, flags);
+
+       if (oldcount > newsize) {
+               for (i = newsize; i < oldcount; ++i) {
+                       free_page((unsigned long)old[i]);
+               }
+       }
+       kfree(old);
+
+       return 0;
+}
+
+
+/*****************************************************************************/
+/*      The extended error reporting functionality                           */
+/*****************************************************************************/
+
+/*
+ * When a DASD device driver wants to report an error, it calls the
+ * function dasd_eer_write_trigger (via a notifier mechanism) and gives the
+ * respective trigger ID as parameter.
+ * Currently there are four kinds of triggers:
+ *
+ * DASD_EER_FATALERROR:  all kinds of unrecoverable I/O problems
+ * DASD_EER_PPRCSUSPEND: PPRC was suspended
+ * DASD_EER_NOPATH:      There is no path to the device left.
+ * DASD_EER_STATECHANGE: The state of the device has changed.
+ *
+ * For the first three triggers all required information can be supplied by
+ * the caller. For these triggers a record is written by the function
+ * dasd_eer_write_standard_trigger.
+ *
+ * When dasd_eer_write_trigger is called to write a DASD_EER_STATECHANGE
+ * trigger, we have to gather the necessary sense data first. We cannot queue
+ * the necessary SNSS (sense subsystem status) request immediatly, since we
+ * are likely to run in a deadlock situation. Instead, we schedule a
+ * work_struct that calls the function dasd_eer_sense_subsystem_status to
+ * create and start an SNSS  request asynchronously.
+ *
+ * To avoid memory allocations at runtime, the necessary memory is allocated
+ * when the extended error reporting is enabled for a device (by
+ * dasd_eer_probe). There is one private eer data structure for each eer
+ * enabled DASD device. It contains memory for the work_struct, one SNSS cqr
+ * and a flags field that is used to coordinate the use of the cqr. The call
+ * to write a state change trigger can come in at any time, so we have one flag
+ * CQR_IN_USE that protects the cqr itself. When this flag indicates that the
+ * cqr is currently in use, dasd_eer_sense_subsystem_status cannot start a
+ * second request but sets the SNSS_REQUESTED flag instead.
+ *
+ * When the request is finished, the callback function dasd_eer_SNSS_cb
+ * is called. This function will invoke the function
+ * dasd_eer_write_SNSS_trigger to finally write the trigger. It will also
+ * check the SNSS_REQUESTED flag and if it is set it will call
+ * dasd_eer_sense_subsystem_status again.
+ *
+ * To avoid race conditions during the handling of the lock, the flags must
+ * be protected by the snsslock.
+ */
+
+struct dasd_eer_private {
+       struct dasd_ccw_req *cqr;
+       unsigned long flags;
+       struct work_struct worker;
+};
+
+static void dasd_eer_destroy(struct dasd_device *device,
+                            struct dasd_eer_private *eer);
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger);
+static void dasd_eer_sense_subsystem_status(void *data);
+static int dasd_eer_notify(struct notifier_block *self,
+                          unsigned long action, void *data);
+
+struct workqueue_struct *dasd_eer_workqueue;
+
+#define SNSS_DATA_SIZE 44
+static spinlock_t snsslock = SPIN_LOCK_UNLOCKED;
+
+#define DASD_EER_BUSID_SIZE 10
+struct dasd_eer_header {
+       __u32 total_size;
+       __u32 trigger;
+       __u64 tv_sec;
+       __u64 tv_usec;
+       char busid[DASD_EER_BUSID_SIZE];
+} __attribute__ ((packed));
+
+static struct notifier_block dasd_eer_nb = {
+       .notifier_call = dasd_eer_notify,
+};
+
+/*
+ * flags for use with dasd_eer_private
+ */
+#define CQR_IN_USE     0
+#define SNSS_REQUESTED 1
+
+/*
+ * This function checks if extended error reporting is available for a given
+ * dasd_device. If yes, then it creates and returns a struct dasd_eer,
+ * otherwise it returns an -EPERM error pointer.
+ */
+struct dasd_eer_private *
+dasd_eer_probe(struct dasd_device *device)
+{
+       struct dasd_eer_private *private;
+
+       if (!(device && device->discipline
+             && !strcmp(device->discipline->name, "ECKD"))) {
+               return ERR_PTR(-EPERM);
+       }
+       /* allocate the private data structure */
+       private = (struct dasd_eer_private *)kmalloc(
+               sizeof(struct dasd_eer_private), GFP_KERNEL);
+       if (!private) {
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_WORK(&private->worker, dasd_eer_sense_subsystem_status,
+                 (void *)device);
+       private->cqr = dasd_kmalloc_request("ECKD",
+                                           1 /* SNSS */ ,
+                                           SNSS_DATA_SIZE ,
+                                           device);
+       if (!private->cqr) {
+               kfree(private);
+               return ERR_PTR(-ENOMEM);
+       }
+       private->flags = 0;
+       return private;
+};
+
+/*
+ * If our private SNSS request is queued, remove it from the
+ * dasd ccw queue so we can free the requests memory.
+ */
+static void
+dasd_eer_dequeue_SNSS_request(struct dasd_device *device,
+                             struct dasd_eer_private *eer)
+{
+       struct list_head *lst, *nxt;
+       struct dasd_ccw_req *cqr, *erpcqr;
+       dasd_erp_fn_t erp_fn;
+
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       list_for_each_safe(lst, nxt, &device->ccw_queue) {
+               cqr = list_entry(lst, struct dasd_ccw_req, list);
+               /* we are looking for two kinds or requests */
+               /* first kind: our SNSS request: */
+               if (cqr == eer->cqr) {
+                       if (cqr->status == DASD_CQR_IN_IO)
+                               device->discipline->term_IO(cqr);
+                       list_del(&cqr->list);
+                       break;
+               }
+               /* second kind: ERP requests for our SNSS request */
+               if (cqr->refers) {
+                       /* If this erp request chain ends in our cqr, then */
+                        /* cal the erp_postaction to clean it up  */
+                       erpcqr = cqr;
+                       while (erpcqr->refers) {
+                               erpcqr = erpcqr->refers;
+                       }
+                       if (erpcqr == eer->cqr) {
+                               erp_fn = device->discipline->erp_postaction(
+                                        cqr);
+                               erp_fn(cqr);
+                       }
+                       continue;
+               }
+       }
+       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+/*
+ * This function dismantles a struct dasd_eer that was created by
+ * dasd_eer_probe. Since we want to free our private data structure,
+ * we must make sure that the memory is not in use anymore.
+ * We have to flush the work queue and remove a possible SNSS request
+ * from the dasd queue.
+ */
+static void
+dasd_eer_destroy(struct dasd_device *device, struct dasd_eer_private *eer)
+{
+       flush_workqueue(dasd_eer_workqueue);
+       dasd_eer_dequeue_SNSS_request(device, eer);
+       dasd_kfree_request(eer->cqr, device);
+       kfree(eer);
+};
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_enable_on_device(struct dasd_device *device)
+{
+       void *eer;
+       if (!device)
+               return -ENODEV;
+       if (device->eer)
+               return 0;
+       if (!try_module_get(THIS_MODULE)) {
+               return -EINVAL;
+       }
+       eer = (void *)dasd_eer_probe(device);
+       if (IS_ERR(eer)) {
+               module_put(THIS_MODULE);
+               return PTR_ERR(eer);
+       }
+       device->eer = eer;
+       return 0;
+}
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_disable_on_device(struct dasd_device *device)
+{
+       struct dasd_eer_private *eer = device->eer;
+
+       if (!device)
+               return -ENODEV;
+       if (!device->eer)
+               return 0;
+       device->eer = NULL;
+       dasd_eer_destroy(device,eer);
+       module_put(THIS_MODULE);
+
+       return 0;
+}
+
+/*
+ * Set extended error reporting (eer)
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_set_eer(struct block_device *bdev, int no, long args)
+{
+       struct dasd_device *device;
+       int intval;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (bdev != bdev->bd_contains)
+               /* Error-reporting is not allowed for partitions */
+               return -EINVAL;
+       if (get_user(intval, (int __user *) args))
+               return -EFAULT;
+       device =  bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
+       intval = (intval != 0);
+       DEV_MESSAGE (KERN_DEBUG, device,
+                    "set eer on device to %d", intval);
+       if (intval)
+               return dasd_eer_enable_on_device(device);
+       else
+               return dasd_eer_disable_on_device(device);
+}
+
+/*
+ * Get value of extended error reporting.
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_get_eer(struct block_device *bdev, int no, long args)
+{
+       struct dasd_device *device;
+
+       device =  bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+       return put_user((device->eer != NULL), (int __user *) args);
+}
+
+/*
+ * The following function can be used for those triggers that have
+ * all necessary data available when the function is called.
+ * If the parameter cqr is not NULL, the chain of requests will be searched
+ * for valid sense data, and all valid sense data sets will be added to
+ * the triggers data.
+ */
+static int
+dasd_eer_write_standard_trigger(int trigger, struct dasd_device *device,
+                               struct dasd_ccw_req *cqr)
+{
+       struct dasd_ccw_req *temp_cqr;
+       int data_size;
+       struct timeval tv;
+       struct dasd_eer_header header;
+       unsigned long flags;
+       struct eerbuffer *eerb;
+
+       /* go through cqr chain and count the valid sense data sets */
+       temp_cqr = cqr;
+       data_size = 0;
+       while (temp_cqr) {
+               if (temp_cqr->irb.esw.esw0.erw.cons)
+                       data_size += 32;
+               temp_cqr = temp_cqr->refers;
+       }
+
+       header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+       header.trigger = trigger;
+       do_gettimeofday(&tv);
+       header.tv_sec = tv.tv_sec;
+       header.tv_usec = tv.tv_usec;
+       strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+       spin_lock_irqsave(&bufferlock, flags);
+       list_for_each_entry(eerb, &bufferlist, list) {
+               dasd_eer_start_record(eerb, header.total_size);
+               dasd_eer_write_buffer(eerb, sizeof(header), (char*)(&header));
+               temp_cqr = cqr;
+               while (temp_cqr) {
+                       if (temp_cqr->irb.esw.esw0.erw.cons)
+                               dasd_eer_write_buffer(eerb, 32, cqr->irb.ecw);
+                       temp_cqr = temp_cqr->refers;
+               }
+               dasd_eer_write_buffer(eerb, 4,"EOR");
+       }
+       spin_unlock_irqrestore(&bufferlock, flags);
+
+       wake_up_interruptible(&dasd_eer_read_wait_queue);
+
+       return 0;
+}
+
+/*
+ * This function writes a DASD_EER_STATECHANGE trigger.
+ */
+static void
+dasd_eer_write_SNSS_trigger(struct dasd_device *device,
+                           struct dasd_ccw_req *cqr)
+{
+       int data_size;
+       int snss_rc;
+       struct timeval tv;
+       struct dasd_eer_header header;
+       unsigned long flags;
+       struct eerbuffer *eerb;
+
+       snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+       if (snss_rc)
+               data_size = 0;
+       else
+               data_size = SNSS_DATA_SIZE;
+
+       header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+       header.trigger = DASD_EER_STATECHANGE;
+       do_gettimeofday(&tv);
+       header.tv_sec = tv.tv_sec;
+       header.tv_usec = tv.tv_usec;
+       strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+       spin_lock_irqsave(&bufferlock, flags);
+       list_for_each_entry(eerb, &bufferlist, list) {
+               dasd_eer_start_record(eerb, header.total_size);
+               dasd_eer_write_buffer(eerb, sizeof(header),(char*)(&header));
+               if (!snss_rc)
+                       dasd_eer_write_buffer(eerb, SNSS_DATA_SIZE, cqr->data);
+               dasd_eer_write_buffer(eerb, 4,"EOR");
+       }
+       spin_unlock_irqrestore(&bufferlock, flags);
+
+       wake_up_interruptible(&dasd_eer_read_wait_queue);
+}
+
+/*
+ * callback function for use with SNSS request
+ */
+static void
+dasd_eer_SNSS_cb(struct dasd_ccw_req *cqr, void *data)
+{
+        struct dasd_device *device;
+       struct dasd_eer_private *private;
+       unsigned long irqflags;
+
+        device = (struct dasd_device *)data;
+       private = (struct dasd_eer_private *)device->eer;
+       dasd_eer_write_SNSS_trigger(device, cqr);
+       spin_lock_irqsave(&snsslock, irqflags);
+       if(!test_and_clear_bit(SNSS_REQUESTED, &private->flags)) {
+               clear_bit(CQR_IN_USE, &private->flags);
+               spin_unlock_irqrestore(&snsslock, irqflags);
+               return;
+       };
+       clear_bit(CQR_IN_USE, &private->flags);
+       spin_unlock_irqrestore(&snsslock, irqflags);
+       dasd_eer_sense_subsystem_status(device);
+       return;
+}
+
+/*
+ * clean a used cqr before using it again
+ */
+static void
+dasd_eer_clean_SNSS_request(struct dasd_ccw_req *cqr)
+{
+       struct ccw1 *cpaddr = cqr->cpaddr;
+       void *data = cqr->data;
+
+       memset(cqr, 0, sizeof(struct dasd_ccw_req));
+       memset(cpaddr, 0, sizeof(struct ccw1));
+       memset(data, 0, SNSS_DATA_SIZE);
+       cqr->cpaddr = cpaddr;
+       cqr->data = data;
+       strncpy((char *) &cqr->magic, "ECKD", 4);
+       ASCEBC((char *) &cqr->magic, 4);
+       set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+}
+
+/*
+ * build and start an SNSS request
+ * This function is called from a work queue so we have to
+ * pass the dasd_device pointer as a void pointer.
+ */
+static void
+dasd_eer_sense_subsystem_status(void *data)
+{
+       struct dasd_device *device;
+       struct dasd_eer_private *private;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       unsigned long irqflags;
+
+       device = (struct dasd_device *)data;
+       private = (struct dasd_eer_private *)device->eer;
+       if (!private) /* device not eer enabled any more */
+               return;
+       cqr = private->cqr;
+       spin_lock_irqsave(&snsslock, irqflags);
+       if(test_and_set_bit(CQR_IN_USE, &private->flags)) {
+               set_bit(SNSS_REQUESTED, &private->flags);
+               spin_unlock_irqrestore(&snsslock, irqflags);
+               return;
+       };
+       spin_unlock_irqrestore(&snsslock, irqflags);
+       dasd_eer_clean_SNSS_request(cqr);
+       cqr->device = device;
+       cqr->retries = 255;
+       cqr->expires = 10 * HZ;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_SNSS;
+       ccw->count = SNSS_DATA_SIZE;
+       ccw->flags = 0;
+       ccw->cda = (__u32)(addr_t)cqr->data;
+
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       cqr->callback = dasd_eer_SNSS_cb;
+       cqr->callback_data = (void *)device;
+        dasd_add_request_head(cqr);
+
+       return;
+}
+
+/*
+ * This function is called for all triggers. It calls the appropriate
+ * function that writes the actual trigger records.
+ */
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger)
+{
+       int rc;
+       struct dasd_eer_private *private = trigger->device->eer;
+
+       switch (trigger->id) {
+       case DASD_EER_FATALERROR:
+       case DASD_EER_PPRCSUSPEND:
+               rc = dasd_eer_write_standard_trigger(
+                       trigger->id, trigger->device, trigger->cqr);
+               break;
+       case DASD_EER_NOPATH:
+               rc = dasd_eer_write_standard_trigger(
+                       trigger->id, trigger->device, NULL);
+               break;
+       case DASD_EER_STATECHANGE:
+                if (queue_work(dasd_eer_workqueue, &private->worker)) {
+                        rc=0;
+                } else {
+                        /* If the work_struct was already queued, it can't
+                         * be queued again. But this is OK since we don't
+                         * need to have it queued twice.
+                         */
+                        rc = -EBUSY;
+                }
+               break;
+       default: /* unknown trigger, so we write it without any sense data */
+               rc = dasd_eer_write_standard_trigger(
+                       trigger->id, trigger->device, NULL);
+               break;
+       }
+       return rc;
+}
+
+/*
+ * This function is registered with the dasd device driver and gets called
+ * for all dasd eer notifications.
+ */
+static int dasd_eer_notify(struct notifier_block *self,
+                           unsigned long action, void *data)
+{
+       switch (action) {
+       case DASD_EER_DISABLE:
+               dasd_eer_disable_on_device((struct dasd_device *)data);
+               break;
+       case DASD_EER_TRIGGER:
+               dasd_eer_write_trigger((struct dasd_eer_trigger *)data);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+
+/*****************************************************************************/
+/*      the device operations                                                */
+/*****************************************************************************/
+
+/*
+ * On the one side we need a lock to access our internal buffer, on the
+ * other side a copy_to_user can sleep. So we need to copy the data we have
+ * to transfer in a readbuffer, which is protected by the readbuffer_mutex.
+ */
+static char readbuffer[PAGE_SIZE];
+DECLARE_MUTEX(readbuffer_mutex);
+
+
+static int
+dasd_eer_open(struct inode *inp, struct file *filp)
+{
+       struct eerbuffer *eerb;
+       unsigned long flags;
+
+       eerb = kmalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+       eerb->head = 0;
+       eerb->tail = 0;
+       eerb->residual = 0;
+       eerb->buffer_page_count = 1;
+       eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;
+        eerb->buffer = kmalloc(eerb->buffer_page_count*sizeof(char*),
+                              GFP_KERNEL);
+        if (!eerb->buffer)
+                return -ENOMEM;
+       if (dasd_eer_allocate_buffer_pages(eerb->buffer,
+                                          eerb->buffer_page_count)) {
+               kfree(eerb->buffer);
+               return -ENOMEM;
+       }
+       filp->private_data = eerb;
+       spin_lock_irqsave(&bufferlock, flags);
+       list_add(&eerb->list, &bufferlist);
+       spin_unlock_irqrestore(&bufferlock, flags);
+
+       return nonseekable_open(inp,filp);
+}
+
+static int
+dasd_eer_close(struct inode *inp, struct file *filp)
+{
+       struct eerbuffer *eerb;
+       unsigned long flags;
+
+       eerb = (struct eerbuffer *)filp->private_data;
+       spin_lock_irqsave(&bufferlock, flags);
+       list_del(&eerb->list);
+       spin_unlock_irqrestore(&bufferlock, flags);
+       dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count);
+       kfree(eerb->buffer);
+       kfree(eerb);
+
+       return 0;
+}
+
+static long
+dasd_eer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       int intval;
+       struct eerbuffer *eerb;
+
+       eerb = (struct eerbuffer *)filp->private_data;
+       switch (cmd) {
+       case DASD_EER_PURGE:
+               dasd_eer_purge_buffer(eerb);
+               return 0;
+       case DASD_EER_SETBUFSIZE:
+               if (get_user(intval, (int __user *)arg))
+                       return -EFAULT;
+               return dasd_eer_resize_buffer(eerb, intval);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static ssize_t
+dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+{
+       int tc,rc;
+       int tailcount,effective_count;
+        unsigned long flags;
+       struct eerbuffer *eerb;
+
+       eerb = (struct eerbuffer *)filp->private_data;
+       if(down_interruptible(&readbuffer_mutex))
+               return -ERESTARTSYS;
+
+       spin_lock_irqsave(&bufferlock, flags);
+
+       if (eerb->residual < 0) { /* the remainder of this record */
+                                 /* has been deleted             */
+               eerb->residual = 0;
+               spin_unlock_irqrestore(&bufferlock, flags);
+               up(&readbuffer_mutex);
+               return -EIO;
+       } else if (eerb->residual > 0) {
+               /* OK we still have a second half of a record to deliver */
+               effective_count = min(eerb->residual, (int)count);
+               eerb->residual -= effective_count;
+       } else {
+               tc = 0;
+               while (!tc) {
+                       tc = dasd_eer_read_buffer(eerb,
+                               sizeof(tailcount), (char*)(&tailcount));
+                       if (!tc) {
+                               /* no data available */
+                               spin_unlock_irqrestore(&bufferlock, flags);
+                               up(&readbuffer_mutex);
+                               if (filp->f_flags & O_NONBLOCK)
+                                       return -EAGAIN;
+                               rc = wait_event_interruptible(
+                                       dasd_eer_read_wait_queue,
+                                       eerb->head != eerb->tail);
+                               if (rc) {
+                                       return rc;
+                               }
+                               if(down_interruptible(&readbuffer_mutex))
+                                       return -ERESTARTSYS;
+                               spin_lock_irqsave(&bufferlock, flags);
+                       }
+               }
+               WARN_ON(tc != sizeof(tailcount));
+               effective_count = min(tailcount,(int)count);
+               eerb->residual = tailcount - effective_count;
+       }
+
+       tc = dasd_eer_read_buffer(eerb, effective_count, readbuffer);
+       WARN_ON(tc != effective_count);
+
+       spin_unlock_irqrestore(&bufferlock, flags);
+
+       if (copy_to_user(buf, readbuffer, effective_count)) {
+               up(&readbuffer_mutex);
+               return -EFAULT;
+       }
+
+       up(&readbuffer_mutex);
+       return effective_count;
+}
+
+static unsigned int
+dasd_eer_poll (struct file *filp, poll_table *ptable)
+{
+       unsigned int mask;
+       unsigned long flags;
+       struct eerbuffer *eerb;
+
+       eerb = (struct eerbuffer *)filp->private_data;
+       poll_wait(filp, &dasd_eer_read_wait_queue, ptable);
+       spin_lock_irqsave(&bufferlock, flags);
+       if (eerb->head != eerb->tail)
+               mask = POLLIN | POLLRDNORM ;
+       else
+               mask = 0;
+       spin_unlock_irqrestore(&bufferlock, flags);
+       return mask;
+}
+
+static struct file_operations dasd_eer_fops = {
+       .open           = &dasd_eer_open,
+       .release        = &dasd_eer_close,
+       .unlocked_ioctl = &dasd_eer_ioctl,
+       .compat_ioctl   = &dasd_eer_ioctl,
+       .read           = &dasd_eer_read,
+       .poll           = &dasd_eer_poll,
+       .owner          = THIS_MODULE,
+};
+
+static struct miscdevice dasd_eer_dev = {
+       .minor      = MISC_DYNAMIC_MINOR,
+       .name       = "dasd_eer",
+       .fops       = &dasd_eer_fops,
+};
+
+
+/*****************************************************************************/
+/*     Init and exit                                                        */
+/*****************************************************************************/
+
+static int
+__init dasd_eer_init(void)
+{
+       int rc;
+
+       dasd_eer_workqueue = create_singlethread_workqueue("dasd_eer");
+       if (!dasd_eer_workqueue) {
+               MESSAGE(KERN_ERR , "%s", "dasd_eer_init could not "
+                      "create workqueue \n");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       rc = dasd_register_eer_notifier(&dasd_eer_nb);
+       if (rc) {
+               MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+                      "register error reporting");
+               goto queue;
+       }
+
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDEERSET, dasd_ioctl_set_eer);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDEERGET, dasd_ioctl_get_eer);
+
+       /* we don't need our own character device,
+        * so we just register as misc device */
+       rc = misc_register(&dasd_eer_dev);
+       if (rc) {
+               MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+                      "register misc device");
+               goto unregister;
+       }
+
+       return 0;
+
+unregister:
+       dasd_unregister_eer_notifier(&dasd_eer_nb);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+                                dasd_ioctl_set_eer);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+                                dasd_ioctl_get_eer);
+queue:
+       destroy_workqueue(dasd_eer_workqueue);
+out:
+       return rc;
+
+}
+module_init(dasd_eer_init);
+
+static void
+__exit dasd_eer_exit(void)
+{
+       dasd_unregister_eer_notifier(&dasd_eer_nb);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+                                dasd_ioctl_set_eer);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+                                dasd_ioctl_get_eer);
+       destroy_workqueue(dasd_eer_workqueue);
+
+       WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+}
+module_exit(dasd_eer_exit);
index c20af9874500019fff41d20b7d200cfd84f187c1..d1b08fa13fd224184a9387625c218302b1724eed 100644 (file)
@@ -275,6 +275,34 @@ struct dasd_discipline {
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
 
+
+/*
+ * Notification numbers for extended error reporting notifications:
+ * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
+ * eer pointer) is freed. The error reporting module needs to do all necessary
+ * cleanup steps.
+ * The DASD_EER_TRIGGER notification sends the actual error reports (triggers).
+ */
+#define DASD_EER_DISABLE 0
+#define DASD_EER_TRIGGER 1
+
+/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */
+#define DASD_EER_FATALERROR  1
+#define DASD_EER_NOPATH      2
+#define DASD_EER_STATECHANGE 3
+#define DASD_EER_PPRCSUSPEND 4
+
+/*
+ * The dasd_eer_trigger structure contains all data that we need to send
+ * along with an DASD_EER_TRIGGER notification.
+ */
+struct dasd_eer_trigger {
+       unsigned int id;
+       struct dasd_device *device;
+       struct dasd_ccw_req *cqr;
+};
+
+
 struct dasd_device {
        /* Block device stuff. */
        struct gendisk *gdp;
@@ -288,6 +316,9 @@ struct dasd_device {
        unsigned long flags;            /* per device flags */
        unsigned short features;        /* copy of devmap-features (read-only!) */
 
+       /* extended error reporting stuff (eer) */
+       void *eer;
+
        /* Device discipline stuff. */
        struct dasd_discipline *discipline;
        char *private;
@@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_auto_online (struct ccw_driver *);
+int dasd_register_eer_notifier(struct notifier_block *);
+int dasd_unregister_eer_notifier(struct notifier_block *);
+void dasd_write_eer_trigger(unsigned int , struct dasd_device *,
+                       struct dasd_ccw_req *);
+
+
 
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
index 44e4b4bb1c5abf86c7f069fc2759209f4c556ea8..3e75095f35d03e70f21bb43304d9fa537258c8fa 100644 (file)
@@ -68,6 +68,6 @@ extern void *chsc_get_chp_desc(struct subchannel*, int);
 
 extern int chsc_enable_facility(int);
 
-#define to_channelpath(dev) container_of(dev, struct channel_path, dev)
+#define to_channelpath(device) container_of(device, struct channel_path, dev)
 
 #endif
index 0d38f0f2ae2975d41f08fa059ab796385be2e71e..ee4265d7a8c9d9130b96293b980cb0dc21e3e17f 100644 (file)
@@ -892,20 +892,20 @@ config SERIAL_VR41XX_CONSOLE
          a console on a serial port, say Y.  Otherwise, say N.
 
 config SERIAL_JSM
-        tristate "Digi International NEO PCI Support"
-       depends on PCI && BROKEN
-        select SERIAL_CORE
-        help
-          This is a driver for Digi International's Neo series
-          of cards which provide multiple serial ports. You would need
-          something like this to connect more than two modems to your Linux
-          box, for instance in order to become a dial-in server. This driver
-          supports PCI boards only.
-          If you have a card like this, say Y here and read the file
-          <file:Documentation/jsm.txt>.
-
-          To compile this driver as a module, choose M here: the
-          module will be called jsm.
+       tristate "Digi International NEO PCI Support"
+       depends on PCI
+       select SERIAL_CORE
+       help
+         This is a driver for Digi International's Neo series
+         of cards which provide multiple serial ports. You would need
+         something like this to connect more than two modems to your Linux
+         box, for instance in order to become a dial-in server. This driver
+         supports PCI boards only.
+         If you have a card like this, say Y here and read the file
+         <file:Documentation/jsm.txt>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called jsm.
 
 config SERIAL_SGI_IOC4
        tristate "SGI IOC4 controller serial support"
index 18753193f59b7be467af3bb3a3eca1cd67889341..dfc1e86d3aa119b5977a3d6efc9abbcdeafe67e4 100644 (file)
@@ -380,7 +380,6 @@ struct neo_uart_struct {
 extern struct  uart_driver jsm_uart_driver;
 extern struct  board_ops jsm_neo_ops;
 extern int     jsm_debug;
-extern int     jsm_rawreadok;
 
 /*************************************************************************
  *
index 7e56c78241945975081657176342f0416c935cd7..b1b66e71d281125f990a9dc742ef56dc48786c3e 100644 (file)
@@ -49,11 +49,8 @@ struct uart_driver jsm_uart_driver = {
 };
 
 int jsm_debug;
-int jsm_rawreadok;
 module_param(jsm_debug, int, 0);
-module_param(jsm_rawreadok, int, 0);
 MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input");
 
 static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
index 6fa0d62d6f686269eadf52abacf56e516f7be3f8..4d48b625cd3d9f7fdc67e76b6a742372b3f28953 100644 (file)
  *
  * Contact Information:
  * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
- *
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06:   changed jsm_input routine to use the dynamically allocated
+ *             tty_buffer changes. Contributors: Scott Kilau and Ananda V.
  ***********************************************************************/
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -497,16 +499,15 @@ void jsm_input(struct jsm_channel *ch)
 {
        struct jsm_board *bd;
        struct tty_struct *tp;
+       struct tty_ldisc *ld;
        u32 rmask;
        u16 head;
        u16 tail;
        int data_len;
        unsigned long lock_flags;
-       int flip_len;
+       int flip_len = 0;
        int len = 0;
        int n = 0;
-       char *buf = NULL;
-       char *buf2 = NULL;
        int s = 0;
        int i = 0;
 
@@ -574,56 +575,50 @@ void jsm_input(struct jsm_channel *ch)
 
        /*
         * If the rxbuf is empty and we are not throttled, put as much
-        * as we can directly into the linux TTY flip buffer.
-        * The jsm_rawreadok case takes advantage of carnal knowledge that
-        * the char_buf and the flag_buf are next to each other and
-        * are each of (2 * TTY_FLIPBUF_SIZE) size.
+        * as we can directly into the linux TTY buffer.
         *
-        * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
-        *actually still uses the flag buffer, so you can't
-        *use it for input data
         */
-       if (jsm_rawreadok) {
-               if (tp->real_raw)
-                       flip_len = MYFLIPLEN;
-               else
-                       flip_len = 2 * TTY_FLIPBUF_SIZE;
-       } else
-               flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+       flip_len = TTY_FLIPBUF_SIZE;
 
        len = min(data_len, flip_len);
        len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+       ld = tty_ldisc_ref(tp);
 
-       if (len <= 0) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
-               return;
-       }
+       /*
+        * If the DONT_FLIP flag is on, don't flush our buffer, and act
+        * like the ld doesn't have any space to put the data right now.
+        */
+       if (test_bit(TTY_DONT_FLIP, &tp->flags))
+               len = 0;
 
        /*
-        * If we're bypassing flip buffers on rx, we can blast it
-        * right into the beginning of the buffer.
+        * If we were unable to get a reference to the ld,
+        * don't flush our buffer, and act like the ld doesn't
+        * have any space to put the data right now.
         */
-       if (jsm_rawreadok) {
-               if (tp->real_raw) {
-                       if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "JSM - FLIPBUF in use. delaying input\n");
-                               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-                               return;
-                       }
-                       ch->ch_flags |= CH_FLIPBUF_IN_USE;
-                       buf = ch->ch_bd->flipbuf;
-                       buf2 = NULL;
-               } else {
-                       buf = tp->flip.char_buf;
-                       buf2 = tp->flip.flag_buf;
-               }
+       if (!ld) {
+               len = 0;
        } else {
-               buf = tp->flip.char_buf_ptr;
-               buf2 = tp->flip.flag_buf_ptr;
+               /*
+                * If ld doesn't have a pointer to a receive_buf function,
+                * flush the data, then act like the ld doesn't have any
+                * space to put the data right now.
+                */
+               if (!ld->receive_buf) {
+                               ch->ch_r_head = ch->ch_r_tail;
+                               len = 0;
+               }
        }
 
+       if (len <= 0) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+               if (ld)
+                       tty_ldisc_deref(ld);
+               return;
+       }
+
+       len = tty_buffer_request_room(tp, len);
        n = len;
 
        /*
@@ -638,121 +633,47 @@ void jsm_input(struct jsm_channel *ch)
                if (s <= 0)
                        break;
 
-               memcpy(buf, ch->ch_rqueue + tail, s);
-
-               /* buf2 is only set when port isn't raw */
-               if (buf2)
-                       memcpy(buf2, ch->ch_equeue + tail, s);
-
-               tail += s;
-               buf += s;
-               if (buf2)
-                       buf2 += s;
-               n -= s;
-               /* Flip queue if needed */
-               tail &= rmask;
-       }
+                       /*
+                        * If conditions are such that ld needs to see all
+                        * UART errors, we will have to walk each character
+                        * and error byte and send them to the buffer one at
+                        * a time.
+                        */
 
-       /*
-        * In high performance mode, we don't have to update
-        * flag_buf or any of the counts or pointers into flip buf.
-        */
-       if (!jsm_rawreadok) {
                if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
-                       for (i = 0; i < len; i++) {
+                       for (i = 0; i < s; i++) {
                                /*
                                 * Give the Linux ld the flags in the
                                 * format it likes.
                                 */
-                               if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
-                                       tp->flip.flag_buf_ptr[i] = TTY_BREAK;
-                               else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
-                                       tp->flip.flag_buf_ptr[i] = TTY_PARITY;
-                               else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
-                                       tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+                               if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
                                else
-                                       tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+                               tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
                        }
                } else {
-                       memset(tp->flip.flag_buf_ptr, 0, len);
+                       tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
                }
-
-               tp->flip.char_buf_ptr += len;
-               tp->flip.flag_buf_ptr += len;
-               tp->flip.count += len;
-       }
-       else if (!tp->real_raw) {
-               if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
-                       for (i = 0; i < len; i++) {
-                               /*
-                                * Give the Linux ld the flags in the
-                                * format it likes.
-                                */
-                               if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
-                                       tp->flip.flag_buf_ptr[i] = TTY_BREAK;
-                               else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
-                                       tp->flip.flag_buf_ptr[i] = TTY_PARITY;
-                               else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
-                                       tp->flip.flag_buf_ptr[i] = TTY_FRAME;
-                               else
-                                       tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
-                       }
-               } else
-                       memset(tp->flip.flag_buf, 0, len);
+               tail += s;
+               n -= s;
+               /* Flip queue if needed */
+               tail &= rmask;
        }
 
-       /*
-        * If we're doing raw reads, jam it right into the
-        * line disc bypassing the flip buffers.
-        */
-       if (jsm_rawreadok) {
-               if (tp->real_raw) {
-                       ch->ch_r_tail = tail & rmask;
-                       ch->ch_e_tail = tail & rmask;
-
-                       jsm_check_queue_flow_control(ch);
-
-                       /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+       ch->ch_r_tail = tail & rmask;
+       ch->ch_e_tail = tail & rmask;
+       jsm_check_queue_flow_control(ch);
+       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
 
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+       /* Tell the tty layer its okay to "eat" the data now */
+       tty_flip_buffer_push(tp);
 
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
-                               __LINE__, len, ch->ch_bd->boardnum);
-                       tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
-
-                       /* Allow use of channel flip buffer again */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               } else {
-                       ch->ch_r_tail = tail & rmask;
-                       ch->ch_e_tail = tail & rmask;
-
-                       jsm_check_queue_flow_control(ch);
-
-                       /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n",
-                               __LINE__, len, ch->ch_bd->boardnum);
-
-                       tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
-               }
-       } else {
-               ch->ch_r_tail = tail & rmask;
-               ch->ch_e_tail = tail & rmask;
-
-               jsm_check_queue_flow_control(ch);
-
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                       "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__);
-               tty_schedule_flip(tp);
-       }
+       if (ld)
+               tty_ldisc_deref(ld);
 
        jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
 }
index d957a3a9edf1f52bc0ebdeeb6f662ed9cfef7a47..0ef648fa4b2dcddd8e801e87846e3a114d902c2b 100644 (file)
@@ -350,8 +350,7 @@ static inline void receive_chars(struct mcf_serial *info)
                }
                tty_insert_flip_char(tty, ch, flag);
        }
-
-       schedule_work(&tty->flip.work);
+       tty_flip_buffer_push(tty);
        return;
 }
 
index f6704688ee8c2e15efb500ce0ed807030e078280..5578a9dd04e80bcffb92e1119c82bb4aa5ce174b 100644 (file)
@@ -3558,10 +3558,16 @@ static void ixj_write_frame(IXJ *j)
                                }
                        /* Add word 0 to G.729 frames for the 8021.  Right now we don't do VAD/CNG  */
                                if (j->play_codec == G729 && (cnt == 0 || cnt == 10 || cnt == 20)) {
-                                       if(j->write_buffer_rp + cnt == 0 && j->write_buffer_rp + cnt + 1 == 0 && j->write_buffer_rp + cnt + 2 == 0 &&
-                                          j->write_buffer_rp + cnt + 3 == 0 && j->write_buffer_rp + cnt + 4 == 0 && j->write_buffer_rp + cnt + 5 == 0 &&
-                                          j->write_buffer_rp + cnt + 6 == 0 && j->write_buffer_rp + cnt + 7 == 0 && j->write_buffer_rp + cnt + 8 == 0 &&
-                                          j->write_buffer_rp + cnt + 9 == 0) {
+                                       if (j->write_buffer_rp[cnt] == 0 &&
+                                           j->write_buffer_rp[cnt + 1] == 0 &&
+                                           j->write_buffer_rp[cnt + 2] == 0 &&
+                                           j->write_buffer_rp[cnt + 3] == 0 &&
+                                           j->write_buffer_rp[cnt + 4] == 0 &&
+                                           j->write_buffer_rp[cnt + 5] == 0 &&
+                                           j->write_buffer_rp[cnt + 6] == 0 &&
+                                           j->write_buffer_rp[cnt + 7] == 0 &&
+                                           j->write_buffer_rp[cnt + 8] == 0 &&
+                                           j->write_buffer_rp[cnt + 9] == 0) {
                                        /* someone is trying to write silence lets make this a type 0 frame. */
                                                outb_p(0x00, j->DSPbase + 0x0C);
                                                outb_p(0x00, j->DSPbase + 0x0D);
index 32a9f99154e23b30bb804ba6601b6f804c9baff5..bf1f10067960be8feb075d8740229d1419993b53 100644 (file)
@@ -116,13 +116,19 @@ static void buf_put_int64(struct cbuf *buf, u64 val)
        }
 }
 
-static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
 {
+       char *ret;
+
+       ret = NULL;
        if (buf_check_size(buf, slen + 2)) {
                buf_put_int16(buf, slen);
+               ret = buf->p;
                memcpy(buf->p, s, slen);
                buf->p += slen;
        }
+
+       return ret;
 }
 
 static inline void buf_put_string(struct cbuf *buf, const char *s)
@@ -430,15 +436,19 @@ static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
 static void
 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
 {
-       if (data) {
-               str->len = strlen(data);
-               str->str = bufp->p;
-       } else {
-               str->len = 0;
-               str->str = NULL;
-       }
+       int len;
+       char *s;
+
+       if (data)
+               len = strlen(data);
+       else
+               len = 0;
 
-       buf_put_stringn(bufp, data, str->len);
+       s = buf_put_stringn(bufp, data, len);
+       if (str) {
+               str->len = len;
+               str->str = s;
+       }
 }
 
 static int
index 945cb368d451948156bf518ee7e40616ac09e675..ea1134eb47c8e591f6917262f3a340605d310dd5 100644 (file)
@@ -471,10 +471,13 @@ static void v9fs_write_work(void *a)
                }
 
                spin_lock(&m->lock);
-               req =
-                   list_entry(m->unsent_req_list.next, struct v9fs_req,
+again:
+               req = list_entry(m->unsent_req_list.next, struct v9fs_req,
                               req_list);
                list_move_tail(&req->req_list, &m->req_list);
+               if (req->err == ERREQFLUSH)
+                       goto again;
+
                m->wbuf = req->tcall->sdata;
                m->wsize = req->tcall->size;
                m->wpos = 0;
@@ -525,7 +528,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
        struct v9fs_str *ename;
 
        tag = req->tag;
-       if (req->rcall->id == RERROR && !req->err) {
+       if (!req->err && req->rcall->id == RERROR) {
                ecode = req->rcall->params.rerror.errno;
                ename = &req->rcall->params.rerror.error;
 
@@ -551,7 +554,10 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
                        req->err = -EIO;
        }
 
-       if (req->cb && req->err != ERREQFLUSH) {
+       if (req->err == ERREQFLUSH)
+               return;
+
+       if (req->cb) {
                dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n",
                        req->tcall, req->rcall);
 
@@ -812,6 +818,7 @@ v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err)
        struct v9fs_mux_rpc *r;
 
        if (err == ERREQFLUSH) {
+               kfree(rc);
                dprintk(DEBUG_MUX, "err req flush\n");
                return;
        }
index 91f552454c7656470eecd32a6d00513e5b54d81f..63e5b0398e8b9e5f447fc1d2234a0ec11d50680c 100644 (file)
@@ -886,8 +886,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        }
 
        /* copy extension buffer into buffer */
-       if (fcall->params.rstat.stat.extension.len < buflen)
-               buflen = fcall->params.rstat.stat.extension.len;
+       if (fcall->params.rstat.stat.extension.len+1 < buflen)
+               buflen = fcall->params.rstat.stat.extension.len + 1;
 
        memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
        buffer[buflen-1] = 0;
@@ -951,7 +951,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
        if (!link)
                link = ERR_PTR(-ENOMEM);
        else {
-               len = v9fs_readlink(dentry, link, strlen(link));
+               len = v9fs_readlink(dentry, link, PATH_MAX);
 
                if (len < 0) {
                        __putname(link);
index 5e4a90ee103f5eacedc1f8acaafacb847f56b5ec..62cfd17dc5fee6c87a1dbaabe5e01299e89dc5ad 100644 (file)
@@ -2867,22 +2867,22 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
                else if (test_set_buffer_locked(bh))
                        continue;
 
-               get_bh(bh);
                if (rw == WRITE || rw == SWRITE) {
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
+                               get_bh(bh);
                                submit_bh(WRITE, bh);
                                continue;
                        }
                } else {
                        if (!buffer_uptodate(bh)) {
                                bh->b_end_io = end_buffer_read_sync;
+                               get_bh(bh);
                                submit_bh(rw, bh);
                                continue;
                        }
                }
                unlock_buffer(bh);
-               put_bh(bh);
        }
 }
 
index 86bdb93789c6629c60027fdba100e99aa2709610..a173bba326666e322ca92813c1667671f783f65e 100644 (file)
@@ -743,7 +743,9 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        dentry->d_op = NULL;
        dentry->d_fsdata = NULL;
        dentry->d_mounted = 0;
+#ifdef CONFIG_PROFILING
        dentry->d_cookie = NULL;
+#endif
        INIT_HLIST_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
index 30dbbd1df51191a68d536ca430fad8001a80c39f..848044af7e1677e6fba1c2d3f76897a916b1bb93 100644 (file)
@@ -857,6 +857,7 @@ do_holes:
                        /* Handle holes */
                        if (!buffer_mapped(map_bh)) {
                                char *kaddr;
+                               loff_t i_size_aligned;
 
                                /* AKPM: eargh, -ENOTBLK is a hack */
                                if (dio->rw == WRITE) {
@@ -864,8 +865,14 @@ do_holes:
                                        return -ENOTBLK;
                                }
 
+                               /*
+                                * Be sure to account for a partial block as the
+                                * last block in the file
+                                */
+                               i_size_aligned = ALIGN(i_size_read(dio->inode),
+                                                       1 << blkbits);
                                if (dio->block_in_file >=
-                                       i_size_read(dio->inode)>>blkbits) {
+                                               i_size_aligned >> blkbits) {
                                        /* We hit eof */
                                        page_cache_release(page);
                                        goto out;
index 35acc43b897f7e46b1563b2fa696973dec67ebe7..da52b4a5db64005173124575e63161ed1d6c3d35 100644 (file)
@@ -220,7 +220,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        struct ext2_inode_info *ei = EXT2_I(inode);
        int name_index;
        void *value = NULL;
-       size_t size;
+       size_t size = 0;
        int error;
 
        if (S_ISLNK(inode->i_mode))
index 74714af4ae6979acf4516ff614e77b79155d3a80..e52765219e165eb866c4a0dafd120ce1d966806c 100644 (file)
@@ -605,7 +605,7 @@ got:
        insert_inode_hash(inode);
 
        if (DQUOT_ALLOC_INODE(inode)) {
-               err = -ENOSPC;
+               err = -EDQUOT;
                goto fail_drop;
        }
 
index 8d6819846fc97241375542c7316d2d9cd6a0b26e..cb6f9bd658de9646da588af8feacb64bbe1d3742 100644 (file)
@@ -221,6 +221,11 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",grpquota");
 #endif
 
+#if defined(CONFIG_EXT2_FS_XIP)
+       if (sbi->s_mount_opt & EXT2_MOUNT_XIP)
+               seq_puts(seq, ",xip");
+#endif
+
        return 0;
 }
 
index 47a9da2dfb4fbd9739ab46531fca3ec2d5040c9d..0d21d558b87a19d2105d32ff8df19698ffe439a5 100644 (file)
@@ -226,7 +226,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
        struct ext3_inode_info *ei = EXT3_I(inode);
        int name_index;
        void *value = NULL;
-       size_t size;
+       size_t size = 0;
        int error;
 
        if (S_ISLNK(inode->i_mode))
index e99c5a73b39e6f172e52ee394cba5b9289a78e87..88aa1ae13f9f3022c7978d9bbd7e5cb20c2d71aa 100644 (file)
@@ -210,10 +210,30 @@ static int fat_free(struct inode *inode, int skip)
        if (MSDOS_I(inode)->i_start == 0)
                return 0;
 
-       /*
-        * Write a new EOF, and get the remaining cluster chain for freeing.
-        */
+       fat_cache_inval_inode(inode);
+
        wait = IS_DIRSYNC(inode);
+       i_start = free_start = MSDOS_I(inode)->i_start;
+       i_logstart = MSDOS_I(inode)->i_logstart;
+
+       /* First, we write the new file size. */
+       if (!skip) {
+               MSDOS_I(inode)->i_start = 0;
+               MSDOS_I(inode)->i_logstart = 0;
+       }
+       MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+       if (wait) {
+               err = fat_sync_inode(inode);
+               if (err) {
+                       MSDOS_I(inode)->i_start = i_start;
+                       MSDOS_I(inode)->i_logstart = i_logstart;
+                       return err;
+               }
+       } else
+               mark_inode_dirty(inode);
+
+       /* Write a new EOF, and get the remaining cluster chain for freeing. */
        if (skip) {
                struct fat_entry fatent;
                int ret, fclus, dclus;
@@ -244,35 +264,11 @@ static int fat_free(struct inode *inode, int skip)
                        return ret;
 
                free_start = ret;
-               i_start = i_logstart = 0;
-               fat_cache_inval_inode(inode);
-       } else {
-               fat_cache_inval_inode(inode);
-
-               i_start = free_start = MSDOS_I(inode)->i_start;
-               i_logstart = MSDOS_I(inode)->i_logstart;
-               MSDOS_I(inode)->i_start = 0;
-               MSDOS_I(inode)->i_logstart = 0;
        }
-       MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
-       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
-       if (wait) {
-               err = fat_sync_inode(inode);
-               if (err)
-                       goto error;
-       } else
-               mark_inode_dirty(inode);
        inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
 
        /* Freeing the remained cluster chain */
        return fat_free_clusters(inode, free_start);
-
-error:
-       if (i_start) {
-               MSDOS_I(inode)->i_start = i_start;
-               MSDOS_I(inode)->i_logstart = i_logstart;
-       }
-       return err;
 }
 
 void fat_truncate(struct inode *inode)
index 32fb0a3f1da46b712ab514037ed0d8fbe0233808..944652e9dde13c4e7438b3a3074a5b6f95066a34 100644 (file)
@@ -196,19 +196,9 @@ EXPORT_SYMBOL_GPL(fat_date_unix2dos);
 
 int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
 {
-       int i, e, err = 0;
+       int i, err = 0;
 
-       for (i = 0; i < nr_bhs; i++) {
-               lock_buffer(bhs[i]);
-               if (test_clear_buffer_dirty(bhs[i])) {
-                       get_bh(bhs[i]);
-                       bhs[i]->b_end_io = end_buffer_write_sync;
-                       e = submit_bh(WRITE, bhs[i]);
-                       if (!err && e)
-                               err = e;
-               } else
-                       unlock_buffer(bhs[i]);
-       }
+       ll_rw_block(SWRITE, nr_bhs, bhs);
        for (i = 0; i < nr_bhs; i++) {
                wait_on_buffer(bhs[i]);
                if (buffer_eopnotsupp(bhs[i])) {
index 5f96786d1c73dc6c9ac27565b521835f6fe5ff12..dc4a7007f4e742c4e30563db78b34bd21d39ab58 100644 (file)
@@ -208,8 +208,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
        struct inode * inode = filp->f_dentry->d_inode;
        int error = 0;
 
-       /* O_APPEND cannot be cleared if the file is marked as append-only */
-       if (!(arg & O_APPEND) && IS_APPEND(inode))
+       /*
+        * O_APPEND cannot be cleared if the file is marked as append-only
+        * and the file is open for write.
+        */
+       if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode))
                return -EPERM;
 
        /* O_NOATIME can only be set by the owner or superuser */
index b2e95421d932025407f758bb590d49b165a0a05a..ce7b54b0b2b7596333276bdcf42d40cf3011df0a 100644 (file)
@@ -1965,7 +1965,7 @@ retry:
                iovec_cnt++;
 
                if (JFFS_GET_PAD_BYTES(raw_inode->nsize)) {
-                       static char allff[3]={255,255,255};
+                       static unsigned char allff[3]={255,255,255};
                        /* Add some extra padding if necessary */
                        node_iovec[iovec_cnt].iov_base = allff;
                        node_iovec[iovec_cnt].iov_len =
index 63c020e6589e5c81e296f2eae3b9a2e5917aeee0..71fd08fa410301deef23dcc563f9232c92081fa9 100644 (file)
@@ -388,6 +388,7 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
+       inode->i_nlink = 2;
        root = d_alloc_root(inode);
        if (!root) {
                iput(inode);
index 8f8014285a349c14f547c8e3d92d47cc9a6ff4b7..1d24fead51a6385d9e2ce69c9e7353ade88c039a 100644 (file)
@@ -548,7 +548,7 @@ static int show_stat(struct seq_file *p, void *v)
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA)
+#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
        for (i = 0; i < NR_IRQS; i++)
                seq_printf(p, " %u", kstat_irqs(i));
 #endif
index a4ef91bb4f3b9afe61628d52a7bb3e08356b42da..b4199ec3ece460bd9818c419b7b9ed1a10fab06f 100644 (file)
@@ -35,7 +35,7 @@ static int v2_check_quota_file(struct super_block *sb, int type)
  
        size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
        if (size != sizeof(struct v2_disk_dqheader)) {
-               printk("quota_v2: failed read expected=%d got=%d\n",
+               printk("quota_v2: failed read expected=%zd got=%zd\n",
                        sizeof(struct v2_disk_dqheader), size);
                return 0;
        }
index 77891de0e02e7b0f470545b98fc1bb00e075e508..ef5e5414e7a83eb9b4295bbaba5464410b11e030 100644 (file)
@@ -1125,7 +1125,7 @@ static void handle_attrs(struct super_block *s)
                        REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
                }
        } else if (le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared) {
-               REISERFS_SB(s)->s_mount_opt |= REISERFS_ATTRS;
+               REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ATTRS);
        }
 }
 
index 4fae57d9d1151008fa690a889c98ee4e0c737ecd..201049ac8a96f94851213604d2017043b1dee155 100644 (file)
@@ -579,10 +579,9 @@ static void udf_table_free_blocks(struct super_block * sb,
                        {
                                loffset = nextoffset;
                                aed->lengthAllocDescs = cpu_to_le32(adsize);
-                               if (obh)
-                                       sptr = UDF_I_DATA(inode) + nextoffset -  udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode) - adsize;
-                               else
-                                       sptr = obh->b_data + nextoffset - adsize;
+                               sptr = UDF_I_DATA(inode) + nextoffset -
+                                       udf_file_entry_alloc_offset(inode) +
+                                       UDF_I_LENEATTR(inode) - adsize;
                                dptr = nbh->b_data + sizeof(struct allocExtDesc);
                                memcpy(dptr, sptr, adsize);
                                nextoffset = sizeof(struct allocExtDesc) + adsize;
index ca732e79c48bb60af77c28dfe8f0a4f75b9f64b1..ab9a7629d23e82c094e8b7db9606a57af007e294 100644 (file)
@@ -296,7 +296,7 @@ static struct dentry *
 udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = NULL;
-       struct fileIdentDesc cfi, *fi;
+       struct fileIdentDesc cfi;
        struct udf_fileident_bh fibh;
 
        if (dentry->d_name.len > UDF_NAME_LEN-2)
@@ -318,7 +318,7 @@ udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        else
 #endif /* UDF_RECOVERY */
 
-       if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
+       if (udf_find_entry(dir, dentry, &fibh, &cfi))
        {
                if (fibh.sbh != fibh.ebh)
                        udf_release_data(fibh.ebh);
index e0c04e36a0518a42548d4b4aad82743f7572bb82..3c3f62ce2ad9a926e71b5e52bb76f6b763009425 100644 (file)
@@ -376,7 +376,7 @@ out:
  * This function gets the block which contains the fragment.
  */
 
-static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
+int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
        struct super_block * sb = inode->i_sb;
        struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
index d4aacee593ffbb9a2daec491518ff9c4bf3dfec0..e9055ef7f5ac97dbe33791e0d5f9c227a06985f9 100644 (file)
@@ -388,7 +388,8 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
 /*
  * Read on-disk structures associated with cylinder groups
  */
-static int ufs_read_cylinder_structures (struct super_block *sb) {
+static int ufs_read_cylinder_structures (struct super_block *sb)
+{
        struct ufs_sb_info * sbi = UFS_SB(sb);
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block *usb;
@@ -415,6 +416,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb) {
        base = space = kmalloc(size, GFP_KERNEL);
        if (!base)
                goto failed; 
+       sbi->s_csp = (struct ufs_csum *)space;
        for (i = 0; i < blks; i += uspi->s_fpb) {
                size = uspi->s_bsize;
                if (i + uspi->s_fpb > blks)
@@ -430,7 +432,6 @@ static int ufs_read_cylinder_structures (struct super_block *sb) {
                        goto failed;
 
                ubh_ubhcpymem (space, ubh, size);
-               sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
 
                space += size;
                ubh_brelse (ubh);
@@ -486,7 +487,8 @@ failed:
  * Put on-disk structures associated with cylinder groups and 
  * write them back to disk
  */
-static void ufs_put_cylinder_structures (struct super_block *sb) {
+static void ufs_put_cylinder_structures (struct super_block *sb)
+{
        struct ufs_sb_info * sbi = UFS_SB(sb);
        struct ufs_sb_private_info * uspi;
        struct ufs_buffer_head * ubh;
@@ -499,7 +501,7 @@ static void ufs_put_cylinder_structures (struct super_block *sb) {
 
        size = uspi->s_cssize;
        blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
-       base = space = (char*) sbi->s_csp[0];
+       base = space = (char*) sbi->s_csp;
        for (i = 0; i < blks; i += uspi->s_fpb) {
                size = uspi->s_bsize;
                if (i + uspi->s_fpb > blks)
index 61d2e35012a462e2cb6be0f9fc27bd10e20db0b1..02e86291ef8adfde874aac0e72b37fd2f51bad85 100644 (file)
  * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
  */
 
+/*
+ * Modified to avoid infinite loop on 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru>
+ */
+
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
 #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
 
-#define DATA_BUFFER_USED(bh) \
-       (atomic_read(&bh->b_count)>1 || buffer_locked(bh))
 
 static int ufs_trunc_direct (struct inode * inode)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct buffer_head * bh;
        __fs32 * p;
        unsigned frag1, frag2, frag3, frag4, block1, block2;
        unsigned frag_to_free, free_count;
-       unsigned i, j, tmp;
+       unsigned i, tmp;
        int retry;
        
        UFSD(("ENTER\n"))
@@ -117,15 +119,7 @@ static int ufs_trunc_direct (struct inode * inode)
                ufs_panic (sb, "ufs_trunc_direct", "internal error");
        frag1 = ufs_fragnum (frag1);
        frag2 = ufs_fragnum (frag2);
-       for (j = frag1; j < frag2; j++) {
-               bh = sb_find_get_block (sb, tmp + j);
-               if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
-                       retry = 1;
-                       brelse (bh);
-                       goto next1;
-               }
-               bforget (bh);
-       }
+
        inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
        mark_inode_dirty(inode);
        ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
@@ -140,15 +134,7 @@ next1:
                tmp = fs32_to_cpu(sb, *p);
                if (!tmp)
                        continue;
-               for (j = 0; j < uspi->s_fpb; j++) {
-                       bh = sb_find_get_block(sb, tmp + j);
-                       if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
-                               retry = 1;
-                               brelse (bh);
-                               goto next2;
-                       }
-                       bforget (bh);
-               }
+
                *p = 0;
                inode->i_blocks -= uspi->s_nspb;
                mark_inode_dirty(inode);
@@ -162,7 +148,6 @@ next1:
                        frag_to_free = tmp;
                        free_count = uspi->s_fpb;
                }
-next2:;
        }
        
        if (free_count > 0)
@@ -179,15 +164,7 @@ next2:;
        if (!tmp )
                ufs_panic(sb, "ufs_truncate_direct", "internal error");
        frag4 = ufs_fragnum (frag4);
-       for (j = 0; j < frag4; j++) {
-               bh = sb_find_get_block (sb, tmp + j);
-               if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
-                       retry = 1;
-                       brelse (bh);
-                       goto next1;
-               }
-               bforget (bh);
-       }
+
        *p = 0;
        inode->i_blocks -= frag4 << uspi->s_nspfshift;
        mark_inode_dirty(inode);
@@ -204,9 +181,8 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
        struct ufs_buffer_head * ind_ubh;
-       struct buffer_head * bh;
        __fs32 * ind;
-       unsigned indirect_block, i, j, tmp;
+       unsigned indirect_block, i, tmp;
        unsigned frag_to_free, free_count;
        int retry;
 
@@ -238,15 +214,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
                tmp = fs32_to_cpu(sb, *ind);
                if (!tmp)
                        continue;
-               for (j = 0; j < uspi->s_fpb; j++) {
-                       bh = sb_find_get_block(sb, tmp + j);
-                       if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *ind)) {
-                               retry = 1;
-                               brelse (bh);
-                               goto next;
-                       }
-                       bforget (bh);
-               }       
+
                *ind = 0;
                ubh_mark_buffer_dirty(ind_ubh);
                if (free_count == 0) {
@@ -261,7 +229,6 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
                }
                inode->i_blocks -= uspi->s_nspb;
                mark_inode_dirty(inode);
-next:;
        }
 
        if (free_count > 0) {
@@ -430,9 +397,7 @@ void ufs_truncate (struct inode * inode)
        struct ufs_inode_info *ufsi = UFS_I(inode);
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct buffer_head * bh;
-       unsigned offset;
-       int err, retry;
+       int retry;
        
        UFSD(("ENTER\n"))
        sb = inode->i_sb;
@@ -442,6 +407,9 @@ void ufs_truncate (struct inode * inode)
                return;
        if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                return;
+
+       block_truncate_page(inode->i_mapping,   inode->i_size, ufs_getfrag_block);
+
        lock_kernel();
        while (1) {
                retry = ufs_trunc_direct(inode);
@@ -457,15 +425,7 @@ void ufs_truncate (struct inode * inode)
                blk_run_address_space(inode->i_mapping);
                yield();
        }
-       offset = inode->i_size & uspi->s_fshift;
-       if (offset) {
-               bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
-               if (bh) {
-                       memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
-                       mark_buffer_dirty (bh);
-                       brelse (bh);
-               }
-       }
+
        inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
        ufsi->i_lastfrag = DIRECT_FRAGMENT;
        unlock_kernel();
index d3eb0f1e42085c7911aaa6f5d4303d38a78cd022..b7fef1572dc0f52d34ad9efa7eae87faf3ac684a 100644 (file)
@@ -290,7 +290,7 @@ static inline int find_next_zero_bit (const unsigned long * addr, int size, int
        tmp = *p;
        
  found_first:
-       tmp |= ~0UL >> size;
+       tmp |= ~0UL << size;
  found_middle:
        return result + ffz(tmp);
 }
index 02be7b3a8a83fd3fcd652472a4b3848c45cbd255..f686b519878ed34ed5f557d1e40014f869116e53 100644 (file)
@@ -209,7 +209,7 @@ static inline int find_next_zero_bit(const void *addr, int size, int offset)
        tmp = *p;
 
 found_first:
-       tmp |= ~0UL >> size;
+       tmp |= ~0UL << size;
 found_middle:
        return result + ffz(tmp);
 }
index c0411ec9d651785200e64d45734983db17d2fcbc..ff7c2b7215946a37fc8fc11eb9c2f29750d1f963 100644 (file)
@@ -227,7 +227,7 @@ static __inline__ int find_next_zero_bit (const unsigned long * addr, int size,
        tmp = *p;
 
 found_first:
-       tmp |= ~0UL >> size;
+       tmp |= ~0UL << size;
 found_middle:
        return result + ffz(tmp);
 }
index d7e19eb344b7ab4f83c6611ec3afb675edf86d13..af503a122b23592eb6e82836fffd30ead57de91a 100644 (file)
 #ifndef _ASM_I386_TOPOLOGY_H
 #define _ASM_I386_TOPOLOGY_H
 
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu)                              \
+       (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
+#define topology_core_id(cpu)                                          \
+       (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_core_siblings(cpu)            (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#endif
+
 #ifdef CONFIG_NUMA
 
 #include <asm/mpspec.h>
index e62b95301d513321befd401291a90d6c867f4325..93f45c5f189f0649bc0df0b62fcc6f10bc270a50 100644 (file)
 
 #include <linux/irq.h>
 
-#ifndef MAX_HWIFS
-# ifdef CONFIG_PCI
-#define MAX_HWIFS      10
-# else
-#define MAX_HWIFS      6
-# endif
-#endif
-
 #define IDE_ARCH_OBSOLETE_DEFAULTS
 
 static inline int ide_default_irq(unsigned long base)
index 412ef8e493a8cc2644ad79294f9907ddd8e4566c..3ee19dfa46dfde66f5723030f5a0e3a9e114bca6 100644 (file)
@@ -102,6 +102,13 @@ void build_cpu_to_node_map(void);
 
 #endif /* CONFIG_NUMA */
 
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu)      (cpu_data(cpu)->socket_id)
+#define topology_core_id(cpu)                  (cpu_data(cpu)->core_id)
+#define topology_core_siblings(cpu)            (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#endif
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_IA64_TOPOLOGY_H */
index 1630c26e8f45a5c27eef949454fb4702747fc7f0..c744ff33b1df62b0ead905356025a1e650c6b1e8 100644 (file)
@@ -204,7 +204,8 @@ typedef struct attrib_data_t {
  *
  * Here ist how the ioctl-nr should be used:
  *    0 -   31   DASD driver itself
- *   32 -  239   still open
+ *   32 -  229   still open
+ *  230 -  239   DASD extended error reporting
  *  240 -  255   reserved for EMC 
  *******************************************************************************/
 
@@ -236,12 +237,22 @@ typedef struct attrib_data_t {
 #define BIODASDPSRD    _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t)
 /* Get Attributes (cache operations) */
 #define BIODASDGATTR   _IOR(DASD_IOCTL_LETTER,5,attrib_data_t) 
+/* retrieve extended error-reporting value */
+#define BIODASDEERGET  _IOR(DASD_IOCTL_LETTER,6,int)
 
 
 /* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
 #define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
 /* Set Attributes (cache operations) */
 #define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
+/* retrieve extended error-reporting value */
+#define BIODASDEERSET  _IOW(DASD_IOCTL_LETTER,3,int)
+
+
+/* remove all records from the eer buffer */
+#define DASD_EER_PURGE       _IO(DASD_IOCTL_LETTER,230)
+/* set the number of pages that are used for the internal eer buffer */
+#define DASD_EER_SETBUFSIZE  _IOW(DASD_IOCTL_LETTER,230,int)
 
 
 #endif                         /* DASD_H */
index 71f55eb2350a3e77838d73684b08fff5d34b7fde..b05825dd16d7043d3e578d515433e1ceda0b124f 100644 (file)
@@ -90,10 +90,16 @@ extern void iounmap(void *addr);
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
 
 #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
 #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
 #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
 
 #define memset_io(a,b,c)        memset(__io_virt(a),(b),(c))
 #define memcpy_fromio(a,b,c)    memcpy((a),__io_virt(b),(c))
index ea0788967c5127a931a2f8974cc5429e23ade6ea..fcd6c256a2d194aa4b1269f89cfc25fabb8c96a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  include/asm-s390/timer.h
  *
- *  (C) Copyright IBM Corp. 2003
+ *  (C) Copyright IBM Corp. 2003,2006
  *  Virtual CPU timer
  *
  *  Author: Jan Glauber (jang@de.ibm.com)
@@ -10,6 +10,8 @@
 #ifndef _ASM_S390_TIMER_H
 #define _ASM_S390_TIMER_H
 
+#ifdef __KERNEL__
+
 #include <linux/timer.h>
 
 #define VTIMER_MAX_SLICE (0x7ffffffffffff000LL)
@@ -43,4 +45,6 @@ extern void add_virt_timer_periodic(void *new);
 extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
 extern int del_virt_timer(struct vtimer_list *timer);
 
-#endif
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_S390_TIMER_H */
index 8955d2376ac824e5e3a7bd3e97459b442f206cf7..609b9e87222a41c3594014e4f585d6a88333af79 100644 (file)
@@ -188,7 +188,7 @@ static inline int find_next_zero_bit(const void *addr, int size, int offset)
        tmp = *p;
 
  found_first:
-       tmp |= ~0UL >> size;
+       tmp |= ~0UL << size;
  found_middle:
        return result + ffz (tmp);
 }
index ae28cd44bcd3158433641c67e3afdf26a1a25cd8..c564bae034338272e952c05fb84646b9b60a669f 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _X86_64_KEXEC_H
 #define _X86_64_KEXEC_H
 
+#include <linux/string.h>
+
 #include <asm/page.h>
-#include <asm/proto.h>
 #include <asm/ptrace.h>
 
 /*
index 2fa7f27381b40b69d39562a5e6394b1a975ec803..c642f5d9882df400e91b3f1fdf7ba3ff966c54bf 100644 (file)
@@ -57,6 +57,15 @@ extern int __node_distance(int, int);
 
 #endif
 
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu)                              \
+       (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
+#define topology_core_id(cpu)                                          \
+       (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_core_siblings(cpu)            (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#endif
+
 #include <asm-generic/topology.h>
 
 #endif
index 6a2a19f14bb26bb3f4f49815b566c2a4e8353cab..208650b1ad3ac08a340d93e87729890d807a3bdb 100644 (file)
@@ -81,7 +81,7 @@ static inline int generic_fls64(__u64 x)
 {
        __u32 h = x >> 32;
        if (h)
-               return fls(x) + 32;
+               return fls(h) + 32;
        return fls(x);
 }
 
index a3ed5e059d479eb2ff7ee712f6adff5170c2a4be..a3f09947940ecabe5e924a329b55c43fc2994078 100644 (file)
@@ -108,7 +108,9 @@ struct dentry {
        struct dentry_operations *d_op;
        struct super_block *d_sb;       /* The root of the dentry tree */
        void *d_fsdata;                 /* fs-specific data */
+#ifdef CONFIG_PROFILING
        struct dcookie_struct *d_cookie; /* cookie, if any */
+#endif
        int d_mounted;
        unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
 };
index dbd7bb4a33b7e8aa2eabed69674930400798e775..0cf0bea010fe2110417f98e83c3cbf60f94f2da5 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/signal.h>
 #include <linux/time.h>
 #include <linux/user.h>
+#include <linux/ptrace.h>
 
 struct elf_siginfo
 {
index 9ba8067966677bca95064140fdc124610b7437d8..5a9d8c5991719d121b25471f79b66fd9b25012b0 100644 (file)
@@ -1115,9 +1115,11 @@ static inline struct i2o_message *i2o_msg_get(struct i2o_controller *c)
                return ERR_PTR(-ENOMEM);
 
        mmsg->mfa = readl(c->in_port);
-       if (mmsg->mfa == I2O_QUEUE_EMPTY) {
+       if (unlikely(mmsg->mfa >= c->in_queue.len)) {
                mempool_free(mmsg, c->in_msg.mempool);
-               return ERR_PTR(-EBUSY);
+               if(mmsg->mfa == I2O_QUEUE_EMPTY)
+                       return ERR_PTR(-EBUSY);
+               return ERR_PTR(-EFAULT);
        }
 
        return &mmsg->msg;
index 110b3cfac021af3be75a1feb2c65fbec359fb72c..a7fc4cc79b235f5ffefae57b99c2668d1ed3397a 100644 (file)
@@ -582,7 +582,6 @@ typedef struct ide_drive_s {
        unsigned noprobe        : 1;    /* from:  hdx=noprobe */
        unsigned removable      : 1;    /* 1 if need to do check_media_change */
        unsigned attach         : 1;    /* needed for removable devices */
-       unsigned is_flash       : 1;    /* 1 if probed as flash */
        unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
        unsigned no_unmask      : 1;    /* disallow setting unmask bit */
        unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
@@ -1006,7 +1005,6 @@ extern    ide_hwif_t      ide_hwifs[];            /* master data repository */
 extern int noautodma;
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
-extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
index 45f625d7d0b2aab6ca2ee0e99dda5f0cd03109e3..3aed37314ab805de8fe3dcfec0a5282d7035cc54 100644 (file)
@@ -151,6 +151,11 @@ extern unsigned int keymap_count;
 
 static inline void con_schedule_flip(struct tty_struct *t)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&t->buf.lock, flags);
+       if (t->buf.tail != NULL)
+               t->buf.tail->active = 0;
+       spin_unlock_irqrestore(&t->buf.lock, flags);
        schedule_work(&t->buf.work);
 }
 
index 945daa1f13dd05d6a7ad95e6022108a824d6a3dd..47208bd99f9e1c2ef6753e4b7d56739691531576 100644 (file)
@@ -34,9 +34,11 @@ struct list_head {
 #define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)
 
-#define INIT_LIST_HEAD(ptr) do { \
-       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
 
 /*
  * Insert a new entry between two known consecutive entries.
@@ -534,7 +536,11 @@ struct hlist_node {
 #define HLIST_HEAD_INIT { .first = NULL }
 #define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
 #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+       h->next = NULL;
+       h->pprev = NULL;
+}
 
 static inline int hlist_unhashed(const struct hlist_node *h)
 {
index f67f838a3a1f27390711aa90259723ea951f771a..008d736a6c9a59766a7a4114223fd8bddc456ecc 100644 (file)
@@ -128,6 +128,11 @@ struct amiga_parport_state {
        unsigned char statusdir;/* ciab.ddrb & 7 */
 };
 
+struct ip32_parport_state {
+       unsigned int dcr;
+       unsigned int ecr;
+};
+
 struct parport_state {
        union {
                struct pc_parport_state pc;
@@ -135,6 +140,7 @@ struct parport_state {
                struct ax_parport_state ax;
                struct amiga_parport_state amiga;
                /* Atari has not state. */
+               struct ip32_parport_state ip32;
                void *misc; 
        } u;
 };
index 4f34d3d60f2ed6485d450bd4ca06cbea450e6997..21e5a9124856bbcc6a2c2c3cdf02fff4a56d62d3 100644 (file)
@@ -190,7 +190,6 @@ static __inline__ int DQUOT_OFF(struct super_block *sb)
  */
 #define sb_dquot_ops                           (NULL)
 #define sb_quotactl_ops                                (NULL)
-#define sync_dquots_dev(dev,type)              (NULL)
 #define DQUOT_INIT(inode)                      do { } while(0)
 #define DQUOT_DROP(inode)                      do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)               (0)
index 981f9aa433538a8ec2e8b0142da769b2e5a4dd87..b87aefa082e2b69c868f673946dd1cbc16610a51 100644 (file)
@@ -240,11 +240,14 @@ extern int rcu_pending(int cpu);
  * This means that all preempt_disable code sequences, including NMI and
  * hardware-interrupt handlers, in progress on entry will have completed
  * before this primitive returns.  However, this does not guarantee that
- * softirq handlers will have completed, since in some kernels
+ * softirq handlers will have completed, since in some kernels, these
+ * handlers can run in process context, and can block.
  *
  * This primitive provides the guarantees made by the (deprecated)
  * synchronize_kernel() API.  In contrast, synchronize_rcu() only
  * guarantees that rcu_read_lock() sections will have completed.
+ * In "classic RCU", these two guarantees happen to be one and
+ * the same, but can differ in realtime RCU implementations.
  */
 #define synchronize_sched() synchronize_rcu()
 
index 5dc94e777fab926d408477dbea464a3c78bcd3fd..43bcd13eb1ecbda0047e5db52868589b06a22318 100644 (file)
@@ -42,10 +42,6 @@ extern void mark_free_pages(struct zone *zone);
 #ifdef CONFIG_PM
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
-
-extern int pm_prepare_console(void);
-extern void pm_restore_console(void);
-
 #else
 static inline int software_suspend(void)
 {
index 3787102e4b129abe52f3b53461ff1e7fffb33b40..a7bd3b4558d26efaa3ed8dae0b5bb53f0d184cab 100644 (file)
@@ -57,6 +57,7 @@ struct tty_buffer {
        unsigned char *flag_buf_ptr;
        int used;
        int size;
+       int active;
        /* Data points here */
        unsigned long data[0];
 };
@@ -64,6 +65,7 @@ struct tty_buffer {
 struct tty_bufhead {
        struct work_struct              work;
        struct semaphore pty_sem;
+       spinlock_t lock;
        struct tty_buffer *head;        /* Queue head */
        struct tty_buffer *tail;        /* Active buffer */
        struct tty_buffer *free;        /* Free queue head */
index be1400e82482f8aebd4d14e17e9d5ea99958cd85..82961eb1988861a08c6c459d3d095a1535bf52fb 100644 (file)
@@ -17,7 +17,7 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty,
                                   unsigned char ch, char flag)
 {
        struct tty_buffer *tb = tty->buf.tail;
-       if (tb && tb->used < tb->size) {
+       if (tb && tb->active && tb->used < tb->size) {
                tb->flag_buf_ptr[tb->used] = flag;
                tb->char_buf_ptr[tb->used++] = ch;
                return 1;
@@ -27,6 +27,11 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty,
 
 _INLINE_ void tty_schedule_flip(struct tty_struct *tty)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->active = 0;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
        schedule_delayed_work(&tty->buf.work, 1);
 }
 
index 7a6babeca25619fdadfe639f5c9696822c7341e0..b0ffe4356e5a60c8a7e74101ae45053fcc44b8d6 100644 (file)
@@ -148,11 +148,11 @@ typedef __u16 __bitwise __fs16;
 #define UFS_USEEFT  ((__u16)65535)
 
 #define UFS_FSOK      0x7c269d38
-#define UFS_FSACTIVE  ((char)0x00)
-#define UFS_FSCLEAN   ((char)0x01)
-#define UFS_FSSTABLE  ((char)0x02)
-#define UFS_FSOSF1    ((char)0x03)     /* is this correct for DEC OSF/1? */
-#define UFS_FSBAD     ((char)0xff)
+#define UFS_FSACTIVE  ((__s8)0x00)
+#define UFS_FSCLEAN   ((__s8)0x01)
+#define UFS_FSSTABLE  ((__s8)0x02)
+#define UFS_FSOSF1    ((__s8)0x03)     /* is this correct for DEC OSF/1? */
+#define UFS_FSBAD     ((__s8)0xff)
 
 /* From here to next blank line, s_flags for ufs_sb_info */
 /* directory entry encoding */
@@ -502,8 +502,7 @@ struct ufs_super_block {
 /*
  * Convert cylinder group to base address of its global summary info.
  */
-#define fs_cs(indx) \
-       s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+#define fs_cs(indx) s_csp[(indx)]
 
 /*
  * Cylinder group block for a file system.
@@ -913,6 +912,7 @@ extern int ufs_sync_inode (struct inode *);
 extern void ufs_delete_inode (struct inode *);
 extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
 
 /* namei.c */
 extern struct file_operations ufs_dir_operations;
index c1be4c2264862e0f768b6d1cc129eab37bea3400..8ff13c160f3d6a6bcba70055ccbec0d26d882317 100644 (file)
@@ -25,7 +25,7 @@ struct ufs_csum;
 
 struct ufs_sb_info {
        struct ufs_sb_private_info * s_uspi;    
-       struct ufs_csum * s_csp[UFS_MAXCSBUFS];
+       struct ufs_csum * s_csp;
        unsigned s_bytesex;
        unsigned s_flags;
        struct buffer_head ** s_ucg;
index 8c522ae031bbf5a3011212e00f16289b06e6648c..072f407848a6fe1464a77a4d2bd1f47a052e6e40 100644 (file)
@@ -700,7 +700,7 @@ struct sctp_chunk {
        __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? */
+       __s8 fast_retransmit;    /* Is this chunk fast retransmitted? */
        __u8 tsn_missing_report; /* Data chunk missing counter. */
 };
 
index 1806e5b6141936376352373343c3a37510af6bbf..30758035d6161b13eb7b6715978340d28058bb3f 100644 (file)
@@ -1354,12 +1354,12 @@ extern int sock_get_timestamp(struct sock *, struct timeval __user *);
  *     Enable debug/info messages 
  */
 
-#if 0
-#define NETDEBUG(fmt, args...) do { } while (0)
-#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
-#else
+#ifdef CONFIG_NETDEBUG
 #define NETDEBUG(fmt, args...) printk(fmt,##args)
 #define LIMIT_NETDEBUG(fmt, args...) do { if (net_ratelimit()) printk(fmt,##args); } while(0)
+#else
+#define NETDEBUG(fmt, args...) do { } while (0)
+#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
 #endif
 
 /*
index b9923b1434a2f82a698c5011fbe55191bddf8965..8b7abae87bf9c15ec3934e73322df849595e81dc 100644 (file)
@@ -31,19 +31,8 @@ config EXPERIMENTAL
          you say Y here, you will be offered the choice of using features or
          drivers that are currently considered to be in the alpha-test phase.
 
-config CLEAN_COMPILE
-       bool "Select only drivers expected to compile cleanly" if EXPERIMENTAL
-       default y
-       help
-         Select this option if you don't even want to see the option
-         to configure known-broken drivers.
-
-         If unsure, say Y
-
 config BROKEN
        bool
-       depends on !CLEAN_COMPILE
-       default y
 
 config BROKEN_ON_SMP
        bool
index fe2f71f92ae0b01fbbfe08053bb34e36058e85de..ba42b0a76961f8eb3b667bf4a059405e3b9f52cf 100644 (file)
@@ -641,7 +641,7 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
  * task has been modifying its cpuset.
  */
 
-void cpuset_update_task_memory_state()
+void cpuset_update_task_memory_state(void)
 {
        int my_cpusets_mem_gen;
        struct task_struct *tsk = current;
index 3ea6325228dafd293b8421ac4d47ea49457b17a0..fef1af8a73ce07818862eb434c29b62468e99323 100644 (file)
@@ -344,23 +344,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk)
        spin_unlock_irqrestore(&kretprobe_lock, flags);
 }
 
-/*
- * This kprobe pre_handler is registered with every kretprobe. When probe
- * hits it will set up the return probe.
- */
-static int __kprobes pre_handler_kretprobe(struct kprobe *p,
-                                          struct pt_regs *regs)
-{
-       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
-       unsigned long flags = 0;
-
-       /*TODO: consider to only swap the RA after the last pre_handler fired */
-       spin_lock_irqsave(&kretprobe_lock, flags);
-       arch_prepare_kretprobe(rp, regs);
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-       return 0;
-}
-
 static inline void free_rp_inst(struct kretprobe *rp)
 {
        struct kretprobe_instance *ri;
@@ -578,6 +561,23 @@ void __kprobes unregister_jprobe(struct jprobe *jp)
 
 #ifdef ARCH_SUPPORTS_KRETPROBES
 
+/*
+ * This kprobe pre_handler is registered with every kretprobe. When probe
+ * hits it will set up the return probe.
+ */
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+                                          struct pt_regs *regs)
+{
+       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+       unsigned long flags = 0;
+
+       /*TODO: consider to only swap the RA after the last pre_handler fired */
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       arch_prepare_kretprobe(rp, regs);
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+       return 0;
+}
+
 int __kprobes register_kretprobe(struct kretprobe *rp)
 {
        int ret = 0;
@@ -631,12 +631,12 @@ void __kprobes unregister_kretprobe(struct kretprobe *rp)
        unregister_kprobe(&rp->kp);
        /* No race here */
        spin_lock_irqsave(&kretprobe_lock, flags);
-       free_rp_inst(rp);
        while ((ri = get_used_rp_inst(rp)) != NULL) {
                ri->rp = NULL;
                hlist_del(&ri->uflist);
        }
        spin_unlock_irqrestore(&kretprobe_lock, flags);
+       free_rp_inst(rp);
 }
 
 static int __init init_kprobes(void)
index 618ed6e23ecccf12b16d9bac17a62510758989be..e058aedf6b932d35e23a3c0acb18ff3cb01b78c1 100644 (file)
@@ -2092,7 +2092,8 @@ static unsigned long mod_find_symname(struct module *mod, const char *name)
        unsigned int i;
 
        for (i = 0; i < mod->num_symtab; i++)
-               if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0)
+               if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&
+                   mod->symtab[i].st_info != 'U')
                        return mod->symtab[i].st_value;
        return 0;
 }
index d3efafd8109a3e4597bf89213d8eaa8fa1852f33..b373fc2420da06d73840fd3694301e504688468f 100644 (file)
@@ -283,7 +283,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
        return(q);
 }
 
-static inline void __sigqueue_free(struct sigqueue *q)
+static void __sigqueue_free(struct sigqueue *q)
 {
        if (q->flags & SIGQUEUE_PREALLOC)
                return;
index 1f23e683d6aa01da497a86a8cd5ac6804ef5d6fe..804539165d8b1aea0ea0dac3631377d7ae107f89 100644 (file)
@@ -637,15 +637,16 @@ void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec)
  *
  * Returns the timespec representation of the nsec parameter.
  */
-inline struct timespec ns_to_timespec(const nsec_t nsec)
+struct timespec ns_to_timespec(const nsec_t nsec)
 {
        struct timespec ts;
 
-       if (nsec)
-               ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC,
-                                                    &ts.tv_nsec);
-       else
-               ts.tv_sec = ts.tv_nsec = 0;
+       if (!nsec)
+               return (struct timespec) {0, 0};
+
+       ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec);
+       if (unlikely(nsec < 0))
+               set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);
 
        return ts;
 }
index a5d2cdc5684cfdf0d2834692c3abc6024da515de..fd355a99327cdeab8333781991ea3ecd59997ca4 100644 (file)
@@ -15,7 +15,7 @@ unsigned long int_sqrt(unsigned long x)
        op = x;
        res = 0;
 
-       one = 1 << 30;
+       one = 1UL << (BITS_PER_LONG - 2);
        while (one > op)
                one >>= 2;
 
index 8a8b3a16133ed643ccf572a0f33ceb80d1a9adc7..c4c1ac5fbd1aea372553ce094171ff8c152b2433 100644 (file)
@@ -94,10 +94,28 @@ next:                       bs = bm->bad_shift[text[shift-i]];
        return UINT_MAX;
 }
 
+static int subpattern(u8 *pattern, int i, int j, int g)
+{
+       int x = i+g-1, y = j+g-1, ret = 0;
+
+       while(pattern[x--] == pattern[y--]) {
+               if (y < 0) {
+                       ret = 1;
+                       break;
+               }
+               if (--g == 0) {
+                       ret = pattern[i-1] != pattern[j-1];
+                       break;
+               }
+       }
+
+       return ret;
+}
+
 static void compute_prefix_tbl(struct ts_bm *bm, const u8 *pattern,
                               unsigned int len)
 {
-       int i, j, ended, l[ASIZE];
+       int i, j, g;
 
        for (i = 0; i < ASIZE; i++)
                bm->bad_shift[i] = len;
@@ -106,23 +124,15 @@ static void compute_prefix_tbl(struct ts_bm *bm, const u8 *pattern,
 
        /* Compute the good shift array, used to match reocurrences 
         * of a subpattern */
-       for (i = 1; i < bm->patlen; i++) {
-               for (j = 0; j < bm->patlen && bm->pattern[bm->patlen - 1 - j]
-                               == bm->pattern[bm->patlen - 1 - i - j]; j++);
-               l[i] = j;
-       }  
-
        bm->good_shift[0] = 1;
        for (i = 1; i < bm->patlen; i++)
                bm->good_shift[i] = bm->patlen;
-       for (i = bm->patlen - 1; i > 0; i--)
-               bm->good_shift[l[i]] = i;
-       ended = 0;
-       for (i = 0; i < bm->patlen; i++) {
-               if (l[i] == bm->patlen - 1 - i)
-                       ended = i;
-               if (ended)
-                       bm->good_shift[i] = ended;
+        for (i = bm->patlen-1, g = 1; i > 0; g++, i--) {
+               for (j = i-1; j >= 1-g ; j--)
+                       if (subpattern(bm->pattern, i, j, g)) {
+                               bm->good_shift[g] = bm->patlen-j-g;
+                               break;
+                       }
        }
 }
 
index 4d638944d933bf971c7750425474dfd3079360eb..34e42968b477d9291a1671dfa32a43af77b7a74c 100644 (file)
@@ -59,8 +59,10 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
        proto = find_snap_client(skb->h.raw);
        if (proto) {
                /* Pass the frame on. */
+               u8 *hdr = skb->data;
                skb->h.raw  += 5;
                skb_pull(skb, 5);
+               skb_postpull_rcsum(skb, hdr, 5);
                rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
        } else {
                skb->sk = NULL;
index bc603d9aea56c1a798ae6c763e813365e4f689ea..5126f58d9c44fb2b6dea23f3063904c8fa003243 100644 (file)
@@ -27,6 +27,13 @@ if NET
 
 menu "Networking options"
 
+config NETDEBUG
+       bool "Network packet debugging"
+       help
+         You can say Y here if you want to get additional messages useful in
+         debugging bad packets, but can overwhelm logs under denial of service
+         attacks.
+
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
index 105039eb7629359c92884305de6506235da2dc1b..6bc0887b0834ff9ee85dbe21e3aaf940b76f6fa1 100644 (file)
@@ -385,7 +385,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        u32 daddr;
 
        if (ip_options_echo(&icmp_param->replyopts, skb))
-               goto out;
+               return;
 
        if (icmp_xmit_lock())
                return;
@@ -416,7 +416,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        ip_rt_put(rt);
 out_unlock:
        icmp_xmit_unlock();
-out:;
 }
 
 
index d34a9fa608e0b88dec20adaa567100a5b63c4ee0..342d0b9098f5f8ca9bdd5a019b6a7a0660ace097 100644 (file)
@@ -228,7 +228,7 @@ static void wrandom_set_nhinfo(__u32 network,
        struct multipath_dest *d, *target_dest = NULL;
 
        /* store the weight information for a certain route */
-       spin_lock(&state[state_idx].lock);
+       spin_lock_bh(&state[state_idx].lock);
 
        /* find state entry for gateway or add one if necessary */
        list_for_each_entry_rcu(r, &state[state_idx].head, list) {
@@ -276,7 +276,7 @@ static void wrandom_set_nhinfo(__u32 network,
         * we are finished
         */
 
-       spin_unlock(&state[state_idx].lock);
+       spin_unlock_bh(&state[state_idx].lock);
 }
 
 static void __multipath_free(struct rcu_head *head)
@@ -302,7 +302,7 @@ static void wrandom_flush(void)
        for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
                struct multipath_route *r;
 
-               spin_lock(&state[i].lock);
+               spin_lock_bh(&state[i].lock);
                list_for_each_entry_rcu(r, &state[i].head, list) {
                        struct multipath_dest *d;
                        list_for_each_entry_rcu(d, &r->dests, list) {
@@ -315,7 +315,7 @@ static void wrandom_flush(void)
                                 __multipath_free);
                }
 
-               spin_unlock(&state[i].lock);
+               spin_unlock_bh(&state[i].lock);
        }
 }
 
index d328d59861438ae0b8bad815a3ef34cacf7de328..1db50487916bf002a3ed92316d57b9cbe377f6e5 100644 (file)
@@ -3321,9 +3321,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 
        switch (event) {
        case RTM_NEWADDR:
-               dst_hold(&ifp->rt->u.dst);
-               if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL))
-                       dst_release(&ifp->rt->u.dst);
+               ip6_ins_rt(ifp->rt, NULL, NULL, NULL);
                if (ifp->idev->cnf.forwarding)
                        addrconf_join_anycast(ifp);
                break;
@@ -3334,8 +3332,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                dst_hold(&ifp->rt->u.dst);
                if (ip6_del_rt(ifp->rt, NULL, NULL, NULL))
                        dst_free(&ifp->rt->u.dst);
-               else
-                       dst_release(&ifp->rt->u.dst);
                break;
        }
 }
index 064ffab82a9fe5f7d674bc344e0798b6f97e62ec..6c9711ac1c0324adb5496541efebc55e89a50bf7 100644 (file)
@@ -369,12 +369,6 @@ int inet6_destroy_sock(struct sock *sk)
        struct sk_buff *skb;
        struct ipv6_txoptions *opt;
 
-       /*
-        *      Release destination entry
-        */
-
-       sk_dst_reset(sk);
-
        /* Release rx options */
 
        if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
index a40991ef72c92b4d6a59368b67c15ed7ea2c70e7..437cba7260a4a1a6970546cbf36f650114a785ab 100644 (file)
@@ -608,7 +608,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
         *    When a Fast Retransmit is being performed the sender SHOULD
         *    ignore the value of cwnd and SHOULD NOT delay retransmission.
         */
-       if (!chunk->fast_retransmit)
+       if (chunk->fast_retransmit <= 0)
                if (transport->flight_size >= transport->cwnd) {
                        retval = SCTP_XMIT_RWND_FULL;
                        goto finish;
index efb72faba20cd50aec065d4fe498c85ecae8d4ae..f148f9576dd226035b3b6c34d439d7558818ce4a 100644 (file)
@@ -406,7 +406,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                 * chunks that are not yet acked should be added to the
                 * retransmit queue.
                 */
-               if ((fast_retransmit && chunk->fast_retransmit) ||
+               if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
                   (!fast_retransmit && !chunk->tsn_gap_acked)) {
                        /* RFC 2960 6.2.1 Processing a Received SACK
                         *
@@ -603,7 +603,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        /* Mark the chunk as ineligible for fast retransmit 
                         * after it is retransmitted.
                         */
-                       chunk->fast_retransmit = 0;
+                       if (chunk->fast_retransmit > 0)
+                               chunk->fast_retransmit = -1;
 
                        *start_timer = 1;
                        q->empty = 0;
@@ -621,7 +622,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        list_for_each(lchunk1, lqueue) {
                                chunk1 = list_entry(lchunk1, struct sctp_chunk,
                                                    transmitted_list);
-                               chunk1->fast_retransmit = 0;
+                               if (chunk1->fast_retransmit > 0)
+                                       chunk1->fast_retransmit = -1;
                        }
                }
        }
@@ -1562,11 +1564,11 @@ static void sctp_mark_missing(struct sctp_outq *q,
                /*
                 * M4) If any DATA chunk is found to have a
                 * 'TSN.Missing.Report'
-                * value larger than or equal to 4, mark that chunk for
+                * value larger than or equal to 3, mark that chunk for
                 * retransmission and start the fast retransmit procedure.
                 */
 
-               if (chunk->tsn_missing_report >= 4) {
+               if (chunk->tsn_missing_report >= 3) {
                        chunk->fast_retransmit = 1;
                        do_fast_retransmit = 1;
                }
index 90db5c76cf6e5bdad2778f6a18e6a772dd281c51..0c62798ac7d80149a91cdfc2e0cc447951efe9c2 100644 (file)
@@ -67,9 +67,10 @@ asmlinkage long sys_add_key(const char __user *_type,
        description = kmalloc(dlen + 1, GFP_KERNEL);
        if (!description)
                goto error;
+       description[dlen] = '\0';
 
        ret = -EFAULT;
-       if (copy_from_user(description, _description, dlen + 1) != 0)
+       if (copy_from_user(description, _description, dlen) != 0)
                goto error2;
 
        /* pull the payload in if one was supplied */
@@ -161,9 +162,10 @@ asmlinkage long sys_request_key(const char __user *_type,
        description = kmalloc(dlen + 1, GFP_KERNEL);
        if (!description)
                goto error;
+       description[dlen] = '\0';
 
        ret = -EFAULT;
-       if (copy_from_user(description, _description, dlen + 1) != 0)
+       if (copy_from_user(description, _description, dlen) != 0)
                goto error2;
 
        /* pull the callout info into kernel space */
@@ -182,9 +184,10 @@ asmlinkage long sys_request_key(const char __user *_type,
                callout_info = kmalloc(dlen + 1, GFP_KERNEL);
                if (!callout_info)
                        goto error2;
+               callout_info[dlen] = '\0';
 
                ret = -EFAULT;
-               if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0)
+               if (copy_from_user(callout_info, _callout_info, dlen) != 0)
                        goto error3;
        }
 
@@ -279,9 +282,10 @@ long keyctl_join_session_keyring(const char __user *_name)
                name = kmalloc(nlen + 1, GFP_KERNEL);
                if (!name)
                        goto error;
+               name[nlen] = '\0';
 
                ret = -EFAULT;
-               if (copy_from_user(name, _name, nlen + 1) != 0)
+               if (copy_from_user(name, _name, nlen) != 0)
                        goto error2;
        }
 
@@ -583,9 +587,10 @@ long keyctl_keyring_search(key_serial_t ringid,
        description = kmalloc(dlen + 1, GFP_KERNEL);
        if (!description)
                goto error;
+       description[dlen] = '\0';
 
        ret = -EFAULT;
-       if (copy_from_user(description, _description, dlen + 1) != 0)
+       if (copy_from_user(description, _description, dlen) != 0)
                goto error2;
 
        /* get the keyring at which to begin the search */