Merge master.kernel.org:/home/rmk/linux-2.6-serial
authorLinus Torvalds <torvalds@g5.osdl.org>
Fri, 3 Feb 2006 23:51:48 +0000 (15:51 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 3 Feb 2006 23:51:48 +0000 (15:51 -0800)
246 files changed:
Documentation/cputopology.txt [new file with mode: 0644]
Documentation/driver-model/overview.txt
Documentation/filesystems/configfs/configfs_example.c
Documentation/filesystems/ocfs2.txt
Documentation/networking/ip-sysctl.txt
Documentation/parport-lowlevel.txt
Documentation/pci-error-recovery.txt
MAINTAINERS
Makefile
arch/arm/configs/at91rm9200dk_defconfig
arch/arm/configs/at91rm9200ek_defconfig
arch/arm/configs/csb337_defconfig
arch/arm/configs/csb637_defconfig
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/cpu.c
arch/arm/mach-s3c2410/gpio.c
arch/arm/mach-s3c2410/s3c2400-gpio.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2410-gpio.c [new file with mode: 0644]
arch/arm/mach-s3c2410/sleep.S
arch/arm/mm/cache-v6.S
arch/arm/mm/proc-xscale.S
arch/arm/oprofile/common.c
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/drm/ati_pcigart.c
drivers/char/drm/drmP.h
drivers/char/drm/drm_auth.c
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_ioctl.c
drivers/char/drm/drm_irq.c
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_proc.c
drivers/char/drm/drm_stub.c
drivers/char/drm/drm_vm.c
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drv.h
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drm.h
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_mem.c
drivers/char/drm/radeon_cp.c
drivers/char/drm/savage_bci.c
drivers/char/drm/savage_drv.h
drivers/char/drm/via_dma.c
drivers/char/drm/via_dmablit.c
drivers/char/drm/via_drv.h
drivers/char/drm/via_irq.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/ide/pci/sgiioc4.c
drivers/isdn/hisax/hisax.h
drivers/isdn/sc/ioctl.c
drivers/md/dm-log.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/mmc/au1xmmc.c
drivers/mmc/mmc.c
drivers/mmc/mmc_block.c
drivers/mmc/mmci.c
drivers/mmc/pxamci.c
drivers/mmc/wbsd.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/Kconfig
fs/buffer.c
fs/configfs/configfs_internal.h
fs/configfs/dir.c
fs/configfs/file.c
fs/configfs/inode.c
fs/configfs/mount.c
fs/configfs/symlink.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/lockd/clntproc.c
fs/nfs/direct.c
fs/ocfs2/buffer_head_io.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlm/dlmunlock.c
fs/ocfs2/dlm/userdlm.c
fs/ocfs2/extent_map.c
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/ocfs2.h
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/ocfs2/uptodate.c
fs/ocfs2/uptodate.h
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-arm/arch-s3c2410/hardware.h
include/asm-arm/arch-s3c2410/regs-gpio.h
include/asm-arm/checksum.h
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/configfs.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/lockd/lockd.h
include/linux/mmc/mmc.h
include/linux/mmc/protocol.h
include/linux/parport.h
include/linux/quotaops.h
include/linux/rcupdate.h
include/linux/sunrpc/auth.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
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_unix.c
net/sunrpc/rpc_pipe.c
security/keys/keyctl.c
sound/arm/aaci.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 f3c6e4946f983a3e10a8b61ae9b0975440f453fa..3d4713a6c207f9f18eb1aed4ad5f361bc86ed839 100644 (file)
@@ -320,6 +320,7 @@ static struct config_item_type simple_children_type = {
        .ct_item_ops    = &simple_children_item_ops,
        .ct_group_ops   = &simple_children_group_ops,
        .ct_attrs       = simple_children_attrs,
+       .ct_owner       = THIS_MODULE,
 };
 
 static struct configfs_subsystem simple_children_subsys = {
@@ -403,6 +404,7 @@ static struct config_item_type group_children_type = {
        .ct_item_ops    = &group_children_item_ops,
        .ct_group_ops   = &group_children_group_ops,
        .ct_attrs       = group_children_attrs,
+       .ct_owner       = THIS_MODULE,
 };
 
 static struct configfs_subsystem group_children_subsys = {
index f2595caf052e155c2a809bf4a9ae98b94e06802e..4389c684a80a66d402f464a4ecf3ed7a15bda1bb 100644 (file)
@@ -35,6 +35,7 @@ Features which OCFS2 does not support yet:
          be cluster coherent.
        - quotas
        - cluster aware flock
+       - cluster aware lockf
        - Directory change notification (F_NOTIFY)
        - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
        - POSIX ACLs
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 42955fe1ffa056df2f412280b7d9e45a17060d31..b6cbac5dbfd5ddf972857d85946428751ebe9065 100644 (file)
@@ -557,7 +557,8 @@ S:  Supported
 
 CONFIGFS
 P:     Joel Becker
-M:     Joel Becker <joel.becker@oracle.com>
+M:     joel.becker@oracle.com
+L:     linux-kernel@vger.kernel.org
 S:     Supported
 
 CIRRUS LOGIC GENERIC FBDEV DRIVER
@@ -1984,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 252a659896f32c99d96c60dd5ba849e82bd5a17b..cd5b619db9d8f479171a37ed64b004de7cc47310 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 16
-EXTRAVERSION =-rc1
+EXTRAVERSION =-rc2
 NAME=Sliding Snow Leopard
 
 # *DOCUMENTATION*
index 5cdd13acf8ff14242d73895e6dfa7719cf40a566..1fe73d1988880354336a84f641aaaf66126a97ac 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
index 20838ccf1da7f91948531c3e0cf2a9a27d7a1c08..b7d934cdb1b735a1b28847afef231268f7b98bff 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
index 885a3184830ad6d08a4ecedc24cef9d671bad7f6..94bd9932a4027eb465dc5262d68f7f226c761f84 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
index 95a96a5462a0c8077426ee9b68018331dfd01156..1519124c550106c282dedb8ac12024e097a030bb 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
index b41b1efaa2cf9088e30fe8fe9ee1d4dda6fd46c7..3baa70819f24fb20d6a0024e035946c5e8c49534 100644 (file)
@@ -44,7 +44,7 @@ unsigned int get_clk_frequency_khz( int info)
 
        /* Read clkcfg register: it has turbo, b, half-turbo (and f) */
        asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
-       t  = clkcfg & (1 << 1);
+       t  = clkcfg & (1 << 0);
        ht = clkcfg & (1 << 2);
        b  = clkcfg & (1 << 3);
 
index b4f1e051c768a4dc06d583cdc52da5445e9fb190..1217bf00309c7049d508d90c2c2614b662a705e2 100644 (file)
@@ -10,9 +10,13 @@ obj-m                        :=
 obj-n                  :=
 obj-                   :=
 
+# S3C2400 support files
+obj-$(CONFIG_CPU_S3C2400)  += s3c2400-gpio.o
+
 # S3C2410 support files
 
 obj-$(CONFIG_CPU_S3C2410)  += s3c2410.o
+obj-$(CONFIG_CPU_S3C2410)  += s3c2410-gpio.o
 obj-$(CONFIG_S3C2410_DMA)  += dma.o
 
 # Power Management support
@@ -25,6 +29,7 @@ obj-$(CONFIG_PM_SIMTEC)          += pm-simtec.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o s3c2440-dsc.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440-irq.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440-clock.o
+obj-$(CONFIG_CPU_S3C2440)  += s3c2410-gpio.o
 
 # bast extras
 
index 687fe371369d5e42d01fe5fb988b6f536e86b0f5..00a379334b60b2d325da1a8614a4c3e69e38ebaf 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "cpu.h"
 #include "clock.h"
+#include "s3c2400.h"
 #include "s3c2410.h"
 #include "s3c2440.h"
 
@@ -55,6 +56,7 @@ struct cpu_table {
 
 /* table of supported CPUs */
 
+static const char name_s3c2400[]  = "S3C2400";
 static const char name_s3c2410[]  = "S3C2410";
 static const char name_s3c2440[]  = "S3C2440";
 static const char name_s3c2410a[] = "S3C2410A";
@@ -96,7 +98,16 @@ static struct cpu_table cpu_ids[] __initdata = {
                .init_uarts     = s3c2440_init_uarts,
                .init           = s3c2440_init,
                .name           = name_s3c2440a
-       }
+       },
+       {
+               .idcode         = 0x0,   /* S3C2400 doesn't have an idcode */
+               .idmask         = 0xffffffff,
+               .map_io         = s3c2400_map_io,
+               .init_clocks    = s3c2400_init_clocks,
+               .init_uarts     = s3c2400_init_uarts,
+               .init           = s3c2400_init,
+               .name           = name_s3c2400
+       },
 };
 
 /* minimal IO mapping */
@@ -148,12 +159,15 @@ static struct cpu_table *cpu;
 
 void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 {
-       unsigned long idcode;
+       unsigned long idcode = 0x0;
 
        /* initialise the io descriptors we need for initialisation */
        iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
 
+#ifndef CONFIG_CPU_S3C2400
        idcode = __raw_readl(S3C2410_GSTATUS1);
+#endif
+
        cpu = s3c_lookup_cpu(idcode);
 
        if (cpu == NULL) {
index 23ea3d5fa09c1be9bcc9084c1c8203b72b7c80c4..cd39e86845848ec6a515383fef3c6d4bda3ac114 100644 (file)
@@ -31,6 +31,7 @@
  *     05-Nov-2004  BJD  EXPORT_SYMBOL() added for all code
  *     13-Mar-2005  BJD  Updates for __iomem
  *     26-Oct-2005  BJD  Added generic configuration types
+ *     15-Jan-2006  LCVR Added support for the S3C2400
  */
 
 
@@ -48,7 +49,7 @@
 
 void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
 {
-       void __iomem *base = S3C2410_GPIO_BASE(pin);
+       void __iomem *base = S3C24XX_GPIO_BASE(pin);
        unsigned long mask;
        unsigned long con;
        unsigned long flags;
@@ -95,7 +96,7 @@ EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
 
 unsigned int s3c2410_gpio_getcfg(unsigned int pin)
 {
-       void __iomem *base = S3C2410_GPIO_BASE(pin);
+       void __iomem *base = S3C24XX_GPIO_BASE(pin);
        unsigned long mask;
 
        if (pin < S3C2410_GPIO_BANKB) {
@@ -111,7 +112,7 @@ EXPORT_SYMBOL(s3c2410_gpio_getcfg);
 
 void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
 {
-       void __iomem *base = S3C2410_GPIO_BASE(pin);
+       void __iomem *base = S3C24XX_GPIO_BASE(pin);
        unsigned long offs = S3C2410_GPIO_OFFSET(pin);
        unsigned long flags;
        unsigned long up;
@@ -133,7 +134,7 @@ EXPORT_SYMBOL(s3c2410_gpio_pullup);
 
 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
 {
-       void __iomem *base = S3C2410_GPIO_BASE(pin);
+       void __iomem *base = S3C24XX_GPIO_BASE(pin);
        unsigned long offs = S3C2410_GPIO_OFFSET(pin);
        unsigned long flags;
        unsigned long dat;
@@ -152,7 +153,7 @@ EXPORT_SYMBOL(s3c2410_gpio_setpin);
 
 unsigned int s3c2410_gpio_getpin(unsigned int pin)
 {
-       void __iomem *base = S3C2410_GPIO_BASE(pin);
+       void __iomem *base = S3C24XX_GPIO_BASE(pin);
        unsigned long offs = S3C2410_GPIO_OFFSET(pin);
 
        return __raw_readl(base + 0x04) & (1<< offs);
@@ -166,70 +167,13 @@ unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
        unsigned long misccr;
 
        local_irq_save(flags);
-       misccr = __raw_readl(S3C2410_MISCCR);
+       misccr = __raw_readl(S3C24XX_MISCCR);
        misccr &= ~clear;
        misccr ^= change;
-       __raw_writel(misccr, S3C2410_MISCCR);
+       __raw_writel(misccr, S3C24XX_MISCCR);
        local_irq_restore(flags);
 
        return misccr;
 }
 
 EXPORT_SYMBOL(s3c2410_modify_misccr);
-
-int s3c2410_gpio_getirq(unsigned int pin)
-{
-       if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
-               return -1;      /* not valid interrupts */
-
-       if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
-               return -1;      /* not valid pin */
-
-       if (pin < S3C2410_GPF4)
-               return (pin - S3C2410_GPF0) + IRQ_EINT0;
-
-       if (pin < S3C2410_GPG0)
-               return (pin - S3C2410_GPF4) + IRQ_EINT4;
-
-       return (pin - S3C2410_GPG0) + IRQ_EINT8;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_getirq);
-
-int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
-                          unsigned int config)
-{
-       void __iomem *reg = S3C2410_EINFLT0;
-       unsigned long flags;
-       unsigned long val;
-
-       if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
-               return -1;
-
-       config &= 0xff;
-
-       pin -= S3C2410_GPG8_EINT16;
-       reg += pin & ~3;
-
-       local_irq_save(flags);
-
-       /* update filter width and clock source */
-
-       val = __raw_readl(reg);
-       val &= ~(0xff << ((pin & 3) * 8));
-       val |= config << ((pin & 3) * 8);
-       __raw_writel(val, reg);
-
-       /* update filter enable */
-
-       val = __raw_readl(S3C2410_EXTINT2);
-       val &= ~(1 << ((pin * 4) + 3));
-       val |= on << ((pin * 4) + 3);
-       __raw_writel(val, S3C2410_EXTINT2);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2410/s3c2400-gpio.c
new file mode 100644 (file)
index 0000000..5127f39
--- /dev/null
@@ -0,0 +1,45 @@
+/* linux/arch/arm/mach-s3c2410/gpio.c
+ *
+ * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
+ *
+ * S3C2400 GPIO support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Changelog
+ *     15-Jan-2006  LCVR  Splitted from gpio.c, adding support for the S3C2400
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+int s3c2400_gpio_getirq(unsigned int pin)
+{
+       if (pin < S3C2410_GPE0 || pin > S3C2400_GPE7_EINT7)
+               return -1;  /* not valid interrupts */
+
+       return (pin - S3C2410_GPE0) + IRQ_EINT0;
+}
+
+EXPORT_SYMBOL(s3c2400_gpio_getirq);
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
new file mode 100644 (file)
index 0000000..d5e1cae
--- /dev/null
@@ -0,0 +1,93 @@
+/* linux/arch/arm/mach-s3c2410/gpio.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 GPIO support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Changelog
+ *     15-Jan-2006  LCVR  Splitted from gpio.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
+                          unsigned int config)
+{
+       void __iomem *reg = S3C2410_EINFLT0;
+       unsigned long flags;
+       unsigned long val;
+
+       if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
+               return -1;
+
+       config &= 0xff;
+
+       pin -= S3C2410_GPG8_EINT16;
+       reg += pin & ~3;
+
+       local_irq_save(flags);
+
+       /* update filter width and clock source */
+
+       val = __raw_readl(reg);
+       val &= ~(0xff << ((pin & 3) * 8));
+       val |= config << ((pin & 3) * 8);
+       __raw_writel(val, reg);
+
+       /* update filter enable */
+
+       val = __raw_readl(S3C2410_EXTINT2);
+       val &= ~(1 << ((pin * 4) + 3));
+       val |= on << ((pin * 4) + 3);
+       __raw_writel(val, S3C2410_EXTINT2);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
+
+int s3c2410_gpio_getirq(unsigned int pin)
+{
+       if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
+               return -1;      /* not valid interrupts */
+
+       if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
+               return -1;      /* not valid pin */
+
+       if (pin < S3C2410_GPF4)
+               return (pin - S3C2410_GPF0) + IRQ_EINT0;
+
+       if (pin < S3C2410_GPG0)
+               return (pin - S3C2410_GPF4) + IRQ_EINT4;
+
+       return (pin - S3C2410_GPG0) + IRQ_EINT8;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getirq);
index e9a055b779b7f1158c1759ebd7cecab08e4a2ab7..832fb86a03b430343dd26e9e5be83168ab644c17 100644 (file)
@@ -72,7 +72,7 @@ ENTRY(s3c2410_cpu_suspend)
        @@ prepare cpu to sleep
 
        ldr     r4, =S3C2410_REFRESH
-       ldr     r5, =S3C2410_MISCCR
+       ldr     r5, =S3C24XX_MISCCR
        ldr     r6, =S3C2410_CLKCON
        ldr     r7, [ r4 ]              @ get REFRESH (and ensure in TLB)
        ldr     r8, [ r5 ]              @ get MISCCR (and ensure in TLB)
index 72966d90e956b88ed001605c332128efa081ee58..d921c1024ae0821963125a2f637a825123124f7d 100644 (file)
@@ -92,22 +92,16 @@ ENTRY(v6_coherent_kern_range)
  *     - the Icache does not read data from the write buffer
  */
 ENTRY(v6_coherent_user_range)
-       bic     r0, r0, #CACHE_LINE_SIZE - 1
-1:
+
 #ifdef HARVARD_CACHE
-       mcr     p15, 0, r0, c7, c10, 1          @ clean D line
+       bic     r0, r0, #CACHE_LINE_SIZE - 1
+1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D line
        mcr     p15, 0, r0, c7, c5, 1           @ invalidate I line
-#endif
-       mcr     p15, 0, r0, c7, c5, 7           @ invalidate BTB entry
-       add     r0, r0, #BTB_FLUSH_SIZE
-       mcr     p15, 0, r0, c7, c5, 7           @ invalidate BTB entry
-       add     r0, r0, #BTB_FLUSH_SIZE
-       mcr     p15, 0, r0, c7, c5, 7           @ invalidate BTB entry
-       add     r0, r0, #BTB_FLUSH_SIZE
-       mcr     p15, 0, r0, c7, c5, 7           @ invalidate BTB entry
-       add     r0, r0, #BTB_FLUSH_SIZE
+       add     r0, r0, #CACHE_LINE_SIZE
        cmp     r0, r1
        blo     1b
+#endif
+       mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
 #ifdef HARVARD_CACHE
        mov     r0, #0
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
index 861b35947280fcc78897c01df1e3c9a8dc0da265..2d3823ec315384e5bc117184b8ae33f5d6fa0e51 100644 (file)
@@ -241,7 +241,15 @@ ENTRY(xscale_flush_user_cache_range)
  *     it also trashes the mini I-cache used by JTAG debuggers.
  */
 ENTRY(xscale_coherent_kern_range)
-       /* FALLTHROUGH */
+       bic     r0, r0, #CACHELINESIZE - 1
+1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       add     r0, r0, #CACHELINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 0           @ Invalidate I cache & BTB
+       mcr     p15, 0, r0, c7, c10, 4          @ Drain Write (& Fill) Buffer
+       mov     pc, lr
 
 /*
  *     coherent_user_range(start, end)
@@ -252,18 +260,16 @@ ENTRY(xscale_coherent_kern_range)
  *
  *     - start  - virtual start address
  *     - end    - virtual end address
- *
- *     Note: single I-cache line invalidation isn't used here since
- *     it also trashes the mini I-cache used by JTAG debuggers.
  */
 ENTRY(xscale_coherent_user_range)
        bic     r0, r0, #CACHELINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       mcr     p15, 0, r0, c7, c5, 1           @ Invalidate I cache entry
        add     r0, r0, #CACHELINESIZE
        cmp     r0, r1
        blo     1b
        mov     r0, #0
-       mcr     p15, 0, r0, c7, c5, 0           @ Invalidate I cache & BTB
+       mcr     p15, 0, r0, c7, c5, 6           @ Invalidate BTB
        mcr     p15, 0, r0, c7, c10, 4          @ Drain Write (& Fill) Buffer
        mov     pc, lr
 
index 1415930ceee1a0908d32d540fb8867a1975cdedc..6f8bc1f0e6a11a9eae95968f7356ed5a2b895a78 100644 (file)
@@ -137,8 +137,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        if (spec) {
                init_MUTEX(&op_arm_sem);
 
-               if (spec->init() < 0)
-                       return -ENODEV;
+               ret = spec->init();
+               if (ret < 0)
+                       return ret;
 
                op_arm_model = spec;
                init_driverfs();
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 5485382cadec8cc361293569bba79a985687f97e..bd7be09ea53df24a7bea3301f579d18902fa79bb 100644 (file)
@@ -59,17 +59,16 @@ static void *drm_ati_alloc_pcigart_table(void)
        int i;
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       address = __get_free_pages(GFP_KERNEL, ATI_PCIGART_TABLE_ORDER);
+       address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
+                                  ATI_PCIGART_TABLE_ORDER);
        if (address == 0UL) {
-               return 0;
+               return NULL;
        }
 
        page = virt_to_page(address);
 
-       for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
-               get_page(page);
+       for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
                SetPageReserved(page);
-       }
 
        DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
        return (void *)address;
@@ -83,10 +82,8 @@ static void drm_ati_free_pcigart_table(void *address)
 
        page = virt_to_page((unsigned long)address);
 
-       for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
-               __put_page(page);
+       for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
                ClearPageReserved(page);
-       }
 
        free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
 }
@@ -127,7 +124,7 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
        if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
            && gart_info->addr) {
                drm_ati_free_pcigart_table(gart_info->addr);
-               gart_info->addr = 0;
+               gart_info->addr = NULL;
        }
 
        return 1;
@@ -168,7 +165,7 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
                if (bus_address == 0) {
                        DRM_ERROR("unable to map PCIGART pages!\n");
                        drm_ati_free_pcigart_table(address);
-                       address = 0;
+                       address = NULL;
                        goto done;
                }
        } else {
index 54b561e694862ef6924ef08f61ba2ad520c18a8f..71b8b32b075f2e819beac16ac753cb5e69154c6b 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/smp_lock.h>    /* For (un)lock_kernel */
 #include <linux/mm.h>
 #include <linux/cdev.h>
+#include <linux/mutex.h>
 #if defined(__alpha__) || defined(__powerpc__)
 #include <asm/pgtable.h>       /* For pte_wrprotect */
 #endif
@@ -623,7 +624,7 @@ typedef struct drm_device {
        /** \name Locks */
        /*@{ */
        spinlock_t count_lock;          /**< For inuse, drm_device::open_count, drm_device::buf_use */
-       struct semaphore struct_sem;    /**< For others */
+       struct mutex struct_mutex;      /**< For others */
        /*@} */
 
        /** \name Usage Counters */
@@ -658,7 +659,7 @@ typedef struct drm_device {
        /*@{ */
        drm_ctx_list_t *ctxlist;        /**< Linked list of context handles */
        int ctx_count;                  /**< Number of context handles */
-       struct semaphore ctxlist_sem;   /**< For ctxlist */
+       struct mutex ctxlist_mutex;     /**< For ctxlist */
 
        drm_map_t **context_sareas;         /**< per-context SAREA's */
        int max_context;
index a47b502bc7cc8fdcefa19688fbe9c16e7eaf3525..2a37586a7ee8d4e7ca856723f27be808e6649005 100644 (file)
@@ -56,7 +56,7 @@ static int drm_hash_magic(drm_magic_t magic)
  * \param magic magic number.
  *
  * Searches in drm_device::magiclist within all files with the same hash key
- * the one with matching magic number, while holding the drm_device::struct_sem
+ * the one with matching magic number, while holding the drm_device::struct_mutex
  * lock.
  */
 static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
@@ -65,14 +65,14 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
        drm_magic_entry_t *pt;
        int hash = drm_hash_magic(magic);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
                if (pt->magic == magic) {
                        retval = pt->priv;
                        break;
                }
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return retval;
 }
 
@@ -85,7 +85,7 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
  *
  * Creates a drm_magic_entry structure and appends to the linked list
  * associated the magic number hash key in drm_device::magiclist, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
  */
 static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
                         drm_magic_t magic)
@@ -104,7 +104,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
        entry->priv = priv;
        entry->next = NULL;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (dev->magiclist[hash].tail) {
                dev->magiclist[hash].tail->next = entry;
                dev->magiclist[hash].tail = entry;
@@ -112,7 +112,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
                dev->magiclist[hash].head = entry;
                dev->magiclist[hash].tail = entry;
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -124,7 +124,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
  * \param magic magic number.
  *
  * Searches and unlinks the entry in drm_device::magiclist with the magic
- * number hash key, while holding the drm_device::struct_sem lock.
+ * number hash key, while holding the drm_device::struct_mutex lock.
  */
 static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
 {
@@ -135,7 +135,7 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
        DRM_DEBUG("%d\n", magic);
        hash = drm_hash_magic(magic);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
                if (pt->magic == magic) {
                        if (dev->magiclist[hash].head == pt) {
@@ -147,11 +147,11 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
                        if (prev) {
                                prev->next = pt->next;
                        }
-                       up(&dev->struct_sem);
+                       mutex_unlock(&dev->struct_mutex);
                        return 0;
                }
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
 
index 1db12dcb6802f8e52b7622a415d6072d6c4f00f6..e2637b4d51def2a20db9ddc4e14e4a2e07c6800e 100644 (file)
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
        memset(list, 0, sizeof(*list));
        list->map = map;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        list_add(&list->head, &dev->maplist->head);
        /* Assign a 32-bit handle */
-       /* We do it here so that dev->struct_sem protects the increment */
+       /* We do it here so that dev->struct_mutex protects the increment */
        list->user_token = HandleID(map->type == _DRM_SHM
                                    ? (unsigned long)map->handle
                                    : map->offset, dev);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        *maplist = list;
        return 0;
@@ -392,9 +392,9 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
 {
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm_rmmap_locked(dev, map);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        return ret;
 }
@@ -423,7 +423,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
                return -EFAULT;
        }
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        list_for_each(list, &dev->maplist->head) {
                drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
 
@@ -439,7 +439,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
         * find anything.
         */
        if (list == (&dev->maplist->head)) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
 
@@ -448,13 +448,13 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
 
        /* Register and framebuffer maps are permanent */
        if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return 0;
        }
 
        ret = drm_rmmap_locked(dev, map);
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        return ret;
 }
@@ -566,16 +566,16 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
        atomic_inc(&dev->buf_alloc);
        spin_unlock(&dev->count_lock);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
        if (entry->buf_count) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM; /* May only call once for each order */
        }
 
        if (count < 0 || count > 4096) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -EINVAL;
        }
@@ -583,7 +583,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
        entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
                                   DRM_MEM_BUFS);
        if (!entry->buflist) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -616,7 +616,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
                        drm_cleanup_buf_error(dev, entry);
-                       up(&dev->struct_sem);
+                       mutex_unlock(&dev->struct_mutex);
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
@@ -638,7 +638,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -656,7 +656,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
        DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
        DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        request->count = entry->buf_count;
        request->size = size;
@@ -722,16 +722,16 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
        atomic_inc(&dev->buf_alloc);
        spin_unlock(&dev->count_lock);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
        if (entry->buf_count) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM; /* May only call once for each order */
        }
 
        if (count < 0 || count > 4096) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -EINVAL;
        }
@@ -739,7 +739,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
        entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
                                   DRM_MEM_BUFS);
        if (!entry->buflist) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -750,7 +750,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
        if (!entry->seglist) {
                drm_free(entry->buflist,
                         count * sizeof(*entry->buflist), DRM_MEM_BUFS);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -766,7 +766,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
                         count * sizeof(*entry->buflist), DRM_MEM_BUFS);
                drm_free(entry->seglist,
                         count * sizeof(*entry->seglist), DRM_MEM_SEGS);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -790,7 +790,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
                        drm_free(temp_pagelist,
                                 (dma->page_count + (count << page_order))
                                 * sizeof(*dma->pagelist), DRM_MEM_PAGES);
-                       up(&dev->struct_sem);
+                       mutex_unlock(&dev->struct_mutex);
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
@@ -831,7 +831,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
                                          (count << page_order))
                                         * sizeof(*dma->pagelist),
                                         DRM_MEM_PAGES);
-                               up(&dev->struct_sem);
+                               mutex_unlock(&dev->struct_mutex);
                                atomic_dec(&dev->buf_alloc);
                                return -ENOMEM;
                        }
@@ -853,7 +853,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
                drm_free(temp_pagelist,
                         (dma->page_count + (count << page_order))
                         * sizeof(*dma->pagelist), DRM_MEM_PAGES);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -878,7 +878,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
        dma->page_count += entry->seg_count << page_order;
        dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        request->count = entry->buf_count;
        request->size = size;
@@ -948,16 +948,16 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
        atomic_inc(&dev->buf_alloc);
        spin_unlock(&dev->count_lock);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
        if (entry->buf_count) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM; /* May only call once for each order */
        }
 
        if (count < 0 || count > 4096) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -EINVAL;
        }
@@ -965,7 +965,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
        entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
                                   DRM_MEM_BUFS);
        if (!entry->buflist) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -999,7 +999,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
                        drm_cleanup_buf_error(dev, entry);
-                       up(&dev->struct_sem);
+                       mutex_unlock(&dev->struct_mutex);
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
@@ -1022,7 +1022,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -1040,7 +1040,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
        DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
        DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        request->count = entry->buf_count;
        request->size = size;
@@ -1110,16 +1110,16 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
        atomic_inc(&dev->buf_alloc);
        spin_unlock(&dev->count_lock);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
        if (entry->buf_count) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM; /* May only call once for each order */
        }
 
        if (count < 0 || count > 4096) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -EINVAL;
        }
@@ -1127,7 +1127,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
        entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
                                   DRM_MEM_BUFS);
        if (!entry->buflist) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -1160,7 +1160,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
                        drm_cleanup_buf_error(dev, entry);
-                       up(&dev->struct_sem);
+                       mutex_unlock(&dev->struct_mutex);
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
@@ -1182,7 +1182,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
@@ -1200,7 +1200,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
        DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
        DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        request->count = entry->buf_count;
        request->size = size;
index f8425452694957d6c74a2955eac8e3abc8310f03..83094c73da67abff05ab809bb76f0b0dd39c7e3f 100644 (file)
@@ -53,7 +53,7 @@
  * \param ctx_handle context handle.
  *
  * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
- * in drm_device::context_sareas, while holding the drm_device::struct_sem
+ * in drm_device::context_sareas, while holding the drm_device::struct_mutex
  * lock.
  */
 void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
@@ -64,10 +64,10 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
                goto failed;
 
        if (ctx_handle < DRM_MAX_CTXBITMAP) {
-               down(&dev->struct_sem);
+               mutex_lock(&dev->struct_mutex);
                clear_bit(ctx_handle, dev->ctx_bitmap);
                dev->context_sareas[ctx_handle] = NULL;
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return;
        }
       failed:
@@ -83,7 +83,7 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
  *
  * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
  * drm_device::context_sareas to accommodate the new entry while holding the
- * drm_device::struct_sem lock.
+ * drm_device::struct_mutex lock.
  */
 static int drm_ctxbitmap_next(drm_device_t * dev)
 {
@@ -92,7 +92,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
        if (!dev->ctx_bitmap)
                return -1;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
        if (bit < DRM_MAX_CTXBITMAP) {
                set_bit(bit, dev->ctx_bitmap);
@@ -113,7 +113,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
                                                         DRM_MEM_MAPS);
                                if (!ctx_sareas) {
                                        clear_bit(bit, dev->ctx_bitmap);
-                                       up(&dev->struct_sem);
+                                       mutex_unlock(&dev->struct_mutex);
                                        return -1;
                                }
                                dev->context_sareas = ctx_sareas;
@@ -126,16 +126,16 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
                                              DRM_MEM_MAPS);
                                if (!dev->context_sareas) {
                                        clear_bit(bit, dev->ctx_bitmap);
-                                       up(&dev->struct_sem);
+                                       mutex_unlock(&dev->struct_mutex);
                                        return -1;
                                }
                                dev->context_sareas[bit] = NULL;
                        }
                }
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return bit;
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return -1;
 }
 
@@ -145,24 +145,24 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
  * \param dev DRM device.
  *
  * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
  */
 int drm_ctxbitmap_init(drm_device_t * dev)
 {
        int i;
        int temp;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
                                                     DRM_MEM_CTXBITMAP);
        if (dev->ctx_bitmap == NULL) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -ENOMEM;
        }
        memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
        dev->context_sareas = NULL;
        dev->max_context = -1;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
                temp = drm_ctxbitmap_next(dev);
@@ -178,17 +178,17 @@ int drm_ctxbitmap_init(drm_device_t * dev)
  * \param dev DRM device.
  *
  * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
  */
 void drm_ctxbitmap_cleanup(drm_device_t * dev)
 {
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (dev->context_sareas)
                drm_free(dev->context_sareas,
                         sizeof(*dev->context_sareas) *
                         dev->max_context, DRM_MEM_MAPS);
        drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 /*@}*/
@@ -222,15 +222,15 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        if (copy_from_user(&request, argp, sizeof(request)))
                return -EFAULT;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (dev->max_context < 0
            || request.ctx_id >= (unsigned)dev->max_context) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
 
        map = dev->context_sareas[request.ctx_id];
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        request.handle = NULL;
        list_for_each_entry(_entry, &dev->maplist->head, head) {
@@ -274,7 +274,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
                           (drm_ctx_priv_map_t __user *) arg, sizeof(request)))
                return -EFAULT;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
                if (r_list->map
@@ -282,7 +282,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
                        goto found;
        }
       bad:
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return -EINVAL;
 
       found:
@@ -294,7 +294,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
        if (request.ctx_id >= (unsigned)dev->max_context)
                goto bad;
        dev->context_sareas[request.ctx_id] = map;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return 0;
 }
 
@@ -448,10 +448,10 @@ int drm_addctx(struct inode *inode, struct file *filp,
        ctx_entry->handle = ctx.handle;
        ctx_entry->tag = priv;
 
-       down(&dev->ctxlist_sem);
+       mutex_lock(&dev->ctxlist_mutex);
        list_add(&ctx_entry->head, &dev->ctxlist->head);
        ++dev->ctx_count;
-       up(&dev->ctxlist_sem);
+       mutex_unlock(&dev->ctxlist_mutex);
 
        if (copy_to_user(argp, &ctx, sizeof(ctx)))
                return -EFAULT;
@@ -574,7 +574,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
                drm_ctxbitmap_free(dev, ctx.handle);
        }
 
-       down(&dev->ctxlist_sem);
+       mutex_lock(&dev->ctxlist_mutex);
        if (!list_empty(&dev->ctxlist->head)) {
                drm_ctx_list_t *pos, *n;
 
@@ -586,7 +586,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
                        }
                }
        }
-       up(&dev->ctxlist_sem);
+       mutex_unlock(&dev->ctxlist_mutex);
 
        return 0;
 }
index c4fa5a29582b515fadbbd4aa5ec6ab1d98089722..dc6bbe8a18dc762e158ed8084071ddbaf4eb6ce6 100644 (file)
@@ -151,7 +151,7 @@ int drm_lastclose(drm_device_t * dev)
        if (dev->irq_enabled)
                drm_irq_uninstall(dev);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        del_timer(&dev->timer);
 
        /* Clear pid list */
@@ -231,7 +231,7 @@ int drm_lastclose(drm_device_t * dev)
                dev->lock.filp = NULL;
                wake_up_interruptible(&dev->lock.lock_queue);
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG("lastclose completed\n");
        return 0;
index 403f44a1bf016cebe684f8d35719bf3b8d6dbf06..641f7633878c798d660657a5d56a1e1395e9ad38 100644 (file)
@@ -262,7 +262,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                        goto out_free;
        }
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (!dev->file_last) {
                priv->next = NULL;
                priv->prev = NULL;
@@ -276,7 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                dev->file_last->next = priv;
                dev->file_last = priv;
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
 #ifdef __alpha__
        /*
@@ -413,7 +413,7 @@ int drm_release(struct inode *inode, struct file *filp)
 
        drm_fasync(-1, filp, 0);
 
-       down(&dev->ctxlist_sem);
+       mutex_lock(&dev->ctxlist_mutex);
        if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
                drm_ctx_list_t *pos, *n;
 
@@ -432,9 +432,9 @@ int drm_release(struct inode *inode, struct file *filp)
                        }
                }
        }
-       up(&dev->ctxlist_sem);
+       mutex_unlock(&dev->ctxlist_mutex);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (priv->remove_auth_on_close == 1) {
                drm_file_t *temp = dev->file_first;
                while (temp) {
@@ -452,7 +452,7 @@ int drm_release(struct inode *inode, struct file *filp)
        } else {
                dev->file_last = priv->prev;
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        if (dev->driver->postclose)
                dev->driver->postclose(dev, priv);
index bcd4e604d3ecd8f9c1c2467218f363e15fcfd331..555f323b8a32c350578b4f75ea04b5a345472c80 100644 (file)
@@ -194,9 +194,9 @@ int drm_getmap(struct inode *inode, struct file *filp,
                return -EFAULT;
        idx = map.offset;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        if (idx < 0) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
 
@@ -209,7 +209,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
                i++;
        }
        if (!r_list || !r_list->map) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
 
@@ -219,7 +219,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
        map.flags = r_list->map->flags;
        map.handle = (void *)(unsigned long)r_list->user_token;
        map.mtrr = r_list->map->mtrr;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        if (copy_to_user(argp, &map, sizeof(map)))
                return -EFAULT;
@@ -253,11 +253,11 @@ int drm_getclient(struct inode *inode, struct file *filp,
        if (copy_from_user(&client, argp, sizeof(client)))
                return -EFAULT;
        idx = client.idx;
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ;
 
        if (!pt) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
        client.auth = pt->authenticated;
@@ -265,7 +265,7 @@ int drm_getclient(struct inode *inode, struct file *filp,
        client.uid = pt->uid;
        client.magic = pt->magic;
        client.iocs = pt->ioctl_count;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        if (copy_to_user(argp, &client, sizeof(client)))
                return -EFAULT;
@@ -292,7 +292,7 @@ int drm_getstats(struct inode *inode, struct file *filp,
 
        memset(&stats, 0, sizeof(stats));
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
 
        for (i = 0; i < dev->counters; i++) {
                if (dev->types[i] == _DRM_STAT_LOCK)
@@ -305,7 +305,7 @@ int drm_getstats(struct inode *inode, struct file *filp,
 
        stats.count = dev->counters;
 
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats)))
                return -EFAULT;
index b0d4b236e8372f349d1d2eae58fcac8b5ee808eb..611a1173091de92116cb4a018cbd0d473bdadee3 100644 (file)
@@ -98,20 +98,20 @@ static int drm_irq_install(drm_device_t * dev)
        if (dev->irq == 0)
                return -EINVAL;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
 
        /* Driver must have been initialized */
        if (!dev->dev_private) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
 
        if (dev->irq_enabled) {
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return -EBUSY;
        }
        dev->irq_enabled = 1;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
 
@@ -135,9 +135,9 @@ static int drm_irq_install(drm_device_t * dev)
        ret = request_irq(dev->irq, dev->driver->irq_handler,
                          sh_flags, dev->devname, dev);
        if (ret < 0) {
-               down(&dev->struct_sem);
+               mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = 0;
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
@@ -161,10 +161,10 @@ int drm_irq_uninstall(drm_device_t * dev)
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        irq_enabled = dev->irq_enabled;
        dev->irq_enabled = 0;
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 
        if (!irq_enabled)
                return -EINVAL;
index 5b1d3a04458d06bd5af8c81e0c8ef105a30426e1..8fd6357a48da1ae648874cedcb1973d8110afe6d 100644 (file)
@@ -3,6 +3,7 @@
    Please contact dri-devel@lists.sf.net to add new cards to this list
 */
 #define radeon_PCI_IDS \
+       {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\
        {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
        {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
        {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
        {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
index 6f943e3309ef911e7e4d6e3f968d754697fbaf42..362a270af0f10c53387069b2b7124ce788f23e96 100644 (file)
@@ -258,7 +258,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
 }
 
 /**
- * Simply calls _vm_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _vm_info() while holding the drm_device::struct_mutex lock.
  */
 static int drm_vm_info(char *buf, char **start, off_t offset, int request,
                       int *eof, void *data)
@@ -266,9 +266,9 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request,
        drm_device_t *dev = (drm_device_t *) data;
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm__vm_info(buf, start, offset, request, eof, data);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -331,7 +331,7 @@ static int drm__queues_info(char *buf, char **start, off_t offset,
 }
 
 /**
- * Simply calls _queues_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _queues_info() while holding the drm_device::struct_mutex lock.
  */
 static int drm_queues_info(char *buf, char **start, off_t offset, int request,
                           int *eof, void *data)
@@ -339,9 +339,9 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request,
        drm_device_t *dev = (drm_device_t *) data;
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm__queues_info(buf, start, offset, request, eof, data);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -403,7 +403,7 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
 }
 
 /**
- * Simply calls _bufs_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock.
  */
 static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
                         int *eof, void *data)
@@ -411,9 +411,9 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
        drm_device_t *dev = (drm_device_t *) data;
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm__bufs_info(buf, start, offset, request, eof, data);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -459,7 +459,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
 }
 
 /**
- * Simply calls _clients_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _clients_info() while holding the drm_device::struct_mutex lock.
  */
 static int drm_clients_info(char *buf, char **start, off_t offset,
                            int request, int *eof, void *data)
@@ -467,9 +467,9 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
        drm_device_t *dev = (drm_device_t *) data;
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm__clients_info(buf, start, offset, request, eof, data);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -540,9 +540,9 @@ static int drm_vma_info(char *buf, char **start, off_t offset, int request,
        drm_device_t *dev = (drm_device_t *) data;
        int ret;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        ret = drm__vma_info(buf, start, offset, request, eof, data);
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 #endif
index 42d766359caa919d6600f7691dc870ef2f8d7ed4..7a9263ff300720c459321e7937b5f4b6902a2df1 100644 (file)
@@ -61,8 +61,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
 
        spin_lock_init(&dev->count_lock);
        init_timer(&dev->timer);
-       sema_init(&dev->struct_sem, 1);
-       sema_init(&dev->ctxlist_sem, 1);
+       mutex_init(&dev->struct_mutex);
+       mutex_init(&dev->ctxlist_mutex);
 
        dev->pdev = pdev;
 
index 3f73aa774c80975eee97134a29ac43fb0a7de294..0291cd62c69f2b955db736952fd45dc69f444a09 100644 (file)
@@ -188,7 +188,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
 
        map = vma->vm_private_data;
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
                next = pt->next;
                if (pt->vma->vm_private_data == map)
@@ -248,7 +248,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                }
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 /**
@@ -404,12 +404,12 @@ static void drm_vm_open(struct vm_area_struct *vma)
 
        vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
        if (vma_entry) {
-               down(&dev->struct_sem);
+               mutex_lock(&dev->struct_mutex);
                vma_entry->vma = vma;
                vma_entry->next = dev->vmalist;
                vma_entry->pid = current->pid;
                dev->vmalist = vma_entry;
-               up(&dev->struct_sem);
+               mutex_unlock(&dev->struct_mutex);
        }
 }
 
@@ -431,7 +431,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
                  vma->vm_start, vma->vm_end - vma->vm_start);
        atomic_dec(&dev->vma_count);
 
-       down(&dev->struct_sem);
+       mutex_lock(&dev->struct_mutex);
        for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
                if (pt->vma == vma) {
                        if (prev) {
@@ -443,7 +443,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
                        break;
                }
        }
-       up(&dev->struct_sem);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 /**
index cc1b89086876b3f289301685ebb0aefbcd2146a5..ae0aa6d7e0bb74140ca576c89bb4c8bf2fcd5705 100644 (file)
@@ -958,7 +958,7 @@ static int i810_flush_queue(drm_device_t * dev)
 }
 
 /* Must be called with the lock held */
-void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
 {
        drm_device_dma_t *dma = dev->dma;
        int i;
index a18b80d91920b073fc46f787160ed1fa889bd7c9..e8cf3ff606f0c000c4955ab4d5e463d577b6e381 100644 (file)
@@ -113,8 +113,6 @@ typedef struct drm_i810_private {
 } drm_i810_private_t;
 
                                /* i810_dma.c */
-extern void i810_reclaim_buffers(drm_device_t * dev, struct file *filp);
-
 extern int i810_driver_dma_quiescent(drm_device_t * dev);
 extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
                                               struct file *filp);
index 4fea32aed6d240f493946137a7c06c5b29cada72..163f2cbfe60d2dd4b1c90761f4aaf0a95145db76 100644 (file)
@@ -1239,7 +1239,7 @@ static int i830_flush_queue(drm_device_t * dev)
 }
 
 /* Must be called with the lock held */
-void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
 {
        drm_device_dma_t *dma = dev->dma;
        int i;
index bf9075b576bddbcaa36cf29e71464e3c3a90a4f3..85bc5be6f91650f9050444cc6accdad9ef9f5e05 100644 (file)
@@ -123,9 +123,6 @@ typedef struct drm_i830_private {
 extern drm_ioctl_desc_t i830_ioctls[];
 extern int i830_max_ioctl;
 
-/* i830_dma.c */
-extern void i830_reclaim_buffers(drm_device_t * dev, struct file *filp);
-
 /* i830_irq.c */
 extern int i830_irq_emit(struct inode *inode, struct file *filp,
                         unsigned int cmd, unsigned long arg);
index 9140703da1ba0aac8288ab7258fe05d599a6e491..1ff4c7ca0bff0421ea39e97d9df98883faa4b071 100644 (file)
@@ -344,18 +344,20 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
        int i;
        RING_LOCALS;
 
+       if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
+               return DRM_ERR(EINVAL);
+
+       BEGIN_LP_RING(((dwords+1)&~1));
+
        for (i = 0; i < dwords;) {
                int cmd, sz;
 
                if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
                        return DRM_ERR(EINVAL);
 
-/*             printk("%d/%d ", i, dwords); */
-
                if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
                        return DRM_ERR(EINVAL);
 
-               BEGIN_LP_RING(sz);
                OUT_RING(cmd);
 
                while (++i, --sz) {
@@ -365,9 +367,13 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
                        }
                        OUT_RING(cmd);
                }
-               ADVANCE_LP_RING();
        }
 
+       if (dwords & 1)
+               OUT_RING(0);
+
+       ADVANCE_LP_RING();
+
        return 0;
 }
 
@@ -401,6 +407,21 @@ static int i915_emit_box(drm_device_t * dev,
        return 0;
 }
 
+static void i915_emit_breadcrumb(drm_device_t *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+
+       dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+       BEGIN_LP_RING(4);
+       OUT_RING(CMD_STORE_DWORD_IDX);
+       OUT_RING(20);
+       OUT_RING(dev_priv->counter);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+}
+
 static int i915_dispatch_cmdbuffer(drm_device_t * dev,
                                   drm_i915_cmdbuffer_t * cmd)
 {
@@ -429,6 +450,7 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev,
                        return ret;
        }
 
+       i915_emit_breadcrumb(dev);
        return 0;
 }
 
@@ -475,12 +497,7 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
 
        dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
 
-       BEGIN_LP_RING(4);
-       OUT_RING(CMD_STORE_DWORD_IDX);
-       OUT_RING(20);
-       OUT_RING(dev_priv->counter);
-       OUT_RING(0);
-       ADVANCE_LP_RING();
+       i915_emit_breadcrumb(dev);
 
        return 0;
 }
@@ -657,7 +674,7 @@ static int i915_getparam(DRM_IOCTL_ARGS)
                value = READ_BREADCRUMB(dev_priv);
                break;
        default:
-               DRM_ERROR("Unkown parameter %d\n", param.param);
+               DRM_ERROR("Unknown parameter %d\n", param.param);
                return DRM_ERR(EINVAL);
        }
 
@@ -742,7 +759,8 @@ drm_ioctl_desc_t i915_ioctls[] = {
        [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
        [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
        [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH}
+       [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
+       [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index 77412ddac007625637e24aabd38a69f94a690cd3..4cb3da578330b631ff05f1b8882e9124a31ab4ec 100644 (file)
@@ -74,6 +74,30 @@ typedef struct _drm_i915_sarea {
        int pf_active;
        int pf_current_page;    /* which buffer is being displayed? */
        int perf_boxes;         /* performance boxes to be displayed */
+       int width, height;      /* screen size in pixels */
+
+       drm_handle_t front_handle;
+       int front_offset;
+       int front_size;
+
+       drm_handle_t back_handle;
+       int back_offset;
+       int back_size;
+
+       drm_handle_t depth_handle;
+       int depth_offset;
+       int depth_size;
+
+       drm_handle_t tex_handle;
+       int tex_offset;
+       int tex_size;
+       int log_tex_granularity;
+       int pitch;
+       int rotation;           /* 0, 90, 180 or 270 */
+       int rotated_offset;
+       int rotated_size;
+       int rotated_pitch;
+       int virtualX, virtualY;
 } drm_i915_sarea_t;
 
 /* Flags for perf_boxes
@@ -99,6 +123,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_FREE          0x09
 #define DRM_I915_INIT_HEAP     0x0a
 #define DRM_I915_CMDBUFFER     0x0b
+#define DRM_I915_DESTROY_HEAP  0x0c
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -112,6 +137,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_FREE             DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t)
 #define DRM_IOCTL_I915_INIT_HEAP        DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
 #define DRM_IOCTL_I915_CMDBUFFER       DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
+#define DRM_IOCTL_I915_DESTROY_HEAP    DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -191,4 +217,11 @@ typedef struct drm_i915_mem_init_heap {
        int start;
 } drm_i915_mem_init_heap_t;
 
+/* Allow memory manager to be torn down and re-initialized (eg on
+ * rotate):
+ */
+typedef struct drm_i915_mem_destroy_heap {
+       int region;
+} drm_i915_mem_destroy_heap_t;
+
 #endif                         /* _I915_DRM_H_ */
index c6c71b45f1013b92949c0a92c800f79a840a358a..7a65666899e49523c5ff55e3d21e8afe01abcd36 100644 (file)
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20051209"
+#define DRIVER_DATE            "20060119"
 
 /* Interface history:
  *
  * 1.1: Original.
  * 1.2: Add Power Management
  * 1.3: Add vblank support
+ * 1.4: Fix cmdbuffer path, add heap destroy
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           3
+#define DRIVER_MINOR           4
 #define DRIVER_PATCHLEVEL      0
 
 typedef struct _drm_i915_ring_buffer {
@@ -123,6 +124,7 @@ extern void i915_driver_irq_uninstall(drm_device_t * dev);
 extern int i915_mem_alloc(DRM_IOCTL_ARGS);
 extern int i915_mem_free(DRM_IOCTL_ARGS);
 extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
+extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
 extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(drm_device_t * dev,
                             DRMFILE filp, struct mem_block *heap);
index ba87ff17ff64cfaf123afe895a4b0d6a5a0bc262..52c67324df58953f6b98db130f8f6d05bbaa1dda 100644 (file)
@@ -365,3 +365,34 @@ int i915_mem_init_heap(DRM_IOCTL_ARGS)
 
        return init_heap(heap, initheap.start, initheap.size);
 }
+
+int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_mem_destroy_heap_t destroyheap;
+       struct mem_block **heap;
+
+       if ( !dev_priv ) {
+               DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
+                                 sizeof(destroyheap) );
+
+       heap = get_heap( dev_priv, destroyheap.region );
+       if (!heap) {
+               DRM_ERROR("get_heap failed");
+               return DRM_ERR(EFAULT);
+       }
+       
+       if (!*heap) {
+               DRM_ERROR("heap not initialized?");
+               return DRM_ERR(EFAULT);
+       }
+
+       i915_mem_takedown( heap );
+       return 0;
+}
+
index 915665c7fe7c672bebe54a7f8f73f6d80dc65d29..9bb8ae0c1c2720a31794179364fca10d83c1fb3e 100644 (file)
@@ -1640,7 +1640,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
                if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
                {
                        drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
-                       dev_priv->gart_info.addr = 0;
+                       dev_priv->gart_info.addr = NULL;
                }
        }
        /* only clear to the start of flags */
index 0d426deeefec1992681f43259ea0c55aae4b0cdd..59c7520bf9a2ab9419910ac10c186322d3b6ffc8 100644 (file)
@@ -32,6 +32,8 @@
 #define SAVAGE_EVENT_USEC_TIMEOUT      5000000 /* 5s */
 #define SAVAGE_FREELIST_DEBUG          0
 
+static int savage_do_cleanup_bci(drm_device_t *dev);
+
 static int
 savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
 {
@@ -895,7 +897,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
        return 0;
 }
 
-int savage_do_cleanup_bci(drm_device_t * dev)
+static int savage_do_cleanup_bci(drm_device_t * dev)
 {
        drm_savage_private_t *dev_priv = dev->dev_private;
 
index dd46cb85439c846d03a46ae019f721948d87857a..8f04b3d82292bc0419158f93eeb497c97c578ef3 100644 (file)
@@ -212,7 +212,6 @@ extern int savage_driver_load(drm_device_t *dev, unsigned long chipset);
 extern int savage_driver_firstopen(drm_device_t *dev);
 extern void savage_driver_lastclose(drm_device_t *dev);
 extern int savage_driver_unload(drm_device_t *dev);
-extern int savage_do_cleanup_bci(drm_device_t * dev);
 extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp);
 
 /* state functions */
index 593c0b8f650a911c51a3558b0ff136780df63bf4..a691ae74129db2db470f843de39ec1199e7a82e1 100644 (file)
@@ -222,7 +222,7 @@ static int via_initialize(drm_device_t * dev,
        return 0;
 }
 
-int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -321,7 +321,7 @@ int via_driver_dma_quiescent(drm_device_t * dev)
        return 0;
 }
 
-int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
 
@@ -330,7 +330,7 @@ int via_flush_ioctl(DRM_IOCTL_ARGS)
        return via_driver_dma_quiescent(dev);
 }
 
-int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
        drm_via_cmdbuffer_t cmdbuf;
@@ -375,7 +375,7 @@ static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
        return ret;
 }
 
-int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
        drm_via_cmdbuffer_t cmdbuf;
@@ -665,7 +665,7 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
  * User interface to the space and lag functions.
  */
 
-int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
        drm_via_cmdbuf_size_t d_siz;
index 9d5e027dae0e2b8908bd6550863cbab3ef4fa3ea..b7f17457b4243bb1c18e8dea11b6b7149a22e7fe 100644 (file)
@@ -108,7 +108,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
        int num_desc = 0;
        int cur_line;
        dma_addr_t next = 0 | VIA_DMA_DPR_EC;
-       drm_via_descriptor_t *desc_ptr = 0;
+       drm_via_descriptor_t *desc_ptr = NULL;
 
        if (mode == 1) 
                desc_ptr = vsg->desc_pages[cur_descriptor_page];
@@ -167,7 +167,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
  */
 
 
-void
+static void
 via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) 
 {
        struct page *page;
@@ -581,7 +581,7 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
        int ret = 0;
        
        vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-       vsg->bounce_buffer = 0;
+       vsg->bounce_buffer = NULL;
 
        vsg->state = dr_via_sg_init;
 
index aad4f99f540578964013702f310daa67e46e361e..52bcc7b1ba4560065be1a85eb981b15e5a46aea8 100644 (file)
@@ -110,11 +110,6 @@ extern int via_mem_free(DRM_IOCTL_ARGS);
 extern int via_agp_init(DRM_IOCTL_ARGS);
 extern int via_map_init(DRM_IOCTL_ARGS);
 extern int via_decoder_futex(DRM_IOCTL_ARGS);
-extern int via_dma_init(DRM_IOCTL_ARGS);
-extern int via_cmdbuffer(DRM_IOCTL_ARGS);
-extern int via_flush_ioctl(DRM_IOCTL_ARGS);
-extern int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
-extern int via_cmdbuf_size(DRM_IOCTL_ARGS);
 extern int via_wait_irq(DRM_IOCTL_ARGS);
 extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
 extern int via_dma_blit( DRM_IOCTL_ARGS );
@@ -139,8 +134,6 @@ extern int via_driver_dma_quiescent(drm_device_t * dev);
 extern void via_init_futex(drm_via_private_t * dev_priv);
 extern void via_cleanup_futex(drm_via_private_t * dev_priv);
 extern void via_release_futex(drm_via_private_t * dev_priv, int context);
-extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq,
-                              int force_sequence, unsigned int *sequence);
 
 extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
 extern void via_init_dmablit(drm_device_t *dev);
index 56d7e3daea126d8a2f926cd0e21e5444b4d6c479..6152415644e9b4a327549841df072edd0c45f8e5 100644 (file)
@@ -190,7 +190,7 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
        return ret;
 }
 
-int
+static int
 via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
                    unsigned int *sequence)
 {
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 4ee597d087978c3e64c397849fccab1abeeb36cf..2b286e8651632fcd1f4af7dead2fc67d7a5eefcf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -510,7 +510,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                                       drive->name);
                                goto use_pio_instead;
                        } else {
-                               u32 xcount, bcount =
+                               u32 bcount =
                                    0x10000 - (cur_addr & 0xffff);
 
                                if (bcount > cur_len)
@@ -525,8 +525,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                                *table = 0x0;
                                table++;
 
-                               xcount = bcount & 0xffff;
-                               *table = cpu_to_be32(xcount);
+                               *table = cpu_to_be32(bcount);
                                table++;
 
                                cur_addr += bcount;
@@ -680,7 +679,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
                return -EIO;
 
        /* Create /proc/ide entries */
-       create_proc_ide_interfaces(); 
+       create_proc_ide_interfaces();
 
        return 0;
 }
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 74039db846baa3eb19c4574c91827f4d58cb9050..d73779a42417f25a1fac190d4bc4907aa939a782 100644 (file)
@@ -545,7 +545,8 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
                return 0;
 
        do {
-               *region = find_next_zero_bit((unsigned long *) lc->sync_bits,
+               *region = ext2_find_next_zero_bit(
+                                            (unsigned long *) lc->sync_bits,
                                             lc->region_count,
                                             lc->sync_search);
                lc->sync_search = *region + 1;
index 7145cd150f7b2cac4f00c40f9efef5a36b5fad15..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);
@@ -1161,6 +1163,9 @@ 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<<1);
+
        if (mddev->bitmap && mddev->bitmap_file == NULL) {
                sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
                sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
@@ -2686,14 +2691,6 @@ static int do_md_stop(mddev_t * mddev, int ro)
                        set_disk_ro(disk, 1);
        }
 
-       bitmap_destroy(mddev);
-       if (mddev->bitmap_file) {
-               atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
-               fput(mddev->bitmap_file);
-               mddev->bitmap_file = NULL;
-       }
-       mddev->bitmap_offset = 0;
-
        /*
         * Free resources if final stop
         */
@@ -2703,6 +2700,14 @@ static int do_md_stop(mddev_t * mddev, int ro)
                struct gendisk *disk;
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
+               bitmap_destroy(mddev);
+               if (mddev->bitmap_file) {
+                       atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+                       fput(mddev->bitmap_file);
+                       mddev->bitmap_file = NULL;
+               }
+               mddev->bitmap_offset = 0;
+
                ITERATE_RDEV(mddev,rdev,tmp)
                        if (rdev->raid_disk >= 0) {
                                char nm[20];
@@ -2939,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;
@@ -3465,7 +3472,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
                bdev = bdget_disk(mddev->gendisk, 0);
                if (bdev) {
                        mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode, mddev->array_size << 10);
+                       i_size_write(bdev->bd_inode, (loff_t)mddev->array_size << 10);
                        mutex_unlock(&bdev->bd_inode->i_mutex);
                        bdput(bdev);
                }
@@ -3485,17 +3492,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
        if (mddev->sync_thread)
                return -EBUSY;
        rv = mddev->pers->reshape(mddev, raid_disks);
-       if (!rv) {
-               struct block_device *bdev;
-
-               bdev = bdget_disk(mddev->gendisk, 0);
-               if (bdev) {
-                       mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode, mddev->array_size << 10);
-                       mutex_unlock(&bdev->bd_inode->i_mutex);
-                       bdput(bdev);
-               }
-       }
        return rv;
 }
 
@@ -3531,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++;
@@ -3548,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 f618a53b98bee235cca1160e4d08b16bd955ff0c..cd477ebf2ee44d8b963ec3157a5674300e1e85f5 100644 (file)
@@ -115,7 +115,7 @@ static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
                        list_add_tail(&sh->lru, &conf->inactive_list);
                        atomic_dec(&conf->active_stripes);
                        if (!conf->inactive_blocked ||
-                           atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4))
+                           atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
                                wake_up(&conf->wait_for_stripe);
                }
        }
@@ -273,7 +273,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
                                conf->inactive_blocked = 1;
                                wait_event_lock_irq(conf->wait_for_stripe,
                                                    !list_empty(&conf->inactive_list) &&
-                                                   (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4)
+                                                   (atomic_read(&conf->active_stripes)
+                                                    < (conf->max_nr_stripes *3/4)
                                                     || !conf->inactive_blocked),
                                                    conf->device_lock,
                                                    unplug_slaves(conf->mddev);
@@ -302,9 +303,31 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
        return sh;
 }
 
-static int grow_stripes(raid6_conf_t *conf, int num)
+static int grow_one_stripe(raid6_conf_t *conf)
 {
        struct stripe_head *sh;
+       sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+       if (!sh)
+               return 0;
+       memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+       sh->raid_conf = conf;
+       spin_lock_init(&sh->lock);
+
+       if (grow_buffers(sh, conf->raid_disks)) {
+               shrink_buffers(sh, conf->raid_disks);
+               kmem_cache_free(conf->slab_cache, sh);
+               return 0;
+       }
+       /* we just created an active stripe so... */
+       atomic_set(&sh->count, 1);
+       atomic_inc(&conf->active_stripes);
+       INIT_LIST_HEAD(&sh->lru);
+       release_stripe(sh);
+       return 1;
+}
+
+static int grow_stripes(raid6_conf_t *conf, int num)
+{
        kmem_cache_t *sc;
        int devs = conf->raid_disks;
 
@@ -316,45 +339,35 @@ static int grow_stripes(raid6_conf_t *conf, int num)
        if (!sc)
                return 1;
        conf->slab_cache = sc;
-       while (num--) {
-               sh = kmem_cache_alloc(sc, GFP_KERNEL);
-               if (!sh)
-                       return 1;
-               memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
-               sh->raid_conf = conf;
-               spin_lock_init(&sh->lock);
-
-               if (grow_buffers(sh, conf->raid_disks)) {
-                       shrink_buffers(sh, conf->raid_disks);
-                       kmem_cache_free(sc, sh);
+       while (num--)
+               if (!grow_one_stripe(conf))
                        return 1;
-               }
-               /* we just created an active stripe so... */
-               atomic_set(&sh->count, 1);
-               atomic_inc(&conf->active_stripes);
-               INIT_LIST_HEAD(&sh->lru);
-               release_stripe(sh);
-       }
        return 0;
 }
 
-static void shrink_stripes(raid6_conf_t *conf)
+static int drop_one_stripe(raid6_conf_t *conf)
 {
        struct stripe_head *sh;
+       spin_lock_irq(&conf->device_lock);
+       sh = get_free_stripe(conf);
+       spin_unlock_irq(&conf->device_lock);
+       if (!sh)
+               return 0;
+       if (atomic_read(&sh->count))
+               BUG();
+       shrink_buffers(sh, conf->raid_disks);
+       kmem_cache_free(conf->slab_cache, sh);
+       atomic_dec(&conf->active_stripes);
+       return 1;
+}
 
-       while (1) {
-               spin_lock_irq(&conf->device_lock);
-               sh = get_free_stripe(conf);
-               spin_unlock_irq(&conf->device_lock);
-               if (!sh)
-                       break;
-               if (atomic_read(&sh->count))
-                       BUG();
-               shrink_buffers(sh, conf->raid_disks);
-               kmem_cache_free(conf->slab_cache, sh);
-               atomic_dec(&conf->active_stripes);
-       }
-       kmem_cache_destroy(conf->slab_cache);
+static void shrink_stripes(raid6_conf_t *conf)
+{
+       while (drop_one_stripe(conf))
+               ;
+
+       if (conf->slab_cache)
+               kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
@@ -1912,6 +1925,74 @@ static void raid6d (mddev_t *mddev)
        PRINTK("--- raid6d inactive\n");
 }
 
+static ssize_t
+raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", conf->max_nr_stripes);
+       else
+               return 0;
+}
+
+static ssize_t
+raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       char *end;
+       int new;
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       new = simple_strtoul(page, &end, 10);
+       if (!*page || (*end && *end != '\n') )
+               return -EINVAL;
+       if (new <= 16 || new > 32768)
+               return -EINVAL;
+       while (new < conf->max_nr_stripes) {
+               if (drop_one_stripe(conf))
+                       conf->max_nr_stripes--;
+               else
+                       break;
+       }
+       while (new > conf->max_nr_stripes) {
+               if (grow_one_stripe(conf))
+                       conf->max_nr_stripes++;
+               else break;
+       }
+       return len;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+                               raid6_show_stripe_cache_size,
+                               raid6_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+       else
+               return 0;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid6_attrs[] =  {
+       &raid6_stripecache_size.attr,
+       &raid6_stripecache_active.attr,
+       NULL,
+};
+static struct attribute_group raid6_attrs_group = {
+       .name = NULL,
+       .attrs = raid6_attrs,
+};
+
 static int run(mddev_t *mddev)
 {
        raid6_conf_t *conf;
@@ -2095,6 +2176,7 @@ static int stop (mddev_t *mddev)
        shrink_stripes(conf);
        kfree(conf->stripe_hashtbl);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+       sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
        kfree(conf);
        mddev->private = NULL;
        return 0;
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 aaf04638054e64148babae42a6e18e12079019cb..227c39a7c1b443a1ffa328391e36f991f0a102df 100644 (file)
@@ -194,7 +194,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
 
        u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
 
-       switch(cmd->flags) {
+       switch (mmc_rsp_type(cmd->flags)) {
        case MMC_RSP_R1:
                mmccmd |= SD_CMD_RT_1;
                break;
@@ -483,34 +483,35 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
        cmd = mrq->cmd;
        cmd->error = MMC_ERR_NONE;
 
-       if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) {
-
-               /* Techincally, we should be getting all 48 bits of the response
-                * (SD_RESP1 + SD_RESP2), but because our response omits the CRC,
-                * our data ends up being shifted 8 bits to the right.  In this case,
-                * that means that the OSR data starts at bit 31, so we can just
-                * read RESP0 and return that
-                */
-
-               cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
-       }
-       else if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG) {
-               u32 r[4];
-               int i;
-
-               r[0] = au_readl(host->iobase + SD_RESP3);
-               r[1] = au_readl(host->iobase + SD_RESP2);
-               r[2] = au_readl(host->iobase + SD_RESP1);
-               r[3] = au_readl(host->iobase + SD_RESP0);
-
-               /* The CRC is omitted from the response, so really we only got
-                * 120 bytes, but the engine expects 128 bits, so we have to shift
-                * things up
-                */
-
-               for(i = 0; i < 4; i++) {
-                       cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
-                       if (i != 3) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
+                       u32 r[4];
+                       int i;
+
+                       r[0] = au_readl(host->iobase + SD_RESP3);
+                       r[1] = au_readl(host->iobase + SD_RESP2);
+                       r[2] = au_readl(host->iobase + SD_RESP1);
+                       r[3] = au_readl(host->iobase + SD_RESP0);
+
+                       /* The CRC is omitted from the response, so really
+                        * we only got 120 bytes, but the engine expects
+                        * 128 bits, so we have to shift things up
+                        */
+
+                       for(i = 0; i < 4; i++) {
+                               cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
+                               if (i != 3)
+                                       cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+                       }
+               } else {
+                       /* Techincally, we should be getting all 48 bits of
+                        * the response (SD_RESP1 + SD_RESP2), but because
+                        * our response omits the CRC, our data ends up
+                        * being shifted 8 bits to the right.  In this case,
+                        * that means that the OSR data starts at bit 31,
+                        * so we can just read RESP0 and return that
+                        */
+                       cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
                }
        }
 
index bfca5c176e8862c559e9f3abc1bf91c2ba9825c7..1888060c5e0c415cf5701250f845bf4d27a5e0a4 100644 (file)
@@ -211,7 +211,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
 
                appcmd.opcode = MMC_APP_CMD;
                appcmd.arg = rca << 16;
-               appcmd.flags = MMC_RSP_R1;
+               appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
                appcmd.retries = 0;
                memset(appcmd.resp, 0, sizeof(appcmd.resp));
                appcmd.data = NULL;
@@ -331,7 +331,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 
        cmd.opcode = MMC_SELECT_CARD;
        cmd.arg = card->rca << 16;
-       cmd.flags = MMC_RSP_R1;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
        err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
        if (err != MMC_ERR_NONE)
@@ -358,7 +358,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
                        struct mmc_command cmd;
                        cmd.opcode = SD_APP_SET_BUS_WIDTH;
                        cmd.arg = SD_BUS_WIDTH_4;
-                       cmd.flags = MMC_RSP_R1;
+                       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
                        err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
                                CMD_RETRIES);
@@ -386,7 +386,7 @@ static void mmc_deselect_cards(struct mmc_host *host)
 
                cmd.opcode = MMC_SELECT_CARD;
                cmd.arg = 0;
-               cmd.flags = MMC_RSP_NONE;
+               cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
 
                mmc_wait_for_cmd(host, &cmd, 0);
        }
@@ -677,7 +677,7 @@ static void mmc_idle_cards(struct mmc_host *host)
 
        cmd.opcode = MMC_GO_IDLE_STATE;
        cmd.arg = 0;
-       cmd.flags = MMC_RSP_NONE;
+       cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
 
        mmc_wait_for_cmd(host, &cmd, 0);
 
@@ -738,7 +738,7 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 
        cmd.opcode = MMC_SEND_OP_COND;
        cmd.arg = ocr;
-       cmd.flags = MMC_RSP_R3;
+       cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
 
        for (i = 100; i; i--) {
                err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -766,7 +766,7 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 
        cmd.opcode = SD_APP_OP_COND;
        cmd.arg = ocr;
-       cmd.flags = MMC_RSP_R3;
+       cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
 
        for (i = 100; i; i--) {
                err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
@@ -805,7 +805,7 @@ static void mmc_discover_cards(struct mmc_host *host)
 
                cmd.opcode = MMC_ALL_SEND_CID;
                cmd.arg = 0;
-               cmd.flags = MMC_RSP_R2;
+               cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
 
                err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                if (err == MMC_ERR_TIMEOUT) {
@@ -835,7 +835,7 @@ static void mmc_discover_cards(struct mmc_host *host)
 
                        cmd.opcode = SD_SEND_RELATIVE_ADDR;
                        cmd.arg = 0;
-                       cmd.flags = MMC_RSP_R6;
+                       cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
 
                        err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                        if (err != MMC_ERR_NONE)
@@ -856,7 +856,7 @@ static void mmc_discover_cards(struct mmc_host *host)
                } else {
                        cmd.opcode = MMC_SET_RELATIVE_ADDR;
                        cmd.arg = card->rca << 16;
-                       cmd.flags = MMC_RSP_R1;
+                       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
                        err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                        if (err != MMC_ERR_NONE)
@@ -878,7 +878,7 @@ static void mmc_read_csds(struct mmc_host *host)
 
                cmd.opcode = MMC_SEND_CSD;
                cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R2;
+               cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
 
                err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                if (err != MMC_ERR_NONE) {
@@ -920,7 +920,7 @@ static void mmc_read_scrs(struct mmc_host *host)
 
                cmd.opcode = MMC_APP_CMD;
                cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
                err = mmc_wait_for_cmd(host, &cmd, 0);
                if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
@@ -932,7 +932,7 @@ static void mmc_read_scrs(struct mmc_host *host)
 
                cmd.opcode = SD_APP_SEND_SCR;
                cmd.arg = 0;
-               cmd.flags = MMC_RSP_R1;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 
                memset(&data, 0, sizeof(struct mmc_data));
 
@@ -1003,7 +1003,7 @@ static void mmc_check_cards(struct mmc_host *host)
 
                cmd.opcode = MMC_SEND_STATUS;
                cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
                err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                if (err == MMC_ERR_NONE)
index 5b014c370e809dc5ecfd6acd57384f6f6295877c..8eb2a2ede64b5c1272515c7f2d37150a5eb792df 100644 (file)
@@ -171,14 +171,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                brq.mrq.data = &brq.data;
 
                brq.cmd.arg = req->sector << 9;
-               brq.cmd.flags = MMC_RSP_R1;
+               brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
                brq.data.timeout_ns = card->csd.tacc_ns * 10;
                brq.data.timeout_clks = card->csd.tacc_clks * 10;
                brq.data.blksz_bits = md->block_bits;
                brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
                brq.stop.opcode = MMC_STOP_TRANSMISSION;
                brq.stop.arg = 0;
-               brq.stop.flags = MMC_RSP_R1B;
+               brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
 
                if (rq_data_dir(req) == READ) {
                        brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
@@ -223,7 +223,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
                        cmd.opcode = MMC_SEND_STATUS;
                        cmd.arg = card->rca << 16;
-                       cmd.flags = MMC_RSP_R1;
+                       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
                        err = mmc_wait_for_cmd(card->host, &cmd, 5);
                        if (err) {
                                printk(KERN_ERR "%s: error %d requesting status\n",
@@ -430,7 +430,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
        mmc_card_claim_host(card);
        cmd.opcode = MMC_SET_BLOCKLEN;
        cmd.arg = 1 << md->block_bits;
-       cmd.flags = MMC_RSP_R1;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 5);
        mmc_card_release_host(card);
 
index 634ef53e85a50e63bbb52a5ae3008c7297a73f5d..37ee7f8dc82fe305195472e0ad5dd281e5c5f219 100644 (file)
@@ -124,15 +124,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
        }
 
        c |= cmd->opcode | MCI_CPSM_ENABLE;
-       switch (cmd->flags & MMC_RSP_MASK) {
-       case MMC_RSP_NONE:
-       default:
-               break;
-       case MMC_RSP_LONG:
-               c |= MCI_CPSM_LONGRSP;
-       case MMC_RSP_SHORT:
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136)
+                       c |= MCI_CPSM_LONGRSP;
                c |= MCI_CPSM_RESPONSE;
-               break;
        }
        if (/*interrupt*/0)
                c |= MCI_CPSM_INTERRUPT;
index ee8f8a0420d1c7d16c164d65746f9c9411141892..285d7d0680977a6fbba99139a71a77fe7645d168 100644 (file)
@@ -178,14 +178,15 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd,
        if (cmd->flags & MMC_RSP_BUSY)
                cmdat |= CMDAT_BUSY;
 
-       switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) {
-       case MMC_RSP_SHORT | MMC_RSP_CRC:
+#define RSP_TYPE(x)    ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+       switch (RSP_TYPE(mmc_resp_type(cmd))) {
+       case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */
                cmdat |= CMDAT_RESP_SHORT;
                break;
-       case MMC_RSP_SHORT:
+       case RSP_TYPE(MMC_RSP_R3):
                cmdat |= CMDAT_RESP_R3;
                break;
-       case MMC_RSP_LONG | MMC_RSP_CRC:
+       case RSP_TYPE(MMC_RSP_R2):
                cmdat |= CMDAT_RESP_R2;
                break;
        default:
index f257576253613f6ca7d90f1fb2f9d545f2bfbfee..3be397d436fab83c9d76f5576eb5bcfda953aeeb 100644 (file)
@@ -459,7 +459,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
        /*
         * Do we expect a reply?
         */
-       if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) {
+       if (cmd->flags & MMC_RSP_PRESENT) {
                /*
                 * Read back status.
                 */
@@ -476,10 +476,10 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
                        cmd->error = MMC_ERR_BADCRC;
                /* All ok */
                else {
-                       if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
-                               wbsd_get_short_reply(host, cmd);
-                       else
+                       if (cmd->flags & MMC_RSP_136)
                                wbsd_get_long_reply(host, cmd);
+                       else
+                               wbsd_get_short_reply(host, cmd);
                }
        }
 
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 42d1de155292439c3c950ad728f511ccefb4c3c2..0f4361c8466b3d495442e9ca69fd17250606b0ef 100644 (file)
@@ -893,20 +893,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 93b5dc4082ff24e3e015244c31ff3e7a35d757d1..e9749b0eecd8a27e5a1d09ece2eee57e63c14529 100644 (file)
@@ -883,8 +883,6 @@ config CONFIGFS_FS
          Both sysfs and configfs can and should exist together on the
          same system. One is not a replacement for the other.
 
-         If unsure, say N.
-
 endmenu
 
 menu "Miscellaneous filesystems"
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 8899d9c5f6bf76ec7f8d4a3b825ca95a182b85d1..f70e46951b3781ec1baa4677e715919ac78724c2 100644 (file)
@@ -36,6 +36,7 @@ struct configfs_dirent {
        int                     s_type;
        umode_t                 s_mode;
        struct dentry           * s_dentry;
+       struct iattr            * s_iattr;
 };
 
 #define CONFIGFS_ROOT          0x0001
@@ -48,10 +49,11 @@ struct configfs_dirent {
 #define CONFIGFS_NOT_PINNED    (CONFIGFS_ITEM_ATTR)
 
 extern struct vfsmount * configfs_mount;
+extern kmem_cache_t *configfs_dir_cachep;
 
 extern int configfs_is_root(struct config_item *item);
 
-extern struct inode * configfs_new_inode(mode_t mode);
+extern struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent *);
 extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
 extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
@@ -63,6 +65,7 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
 
 extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
 extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
+extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
 
 extern int configfs_pin_fs(void);
 extern void configfs_release_fs(void);
@@ -120,8 +123,10 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
 
 static inline void release_configfs_dirent(struct configfs_dirent * sd)
 {
-       if (!(sd->s_type & CONFIGFS_ROOT))
-               kfree(sd);
+       if (!(sd->s_type & CONFIGFS_ROOT)) {
+               kfree(sd->s_iattr);
+               kmem_cache_free(configfs_dir_cachep, sd);
+       }
 }
 
 static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd)
index b668ec61527e19b6c2160c7fd65595b536372964..ca60e3abef451d64ce9df9374b2b49dfe8a5d97c 100644 (file)
@@ -72,7 +72,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare
 {
        struct configfs_dirent * sd;
 
-       sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+       sd = kmem_cache_alloc(configfs_dir_cachep, GFP_KERNEL);
        if (!sd)
                return NULL;
 
@@ -136,13 +136,19 @@ static int create_dir(struct config_item * k, struct dentry * p,
        int error;
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 
-       error = configfs_create(d, mode, init_dir);
+       error = configfs_make_dirent(p->d_fsdata, d, k, mode,
+                                    CONFIGFS_DIR);
        if (!error) {
-               error = configfs_make_dirent(p->d_fsdata, d, k, mode,
-                                          CONFIGFS_DIR);
+               error = configfs_create(d, mode, init_dir);
                if (!error) {
                        p->d_inode->i_nlink++;
                        (d)->d_op = &configfs_dentry_ops;
+               } else {
+                       struct configfs_dirent *sd = d->d_fsdata;
+                       if (sd) {
+                               list_del_init(&sd->s_sibling);
+                               configfs_put(sd);
+                       }
                }
        }
        return error;
@@ -182,12 +188,19 @@ int configfs_create_link(struct configfs_symlink *sl,
        int err = 0;
        umode_t mode = S_IFLNK | S_IRWXUGO;
 
-       err = configfs_create(dentry, mode, init_symlink);
+       err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode,
+                                  CONFIGFS_ITEM_LINK);
        if (!err) {
-               err = configfs_make_dirent(parent->d_fsdata, dentry, sl,
-                                        mode, CONFIGFS_ITEM_LINK);
+               err = configfs_create(dentry, mode, init_symlink);
                if (!err)
                        dentry->d_op = &configfs_dentry_ops;
+               else {
+                       struct configfs_dirent *sd = dentry->d_fsdata;
+                       if (sd) {
+                               list_del_init(&sd->s_sibling);
+                               configfs_put(sd);
+                       }
+               }
        }
        return err;
 }
@@ -241,13 +254,15 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
        struct configfs_attribute * attr = sd->s_element;
        int error;
 
+       dentry->d_fsdata = configfs_get(sd);
+       sd->s_dentry = dentry;
        error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file);
-       if (error)
+       if (error) {
+               configfs_put(sd);
                return error;
+       }
 
        dentry->d_op = &configfs_dentry_ops;
-       dentry->d_fsdata = configfs_get(sd);
-       sd->s_dentry = dentry;
        d_rehash(dentry);
 
        return 0;
@@ -839,6 +854,7 @@ struct inode_operations configfs_dir_inode_operations = {
        .symlink        = configfs_symlink,
        .unlink         = configfs_unlink,
        .lookup         = configfs_lookup,
+       .setattr        = configfs_setattr,
 };
 
 #if 0
index c26cd61f13afd3c9cc02ff7799ff95c58f622df5..3921920d8716a32f3495e8200abad6c0b2d08f2c 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/fs.h>
 #include <linux/module.h>
-#include <linux/dnotify.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
@@ -150,7 +149,7 @@ out:
 /**
  *     fill_write_buffer - copy buffer from userspace.
  *     @buffer:        data buffer for file.
- *     @userbuf:       data from user.
+ *     @buf:           data from user.
  *     @count:         number of bytes in @userbuf.
  *
  *     Allocate @buffer->page if it hasn't been already, then
@@ -177,8 +176,9 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
 
 /**
  *     flush_write_buffer - push buffer to config_item.
- *     @file:          file pointer.
+ *     @dentry:        dentry to the attribute
  *     @buffer:        data buffer for file.
+ *     @count:         number of bytes
  *
  *     Get the correct pointers for the config_item and the attribute we're
  *     dealing with, then call the store() method for the attribute,
@@ -217,15 +217,16 @@ static ssize_t
 configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
        struct configfs_buffer * buffer = file->private_data;
+       ssize_t len;
 
        down(&buffer->sem);
-       count = fill_write_buffer(buffer,buf,count);
-       if (count > 0)
-               count = flush_write_buffer(file->f_dentry,buffer,count);
-       if (count > 0)
-               *ppos += count;
+       len = fill_write_buffer(buffer, buf, count);
+       if (len > 0)
+               len = flush_write_buffer(file->f_dentry, buffer, count);
+       if (len > 0)
+               *ppos += len;
        up(&buffer->sem);
-       return count;
+       return len;
 }
 
 static int check_perm(struct inode * inode, struct file * file)
index 6577c588de9d31d1795f7cd683fd81a149a716d1..c153bd9534cb6d72066094c8110ce0f35fec3ff3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/pagemap.h>
 #include <linux/namei.h>
 #include <linux/backing-dev.h>
+#include <linux/capability.h>
 
 #include <linux/configfs.h>
 #include "configfs_internal.h"
@@ -48,18 +49,107 @@ static struct backing_dev_info configfs_backing_dev_info = {
        .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
-struct inode * configfs_new_inode(mode_t mode)
+static struct inode_operations configfs_inode_operations ={
+       .setattr        = configfs_setattr,
+};
+
+int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
+{
+       struct inode * inode = dentry->d_inode;
+       struct configfs_dirent * sd = dentry->d_fsdata;
+       struct iattr * sd_iattr;
+       unsigned int ia_valid = iattr->ia_valid;
+       int error;
+
+       if (!sd)
+               return -EINVAL;
+
+       sd_iattr = sd->s_iattr;
+
+       error = inode_change_ok(inode, iattr);
+       if (error)
+               return error;
+
+       error = inode_setattr(inode, iattr);
+       if (error)
+               return error;
+
+       if (!sd_iattr) {
+               /* setting attributes for the first time, allocate now */
+               sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+               if (!sd_iattr)
+                       return -ENOMEM;
+               /* assign default attributes */
+               memset(sd_iattr, 0, sizeof(struct iattr));
+               sd_iattr->ia_mode = sd->s_mode;
+               sd_iattr->ia_uid = 0;
+               sd_iattr->ia_gid = 0;
+               sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
+               sd->s_iattr = sd_iattr;
+       }
+
+       /* attributes were changed atleast once in past */
+
+       if (ia_valid & ATTR_UID)
+               sd_iattr->ia_uid = iattr->ia_uid;
+       if (ia_valid & ATTR_GID)
+               sd_iattr->ia_gid = iattr->ia_gid;
+       if (ia_valid & ATTR_ATIME)
+               sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_MTIME)
+               sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_CTIME)
+               sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_MODE) {
+               umode_t mode = iattr->ia_mode;
+
+               if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+                       mode &= ~S_ISGID;
+               sd_iattr->ia_mode = sd->s_mode = mode;
+       }
+
+       return error;
+}
+
+static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
+{
+       inode->i_mode = mode;
+       inode->i_uid = 0;
+       inode->i_gid = 0;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
+static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
+{
+       inode->i_mode = iattr->ia_mode;
+       inode->i_uid = iattr->ia_uid;
+       inode->i_gid = iattr->ia_gid;
+       inode->i_atime = iattr->ia_atime;
+       inode->i_mtime = iattr->ia_mtime;
+       inode->i_ctime = iattr->ia_ctime;
+}
+
+struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
 {
        struct inode * inode = new_inode(configfs_sb);
        if (inode) {
-               inode->i_mode = mode;
-               inode->i_uid = 0;
-               inode->i_gid = 0;
                inode->i_blksize = PAGE_CACHE_SIZE;
                inode->i_blocks = 0;
-               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                inode->i_mapping->a_ops = &configfs_aops;
                inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
+               inode->i_op = &configfs_inode_operations;
+
+               if (sd->s_iattr) {
+                       /* sysfs_dirent has non-default attributes
+                        * get them for the new inode from persistent copy
+                        * in sysfs_dirent
+                        */
+                       set_inode_attr(inode, sd->s_iattr);
+               } else
+                       set_default_inode_attr(inode, mode);
        }
        return inode;
 }
@@ -70,7 +160,8 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
        struct inode * inode = NULL;
        if (dentry) {
                if (!dentry->d_inode) {
-                       if ((inode = configfs_new_inode(mode))) {
+                       struct configfs_dirent *sd = dentry->d_fsdata;
+                       if ((inode = configfs_new_inode(mode, sd))) {
                                if (dentry->d_parent && dentry->d_parent->d_inode) {
                                        struct inode *p_inode = dentry->d_parent->d_inode;
                                        p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
@@ -103,10 +194,9 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
  */
 const unsigned char * configfs_get_name(struct configfs_dirent *sd)
 {
-       struct attribute * attr;
+       struct configfs_attribute *attr;
 
-       if (!sd || !sd->s_element)
-               BUG();
+       BUG_ON(!sd || !sd->s_element);
 
        /* These always have a dentry, so use that */
        if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK))
@@ -114,7 +204,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd)
 
        if (sd->s_type & CONFIGFS_ITEM_ATTR) {
                attr = sd->s_element;
-               return attr->name;
+               return attr->ca_name;
        }
        return NULL;
 }
@@ -130,13 +220,17 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
 
        if (dentry) {
                spin_lock(&dcache_lock);
+               spin_lock(&dentry->d_lock);
                if (!(d_unhashed(dentry) && dentry->d_inode)) {
                        dget_locked(dentry);
                        __d_drop(dentry);
+                       spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
                        simple_unlink(parent->d_inode, dentry);
-               } else
+               } else {
+                       spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
+               }
        }
 }
 
@@ -145,6 +239,10 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name)
        struct configfs_dirent * sd;
        struct configfs_dirent * parent_sd = dir->d_fsdata;
 
+       if (dir->d_inode == NULL)
+               /* no inode means this hasn't been made visible yet */
+               return;
+
        mutex_lock(&dir->d_inode->i_mutex);
        list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
                if (!sd->s_element)
index 1a2f6f6a4d917da58791d8f1287f29a90e14bed1..f920d30478e531a7a656548d9d9c7169a0cc99bf 100644 (file)
@@ -38,6 +38,7 @@
 
 struct vfsmount * configfs_mount = NULL;
 struct super_block * configfs_sb = NULL;
+kmem_cache_t *configfs_dir_cachep;
 static int configfs_mnt_count = 0;
 
 static struct super_operations configfs_ops = {
@@ -62,6 +63,7 @@ static struct configfs_dirent configfs_root = {
        .s_children     = LIST_HEAD_INIT(configfs_root.s_children),
        .s_element      = &configfs_root_group.cg_item,
        .s_type         = CONFIGFS_ROOT,
+       .s_iattr        = NULL,
 };
 
 static int configfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -73,9 +75,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = CONFIGFS_MAGIC;
        sb->s_op = &configfs_ops;
+       sb->s_time_gran = 1;
        configfs_sb = sb;
 
-       inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
+       inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+                                  &configfs_root);
        if (inode) {
                inode->i_op = &configfs_dir_inode_operations;
                inode->i_fop = &configfs_dir_operations;
@@ -128,19 +132,31 @@ static decl_subsys(config, NULL, NULL);
 
 static int __init configfs_init(void)
 {
-       int err;
+       int err = -ENOMEM;
+
+       configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",
+                                               sizeof(struct configfs_dirent),
+                                               0, 0, NULL, NULL);
+       if (!configfs_dir_cachep)
+               goto out;
 
        kset_set_kset_s(&config_subsys, kernel_subsys);
        err = subsystem_register(&config_subsys);
-       if (err)
-               return err;
+       if (err) {
+               kmem_cache_destroy(configfs_dir_cachep);
+               configfs_dir_cachep = NULL;
+               goto out;
+       }
 
        err = register_filesystem(&configfs_fs_type);
        if (err) {
                printk(KERN_ERR "configfs: Unable to register filesystem!\n");
                subsystem_unregister(&config_subsys);
+               kmem_cache_destroy(configfs_dir_cachep);
+               configfs_dir_cachep = NULL;
        }
 
+out:
        return err;
 }
 
@@ -148,11 +164,13 @@ static void __exit configfs_exit(void)
 {
        unregister_filesystem(&configfs_fs_type);
        subsystem_unregister(&config_subsys);
+       kmem_cache_destroy(configfs_dir_cachep);
+       configfs_dir_cachep = NULL;
 }
 
 MODULE_AUTHOR("Oracle");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.1");
+MODULE_VERSION("0.0.2");
 MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
 
 module_init(configfs_init);
index 50f5840521a93c0b91fda648a9f3fc9debc659d8..e5512e295cf2970b865d7ee398ed41d87634e067 100644 (file)
@@ -162,8 +162,7 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry)
        if (!(sd->s_type & CONFIGFS_ITEM_LINK))
                goto out;
 
-       if (dentry->d_parent == configfs_sb->s_root)
-               BUG();
+       BUG_ON(dentry->d_parent == configfs_sb->s_root);
 
        sl = sd->s_element;
 
@@ -277,5 +276,6 @@ struct inode_operations configfs_symlink_inode_operations = {
        .follow_link = configfs_follow_link,
        .readlink = generic_readlink,
        .put_link = configfs_put_link,
+       .setattr = configfs_setattr,
 };
 
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 145524039577c2719bd6c95cced7fb3469cf4453..220058d8616d143d7afb386a395b818b60a855aa 100644 (file)
 #define NLMDBG_FACILITY                NLMDBG_CLIENT
 #define NLMCLNT_GRACE_WAIT     (5*HZ)
 #define NLMCLNT_POLL_TIMEOUT   (30*HZ)
+#define NLMCLNT_MAX_RETRIES    3
 
 static int     nlmclnt_test(struct nlm_rqst *, struct file_lock *);
 static int     nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
 static int     nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
 static int     nlm_stat_to_errno(u32 stat);
 static void    nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
+static int     nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
 
 static const struct rpc_call_ops nlmclnt_unlock_ops;
 static const struct rpc_call_ops nlmclnt_cancel_ops;
@@ -598,7 +600,7 @@ out_unblock:
        nlmclnt_finish_block(req);
        /* Cancel the blocked request if it is still pending */
        if (resp->status == NLM_LCK_BLOCKED)
-               nlmclnt_cancel(host, fl);
+               nlmclnt_cancel(host, req->a_args.block, fl);
 out:
        nlmclnt_release_lockargs(req);
        return status;
@@ -728,8 +730,7 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = {
  * We always use an async RPC call for this in order not to hang a
  * process that has been Ctrl-C'ed.
  */
-int
-nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
+static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
 {
        struct nlm_rqst *req;
        unsigned long   flags;
@@ -750,6 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
        req->a_flags = RPC_TASK_ASYNC;
 
        nlmclnt_setlockargs(req, fl);
+       req->a_args.block = block;
 
        status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
        if (status < 0) {
@@ -801,6 +803,9 @@ die:
        return;
 
 retry_cancel:
+       /* Don't ever retry more than 3 times */
+       if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
+               goto die;
        nlm_rebind_host(req->a_host);
        rpc_restart_call(task);
        rpc_delay(task, 30 * HZ);
index 10ae377e68ff2e0e3253a51ef411c040a3a89f7d..04ab2fc360e792404815e67ee44c3adb03510a25 100644 (file)
@@ -481,7 +481,7 @@ retry:
                if (wdata->verf.committed != NFS_FILE_SYNC) {
                        need_commit = 1;
                        if (memcmp(&first_verf.verifier, &wdata->verf.verifier,
-                                       sizeof(first_verf.verifier)));
+                                       sizeof(first_verf.verifier)))
                                goto sync_retry;
                }
 
index d424041b38e9b568ffba1a287639f68f4c9d07f3..bae3d7548beae59961a436033fd69a99da391a57 100644 (file)
@@ -58,7 +58,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
                goto out;
        }
 
-       down(&OCFS2_I(inode)->ip_io_sem);
+       mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
 
        lock_buffer(bh);
        set_buffer_uptodate(bh);
@@ -82,7 +82,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
                brelse(bh);
        }
 
-       up(&OCFS2_I(inode)->ip_io_sem);
+       mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 out:
        mlog_exit(ret);
        return ret;
@@ -125,13 +125,13 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                flags &= ~OCFS2_BH_CACHED;
 
        if (inode)
-               down(&OCFS2_I(inode)->ip_io_sem);
+               mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
        for (i = 0 ; i < nr ; i++) {
                if (bhs[i] == NULL) {
                        bhs[i] = sb_getblk(sb, block++);
                        if (bhs[i] == NULL) {
                                if (inode)
-                                       up(&OCFS2_I(inode)->ip_io_sem);
+                                       mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
                                status = -EIO;
                                mlog_errno(status);
                                goto bail;
@@ -220,7 +220,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                        ocfs2_set_buffer_uptodate(inode, bh);
        }
        if (inode)
-               up(&OCFS2_I(inode)->ip_io_sem);
+               mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 
        mlog(ML_BH_IO, "block=(%"MLFu64"), nr=(%d), cached=%s\n", block, nr,
             (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes");
index 7307ba528913e660a0ebb235944c7736d5323fac..d08971d29b63b39c9478945bc64e900abc742a07 100644 (file)
@@ -917,8 +917,9 @@ static int o2hb_thread(void *data)
                elapsed_msec = o2hb_elapsed_msecs(&before_hb, &after_hb);
 
                mlog(0, "start = %lu.%lu, end = %lu.%lu, msec = %u\n",
-                    before_hb.tv_sec, before_hb.tv_usec,
-                    after_hb.tv_sec, after_hb.tv_usec, elapsed_msec);
+                    before_hb.tv_sec, (unsigned long) before_hb.tv_usec,
+                    after_hb.tv_sec, (unsigned long) after_hb.tv_usec,
+                    elapsed_msec);
 
                if (elapsed_msec < reg->hr_timeout_ms) {
                        /* the kthread api has blocked signals for us so no
index 35d92c01a9724110f6de8a35c87359afd9b9485b..d22d4cf08db165a80f8cd14ffe6304ebfba45e6a 100644 (file)
@@ -1285,14 +1285,16 @@ static void o2net_idle_timer(unsigned long data)
        mlog(ML_NOTICE, "here are some times that might help debug the "
             "situation: (tmr %ld.%ld now %ld.%ld dr %ld.%ld adv "
             "%ld.%ld:%ld.%ld func (%08x:%u) %ld.%ld:%ld.%ld)\n",
-            sc->sc_tv_timer.tv_sec, sc->sc_tv_timer.tv_usec, 
-            now.tv_sec, now.tv_usec,
-            sc->sc_tv_data_ready.tv_sec, sc->sc_tv_data_ready.tv_usec, 
-            sc->sc_tv_advance_start.tv_sec, sc->sc_tv_advance_start.tv_usec, 
-            sc->sc_tv_advance_stop.tv_sec, sc->sc_tv_advance_stop.tv_usec, 
+            sc->sc_tv_timer.tv_sec, (long) sc->sc_tv_timer.tv_usec, 
+            now.tv_sec, (long) now.tv_usec,
+            sc->sc_tv_data_ready.tv_sec, (long) sc->sc_tv_data_ready.tv_usec,
+            sc->sc_tv_advance_start.tv_sec,
+            (long) sc->sc_tv_advance_start.tv_usec,
+            sc->sc_tv_advance_stop.tv_sec,
+            (long) sc->sc_tv_advance_stop.tv_usec,
             sc->sc_msg_key, sc->sc_msg_type,
-            sc->sc_tv_func_start.tv_sec, sc->sc_tv_func_start.tv_usec,
-            sc->sc_tv_func_stop.tv_sec, sc->sc_tv_func_stop.tv_usec);
+            sc->sc_tv_func_start.tv_sec, (long) sc->sc_tv_func_start.tv_usec,
+            sc->sc_tv_func_stop.tv_sec, (long) sc->sc_tv_func_stop.tv_usec);
 
        o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
 }
index 3fecba0a60233ebc8458deb970f13d76c74deaab..42eb53b5293be362df0b5d3a608c5f360a004122 100644 (file)
@@ -657,6 +657,7 @@ void dlm_complete_thread(struct dlm_ctxt *dlm);
 int dlm_launch_recovery_thread(struct dlm_ctxt *dlm);
 void dlm_complete_recovery_thread(struct dlm_ctxt *dlm);
 void dlm_wait_for_recovery(struct dlm_ctxt *dlm);
+int dlm_is_node_dead(struct dlm_ctxt *dlm, u8 node);
 
 void dlm_put(struct dlm_ctxt *dlm);
 struct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm);
index da3c22045f898152b7b2ccbd5ac2f1761b5bd9c0..6ee30837389c9feed2ba7af4475cbaf51b1932e7 100644 (file)
@@ -573,8 +573,11 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
        spin_lock(&dlm_domain_lock);
        dlm = __dlm_lookup_domain_full(query->domain, query->name_len);
        /* Once the dlm ctxt is marked as leaving then we don't want
-        * to be put in someone's domain map. */
+        * to be put in someone's domain map. 
+        * Also, explicitly disallow joining at certain troublesome
+        * times (ie. during recovery). */
        if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) {
+               int bit = query->node_idx;
                spin_lock(&dlm->spinlock);
 
                if (dlm->dlm_state == DLM_CTXT_NEW &&
@@ -586,6 +589,19 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
                } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) {
                        /* Disallow parallel joins. */
                        response = JOIN_DISALLOW;
+               } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) {
+                       mlog(ML_NOTICE, "node %u trying to join, but recovery "
+                            "is ongoing.\n", bit);
+                       response = JOIN_DISALLOW;
+               } else if (test_bit(bit, dlm->recovery_map)) {
+                       mlog(ML_NOTICE, "node %u trying to join, but it "
+                            "still needs recovery.\n", bit);
+                       response = JOIN_DISALLOW;
+               } else if (test_bit(bit, dlm->domain_map)) {
+                       mlog(ML_NOTICE, "node %u trying to join, but it "
+                            "is still in the domain! needs recovery?\n",
+                            bit);
+                       response = JOIN_DISALLOW;
                } else {
                        /* Alright we're fully a part of this domain
                         * so we keep some state as to who's joining
index 27e984f7e4cdbd40585a2927e3f9080282ed7af3..a3194fe173d97b498b5753777e85306569ed094b 100644 (file)
@@ -1050,17 +1050,10 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm,
        node = dlm_bitmap_diff_iter_next(&bdi, &sc);
        while (node >= 0) {
                if (sc == NODE_UP) {
-                       /* a node came up.  easy.  might not even need
-                        * to talk to it if its node number is higher
-                        * or if we are already blocked. */
-                       mlog(0, "node up! %d\n", node);
-                       if (blocked)
-                               goto next;
-
-                       if (node > dlm->node_num) {
-                               mlog(0, "node > this node. skipping.\n");
-                               goto next;
-                       }
+                       /* a node came up.  clear any old vote from
+                        * the response map and set it in the vote map
+                        * then restart the mastery. */
+                       mlog(ML_NOTICE, "node %d up while restarting\n", node);
 
                        /* redo the master request, but only for the new node */
                        mlog(0, "sending request to new node\n");
@@ -2005,6 +1998,15 @@ fail:
                                break;
 
                        mlog(0, "timed out during migration\n");
+                       /* avoid hang during shutdown when migrating lockres 
+                        * to a node which also goes down */
+                       if (dlm_is_node_dead(dlm, target)) {
+                               mlog(0, "%s:%.*s: expected migration target %u "
+                                    "is no longer up.  restarting.\n",
+                                    dlm->name, res->lockname.len,
+                                    res->lockname.name, target);
+                               ret = -ERESTARTSYS;
+                       }
                }
                if (ret == -ERESTARTSYS) {
                        /* migration failed, detach and clean up mle */
index 0c8eb1093f0056bb4d8673e42c633c5a6ce3e8fe..186e9a76aa5807565ad09e31e0bd0fa7584dcab5 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/inet.h>
 #include <linux/timer.h>
 #include <linux/kthread.h>
+#include <linux/delay.h>
 
 
 #include "cluster/heartbeat.h"
@@ -256,6 +257,27 @@ static int dlm_recovery_thread(void *data)
        return 0;
 }
 
+/* returns true when the recovery master has contacted us */
+static int dlm_reco_master_ready(struct dlm_ctxt *dlm)
+{
+       int ready;
+       spin_lock(&dlm->spinlock);
+       ready = (dlm->reco.new_master != O2NM_INVALID_NODE_NUM);
+       spin_unlock(&dlm->spinlock);
+       return ready;
+}
+
+/* returns true if node is no longer in the domain
+ * could be dead or just not joined */
+int dlm_is_node_dead(struct dlm_ctxt *dlm, u8 node)
+{
+       int dead;
+       spin_lock(&dlm->spinlock);
+       dead = test_bit(node, dlm->domain_map);
+       spin_unlock(&dlm->spinlock);
+       return dead;
+}
+
 /* callers of the top-level api calls (dlmlock/dlmunlock) should
  * block on the dlm->reco.event when recovery is in progress.
  * the dlm recovery thread will set this state when it begins
@@ -297,6 +319,7 @@ static void dlm_end_recovery(struct dlm_ctxt *dlm)
 static int dlm_do_recovery(struct dlm_ctxt *dlm)
 {
        int status = 0;
+       int ret;
 
        spin_lock(&dlm->spinlock);
 
@@ -343,10 +366,13 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm)
                goto master_here;
 
        if (dlm->reco.new_master == O2NM_INVALID_NODE_NUM) {
-               /* choose a new master */
-               if (!dlm_pick_recovery_master(dlm)) {
+               /* choose a new master, returns 0 if this node
+                * is the master, -EEXIST if it's another node.
+                * this does not return until a new master is chosen
+                * or recovery completes entirely. */
+               ret = dlm_pick_recovery_master(dlm);
+               if (!ret) {
                        /* already notified everyone.  go. */
-                       dlm->reco.new_master = dlm->node_num;
                        goto master_here;
                }
                mlog(0, "another node will master this recovery session.\n");
@@ -371,8 +397,13 @@ master_here:
        if (status < 0) {
                mlog(ML_ERROR, "error %d remastering locks for node %u, "
                     "retrying.\n", status, dlm->reco.dead_node);
+               /* yield a bit to allow any final network messages
+                * to get handled on remaining nodes */
+               msleep(100);
        } else {
                /* success!  see if any other nodes need recovery */
+               mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n",
+                    dlm->name, dlm->reco.dead_node, dlm->node_num);
                dlm_reset_recovery(dlm);
        }
        dlm_end_recovery(dlm);
@@ -477,7 +508,7 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
                                        BUG();
                                        break;
                                case DLM_RECO_NODE_DATA_DEAD:
-                                       mlog(0, "node %u died after "
+                                       mlog(ML_NOTICE, "node %u died after "
                                             "requesting recovery info for "
                                             "node %u\n", ndata->node_num,
                                             dead_node);
@@ -485,6 +516,19 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
                                        // start all over
                                        destroy = 1;
                                        status = -EAGAIN;
+                                       /* instead of spinning like crazy here,
+                                        * wait for the domain map to catch up
+                                        * with the network state.  otherwise this
+                                        * can be hit hundreds of times before
+                                        * the node is really seen as dead. */
+                                       wait_event_timeout(dlm->dlm_reco_thread_wq,
+                                                          dlm_is_node_dead(dlm,
+                                                               ndata->node_num),
+                                                          msecs_to_jiffies(1000));
+                                       mlog(0, "waited 1 sec for %u, "
+                                            "dead? %s\n", ndata->node_num,
+                                            dlm_is_node_dead(dlm, ndata->node_num) ?
+                                            "yes" : "no");
                                        goto leave;
                                case DLM_RECO_NODE_DATA_RECEIVING:
                                case DLM_RECO_NODE_DATA_REQUESTED:
@@ -678,11 +722,27 @@ static void dlm_request_all_locks_worker(struct dlm_work_item *item, void *data)
        dlm = item->dlm;
        dead_node = item->u.ral.dead_node;
        reco_master = item->u.ral.reco_master;
+       mres = (struct dlm_migratable_lockres *)data;
+
+       if (dead_node != dlm->reco.dead_node ||
+           reco_master != dlm->reco.new_master) {
+               /* show extra debug info if the recovery state is messed */
+               mlog(ML_ERROR, "%s: bad reco state: reco(dead=%u, master=%u), "
+                    "request(dead=%u, master=%u)\n",
+                    dlm->name, dlm->reco.dead_node, dlm->reco.new_master,
+                    dead_node, reco_master);
+               mlog(ML_ERROR, "%s: name=%.*s master=%u locks=%u/%u flags=%u "
+                    "entry[0]={c=%"MLFu64",l=%u,f=%u,t=%d,ct=%d,hb=%d,n=%u}\n",
+                    dlm->name, mres->lockname_len, mres->lockname, mres->master,
+                    mres->num_locks, mres->total_locks, mres->flags,
+                    mres->ml[0].cookie, mres->ml[0].list, mres->ml[0].flags,
+                    mres->ml[0].type, mres->ml[0].convert_type,
+                    mres->ml[0].highest_blocked, mres->ml[0].node);
+               BUG();
+       }
        BUG_ON(dead_node != dlm->reco.dead_node);
        BUG_ON(reco_master != dlm->reco.new_master);
 
-       mres = (struct dlm_migratable_lockres *)data;
-
        /* lock resources should have already been moved to the
         * dlm->reco.resources list.  now move items from that list
         * to a temp list if the dead owner matches.  note that the
@@ -757,15 +817,18 @@ int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data)
                        continue;
 
                switch (ndata->state) {
+                       /* should have moved beyond INIT but not to FINALIZE yet */
                        case DLM_RECO_NODE_DATA_INIT:
                        case DLM_RECO_NODE_DATA_DEAD:
-                       case DLM_RECO_NODE_DATA_DONE:
                        case DLM_RECO_NODE_DATA_FINALIZE_SENT:
                                mlog(ML_ERROR, "bad ndata state for node %u:"
                                     " state=%d\n", ndata->node_num,
                                     ndata->state);
                                BUG();
                                break;
+                       /* these states are possible at this point, anywhere along
+                        * the line of recovery */
+                       case DLM_RECO_NODE_DATA_DONE:
                        case DLM_RECO_NODE_DATA_RECEIVING:
                        case DLM_RECO_NODE_DATA_REQUESTED:
                        case DLM_RECO_NODE_DATA_REQUESTING:
@@ -799,13 +862,31 @@ static void dlm_move_reco_locks_to_list(struct dlm_ctxt *dlm,
 {
        struct dlm_lock_resource *res;
        struct list_head *iter, *iter2;
+       struct dlm_lock *lock;
 
        spin_lock(&dlm->spinlock);
        list_for_each_safe(iter, iter2, &dlm->reco.resources) {
                res = list_entry (iter, struct dlm_lock_resource, recovering);
+               /* always prune any $RECOVERY entries for dead nodes,
+                * otherwise hangs can occur during later recovery */
                if (dlm_is_recovery_lock(res->lockname.name,
-                                        res->lockname.len))
+                                        res->lockname.len)) {
+                       spin_lock(&res->spinlock);
+                       list_for_each_entry(lock, &res->granted, list) {
+                               if (lock->ml.node == dead_node) {
+                                       mlog(0, "AHA! there was "
+                                            "a $RECOVERY lock for dead "
+                                            "node %u (%s)!\n", 
+                                            dead_node, dlm->name);
+                                       list_del_init(&lock->list);
+                                       dlm_lock_put(lock);
+                                       break;
+                               }
+                       }
+                       spin_unlock(&res->spinlock);
                        continue;
+               }
+
                if (res->owner == dead_node) {
                        mlog(0, "found lockres owned by dead node while "
                                  "doing recovery for node %u. sending it.\n",
@@ -1179,7 +1260,7 @@ static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data)
 again:
                ret = dlm_lockres_master_requery(dlm, res, &real_master);
                if (ret < 0) {
-                       mlog(0, "dlm_lockres_master_requery failure: %d\n",
+                       mlog(0, "dlm_lockres_master_requery ret=%d\n",
                                  ret);
                        goto again;
                }
@@ -1757,6 +1838,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
        struct dlm_lock_resource *res;
        int i;
        struct list_head *bucket;
+       struct dlm_lock *lock;
 
 
        /* purge any stale mles */
@@ -1780,10 +1862,25 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
                bucket = &(dlm->resources[i]);
                list_for_each(iter, bucket) {
                        res = list_entry (iter, struct dlm_lock_resource, list);
+                       /* always prune any $RECOVERY entries for dead nodes,
+                        * otherwise hangs can occur during later recovery */
                        if (dlm_is_recovery_lock(res->lockname.name,
-                                                res->lockname.len))
+                                                res->lockname.len)) {
+                               spin_lock(&res->spinlock);
+                               list_for_each_entry(lock, &res->granted, list) {
+                                       if (lock->ml.node == dead_node) {
+                                               mlog(0, "AHA! there was "
+                                                    "a $RECOVERY lock for dead "
+                                                    "node %u (%s)!\n",
+                                                    dead_node, dlm->name);
+                                               list_del_init(&lock->list);
+                                               dlm_lock_put(lock);
+                                               break;
+                                       }
+                               }
+                               spin_unlock(&res->spinlock);
                                continue;
-                       
+                       }                       
                        spin_lock(&res->spinlock);
                        /* zero the lvb if necessary */
                        dlm_revalidate_lvb(dlm, res, dead_node);
@@ -1869,12 +1966,9 @@ void dlm_hb_node_up_cb(struct o2nm_node *node, int idx, void *data)
                return;
 
        spin_lock(&dlm->spinlock);
-
        set_bit(idx, dlm->live_nodes_map);
-
-       /* notify any mles attached to the heartbeat events */
-       dlm_hb_event_notify_attached(dlm, idx, 1);
-
+       /* do NOT notify mle attached to the heartbeat events.
+        * new nodes are not interesting in mastery until joined. */
        spin_unlock(&dlm->spinlock);
 
        dlm_put(dlm);
@@ -1897,7 +1991,18 @@ static void dlm_reco_unlock_ast(void *astdata, enum dlm_status st)
        mlog(0, "unlockast for recovery lock fired!\n");
 }
 
-
+/*
+ * dlm_pick_recovery_master will continually attempt to use
+ * dlmlock() on the special "$RECOVERY" lockres with the
+ * LKM_NOQUEUE flag to get an EX.  every thread that enters
+ * this function on each node racing to become the recovery
+ * master will not stop attempting this until either:
+ * a) this node gets the EX (and becomes the recovery master),
+ * or b) dlm->reco.new_master gets set to some nodenum 
+ * != O2NM_INVALID_NODE_NUM (another node will do the reco).
+ * so each time a recovery master is needed, the entire cluster
+ * will sync at this point.  if the new master dies, that will
+ * be detected in dlm_do_recovery */
 static int dlm_pick_recovery_master(struct dlm_ctxt *dlm)
 {
        enum dlm_status ret;
@@ -1906,23 +2011,45 @@ static int dlm_pick_recovery_master(struct dlm_ctxt *dlm)
 
        mlog(0, "starting recovery of %s at %lu, dead=%u, this=%u\n",
             dlm->name, jiffies, dlm->reco.dead_node, dlm->node_num);
-retry:
+again: 
        memset(&lksb, 0, sizeof(lksb));
 
        ret = dlmlock(dlm, LKM_EXMODE, &lksb, LKM_NOQUEUE|LKM_RECOVERY,
                      DLM_RECOVERY_LOCK_NAME, dlm_reco_ast, dlm, dlm_reco_bast);
 
+       mlog(0, "%s: dlmlock($RECOVERY) returned %d, lksb=%d\n",
+            dlm->name, ret, lksb.status);
+
        if (ret == DLM_NORMAL) {
                mlog(0, "dlm=%s dlmlock says I got it (this=%u)\n",
                     dlm->name, dlm->node_num);
-               /* I am master, send message to all nodes saying
-                * that I am beginning a recovery session */
-               status = dlm_send_begin_reco_message(dlm,
-                                             dlm->reco.dead_node);
+               
+               /* got the EX lock.  check to see if another node 
+                * just became the reco master */
+               if (dlm_reco_master_ready(dlm)) {
+                       mlog(0, "%s: got reco EX lock, but %u will "
+                            "do the recovery\n", dlm->name,
+                            dlm->reco.new_master);
+                       status = -EEXIST;
+               } else {
+                       status = dlm_send_begin_reco_message(dlm,
+                                     dlm->reco.dead_node);
+                       /* this always succeeds */
+                       BUG_ON(status);
+
+                       /* set the new_master to this node */
+                       spin_lock(&dlm->spinlock);
+                       dlm->reco.new_master = dlm->node_num;
+                       spin_unlock(&dlm->spinlock);
+               }
 
                /* recovery lock is a special case.  ast will not get fired,
                 * so just go ahead and unlock it. */
                ret = dlmunlock(dlm, &lksb, 0, dlm_reco_unlock_ast, dlm);
+               if (ret == DLM_DENIED) {
+                       mlog(0, "got DLM_DENIED, trying LKM_CANCEL\n");
+                       ret = dlmunlock(dlm, &lksb, LKM_CANCEL, dlm_reco_unlock_ast, dlm);
+               }
                if (ret != DLM_NORMAL) {
                        /* this would really suck. this could only happen
                         * if there was a network error during the unlock
@@ -1930,20 +2057,42 @@ retry:
                         * is actually "done" and the lock structure is
                         * even freed.  we can continue, but only
                         * because this specific lock name is special. */
-                       mlog(0, "dlmunlock returned %d\n", ret);
-               }
-
-               if (status < 0) {
-                       mlog(0, "failed to send recovery message. "
-                                  "must retry with new node map.\n");
-                       goto retry;
+                       mlog(ML_ERROR, "dlmunlock returned %d\n", ret);
                }
        } else if (ret == DLM_NOTQUEUED) {
                mlog(0, "dlm=%s dlmlock says another node got it (this=%u)\n",
                     dlm->name, dlm->node_num);
                /* another node is master. wait on
-                * reco.new_master != O2NM_INVALID_NODE_NUM */
+                * reco.new_master != O2NM_INVALID_NODE_NUM 
+                * for at most one second */
+               wait_event_timeout(dlm->dlm_reco_thread_wq,
+                                        dlm_reco_master_ready(dlm),
+                                        msecs_to_jiffies(1000));
+               if (!dlm_reco_master_ready(dlm)) {
+                       mlog(0, "%s: reco master taking awhile\n",
+                            dlm->name);
+                       goto again;
+               }
+               /* another node has informed this one that it is reco master */
+               mlog(0, "%s: reco master %u is ready to recover %u\n",
+                    dlm->name, dlm->reco.new_master, dlm->reco.dead_node);
                status = -EEXIST;
+       } else {
+               struct dlm_lock_resource *res;
+
+               /* dlmlock returned something other than NOTQUEUED or NORMAL */
+               mlog(ML_ERROR, "%s: got %s from dlmlock($RECOVERY), "
+                    "lksb.status=%s\n", dlm->name, dlm_errname(ret),
+                    dlm_errname(lksb.status));
+               res = dlm_lookup_lockres(dlm, DLM_RECOVERY_LOCK_NAME,
+                                        DLM_RECOVERY_LOCK_NAME_LEN);
+               if (res) {
+                       dlm_print_one_lock_resource(res);
+                       dlm_lockres_put(res);
+               } else {
+                       mlog(ML_ERROR, "recovery lock not found\n");
+               }
+               BUG();
        }
 
        return status;
@@ -1982,7 +2131,7 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
                        mlog(0, "not sending begin reco to self\n");
                        continue;
                }
-
+retry:
                ret = -EINVAL;
                mlog(0, "attempting to send begin reco msg to %d\n",
                          nodenum);
@@ -1991,8 +2140,17 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
                /* negative status is handled ok by caller here */
                if (ret >= 0)
                        ret = status;
+               if (dlm_is_host_down(ret)) {
+                       /* node is down.  not involved in recovery
+                        * so just keep going */
+                       mlog(0, "%s: node %u was down when sending "
+                            "begin reco msg (%d)\n", dlm->name, nodenum, ret);
+                       ret = 0;
+               }
                if (ret < 0) {
                        struct dlm_lock_resource *res;
+                       /* this is now a serious problem, possibly ENOMEM 
+                        * in the network stack.  must retry */
                        mlog_errno(ret);
                        mlog(ML_ERROR, "begin reco of dlm %s to node %u "
                            " returned %d\n", dlm->name, nodenum, ret);
@@ -2004,7 +2162,10 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
                        } else {
                                mlog(ML_ERROR, "recovery lock not found\n");
                        }
-                       break;
+                       /* sleep for a bit in hopes that we can avoid 
+                        * another ENOMEM */
+                       msleep(100);
+                       goto retry;
                }
        }
 
@@ -2027,19 +2188,34 @@ int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data)
 
        spin_lock(&dlm->spinlock);
        if (dlm->reco.new_master != O2NM_INVALID_NODE_NUM) {
-               mlog(0, "new_master already set to %u!\n",
-                         dlm->reco.new_master);
+               if (test_bit(dlm->reco.new_master, dlm->recovery_map)) {
+                       mlog(0, "%s: new_master %u died, changing "
+                            "to %u\n", dlm->name, dlm->reco.new_master,
+                            br->node_idx);
+               } else {
+                       mlog(0, "%s: new_master %u NOT DEAD, changing "
+                            "to %u\n", dlm->name, dlm->reco.new_master,
+                            br->node_idx);
+                       /* may not have seen the new master as dead yet */
+               }
        }
        if (dlm->reco.dead_node != O2NM_INVALID_NODE_NUM) {
-               mlog(0, "dead_node already set to %u!\n",
-                         dlm->reco.dead_node);
+               mlog(ML_NOTICE, "%s: dead_node previously set to %u, "
+                    "node %u changing it to %u\n", dlm->name, 
+                    dlm->reco.dead_node, br->node_idx, br->dead_node);
        }
        dlm->reco.new_master = br->node_idx;
        dlm->reco.dead_node = br->dead_node;
        if (!test_bit(br->dead_node, dlm->recovery_map)) {
-               mlog(ML_ERROR, "recovery master %u sees %u as dead, but this "
+               mlog(0, "recovery master %u sees %u as dead, but this "
                     "node has not yet.  marking %u as dead\n",
                     br->node_idx, br->dead_node, br->dead_node);
+               if (!test_bit(br->dead_node, dlm->domain_map) ||
+                   !test_bit(br->dead_node, dlm->live_nodes_map))
+                       mlog(0, "%u not in domain/live_nodes map "
+                            "so setting it in reco map manually\n",
+                            br->dead_node);
+               set_bit(br->dead_node, dlm->recovery_map);
                __dlm_hb_node_down(dlm, br->dead_node);
        }
        spin_unlock(&dlm->spinlock);
index cec2ce1cd318962ecf4dcfc553dda8a111a16fba..c95f08d2e925493fba9ab0a690769cfdda8243e3 100644 (file)
@@ -188,6 +188,19 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
                        actions &= ~(DLM_UNLOCK_REMOVE_LOCK|
                                     DLM_UNLOCK_REGRANT_LOCK|
                                     DLM_UNLOCK_CLEAR_CONVERT_TYPE);
+               } else if (status == DLM_RECOVERING || 
+                          status == DLM_MIGRATING || 
+                          status == DLM_FORWARD) {
+                       /* must clear the actions because this unlock
+                        * is about to be retried.  cannot free or do
+                        * any list manipulation. */
+                       mlog(0, "%s:%.*s: clearing actions, %s\n",
+                            dlm->name, res->lockname.len,
+                            res->lockname.name,
+                            status==DLM_RECOVERING?"recovering":
+                            (status==DLM_MIGRATING?"migrating":
+                             "forward"));
+                       actions = 0;
                }
                if (flags & LKM_CANCEL)
                        lock->cancel_pending = 0;
index e1fdd288796ecaf4d3879ac841e6d7b3d3a295d3..c3764f4744ee60c9a7f6e6e2b11ff7c1fd9f48c4 100644 (file)
@@ -27,7 +27,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
-#include <asm/signal.h>
+#include <linux/signal.h>
 
 #include <linux/module.h>
 #include <linux/fs.h>
index f2fb40cd296a2890b1af082794c1324ba6969c0d..b6ba292e9544000444718395aee0be5f39bf6de0 100644 (file)
@@ -262,8 +262,7 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
                el = &eb->h_list;
        }
 
-       if (el->l_tree_depth)
-               BUG();
+       BUG_ON(el->l_tree_depth);
 
        for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
                rec = &el->l_recs[i];
@@ -364,8 +363,8 @@ static int ocfs2_extent_map_lookup_read(struct inode *inode,
                return ret;
        }
 
-       if (ent->e_tree_depth)
-               BUG();  /* FIXME: Make sure this isn't a corruption */
+       /* FIXME: Make sure this isn't a corruption */
+       BUG_ON(ent->e_tree_depth);
 
        *ret_ent = ent;
 
@@ -423,8 +422,7 @@ static int ocfs2_extent_map_try_insert(struct inode *inode,
                                          le32_to_cpu(rec->e_clusters), NULL,
                                          NULL);
 
-       if (!old_ent)
-               BUG();
+       BUG_ON(!old_ent);
 
        ret = -EEXIST;
        if (old_ent->e_tree_depth < tree_depth)
@@ -988,7 +986,7 @@ int __init init_ocfs2_extent_maps(void)
        return 0;
 }
 
-void __exit exit_ocfs2_extent_maps(void)
+void exit_ocfs2_extent_maps(void)
 {
        kmem_cache_destroy(ocfs2_em_ent_cachep);
 }
index eaf33caa0a1f8b73dad142387216bd837dda5add..1715bc90e705eb36e3e0e56577265bb3053b38c6 100644 (file)
@@ -1022,8 +1022,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                }
                newsize = count + saved_pos;
 
-               mlog(0, "pos=%lld newsize=%"MLFu64" cursize=%lld\n",
-                    saved_pos, newsize, i_size_read(inode));
+               mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
+                    (long long) saved_pos, (long long) newsize,
+                    (long long) i_size_read(inode));
 
                /* No need for a higher level metadata lock if we're
                 * never going past i_size. */
@@ -1042,8 +1043,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                spin_unlock(&OCFS2_I(inode)->ip_lock);
 
                mlog(0, "Writing at EOF, may need more allocation: "
-                    "i_size = %lld, newsize = %"MLFu64", need %u clusters\n",
-                    i_size_read(inode), newsize, clusters);
+                    "i_size = %lld, newsize = %lld, need %u clusters\n",
+                    (long long) i_size_read(inode), (long long) newsize,
+                    clusters);
 
                /* We only want to continue the rest of this loop if
                 * our extend will actually require more
index d4ecc0627716fbc6a7d44a178384dffce5f3fed6..8122489c5762bb9c7f042ba5ebb3cf79a852b60c 100644 (file)
@@ -903,10 +903,10 @@ void ocfs2_clear_inode(struct inode *inode)
                        "Clear inode of %"MLFu64", inode is locked\n",
                        oi->ip_blkno);
 
-       mlog_bug_on_msg(down_trylock(&oi->ip_io_sem),
-                       "Clear inode of %"MLFu64", io_sem is locked\n",
+       mlog_bug_on_msg(!mutex_trylock(&oi->ip_io_mutex),
+                       "Clear inode of %"MLFu64", io_mutex is locked\n",
                        oi->ip_blkno);
-       up(&oi->ip_io_sem);
+       mutex_unlock(&oi->ip_io_mutex);
 
        /*
         * down_trylock() returns 0, down_write_trylock() returns 1
index 9b017743365380bf92f5c7c31912d24f031b9c0f..84c5079612870bae7ba80aa5e8831a63564687d9 100644 (file)
@@ -46,10 +46,10 @@ struct ocfs2_inode_info
        struct list_head                ip_io_markers;
        int                             ip_orphaned_slot;
 
-       struct semaphore                ip_io_sem;
+       struct mutex                    ip_io_mutex;
 
        /* Used by the journalling code to attach an inode to a
-        * handle.  These are protected by ip_io_sem in order to lock
+        * handle.  These are protected by ip_io_mutex in order to lock
         * out other I/O to the inode until we either commit or
         * abort. */
        struct list_head                ip_handle_list;
index 303c8d96457f818d7623b0025e7fbcfd74a2dfb5..fa0bcac5ceaef0aeef8539f45a4b7ace3c6be648 100644 (file)
@@ -147,8 +147,7 @@ struct ocfs2_journal_handle *ocfs2_start_trans(struct ocfs2_super *osb,
 
        mlog_entry("(max_buffs = %d)\n", max_buffs);
 
-       if (!osb || !osb->journal->j_journal)
-               BUG();
+       BUG_ON(!osb || !osb->journal->j_journal);
 
        if (ocfs2_is_hard_readonly(osb)) {
                ret = -EROFS;
@@ -401,7 +400,7 @@ int ocfs2_journal_access(struct ocfs2_journal_handle *handle,
         * j_trans_barrier for us. */
        ocfs2_set_inode_lock_trans(OCFS2_SB(inode->i_sb)->journal, inode);
 
-       down(&OCFS2_I(inode)->ip_io_sem);
+       mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
        switch (type) {
        case OCFS2_JOURNAL_ACCESS_CREATE:
        case OCFS2_JOURNAL_ACCESS_WRITE:
@@ -416,7 +415,7 @@ int ocfs2_journal_access(struct ocfs2_journal_handle *handle,
                status = -EINVAL;
                mlog(ML_ERROR, "Uknown access type!\n");
        }
-       up(&OCFS2_I(inode)->ip_io_sem);
+       mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 
        if (status < 0)
                mlog(ML_ERROR, "Error %d getting %d access to buffer!\n",
@@ -561,7 +560,11 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        SET_INODE_JOURNAL(inode);
        OCFS2_I(inode)->ip_open_count++;
 
-       status = ocfs2_meta_lock(inode, NULL, &bh, 1);
+       /* Skip recovery waits here - journal inode metadata never
+        * changes in a live cluster so it can be considered an
+        * exception to the rule. */
+       status = ocfs2_meta_lock_full(inode, NULL, &bh, 1,
+                                     OCFS2_META_LOCK_RECOVERY);
        if (status < 0) {
                if (status != -ERESTARTSYS)
                        mlog(ML_ERROR, "Could not get lock on journal!\n");
@@ -672,8 +675,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
-       if (!osb)
-               BUG();
+       BUG_ON(!osb);
 
        journal = osb->journal;
        if (!journal)
@@ -805,8 +807,7 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full)
 
        mlog_entry_void();
 
-       if (!journal)
-               BUG();
+       BUG_ON(!journal);
 
        status = journal_wipe(journal->j_journal, full);
        if (status < 0) {
@@ -1072,10 +1073,10 @@ restart:
                                        NULL);
 
 bail:
-       down(&osb->recovery_lock);
+       mutex_lock(&osb->recovery_lock);
        if (!status &&
            !ocfs2_node_map_is_empty(osb, &osb->recovery_map)) {
-               up(&osb->recovery_lock);
+               mutex_unlock(&osb->recovery_lock);
                goto restart;
        }
 
@@ -1083,7 +1084,7 @@ bail:
        mb(); /* sync with ocfs2_recovery_thread_running */
        wake_up(&osb->recovery_event);
 
-       up(&osb->recovery_lock);
+       mutex_unlock(&osb->recovery_lock);
 
        mlog_exit(status);
        /* no one is callint kthread_stop() for us so the kthread() api
@@ -1098,7 +1099,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num)
        mlog_entry("(node_num=%d, osb->node_num = %d)\n",
                   node_num, osb->node_num);
 
-       down(&osb->recovery_lock);
+       mutex_lock(&osb->recovery_lock);
        if (osb->disable_recovery)
                goto out;
 
@@ -1120,7 +1121,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num)
        }
 
 out:
-       up(&osb->recovery_lock);
+       mutex_unlock(&osb->recovery_lock);
        wake_up(&osb->recovery_event);
 
        mlog_exit_void();
@@ -1271,8 +1272,7 @@ static int ocfs2_recover_node(struct ocfs2_super *osb,
 
        /* Should not ever be called to recover ourselves -- in that
         * case we should've called ocfs2_journal_load instead. */
-       if (osb->node_num == node_num)
-               BUG();
+       BUG_ON(osb->node_num == node_num);
 
        slot_num = ocfs2_node_num_to_slot(si, node_num);
        if (slot_num == OCFS2_INVALID_SLOT) {
index f468c600cf92297de8cc4999123783518b102c52..8d8e4779df92ba7ffe84f293d17cddb9b7afb6f3 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/rbtree.h>
 #include <linux/workqueue.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 
 #include "cluster/nodemanager.h"
 #include "cluster/heartbeat.h"
@@ -233,7 +234,7 @@ struct ocfs2_super
        struct proc_dir_entry *proc_sub_dir; /* points to /proc/fs/ocfs2/<maj_min> */
 
        atomic_t vol_state;
-       struct semaphore recovery_lock;
+       struct mutex recovery_lock;
        struct task_struct *recovery_thread_task;
        int disable_recovery;
        wait_queue_head_t checkpoint_event;
index 364d64bd5f1067177779bf0a5d3754a67cebde0d..046824b6b6256267d8a9d15275b034e7abeae025 100644 (file)
@@ -932,7 +932,7 @@ static void ocfs2_inode_init_once(void *data,
                oi->ip_dir_start_lookup = 0;
 
                init_rwsem(&oi->ip_alloc_sem);
-               init_MUTEX(&(oi->ip_io_sem));
+               mutex_init(&oi->ip_io_mutex);
 
                oi->ip_blkno = 0ULL;
                oi->ip_clusters = 0;
@@ -1137,9 +1137,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        /* disable any new recovery threads and wait for any currently
         * running ones to exit. Do this before setting the vol_state. */
-       down(&osb->recovery_lock);
+       mutex_lock(&osb->recovery_lock);
        osb->disable_recovery = 1;
-       up(&osb->recovery_lock);
+       mutex_unlock(&osb->recovery_lock);
        wait_event(osb->recovery_event, !ocfs2_recovery_thread_running(osb));
 
        /* At this point, we know that no more recovery threads can be
@@ -1254,8 +1254,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        osb->sb = sb;
        /* Save off for ocfs2_rw_direct */
        osb->s_sectsize_bits = blksize_bits(sector_size);
-       if (!osb->s_sectsize_bits)
-               BUG();
+       BUG_ON(!osb->s_sectsize_bits);
 
        osb->net_response_ids = 0;
        spin_lock_init(&osb->net_response_lock);
@@ -1283,7 +1282,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
                 MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
 
-       init_MUTEX(&osb->recovery_lock);
+       mutex_init(&osb->recovery_lock);
 
        osb->disable_recovery = 0;
        osb->recovery_thread_task = NULL;
index 600a8bc5b54113454868fec31113a097394dd08a..fc29cb7a437d22e861da2e75cf8046fe1f5b9777 100644 (file)
@@ -77,8 +77,7 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        if (arr && ((inode = *arr) != NULL)) {
                /* get a ref in addition to the array ref */
                inode = igrab(inode);
-               if (!inode)
-                       BUG();
+               BUG_ON(!inode);
 
                return inode;
        }
@@ -89,8 +88,7 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        /* add one more if putting into array for first time */
        if (arr && inode) {
                *arr = igrab(inode);
-               if (!*arr)
-                       BUG();
+               BUG_ON(!*arr);
        }
        return inode;
 }
index 3a0458fd3e1b72f6b8d44608639fc3c8984d62d0..300b5bedfb21d8b168a6b94d5304618479ff7236 100644 (file)
@@ -388,7 +388,7 @@ out_free:
        }
 }
 
-/* Item insertion is guarded by ip_io_sem, so the insertion path takes
+/* Item insertion is guarded by ip_io_mutex, so the insertion path takes
  * advantage of this by not rechecking for a duplicate insert during
  * the slow case. Additionally, if the cache needs to be bumped up to
  * a tree, the code will not recheck after acquiring the lock --
@@ -418,7 +418,7 @@ void ocfs2_set_buffer_uptodate(struct inode *inode,
             (unsigned long long) bh->b_blocknr);
 
        /* No need to recheck under spinlock - insertion is guarded by
-        * ip_io_sem */
+        * ip_io_mutex */
        spin_lock(&oi->ip_lock);
        if (ocfs2_insert_can_use_array(oi, ci)) {
                /* Fast case - it's an array and there's a free
@@ -440,7 +440,7 @@ void ocfs2_set_buffer_uptodate(struct inode *inode,
 
 /* Called against a newly allocated buffer. Most likely nobody should
  * be able to read this sort of metadata while it's still being
- * allocated, but this is careful to take ip_io_sem anyway. */
+ * allocated, but this is careful to take ip_io_mutex anyway. */
 void ocfs2_set_new_buffer_uptodate(struct inode *inode,
                                   struct buffer_head *bh)
 {
@@ -451,9 +451,9 @@ void ocfs2_set_new_buffer_uptodate(struct inode *inode,
 
        set_buffer_uptodate(bh);
 
-       down(&oi->ip_io_sem);
+       mutex_lock(&oi->ip_io_mutex);
        ocfs2_set_buffer_uptodate(inode, bh);
-       up(&oi->ip_io_sem);
+       mutex_unlock(&oi->ip_io_mutex);
 }
 
 /* Requires ip_lock. */
@@ -537,7 +537,7 @@ int __init init_ocfs2_uptodate_cache(void)
        return 0;
 }
 
-void __exit exit_ocfs2_uptodate_cache(void)
+void exit_ocfs2_uptodate_cache(void)
 {
        if (ocfs2_uptodate_cachep)
                kmem_cache_destroy(ocfs2_uptodate_cachep);
index e5aacdf4eabf2021d5ded5e3bd0b63dd8cfefa15..01cd32d26b06867c28f67326941ee4c52ab1f087 100644 (file)
@@ -27,7 +27,7 @@
 #define OCFS2_UPTODATE_H
 
 int __init init_ocfs2_uptodate_cache(void);
-void __exit exit_ocfs2_uptodate_cache(void);
+void exit_ocfs2_uptodate_cache(void);
 
 void ocfs2_metadata_cache_init(struct inode *inode);
 void ocfs2_metadata_cache_purge(struct inode *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 1c9de29cafef1b7684a1e5ea4b7a0236f7166fb1..a2330bf83695a8da6fac9febfbf6458bb45acb0e 100644 (file)
@@ -17,6 +17,7 @@
  *  14-Sep-2004 BJD  Added misccr and getpin to gpio
  *  01-Oct-2004 BJD  Added the new gpio functions
  *  16-Oct-2004 BJD  Removed the clock variables
+ *  15-Jan-2006 LCVR Added s3c2400_gpio_getirq()
 */
 
 #ifndef __ASM_ARCH_HARDWARE_H
@@ -55,6 +56,12 @@ extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
 
 extern int s3c2410_gpio_getirq(unsigned int pin);
 
+#ifdef CONFIG_CPU_S3C2400
+
+extern int s3c2400_gpio_getirq(unsigned int pin);
+
+#endif /* CONFIG_CPU_S3C2400 */
+
 /* s3c2410_gpio_irqfilter
  *
  * set the irq filtering on the given pin
index 7f1be48ad67e033d5de562d4ed8670fa0d3cfdf8..9697f93afe742a560eabf1bf6678fc332b8d6bee 100644 (file)
@@ -22,6 +22,7 @@
  *    28-Mar-2005    LCVR    Fixed definition of GPB10
  *    26-Oct-2005    BJD     Added generic configuration types
  *    27-Nov-2005    LCVR    Added definitions to S3C2400 registers
+ *    15-Jan-2006    LCVR    Written S3C24XX_GPIO_BASE() macro
 */
 
 
 #define S3C2410_GPIO_BANKG   (32*6)
 #define S3C2410_GPIO_BANKH   (32*7)
 
+#ifdef CONFIG_CPU_S3C2400
+#define S3C24XX_GPIO_BASE(x)  S3C2400_GPIO_BASE(x)
+#define S3C24XX_MISCCR        S3C2400_MISCCR
+#else
+#define S3C24XX_GPIO_BASE(x)  S3C2410_GPIO_BASE(x)
+#define S3C24XX_MISCCR        S3C2410_MISCCR
+#endif /* CONFIG_CPU_S3C2400 */
+
+
+/* S3C2400 doesn't have a 1:1 mapping to S3C2410 gpio base pins */
+
+#define S3C2400_BANKNUM(pin)     (((pin) & ~31) / 32)
+#define S3C2400_BASEA2B(pin)     ((((pin) & ~31) >> 2))
+#define S3C2400_BASEC2H(pin)     ((S3C2400_BANKNUM(pin) * 10) + \
+                                 (2 * (S3C2400_BANKNUM(pin)-2)))
+
+#define S3C2400_GPIO_BASE(pin)   (pin < S3C2410_GPIO_BANKC ? \
+                                 S3C2400_BASEA2B(pin)+S3C24XX_VA_GPIO : \
+                                 S3C2400_BASEC2H(pin)+S3C24XX_VA_GPIO)
+
+
 #define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
 #define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
 
index d4256d5f3a7c1f84553fec367ccdf47eff71fb6f..747bdd31a74b9bf1af4c5df957ce70812bc1802b 100644 (file)
@@ -77,7 +77,7 @@ ip_fast_csum(unsigned char * iph, unsigned int ihl)
        mov     %0, %0, lsr #16"
        : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1)
        : "1" (iph), "2" (ihl)
-       : "cc");
+       : "cc", "memory");
        return sum;
 }
 
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 acffb8c9073acdf858410baa5bac35032860453a..a7f01502753581f3a27b935645a4f362b4277772 100644 (file)
@@ -126,7 +126,7 @@ extern struct config_item *config_group_find_obj(struct config_group *, const ch
 
 
 struct configfs_attribute {
-       char                    *ca_name;
+       const char              *ca_name;
        struct module           *ca_owner;
        mode_t                  ca_mode;
 };
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 95c8fea293baa8e9e413420adca449e02fd6507f..920766cea79cbc15634411e4c9633c27f6c8fd61 100644 (file)
@@ -84,6 +84,7 @@ struct nlm_rqst {
        struct nlm_args         a_args;         /* arguments */
        struct nlm_res          a_res;          /* result */
        struct nlm_wait *       a_block;
+       unsigned int            a_retries;      /* Retry count */
        char                    a_owner[NLMCLNT_OHSIZE];
 };
 
@@ -148,7 +149,6 @@ struct nlm_rqst * nlmclnt_alloc_call(void);
 int              nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl);
 void             nlmclnt_finish_block(struct nlm_rqst *req);
 long             nlmclnt_block(struct nlm_rqst *req, long timeout);
-int              nlmclnt_cancel(struct nlm_host *, struct file_lock *);
 u32              nlmclnt_grant(struct nlm_lock *);
 void             nlmclnt_recovery(struct nlm_host *, u32);
 int              nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
index ccd3e13de1e82eff1730a7cb17f57a4e9e8b4b56..f38872abc12669e0d08e53ac7da62ceedad01306 100644 (file)
@@ -21,24 +21,35 @@ struct mmc_command {
        u32                     arg;
        u32                     resp[4];
        unsigned int            flags;          /* expected response type */
-#define MMC_RSP_NONE   (0 << 0)
-#define MMC_RSP_SHORT  (1 << 0)
-#define MMC_RSP_LONG   (2 << 0)
-#define MMC_RSP_MASK   (3 << 0)
-#define MMC_RSP_CRC    (1 << 3)                /* expect valid crc */
-#define MMC_RSP_BUSY   (1 << 4)                /* card may send busy */
-#define MMC_RSP_OPCODE (1 << 5)                /* response contains opcode */
+#define MMC_RSP_PRESENT        (1 << 0)
+#define MMC_RSP_136    (1 << 1)                /* 136 bit response */
+#define MMC_RSP_CRC    (1 << 2)                /* expect valid crc */
+#define MMC_RSP_BUSY   (1 << 3)                /* card may send busy */
+#define MMC_RSP_OPCODE (1 << 4)                /* response contains opcode */
+#define MMC_CMD_MASK   (3 << 5)                /* command type */
+#define MMC_CMD_AC     (0 << 5)
+#define MMC_CMD_ADTC   (1 << 5)
+#define MMC_CMD_BC     (2 << 5)
+#define MMC_CMD_BCR    (3 << 5)
 
 /*
  * These are the response types, and correspond to valid bit
  * patterns of the above flags.  One additional valid pattern
  * is all zeros, which means we don't expect a response.
  */
-#define MMC_RSP_R1     (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R1B    (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
-#define MMC_RSP_R2     (MMC_RSP_LONG|MMC_RSP_CRC)
-#define MMC_RSP_R3     (MMC_RSP_SHORT)
-#define MMC_RSP_R6     (MMC_RSP_SHORT|MMC_RSP_CRC)
+#define MMC_RSP_NONE   (0)
+#define MMC_RSP_R1     (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B    (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+#define MMC_RSP_R2     (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3     (MMC_RSP_PRESENT)
+#define MMC_RSP_R6     (MMC_RSP_PRESENT|MMC_RSP_CRC)
+
+#define mmc_resp_type(cmd)     ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+/*
+ * These are the command types.
+ */
+#define mmc_cmd_type(cmd)      ((cmd)->flags & MMC_CMD_TYPE)
 
        unsigned int            retries;        /* max number of retries */
        unsigned int            error;          /* command error */
index a14dc306545b86f2f353d4ab2022523264109a51..81c3f77f652c95f6ec9ba8efee8450dc4e501a8f 100644 (file)
@@ -79,7 +79,7 @@
 /* SD commands                           type  argument     response */
   /* class 8 */
 /* This is basically the same command as for MMC with some quirks. */
-#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+#define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
 
   /* Application commands */
 #define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
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 b68c11a2d6dd912274b146df30d17bc4045800a9..be4772ed43c005add341102aaae7dcd15d1ed818 100644 (file)
@@ -48,7 +48,7 @@ struct rpc_cred {
 
        /* per-flavor data */
 };
-#define RPCAUTH_CRED_LOCKED    0x0001
+#define RPCAUTH_CRED_NEW       0x0001
 #define RPCAUTH_CRED_UPTODATE  0x0002
 
 #define RPCAUTH_CRED_MAGIC     0x0f4aa4f0
@@ -83,9 +83,10 @@ struct rpc_auth {
        struct rpc_cred_cache * au_credcache;
        /* per-flavor data */
 };
-#define RPC_AUTH_PROC_CREDS    0x0010          /* process creds (including
-                                                * uid/gid, fs[ug]id, gids)
-                                                */
+
+/* Flags for rpcauth_lookupcred() */
+#define RPCAUTH_LOOKUP_NEW             0x01    /* Accept an uninitialised cred */
+#define RPCAUTH_LOOKUP_ROOTCREDS       0x02    /* This really ought to go! */
 
 /*
  * Client authentication ops
@@ -105,6 +106,7 @@ struct rpc_authops {
 
 struct rpc_credops {
        const char *            cr_name;        /* Name of the auth flavour */
+       int                     (*cr_init)(struct rpc_auth *, struct rpc_cred *);
        void                    (*crdestroy)(struct rpc_cred *);
 
        int                     (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
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 9ac1b8c26c01184595f34de62db8ef23b15c6890..8d6f1a176b159f9ee1a989dd0803fc0d5eb5d2d0 100644 (file)
@@ -184,7 +184,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
  */
 struct rpc_cred *
 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
-               int taskflags)
+               int flags)
 {
        struct rpc_cred_cache *cache = auth->au_credcache;
        HLIST_HEAD(free);
@@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
                        *cred = NULL;
        int             nr = 0;
 
-       if (!(taskflags & RPC_TASK_ROOTCREDS))
+       if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
                nr = acred->uid & RPC_CREDCACHE_MASK;
 retry:
        spin_lock(&rpc_credcache_lock);
@@ -202,7 +202,7 @@ retry:
        hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
                struct rpc_cred *entry;
                entry = hlist_entry(pos, struct rpc_cred, cr_hash);
-               if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
+               if (entry->cr_ops->crmatch(acred, entry, flags)) {
                        hlist_del(&entry->cr_hash);
                        cred = entry;
                        break;
@@ -224,7 +224,7 @@ retry:
        rpcauth_destroy_credlist(&free);
 
        if (!cred) {
-               new = auth->au_ops->crcreate(auth, acred, taskflags);
+               new = auth->au_ops->crcreate(auth, acred, flags);
                if (!IS_ERR(new)) {
 #ifdef RPC_DEBUG
                        new->cr_magic = RPCAUTH_CRED_MAGIC;
@@ -232,13 +232,21 @@ retry:
                        goto retry;
                } else
                        cred = new;
+       } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+                       && cred->cr_ops->cr_init != NULL
+                       && !(flags & RPCAUTH_LOOKUP_NEW)) {
+               int res = cred->cr_ops->cr_init(auth, cred);
+               if (res < 0) {
+                       put_rpccred(cred);
+                       cred = ERR_PTR(res);
+               }
        }
 
        return (struct rpc_cred *) cred;
 }
 
 struct rpc_cred *
-rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
+rpcauth_lookupcred(struct rpc_auth *auth, int flags)
 {
        struct auth_cred acred = {
                .uid = current->fsuid,
@@ -250,7 +258,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
        dprintk("RPC:     looking up %s cred\n",
                auth->au_ops->au_name);
        get_group_info(acred.group_info);
-       ret = auth->au_ops->lookup_cred(auth, &acred, taskflags);
+       ret = auth->au_ops->lookup_cred(auth, &acred, flags);
        put_group_info(acred.group_info);
        return ret;
 }
@@ -265,11 +273,14 @@ rpcauth_bindcred(struct rpc_task *task)
                .group_info = current->group_info,
        };
        struct rpc_cred *ret;
+       int flags = 0;
 
        dprintk("RPC: %4d looking up %s cred\n",
                task->tk_pid, task->tk_auth->au_ops->au_name);
        get_group_info(acred.group_info);
-       ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags);
+       if (task->tk_flags & RPC_TASK_ROOTCREDS)
+               flags |= RPCAUTH_LOOKUP_ROOTCREDS;
+       ret = auth->au_ops->lookup_cred(auth, &acred, flags);
        if (!IS_ERR(ret))
                task->tk_msg.rpc_cred = ret;
        else
index 8d782282ec194c6f682fd71b2a100c25141c45c0..bb46efd92e5723475b3dd1c1cbf38f78c2af7c82 100644 (file)
@@ -158,6 +158,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
        old = gss_cred->gc_ctx;
        gss_cred->gc_ctx = ctx;
        cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+       cred->cr_flags &= ~RPCAUTH_CRED_NEW;
        write_unlock(&gss_ctx_lock);
        if (old)
                gss_put_ctx(old);
@@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        } else {
                struct auth_cred acred = { .uid = uid };
                spin_unlock(&gss_auth->lock);
-               cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
+               cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW);
                if (IS_ERR(cred)) {
                        err = PTR_ERR(cred);
                        goto err_put_ctx;
@@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc)
  * Lookup RPCSEC_GSS cred for the current process
  */
 static struct rpc_cred *
-gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
-       return rpcauth_lookup_credcache(auth, acred, taskflags);
+       return rpcauth_lookup_credcache(auth, acred, flags);
 }
 
 static struct rpc_cred *
-gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
        struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
        struct gss_cred *cred = NULL;
@@ -785,13 +786,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
         */
        cred->gc_flags = 0;
        cred->gc_base.cr_ops = &gss_credops;
+       cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
        cred->gc_service = gss_auth->service;
-       do {
-               err = gss_create_upcall(gss_auth, cred);
-       } while (err == -EAGAIN);
-       if (err < 0)
-               goto out_err;
-
        return &cred->gc_base;
 
 out_err:
@@ -801,13 +797,34 @@ out_err:
 }
 
 static int
-gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+       struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+       int err;
+
+       do {
+               err = gss_create_upcall(gss_auth, gss_cred);
+       } while (err == -EAGAIN);
+       return err;
+}
+
+static int
+gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
 {
        struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
 
+       /*
+        * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
+        * we don't really care if the credential has expired or not,
+        * since the caller should be prepared to reinitialise it.
+        */
+       if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW))
+               goto out;
        /* Don't match with creds that have expired. */
        if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
                return 0;
+out:
        return (rc->cr_uid == acred->uid);
 }
 
@@ -1241,6 +1258,7 @@ static struct rpc_authops authgss_ops = {
 static struct rpc_credops gss_credops = {
        .cr_name        = "AUTH_GSS",
        .crdestroy      = gss_destroy_cred,
+       .cr_init        = gss_cred_init,
        .crmatch        = gss_match,
        .crmarshal      = gss_marshal,
        .crrefresh      = gss_refresh,
index 1b3ed4fd198735e332b3f8f46492956f91457860..df14b6bfbf10f9a0bc8874b0a332b3b170a06199 100644 (file)
@@ -75,7 +75,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 
        atomic_set(&cred->uc_count, 1);
        cred->uc_flags = RPCAUTH_CRED_UPTODATE;
-       if (flags & RPC_TASK_ROOTCREDS) {
+       if (flags & RPCAUTH_LOOKUP_ROOTCREDS) {
                cred->uc_uid = 0;
                cred->uc_gid = 0;
                cred->uc_gids[0] = NOGROUP;
@@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred)
  * request root creds (e.g. for NFS swapping).
  */
 static int
-unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
+unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
 {
        struct unx_cred *cred = (struct unx_cred *) rcred;
        int             i;
 
-       if (!(taskflags & RPC_TASK_ROOTCREDS)) {
+       if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) {
                int groups;
 
                if (cred->uc_uid != acred->uid
index 9764c80ab0b26927eaa23dd90be7e35bc158ef93..a5c0c7b6e151b4a8712ec67d3c3cdbf32308497c 100644 (file)
@@ -38,44 +38,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly;
 
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
-static void
-__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
+static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+               void (*destroy_msg)(struct rpc_pipe_msg *), int err)
 {
        struct rpc_pipe_msg *msg;
-       void (*destroy_msg)(struct rpc_pipe_msg *);
 
-       destroy_msg = rpci->ops->destroy_msg;
-       while (!list_empty(head)) {
+       if (list_empty(head))
+               return;
+       do {
                msg = list_entry(head->next, struct rpc_pipe_msg, list);
-               list_del_init(&msg->list);
+               list_del(&msg->list);
                msg->errno = err;
                destroy_msg(msg);
-       }
-}
-
-static void
-__rpc_purge_upcall(struct inode *inode, int err)
-{
-       struct rpc_inode *rpci = RPC_I(inode);
-
-       __rpc_purge_list(rpci, &rpci->pipe, err);
-       rpci->pipelen = 0;
+       } while (!list_empty(head));
        wake_up(&rpci->waitq);
 }
 
 static void
 rpc_timeout_upcall_queue(void *data)
 {
+       LIST_HEAD(free_list);
        struct rpc_inode *rpci = (struct rpc_inode *)data;
        struct inode *inode = &rpci->vfs_inode;
+       void (*destroy_msg)(struct rpc_pipe_msg *);
 
-       mutex_lock(&inode->i_mutex);
-       if (rpci->ops == NULL)
-               goto out;
-       if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
-               __rpc_purge_upcall(inode, -ETIMEDOUT);
-out:
-       mutex_unlock(&inode->i_mutex);
+       spin_lock(&inode->i_lock);
+       if (rpci->ops == NULL) {
+               spin_unlock(&inode->i_lock);
+               return;
+       }
+       destroy_msg = rpci->ops->destroy_msg;
+       if (rpci->nreaders == 0) {
+               list_splice_init(&rpci->pipe, &free_list);
+               rpci->pipelen = 0;
+       }
+       spin_unlock(&inode->i_lock);
+       rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
 }
 
 int
@@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
        struct rpc_inode *rpci = RPC_I(inode);
        int res = -EPIPE;
 
-       mutex_lock(&inode->i_mutex);
+       spin_lock(&inode->i_lock);
        if (rpci->ops == NULL)
                goto out;
        if (rpci->nreaders) {
@@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
                res = 0;
        }
 out:
-       mutex_unlock(&inode->i_mutex);
+       spin_unlock(&inode->i_lock);
        wake_up(&rpci->waitq);
        return res;
 }
@@ -115,21 +113,29 @@ static void
 rpc_close_pipes(struct inode *inode)
 {
        struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe_ops *ops;
 
        mutex_lock(&inode->i_mutex);
-       if (rpci->ops != NULL) {
+       ops = rpci->ops;
+       if (ops != NULL) {
+               LIST_HEAD(free_list);
+
+               spin_lock(&inode->i_lock);
                rpci->nreaders = 0;
-               __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE);
-               __rpc_purge_upcall(inode, -EPIPE);
-               rpci->nwriters = 0;
-               if (rpci->ops->release_pipe)
-                       rpci->ops->release_pipe(inode);
+               list_splice_init(&rpci->in_upcall, &free_list);
+               list_splice_init(&rpci->pipe, &free_list);
+               rpci->pipelen = 0;
                rpci->ops = NULL;
+               spin_unlock(&inode->i_lock);
+               rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
+               rpci->nwriters = 0;
+               if (ops->release_pipe)
+                       ops->release_pipe(inode);
+               cancel_delayed_work(&rpci->queue_timeout);
+               flush_scheduled_work();
        }
        rpc_inode_setowner(inode, NULL);
        mutex_unlock(&inode->i_mutex);
-       cancel_delayed_work(&rpci->queue_timeout);
-       flush_scheduled_work();
 }
 
 static struct inode *
@@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
                goto out;
        msg = (struct rpc_pipe_msg *)filp->private_data;
        if (msg != NULL) {
+               spin_lock(&inode->i_lock);
                msg->errno = -EAGAIN;
-               list_del_init(&msg->list);
+               list_del(&msg->list);
+               spin_unlock(&inode->i_lock);
                rpci->ops->destroy_msg(msg);
        }
        if (filp->f_mode & FMODE_WRITE)
                rpci->nwriters --;
-       if (filp->f_mode & FMODE_READ)
+       if (filp->f_mode & FMODE_READ) {
                rpci->nreaders --;
-       if (!rpci->nreaders)
-               __rpc_purge_upcall(inode, -EAGAIN);
+               if (rpci->nreaders == 0) {
+                       LIST_HEAD(free_list);
+                       spin_lock(&inode->i_lock);
+                       list_splice_init(&rpci->pipe, &free_list);
+                       rpci->pipelen = 0;
+                       spin_unlock(&inode->i_lock);
+                       rpc_purge_list(rpci, &free_list,
+                                       rpci->ops->destroy_msg, -EAGAIN);
+               }
+       }
        if (rpci->ops->release_pipe)
                rpci->ops->release_pipe(inode);
 out:
@@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        }
        msg = filp->private_data;
        if (msg == NULL) {
+               spin_lock(&inode->i_lock);
                if (!list_empty(&rpci->pipe)) {
                        msg = list_entry(rpci->pipe.next,
                                        struct rpc_pipe_msg,
@@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
                        filp->private_data = msg;
                        msg->copied = 0;
                }
+               spin_unlock(&inode->i_lock);
                if (msg == NULL)
                        goto out_unlock;
        }
@@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        res = rpci->ops->upcall(filp, msg, buf, len);
        if (res < 0 || msg->len == msg->copied) {
                filp->private_data = NULL;
-               list_del_init(&msg->list);
+               spin_lock(&inode->i_lock);
+               list_del(&msg->list);
+               spin_unlock(&inode->i_lock);
                rpci->ops->destroy_msg(msg);
        }
 out_unlock:
@@ -610,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
                return ERR_PTR(error);
        dir = nd->dentry->d_inode;
        mutex_lock(&dir->i_mutex);
-       dentry = lookup_hash(nd);
+       dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
        if (IS_ERR(dentry))
                goto out_err;
        if (dentry->d_inode) {
@@ -672,7 +692,7 @@ rpc_rmdir(char *path)
                return error;
        dir = nd.dentry->d_inode;
        mutex_lock(&dir->i_mutex);
-       dentry = lookup_hash(&nd);
+       dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
@@ -733,7 +753,7 @@ rpc_unlink(char *path)
                return error;
        dir = nd.dentry->d_inode;
        mutex_lock(&dir->i_mutex);
-       dentry = lookup_hash(&nd);
+       dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
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 */
index 54147c1f6361d67d85db502737830e8da461e86a..149feb410654812ae4612438923ae990761302d3 100644 (file)
@@ -882,14 +882,20 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id)
        writel(0x1fff, aaci->base + AACI_INTCLR);
        writel(aaci->maincr, aaci->base + AACI_MAINCR);
 
+       ret = aaci_probe_ac97(aaci);
+       if (ret)
+               goto out;
+
        /*
-        * Size the FIFOs.
+        * Size the FIFOs (must be multiple of 16).
         */
        aaci->fifosize = aaci_size_fifo(aaci);
-
-       ret = aaci_probe_ac97(aaci);
-       if (ret)
+       if (aaci->fifosize & 15) {
+               printk(KERN_WARNING "AACI: fifosize = %d not supported\n",
+                      aaci->fifosize);
+               ret = -ENODEV;
                goto out;
+       }
 
        ret = aaci_init_pcm(aaci);
        if (ret)