Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 May 2010 16:13:08 +0000 (09:13 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 May 2010 16:13:08 +0000 (09:13 -0700)
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (47 commits)
  mfd: Rename twl5031 sih modules
  mfd: Storage class for timberdale should be before const qualifier
  mfd: Remove unneeded and dangerous clearing of clientdata
  mfd: New AB8500 driver
  gpio: Fix inverted rdc321x gpio data out registers
  mfd: Change rdc321x resources flags to IORESOURCE_IO
  mfd: Move pcf50633 irq related functions to its own file.
  mfd: Use threaded irq for pcf50633
  mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read
  mfd: Fix pcf50633 bitfield logic in interrupt handler
  gpio: rdc321x needs to select MFD_CORE
  mfd: Use menuconfig for quicker config editing
  ARM: AB3550 board configuration and irq for U300
  mfd: AB3550 core driver
  mfd: AB3100 register access change to abx500 API
  mfd: Renamed ab3100.h to abx500.h
  gpio: Add TC35892 GPIO driver
  mfd: Add Toshiba's TC35892 MFD core
  mfd: Delay to mask tsc irq in max8925
  mfd: Remove incorrect wm8350 kfree
  ...

394 files changed:
Documentation/acpi/apei/einj.txt [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/GPIO.txt
Documentation/arm/Samsung-S3C24XX/Overview.txt
Documentation/arm/Samsung/GPIO.txt [new file with mode: 0644]
Documentation/arm/Samsung/Overview.txt
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
Documentation/kernel-parameters.txt
MAINTAINERS
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/devices.h
arch/arm/mach-ux500/ste-dma40-db8500.h [new file with mode: 0644]
arch/arm/plat-s5p/clock.c
arch/arm/plat-samsung/include/plat/gpio-cfg.h
arch/frv/include/asm/cache.h
arch/frv/include/asm/mem-layout.h
arch/ia64/include/asm/acpi.h
arch/ia64/kernel/smpboot.c
arch/ia64/mm/numa.c
arch/ia64/pci/pci.c
arch/parisc/include/asm/cacheflush.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/syscall.S
arch/parisc/math-emu/decode_exc.c
arch/parisc/mm/fault.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/thread_info.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/mcheck/Makefile
arch/x86/kernel/cpu/mcheck/mce-apei.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce-internal.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/lguest/boot.c
arch/x86/mm/numa.c
arch/x86/mm/pat.c
arch/x86/mm/pat_internal.h
arch/x86/mm/pat_rbtree.c
arch/x86/mm/pgtable_32.c
arch/x86/pci/acpi.c
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_pad.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/apei/Kconfig [new file with mode: 0644]
drivers/acpi/apei/Makefile [new file with mode: 0644]
drivers/acpi/apei/apei-base.c [new file with mode: 0644]
drivers/acpi/apei/apei-internal.h [new file with mode: 0644]
drivers/acpi/apei/cper.c [new file with mode: 0644]
drivers/acpi/apei/einj.c [new file with mode: 0644]
drivers/acpi/apei/erst.c [new file with mode: 0644]
drivers/acpi/apei/ghes.c [new file with mode: 0644]
drivers/acpi/apei/hest.c [new file with mode: 0644]
drivers/acpi/atomicio.c [new file with mode: 0644]
drivers/acpi/ec.c
drivers/acpi/hed.c [new file with mode: 0644]
drivers/acpi/hest.c [deleted file]
drivers/acpi/pci_root.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/acpi/sleep.h
drivers/acpi/tables.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-sff.c
drivers/ata/pata_acpi.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_icside.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_macio.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ninja32.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_piccolo.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rdc.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_sch.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/char/ps3flash.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.h
drivers/cpuidle/driver.c
drivers/cpuidle/sysfs.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/pl330.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_state.c
drivers/idle/Kconfig
drivers/idle/Makefile
drivers/idle/intel_idle.c [new file with mode: 0755]
drivers/infiniband/core/ucm.c
drivers/infiniband/hw/qib/qib_fs.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_init.c
drivers/leds/Kconfig
drivers/leds/leds-gpio.c
drivers/mtd/ubi/cdev.c
drivers/net/3c507.c
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/cnic.c
drivers/net/cnic_if.h
drivers/net/fec.c
drivers/net/hamradio/yam.c
drivers/net/ll_temac.h
drivers/net/ll_temac_main.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/probe.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio.c
drivers/serial/s5pv210.c
drivers/staging/pohmelfs/inode.c
drivers/usb/gadget/printer.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/video/fb_defio.c
fs/9p/vfs_file.c
fs/adfs/dir.c
fs/adfs/file.c
fs/adfs/inode.c
fs/affs/affs.h
fs/affs/file.c
fs/afs/internal.h
fs/afs/write.c
fs/aio.c
fs/anon_inodes.c
fs/attr.c
fs/bad_inode.c
fs/bfs/dir.c
fs/block_dev.c
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/buffer.c
fs/ceph/auth.c
fs/ceph/auth.h
fs/ceph/auth_none.c
fs/ceph/auth_x.c
fs/ceph/caps.c
fs/ceph/ceph_fs.h
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/messenger.c
fs/ceph/messenger.h
fs/ceph/mon_client.c
fs/ceph/osd_client.c
fs/ceph/osdmap.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/cifsfs.h
fs/cifs/file.c
fs/coda/coda_int.h
fs/coda/file.c
fs/configfs/inode.c
fs/debugfs/file.c
fs/direct-io.c
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/exofs/file.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext3/dir.c
fs/ext3/fsync.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/fsync.c
fs/ext4/super.c
fs/fat/fat.h
fs/fat/file.c
fs/fat/inode.c
fs/file_table.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/ops_inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jfs/file.c
fs/jfs/jfs_inode.h
fs/jfs/super.c
fs/libfs.c
fs/logfs/file.c
fs/logfs/logfs.h
fs/minix/dir.c
fs/minix/file.c
fs/minix/itree_v2.c
fs/namei.c
fs/ncpfs/file.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nilfs2/file.c
fs/nilfs2/nilfs.h
fs/ntfs/dir.c
fs/ntfs/file.c
fs/ocfs2/file.c
fs/ocfs2/super.c
fs/omfs/file.c
fs/pipe.c
fs/qnx4/dir.c
fs/quota/dquot.c
fs/quota/quota.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/reiserfs/dir.c
fs/reiserfs/file.c
fs/reiserfs/super.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/super.c
fs/sync.c
fs/sysfs/inode.c
fs/sysv/dir.c
fs/sysv/file.c
fs/sysv/inode.c
fs/ubifs/file.c
fs/ubifs/ubifs.h
fs/udf/balloc.c
fs/udf/dir.c
fs/udf/file.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/namei.c
fs/udf/super.c
fs/udf/udfdecl.h
fs/ufs/balloc.c
fs/ufs/dir.c
fs/ufs/file.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/truncate.c
fs/xfs/linux-2.6/xfs_file.c
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpi_hest.h [deleted file]
include/acpi/apei.h [new file with mode: 0644]
include/acpi/atomicio.h [new file with mode: 0644]
include/acpi/hed.h [new file with mode: 0644]
include/acpi/processor.h
include/acpi/video.h
include/linux/acpi.h
include/linux/amba/pl330.h [new file with mode: 0644]
include/linux/bitmap.h
include/linux/buffer_head.h
include/linux/completion.h
include/linux/cper.h [new file with mode: 0644]
include/linux/cpuidle.h
include/linux/debugfs.h
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/file.h
include/linux/fs.h
include/linux/libata.h
include/linux/nodemask.h
include/linux/pci.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/rio.h
include/linux/usb/audio-v2.h
include/linux/uuid.h [new file with mode: 0644]
include/net/cls_cgroup.h
include/net/sctp/structs.h
include/net/sock.h
include/trace/events/ext4.h
ipc/shm.c
kernel/cpu.c
kernel/fork.c
kernel/hrtimer.c
kernel/perf_event.c
kernel/posix-timers.c
kernel/sched.c
kernel/timer.c
lib/Makefile
lib/atomic64_test.c
lib/bitmap.c
lib/uuid.c [new file with mode: 0644]
mm/shmem.c
mm/truncate.c
net/core/datagram.c
net/core/neighbour.c
net/core/rtnetlink.c
net/core/sock.c
net/ipv4/ipmr.c
net/ipv4/udp.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/udp.c
net/iucv/af_iucv.c
net/netfilter/xt_TEE.c
sound/mips/au1x00.c
sound/oss/dmasound/dmasound_atari.c
sound/pci/asihpi/hpi.h
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpi_internal.h
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpifunc.c
sound/pci/asihpi/hpios.c
sound/pci/asihpi/hpios.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8990.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/sh/siu_dai.c
sound/usb/caiaq/control.c
sound/usb/caiaq/device.c
sound/usb/endpoint.c
sound/usb/format.c
sound/usb/format.h
sound/usb/mixer.c
sound/usb/pcm.c

diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt
new file mode 100644 (file)
index 0000000..dfab718
--- /dev/null
@@ -0,0 +1,59 @@
+                       APEI Error INJection
+                       ~~~~~~~~~~~~~~~~~~~~
+
+EINJ provides a hardware error injection mechanism
+It is very useful for debugging and testing of other APEI and RAS features.
+
+To use EINJ, make sure the following are enabled in your kernel
+configuration:
+
+CONFIG_DEBUG_FS
+CONFIG_ACPI_APEI
+CONFIG_ACPI_APEI_EINJ
+
+The user interface of EINJ is debug file system, under the
+directory apei/einj. The following files are provided.
+
+- available_error_type
+  Reading this file returns the error injection capability of the
+  platform, that is, which error types are supported. The error type
+  definition is as follow, the left field is the error type value, the
+  right field is error description.
+
+    0x00000001 Processor Correctable
+    0x00000002 Processor Uncorrectable non-fatal
+    0x00000004 Processor Uncorrectable fatal
+    0x00000008  Memory Correctable
+    0x00000010  Memory Uncorrectable non-fatal
+    0x00000020  Memory Uncorrectable fatal
+    0x00000040 PCI Express Correctable
+    0x00000080 PCI Express Uncorrectable fatal
+    0x00000100 PCI Express Uncorrectable non-fatal
+    0x00000200 Platform Correctable
+    0x00000400 Platform Uncorrectable non-fatal
+    0x00000800 Platform Uncorrectable fatal
+
+  The format of file contents are as above, except there are only the
+  available error type lines.
+
+- error_type
+  This file is used to set the error type value. The error type value
+  is defined in "available_error_type" description.
+
+- error_inject
+  Write any integer to this file to trigger the error
+  injection. Before this, please specify all necessary error
+  parameters.
+
+- param1
+  This file is used to set the first error parameter value. Effect of
+  parameter depends on error_type specified. For memory error, this is
+  physical memory address.
+
+- param2
+  This file is used to set the second error parameter value. Effect of
+  parameter depends on error_type specified. For memory error, this is
+  physical memory address mask.
+
+For more information about EINJ, please refer to ACPI specification
+version 4.0, section 17.5.
index 2af2cf3..816d607 100644 (file)
@@ -12,6 +12,8 @@ Introduction
   of the s3c2410 GPIO system, please read the Samsung provided
   data-sheet/users manual to find out the complete list.
 
+  See Documentation/arm/Samsung/GPIO.txt for the core implemetation.
+
 
 GPIOLIB
 -------
@@ -24,8 +26,60 @@ GPIOLIB
   listed below will be removed (they may be marked as __deprecated
   in the near future).
 
-  - s3c2410_gpio_getpin
-  - s3c2410_gpio_setpin
+  The following functions now either have a s3c_ specific variant
+  or are merged into gpiolib. See the definitions in
+  arch/arm/plat-samsung/include/plat/gpio-cfg.h:
+
+  s3c2410_gpio_setpin()                gpio_set_value() or gpio_direction_output()
+  s3c2410_gpio_getpin()                gpio_get_value() or gpio_direction_input()
+  s3c2410_gpio_getirq()                gpio_to_irq()
+  s3c2410_gpio_cfgpin()                s3c_gpio_cfgpin()
+  s3c2410_gpio_getcfg()                s3c_gpio_getcfg()
+  s3c2410_gpio_pullup()                s3c_gpio_setpull()
+
+
+GPIOLIB conversion
+------------------
+
+If you need to convert your board or driver to use gpiolib from the exiting
+s3c2410 api, then here are some notes on the process.
+
+1) If your board is exclusively using an GPIO, say to control peripheral
+   power, then it will require to claim the gpio with gpio_request() before
+   it can use it.
+
+   It is recommended to check the return value, with at least WARN_ON()
+   during initialisation.
+
+2) The s3c2410_gpio_cfgpin() can be directly replaced with s3c_gpio_cfgpin()
+   as they have the same arguments, and can either take the pin specific
+   values, or the more generic special-function-number arguments.
+
+3) s3c2410_gpio_pullup() changs have the problem that whilst the 
+   s3c2410_gpio_pullup(x, 1) can be easily translated to the
+   s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0)
+   are not so easy.
+
+   The s3c2410_gpio_pullup(x, 0) case enables the pull-up (or in the case
+   of some of the devices, a pull-down) and as such the new API distinguishes
+   between the UP and DOWN case. There is currently no 'just turn on' setting
+   which may be required if this becomes a problem.
+
+4) s3c2410_gpio_setpin() can be replaced by gpio_set_value(), the old call
+   does not implicitly configure the relevant gpio to output. The gpio
+   direction should be changed before using gpio_set_value().
+
+5) s3c2410_gpio_getpin() is replaceable by gpio_get_value() if the pin
+   has been set to input. It is currently unknown what the behaviour is
+   when using gpio_get_value() on an output pin (s3c2410_gpio_getpin
+   would return the value the pin is supposed to be outputting).
+
+6) s3c2410_gpio_getirq() should be directly replacable with the
+   gpio_to_irq() call.
+
+The s3c2410_gpio and gpio_ calls have always operated on the same gpio
+numberspace, so there is no problem with converting the gpio numbering
+between the calls.
 
 
 Headers
@@ -54,6 +108,11 @@ PIN Numbers
   eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
   the GPIO functions which pin is to be used.
 
+  With the conversion to gpiolib, there is no longer a direct conversion
+  from gpio pin number to register base address as in earlier kernels. This
+  is due to the number space required for newer SoCs where the later
+  GPIOs are not contiguous.
+
 
 Configuring a pin
 -----------------
@@ -71,6 +130,8 @@ Configuring a pin
    which would turn GPA(0) into the lowest Address line A0, and set
    GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
 
+   The s3c_gpio_cfgpin() call is a functional replacement for this call.
+
 
 Reading the current configuration
 ---------------------------------
@@ -82,6 +143,9 @@ Reading the current configuration
   The return value will be from the same set of values which can be
   passed to s3c2410_gpio_cfgpin().
 
+  The s3c_gpio_getcfg() call should be a functional replacement for
+  this call.
+
 
 Configuring a pull-up resistor
 ------------------------------
@@ -95,6 +159,10 @@ Configuring a pull-up resistor
   Where the to value is zero to set the pull-up off, and 1 to enable
   the specified pull-up. Any other values are currently undefined.
 
+  The s3c_gpio_setpull() offers similar functionality, but with the
+  ability to encode whether the pull is up or down. Currently there
+  is no 'just on' state, so up or down must be selected.
+
 
 Getting the state of a PIN
 --------------------------
@@ -106,6 +174,9 @@ Getting the state of a PIN
   This will return either zero or non-zero. Do not count on this
   function returning 1 if the pin is set.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Setting the state of a PIN
 --------------------------
@@ -117,6 +188,9 @@ Setting the state of a PIN
   Which sets the given pin to the value. Use 0 to write 0, and 1 to
   set the output to 1.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Getting the IRQ number associated with a PIN
 --------------------------------------------
@@ -128,6 +202,9 @@ Getting the IRQ number associated with a PIN
 
   Note, not all pins have an IRQ.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Authour
 -------
index 081892d..c12bfc1 100644 (file)
@@ -8,10 +8,16 @@ Introduction
 
   The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
   by the 's3c2410' architecture of ARM Linux. Currently the S3C2410,
-  S3C2412, S3C2413, S3C2440, S3C2442 and S3C2443 devices are supported.
+  S3C2412, S3C2413, S3C2416 S3C2440, S3C2442, S3C2443 and S3C2450 devices
+  are supported.
 
   Support for the S3C2400 and S3C24A0 series are in progress.
 
+  The S3C2416 and S3C2450 devices are very similar and S3C2450 support is
+  included under the arch/arm/mach-s3c2416 directory. Note, whilst core
+  support for these SoCs is in, work on some of the extra peripherals
+  and extra interrupts is still ongoing.
+
 
 Configuration
 -------------
@@ -209,6 +215,13 @@ GPIO
   Newer kernels carry GPIOLIB, and support is being moved towards
   this with some of the older support in line to be removed.
 
+  As of v2.6.34, the move towards using gpiolib support is almost
+  complete, and very little of the old calls are left.
+
+  See Documentation/arm/Samsung-S3C24XX/GPIO.txt for the S3C24XX specific
+  support and Documentation/arm/Samsung/GPIO.txt for the core Samsung
+  implementation.
+
 
 Clock Management
 ----------------
diff --git a/Documentation/arm/Samsung/GPIO.txt b/Documentation/arm/Samsung/GPIO.txt
new file mode 100644 (file)
index 0000000..05850c6
--- /dev/null
@@ -0,0 +1,42 @@
+               Samsung GPIO implementation
+               ===========================
+
+Introduction
+------------
+
+This outlines the Samsung GPIO implementation and the architecture
+specfic calls provided alongisde the drivers/gpio core.
+
+
+S3C24XX (Legacy)
+----------------
+
+See Documentation/arm/Samsung-S3C24XX/GPIO.txt for more information
+about these devices. Their implementation is being brought into line
+with the core samsung implementation described in this document.
+
+
+GPIOLIB integration
+-------------------
+
+The gpio implementation uses gpiolib as much as possible, only providing
+specific calls for the items that require Samsung specific handling, such
+as pin special-function or pull resistor control.
+
+GPIO numbering is synchronised between the Samsung and gpiolib system.
+
+
+PIN configuration
+-----------------
+
+Pin configuration is specific to the Samsung architecutre, with each SoC
+registering the necessary information for the core gpio configuration
+implementation to configure pins as necessary.
+
+The s3c_gpio_cfgpin() and s3c_gpio_setpull() provide the means for a
+driver or machine to change gpio configuration.
+
+See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
+on these functions.
+
+
index 7cced1f..c3094ea 100644 (file)
@@ -13,9 +13,10 @@ Introduction
 
   - S3C24XX: See Documentation/arm/Samsung-S3C24XX/Overview.txt for full list
   - S3C64XX: S3C6400 and S3C6410
-  - S5PC6440
-
-  S5PC100 and S5PC110 support is currently being merged
+  - S5P6440
+  - S5P6442
+  - S5PC100
+  - S5PC110 / S5PV210
 
 
 S3C24XX Systems
@@ -35,7 +36,10 @@ Configuration
   unifying all the SoCs into one kernel.
 
   s5p6440_defconfig - S5P6440 specific default configuration
+  s5p6442_defconfig - S5P6442 specific default configuration
   s5pc100_defconfig - S5PC100 specific default configuration
+  s5pc110_defconfig - S5PC110 specific default configuration
+  s5pv210_defconfig - S5PV210 specific default configuration
 
 
 Layout
@@ -50,18 +54,27 @@ Layout
   specific information. It contains the base clock, GPIO and device definitions
   to get the system running.
 
-  plat-s3c is the s3c24xx/s3c64xx platform directory, although it is currently
-  involved in other builds this will be phased out once the relevant code is
-  moved elsewhere.
-
   plat-s3c24xx is for s3c24xx specific builds, see the S3C24XX docs.
 
-  plat-s3c64xx is for the s3c64xx specific bits, see the S3C24XX docs.
+  plat-s5p is for s5p specific builds, and contains common support for the
+  S5P specific systems. Not all S5Ps use all the features in this directory
+  due to differences in the hardware.
+
+
+Layout changes
+--------------
+
+  The old plat-s3c and plat-s5pc1xx directories have been removed, with
+  support moved to either plat-samsung or plat-s5p as necessary. These moves
+  where to simplify the include and dependency issues involved with having
+  so many different platform directories.
 
-  plat-s5p is for s5p specific builds, more to be added.
+  It was decided to remove plat-s5pc1xx as some of the support was already
+  in plat-s5p or plat-samsung, with the S5PC110 support added with S5PV210
+  the only user was the S5PC100. The S5PC100 specific items where moved to
+  arch/arm/mach-s5pc100.
 
 
-  [ to finish ]
 
 
 Port Contributors
index 61c98f0..96d4293 100644 (file)
@@ -380,7 +380,7 @@ prototypes:
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
index b668585..94677e7 100644 (file)
@@ -401,11 +401,16 @@ otherwise noted.
        started might not be in the page cache at the end of the
        walk).
 
-  truncate: called by the VFS to change the size of a file.  The
+  truncate: Deprecated. This will not be called if ->setsize is defined.
+       Called by the VFS to change the size of a file.  The
        i_size field of the inode is set to the desired size by the
        VFS before this method is called.  This method is called by
        the truncate(2) system call and related functionality.
 
+       Note: ->truncate and vmtruncate are deprecated. Do not add new
+       instances/calls of these. Filesystems should be converted to do their
+       truncate sequence via ->setattr().
+
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
 
@@ -729,7 +734,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
index b56ea86..1808f11 100644 (file)
@@ -145,11 +145,10 @@ and is between 256 and 4096 characters. It is defined in the file
 
        acpi=           [HW,ACPI,X86]
                        Advanced Configuration and Power Interface
-                       Format: { force | off | ht | strict | noirq | rsdt }
+                       Format: { force | off | strict | noirq | rsdt }
                        force -- enable ACPI if default was off
                        off -- disable ACPI if default was on
                        noirq -- do not use ACPI for IRQ routing
-                       ht -- run only enough ACPI to enable Hyper Threading
                        strict -- Be less tolerant of platforms that are not
                                strictly ACPI specification compliant.
                        rsdt -- prefer RSDT over (default) XSDT
@@ -758,6 +757,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        Default value is 0.
                        Value can be changed at runtime via /selinux/enforce.
 
+       erst_disable    [ACPI]
+                       Disable Error Record Serialization Table (ERST)
+                       support.
+
        ether=          [HW,NET] Ethernet cards parameters
                        This option is obsoleted by the "netdev=" option, which
                        has equivalent usage. See its documentation for details.
@@ -852,6 +855,11 @@ and is between 256 and 4096 characters. It is defined in the file
        hd=             [EIDE] (E)IDE hard drive subsystem geometry
                        Format: <cyl>,<head>,<sect>
 
+       hest_disable    [ACPI]
+                       Disable Hardware Error Source Table (HEST) support;
+                       corresponding firmware-first mode error processing
+                       logic will be disabled.
+
        highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact
                        size of <nn>. This works even on boxes that have no
                        highmem otherwise. This also works to reduce highmem
@@ -1252,6 +1260,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        * nohrst, nosrst, norst: suppress hard, soft
                           and both resets.
 
+                       * dump_id: dump IDENTIFY data.
+
                        If there are multiple matching configurations changing
                        the same attribute, the last one is used.
 
index 33047a6..13608bd 100644 (file)
@@ -2887,6 +2887,13 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
 S:     Maintained
 F:     drivers/input/
 
+INTEL IDLE DRIVER
+M:     Len Brown <lenb@kernel.org>
+L:     linux-pm@lists.linux-foundation.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
+S:     Supported
+F:     drivers/idle/intel_idle.c
+
 INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
 M:     Maik Broemme <mbroemme@plusserver.de>
 L:     linux-fbdev@vger.kernel.org
index 43af89c..44cea2d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.34
-# Wed May 26 19:04:29 2010
+# Fri May 28 19:15:48 2010
 #
 CONFIG_ARM=y
 CONFIG_HAVE_PWM=y
@@ -250,12 +250,15 @@ CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
 CONFIG_S3C_LOWLEVEL_UART_PORT=0
 CONFIG_SAMSUNG_CLKSRC=y
 CONFIG_S3C_GPIO_CFG_S3C24XX=y
+CONFIG_S3C_GPIO_PULL_UPDOWN=y
 CONFIG_S3C_GPIO_PULL_UP=y
 CONFIG_SAMSUNG_GPIO_EXTRA=0
 CONFIG_S3C_GPIO_SPACE=0
 CONFIG_S3C_ADC=y
 CONFIG_S3C_DEV_HSMMC=y
+CONFIG_S3C_DEV_HSMMC1=y
 CONFIG_S3C_DEV_HWMON=y
+CONFIG_S3C_DEV_FB=y
 CONFIG_S3C_DEV_USB_HOST=y
 CONFIG_S3C_DEV_WDT=y
 CONFIG_S3C_DEV_NAND=y
@@ -322,11 +325,13 @@ CONFIG_MACH_SMDK2413=y
 CONFIG_MACH_S3C2413=y
 CONFIG_MACH_SMDK2412=y
 CONFIG_MACH_VSTMS=y
+CONFIG_CPU_S3C2416=y
+CONFIG_S3C2416_DMA=y
 
 #
 # S3C2416 Machines
 #
-# CONFIG_MACH_SMDK2416 is not set
+CONFIG_MACH_SMDK2416=y
 CONFIG_CPU_S3C2440=y
 CONFIG_CPU_S3C2442=y
 CONFIG_CPU_S3C244X=y
@@ -338,9 +343,9 @@ CONFIG_S3C2440_DMA=y
 # S3C2440 and S3C2442 Machines
 #
 CONFIG_MACH_ANUBIS=y
-# CONFIG_MACH_NEO1973_GTA02 is not set
+CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_OSIRIS=y
-# CONFIG_MACH_OSIRIS_DVS is not set
+CONFIG_MACH_OSIRIS_DVS=m
 CONFIG_MACH_RX3715=y
 CONFIG_ARCH_S3C2440=y
 CONFIG_MACH_NEXCODER_2440=y
@@ -348,7 +353,7 @@ CONFIG_SMDK2440_CPU2440=y
 CONFIG_SMDK2440_CPU2442=y
 CONFIG_MACH_AT2440EVB=y
 CONFIG_MACH_MINI2440=y
-# CONFIG_MACH_RX1950 is not set
+CONFIG_MACH_RX1950=y
 CONFIG_CPU_S3C2443=y
 CONFIG_S3C2443_DMA=y
 
@@ -1302,6 +1307,7 @@ CONFIG_INPUT_POWERMATE=m
 CONFIG_INPUT_YEALINK=m
 CONFIG_INPUT_CM109=m
 CONFIG_INPUT_UINPUT=m
+# CONFIG_INPUT_PCF50633_PMU is not set
 # CONFIG_INPUT_PCF8574 is not set
 CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
 
@@ -1490,7 +1496,16 @@ CONFIG_GPIOLIB=y
 # AC97 GPIO expanders:
 #
 # CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_APM_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_CHARGER_PCF50633 is not set
 CONFIG_HWMON=y
 CONFIG_HWMON_VID=m
 # CONFIG_HWMON_DEBUG_CHIP is not set
@@ -1607,7 +1622,7 @@ CONFIG_MFD_SM501=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_HTC_I2CPLD is not set
 # CONFIG_UCB1400_CORE is not set
-# CONFIG_TPS65010 is not set
+CONFIG_TPS65010=m
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
@@ -1620,8 +1635,10 @@ CONFIG_MFD_SM501=y
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_WM8994 is not set
-# CONFIG_MFD_PCF50633 is not set
+CONFIG_MFD_PCF50633=y
 # CONFIG_MFD_MC13783 is not set
+# CONFIG_PCF50633_ADC is not set
+CONFIG_PCF50633_GPIO=y
 # CONFIG_AB3100_CORE is not set
 # CONFIG_EZX_PCAP is not set
 # CONFIG_AB4500_CORE is not set
@@ -1737,6 +1754,7 @@ CONFIG_SND_S3C24XX_SOC_I2S=y
 CONFIG_SND_S3C_I2SV2_SOC=m
 CONFIG_SND_S3C2412_SOC_I2S=m
 CONFIG_SND_S3C_SOC_AC97=m
+# CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753 is not set
 CONFIG_SND_S3C24XX_SOC_JIVE_WM8750=m
 CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710=m
 CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650=m
@@ -2045,6 +2063,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_BQ4802 is not set
 # CONFIG_RTC_DRV_RP5C01 is not set
 # CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_PCF50633 is not set
 
 #
 # on-CPU RTC drivers
index 7d8b4cf..2b64238 100644 (file)
@@ -1,9 +1,10 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.34
-# Wed May 26 19:04:30 2010
+# Fri May 28 19:05:39 2010
 #
 CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
@@ -253,12 +254,15 @@ CONFIG_S3C_GPIO_TRACK=y
 # CONFIG_S3C_ADC is not set
 CONFIG_S3C_DEV_HSMMC=y
 CONFIG_S3C_DEV_HSMMC1=y
+CONFIG_S3C_DEV_HSMMC2=y
+CONFIG_S3C_DEV_HWMON=y
 CONFIG_S3C_DEV_I2C1=y
 CONFIG_S3C_DEV_FB=y
 CONFIG_S3C_DEV_USB_HOST=y
 CONFIG_S3C_DEV_USB_HSOTG=y
 CONFIG_S3C_DEV_WDT=y
 CONFIG_S3C_DEV_NAND=y
+CONFIG_S3C_DEV_RTC=y
 CONFIG_SAMSUNG_DEV_ADC=y
 CONFIG_SAMSUNG_DEV_TS=y
 CONFIG_S3C_DMA=y
@@ -271,6 +275,7 @@ CONFIG_S3C_DMA=y
 # CONFIG_SAMSUNG_PM_CHECK is not set
 CONFIG_SAMSUNG_WAKEMASK=y
 CONFIG_PLAT_S3C64XX=y
+CONFIG_CPU_S3C6400=y
 CONFIG_CPU_S3C6410=y
 CONFIG_S3C64XX_DMA=y
 CONFIG_S3C64XX_SETUP_SDHCI=y
@@ -278,17 +283,18 @@ CONFIG_S3C64XX_SETUP_I2C0=y
 CONFIG_S3C64XX_SETUP_I2C1=y
 CONFIG_S3C64XX_SETUP_FB_24BPP=y
 CONFIG_S3C64XX_SETUP_SDHCI_GPIO=y
-# CONFIG_MACH_SMDK6400 is not set
-# CONFIG_MACH_ANW6410 is not set
+CONFIG_MACH_SMDK6400=y
+CONFIG_MACH_ANW6410=y
 CONFIG_MACH_SMDK6410=y
 CONFIG_SMDK6410_SD_CH0=y
 # CONFIG_SMDK6410_SD_CH1 is not set
 # CONFIG_SMDK6410_WM1190_EV1 is not set
 # CONFIG_SMDK6410_WM1192_EV1 is not set
-# CONFIG_MACH_NCP is not set
-# CONFIG_MACH_HMT is not set
-# CONFIG_MACH_SMARTQ5 is not set
-# CONFIG_MACH_SMARTQ7 is not set
+CONFIG_MACH_NCP=y
+CONFIG_MACH_HMT=y
+CONFIG_MACH_SMARTQ=y
+CONFIG_MACH_SMARTQ5=y
+CONFIG_MACH_SMARTQ7=y
 
 #
 # Processor Type
@@ -475,6 +481,9 @@ CONFIG_MTD_CFI_I2=y
 #
 # Self-contained MTD device drivers
 #
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -501,6 +510,7 @@ CONFIG_MTD_NAND_S3C2410=y
 # CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
@@ -521,6 +531,7 @@ CONFIG_BLK_DEV_LOOP=y
 #
 # DRBD disabled because PROC_FS, INET or CONNECTOR not selected
 #
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
@@ -534,12 +545,14 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_ISL29003 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
 # CONFIG_C2PORT is not set
 
 #
 # EEPROM support
 #
 CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_MAX6875 is not set
 # CONFIG_EEPROM_93CX6 is not set
@@ -654,6 +667,7 @@ CONFIG_SERIAL_SAMSUNG_UARTS=4
 # CONFIG_SERIAL_SAMSUNG_DEBUG is not set
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_S3C6400=y
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_TIMBERDALE is not set
@@ -694,6 +708,7 @@ CONFIG_I2C_S3C2410=y
 #
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
 
 #
 # Other I2C/SMBus bus drivers
@@ -703,7 +718,24 @@ CONFIG_I2C_S3C2410=y
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_S3C64XX=m
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
 
 #
 # PPS support
@@ -735,6 +767,9 @@ CONFIG_GPIOLIB=y
 #
 # SPI GPIO expanders:
 #
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
 
 #
 # AC97 GPIO expanders:
@@ -750,6 +785,7 @@ CONFIG_HWMON=y
 #
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
@@ -771,6 +807,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
 # CONFIG_SENSORS_LM73 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
@@ -785,6 +822,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
 # CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
@@ -796,6 +834,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
 # CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
@@ -809,6 +848,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
 # CONFIG_SENSORS_LIS3_I2C is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
@@ -845,7 +885,10 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
 # CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -854,8 +897,47 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_S3C=y
+# CONFIG_FB_S3C_DEBUG_REGWRITE is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+CONFIG_LCD_LTV350QV=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_PWM=y
 
 #
 # Display device support
@@ -867,6 +949,8 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
 CONFIG_SOUND=y
 CONFIG_SOUND_OSS_CORE=y
 CONFIG_SOUND_OSS_CORE_PRECLAIM=y
@@ -895,6 +979,11 @@ CONFIG_SND_DRIVERS=y
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
 CONFIG_SND_SOC=m
 CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_S3C24XX_SOC=m
@@ -909,29 +998,197 @@ CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
 # CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
 
 #
 # Special HID drivers
 #
+# CONFIG_HID_3M_PCT is not set
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
-# Enable Host or Gadget support to see Inventra options
+# Miscellaneous USB options
 #
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
 # NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_GADGET is not set
 
 #
 # OTG and related infrastructure
 #
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=y
 CONFIG_MMC_DEBUG=y
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -951,11 +1208,77 @@ CONFIG_MMC_SDHCI=y
 # CONFIG_MMC_SDHCI_PLTFM is not set
 CONFIG_MMC_SDHCI_S3C=y
 # CONFIG_MMC_SDHCI_S3C_DMA is not set
+# CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
 # CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_S3C=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
@@ -1052,7 +1375,46 @@ CONFIG_ROMFS_ON_BLOCK=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 
 #
 # Kernel hacking
index 7a4138b..fbd85a9 100644 (file)
@@ -258,6 +258,12 @@ static struct clk init_clocks[] = {
                .parent         = &clk_h,
                .enable         = s3c64xx_hclk_ctrl,
                .ctrlbit        = S3C_CLKCON_HCLK_HSMMC2,
+       }, {
+               .name           = "otg",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_USB,
        }, {
                .name           = "timers",
                .id             = -1,
index 1b2c989..6544855 100644 (file)
@@ -411,7 +411,7 @@ static struct clk_lookup u8500_common_clks[] = {
        CLK(apetraceclk,        "apetrace",     NULL),
        CLK(mcdeclk,    "mcde",         NULL),
        CLK(ipi2clk,    "ipi2",         NULL),
-       CLK(dmaclk,     "dma40",        NULL),
+       CLK(dmaclk,     "dma40.0",      NULL),
        CLK(b2r2clk,    "b2r2",         NULL),
        CLK(tvclk,      "tv",           NULL),
 };
index d04299f..f21c444 100644 (file)
@@ -32,6 +32,7 @@ static struct platform_device *platform_devs[] __initdata = {
        &u8500_gpio_devs[6],
        &u8500_gpio_devs[7],
        &u8500_gpio_devs[8],
+       &u8500_dma40_device,
 };
 
 /* minimum static i/o mapping required to boot U8500 platforms */
@@ -71,6 +72,9 @@ void __init u8500_init_devices(void)
 {
        ux500_init_devices();
 
+       if (cpu_is_u8500ed())
+               dma40_u8500ed_fixup();
+
        /* Register the platform devices */
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
index 2033423..8229034 100644 (file)
 #include <linux/gpio.h>
 #include <linux/amba/bus.h>
 
+#include <plat/ste_dma40.h>
+
 #include <mach/hardware.h>
 #include <mach/setup.h>
 
+#include "ste-dma40-db8500.h"
+
 static struct nmk_gpio_platform_data u8500_gpio_data[] = {
        GPIO_DATA("GPIO-0-31", 0),
        GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */
@@ -105,3 +109,108 @@ struct platform_device u8500_i2c4_device = {
        .resource       = u8500_i2c4_resources,
        .num_resources  = ARRAY_SIZE(u8500_i2c4_resources),
 };
+
+static struct resource dma40_resources[] = {
+       [0] = {
+               .start = U8500_DMA_BASE,
+               .end = U8500_DMA_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+               .name = "base",
+       },
+       [1] = {
+               .start = U8500_DMA_LCPA_BASE,
+               .end = U8500_DMA_LCPA_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+               .name = "lcpa",
+       },
+       [2] = {
+               .start = U8500_DMA_LCLA_BASE,
+               .end = U8500_DMA_LCLA_BASE + 16 * 1024 - 1,
+               .flags = IORESOURCE_MEM,
+               .name = "lcla",
+       },
+       [3] = {
+               .start = IRQ_DMA,
+               .end = IRQ_DMA,
+               .flags = IORESOURCE_IRQ}
+};
+
+/* Default configuration for physcial memcpy */
+struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
+       .channel_type = (STEDMA40_CHANNEL_IN_PHY_MODE |
+                        STEDMA40_LOW_PRIORITY_CHANNEL |
+                        STEDMA40_PCHAN_BASIC_MODE),
+       .dir = STEDMA40_MEM_TO_MEM,
+
+       .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
+       .src_info.data_width = STEDMA40_BYTE_WIDTH,
+       .src_info.psize = STEDMA40_PSIZE_PHY_1,
+
+       .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
+       .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+       .dst_info.psize = STEDMA40_PSIZE_PHY_1,
+
+};
+/* Default configuration for logical memcpy */
+struct stedma40_chan_cfg dma40_memcpy_conf_log = {
+       .channel_type = (STEDMA40_CHANNEL_IN_LOG_MODE |
+                        STEDMA40_LOW_PRIORITY_CHANNEL |
+                        STEDMA40_LCHAN_SRC_LOG_DST_LOG |
+                        STEDMA40_NO_TIM_FOR_LINK),
+       .dir = STEDMA40_MEM_TO_MEM,
+
+       .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
+       .src_info.data_width = STEDMA40_BYTE_WIDTH,
+       .src_info.psize = STEDMA40_PSIZE_LOG_1,
+
+       .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
+       .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+       .dst_info.psize = STEDMA40_PSIZE_LOG_1,
+
+};
+
+/*
+ * Mapping between destination event lines and physical device address.
+ * The event line is tied to a device and therefor the address is constant.
+ */
+static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV];
+
+/* Mapping between source event lines and physical device address */
+static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV];
+
+/* Reserved event lines for memcpy only */
+static int dma40_memcpy_event[] = {
+       STEDMA40_MEMCPY_TX_1,
+       STEDMA40_MEMCPY_TX_2,
+       STEDMA40_MEMCPY_TX_3,
+       STEDMA40_MEMCPY_TX_4,
+};
+
+static struct stedma40_platform_data dma40_plat_data = {
+       .dev_len = STEDMA40_NR_DEV,
+       .dev_rx = dma40_rx_map,
+       .dev_tx = dma40_tx_map,
+       .memcpy = dma40_memcpy_event,
+       .memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
+       .memcpy_conf_phy = &dma40_memcpy_conf_phy,
+       .memcpy_conf_log = &dma40_memcpy_conf_log,
+       .llis_per_log = 8,
+};
+
+struct platform_device u8500_dma40_device = {
+       .dev = {
+               .platform_data = &dma40_plat_data,
+       },
+       .name = "dma40",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(dma40_resources),
+       .resource = dma40_resources
+};
+
+void dma40_u8500ed_fixup(void)
+{
+       dma40_plat_data.memcpy = NULL;
+       dma40_plat_data.memcpy_len = 0;
+       dma40_resources[0].start = U8500_DMA_BASE_ED;
+       dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1;
+}
index 9169e1e..85fc6a8 100644 (file)
@@ -7,6 +7,18 @@
 #ifndef __MACH_DB8500_REGS_H
 #define __MACH_DB8500_REGS_H
 
+/* Base address and bank offsets for ESRAM */
+#define U8500_ESRAM_BASE       0x40000000
+#define U8500_ESRAM_BANK_SIZE  0x00020000
+#define U8500_ESRAM_BANK0      U8500_ESRAM_BASE
+#define U8500_ESRAM_BANK1      (U8500_ESRAM_BASE + U8500_ESRAM_BANK_SIZE)
+#define U8500_ESRAM_BANK2      (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
+#define U8500_ESRAM_BANK3      (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
+#define U8500_ESRAM_BANK4      (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
+/* Use bank 4 for DMA LCLA and LCPA */
+#define U8500_DMA_LCLA_BASE    U8500_ESRAM_BANK4
+#define U8500_DMA_LCPA_BASE    (U8500_ESRAM_BANK4 + 0x4000)
+
 #define U8500_PER3_BASE                0x80000000
 #define U8500_STM_BASE         0x80100000
 #define U8500_STM_REG_BASE     (U8500_STM_BASE + 0xF000)
index 0422af0..c2b2f25 100644 (file)
@@ -25,5 +25,8 @@ extern struct platform_device ux500_i2c3_device;
 
 extern struct platform_device u8500_i2c0_device;
 extern struct platform_device u8500_i2c4_device;
+extern struct platform_device u8500_dma40_device;
+
+void dma40_u8500ed_fixup(void);
 
 #endif
diff --git a/arch/arm/mach-ux500/ste-dma40-db8500.h b/arch/arm/mach-ux500/ste-dma40-db8500.h
new file mode 100644 (file)
index 0000000..e701627
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * arch/arm/mach-ux500/ste_dma40_db8500.h
+ * DB8500-SoC-specific configuration for DMA40
+ *
+ * Copyright (C) ST-Ericsson 2007-2010
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Per Friden <per.friden@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#ifndef STE_DMA40_DB8500_H
+#define STE_DMA40_DB8500_H
+
+#define STEDMA40_NR_DEV 64
+
+enum dma_src_dev_type {
+       STEDMA40_DEV_SPI0_RX = 0,
+       STEDMA40_DEV_SD_MMC0_RX = 1,
+       STEDMA40_DEV_SD_MMC1_RX = 2,
+       STEDMA40_DEV_SD_MMC2_RX = 3,
+       STEDMA40_DEV_I2C1_RX = 4,
+       STEDMA40_DEV_I2C3_RX = 5,
+       STEDMA40_DEV_I2C2_RX = 6,
+       STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */
+       STEDMA40_DEV_SSP0_RX = 8,
+       STEDMA40_DEV_SSP1_RX = 9,
+       STEDMA40_DEV_MCDE_RX = 10,
+       STEDMA40_DEV_UART2_RX = 11,
+       STEDMA40_DEV_UART1_RX = 12,
+       STEDMA40_DEV_UART0_RX = 13,
+       STEDMA40_DEV_MSP2_RX = 14,
+       STEDMA40_DEV_I2C0_RX = 15,
+       STEDMA40_DEV_USB_OTG_IEP_8 = 16,
+       STEDMA40_DEV_USB_OTG_IEP_1_9 = 17,
+       STEDMA40_DEV_USB_OTG_IEP_2_10 = 18,
+       STEDMA40_DEV_USB_OTG_IEP_3_11 = 19,
+       STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
+       STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
+       STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
+       STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
+       STEDMA40_DEV_SRC_SXA0_RX_TX = 24,
+       STEDMA40_DEV_SRC_SXA1_RX_TX = 25,
+       STEDMA40_DEV_SRC_SXA2_RX_TX = 26,
+       STEDMA40_DEV_SRC_SXA3_RX_TX = 27,
+       STEDMA40_DEV_SD_MM2_RX = 28,
+       STEDMA40_DEV_SD_MM0_RX = 29,
+       STEDMA40_DEV_MSP1_RX = 30,
+       /*
+        * This channel is either SlimBus or MSP,
+        * never both at the same time.
+        */
+       STEDMA40_SLIM0_CH0_RX = 31,
+       STEDMA40_DEV_MSP0_RX = 31,
+       STEDMA40_DEV_SD_MM1_RX = 32,
+       STEDMA40_DEV_SPI2_RX = 33,
+       STEDMA40_DEV_I2C3_RX2 = 34,
+       STEDMA40_DEV_SPI1_RX = 35,
+       STEDMA40_DEV_USB_OTG_IEP_4_12 = 36,
+       STEDMA40_DEV_USB_OTG_IEP_5_13 = 37,
+       STEDMA40_DEV_USB_OTG_IEP_6_14 = 38,
+       STEDMA40_DEV_USB_OTG_IEP_7_15 = 39,
+       STEDMA40_DEV_SPI3_RX = 40,
+       STEDMA40_DEV_SD_MM3_RX = 41,
+       STEDMA40_DEV_SD_MM4_RX = 42,
+       STEDMA40_DEV_SD_MM5_RX = 43,
+       STEDMA40_DEV_SRC_SXA4_RX_TX = 44,
+       STEDMA40_DEV_SRC_SXA5_RX_TX = 45,
+       STEDMA40_DEV_SRC_SXA6_RX_TX = 46,
+       STEDMA40_DEV_SRC_SXA7_RX_TX = 47,
+       STEDMA40_DEV_CAC1_RX = 48,
+       /* RX channels 49 and 50 are unused */
+       STEDMA40_DEV_MSHC_RX = 51,
+       STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52,
+       STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53,
+       STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54,
+       STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55,
+       /* RX channels 56 thru 60 are unused */
+       STEDMA40_DEV_CAC0_RX = 61,
+       /* RX channels 62 and 63 are unused */
+};
+
+enum dma_dest_dev_type {
+       STEDMA40_DEV_SPI0_TX = 0,
+       STEDMA40_DEV_SD_MMC0_TX = 1,
+       STEDMA40_DEV_SD_MMC1_TX = 2,
+       STEDMA40_DEV_SD_MMC2_TX = 3,
+       STEDMA40_DEV_I2C1_TX = 4,
+       STEDMA40_DEV_I2C3_TX = 5,
+       STEDMA40_DEV_I2C2_TX = 6,
+       STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */
+       STEDMA40_DEV_SSP0_TX = 8,
+       STEDMA40_DEV_SSP1_TX = 9,
+       /* TX channel 10 is unused */
+       STEDMA40_DEV_UART2_TX = 11,
+       STEDMA40_DEV_UART1_TX = 12,
+       STEDMA40_DEV_UART0_TX= 13,
+       STEDMA40_DEV_MSP2_TX = 14,
+       STEDMA40_DEV_I2C0_TX = 15,
+       STEDMA40_DEV_USB_OTG_OEP_8 = 16,
+       STEDMA40_DEV_USB_OTG_OEP_1_9 = 17,
+       STEDMA40_DEV_USB_OTG_OEP_2_10= 18,
+       STEDMA40_DEV_USB_OTG_OEP_3_11 = 19,
+       STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
+       STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
+       STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
+       STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
+       STEDMA40_DEV_DST_SXA0_RX_TX = 24,
+       STEDMA40_DEV_DST_SXA1_RX_TX = 25,
+       STEDMA40_DEV_DST_SXA2_RX_TX = 26,
+       STEDMA40_DEV_DST_SXA3_RX_TX = 27,
+       STEDMA40_DEV_SD_MM2_TX = 28,
+       STEDMA40_DEV_SD_MM0_TX = 29,
+       STEDMA40_DEV_MSP1_TX = 30,
+       /*
+        * This channel is either SlimBus or MSP,
+        * never both at the same time.
+        */
+       STEDMA40_SLIM0_CH0_TX = 31,
+       STEDMA40_DEV_MSP0_TX = 31,
+       STEDMA40_DEV_SD_MM1_TX = 32,
+       STEDMA40_DEV_SPI2_TX = 33,
+       /* Secondary I2C3 channel */
+       STEDMA40_DEV_I2C3_TX2 = 34,
+       STEDMA40_DEV_SPI1_TX = 35,
+       STEDMA40_DEV_USB_OTG_OEP_4_12 = 36,
+       STEDMA40_DEV_USB_OTG_OEP_5_13 = 37,
+       STEDMA40_DEV_USB_OTG_OEP_6_14 = 38,
+       STEDMA40_DEV_USB_OTG_OEP_7_15 = 39,
+       STEDMA40_DEV_SPI3_TX = 40,
+       STEDMA40_DEV_SD_MM3_TX = 41,
+       STEDMA40_DEV_SD_MM4_TX = 42,
+       STEDMA40_DEV_SD_MM5_TX = 43,
+       STEDMA40_DEV_DST_SXA4_RX_TX = 44,
+       STEDMA40_DEV_DST_SXA5_RX_TX = 45,
+       STEDMA40_DEV_DST_SXA6_RX_TX = 46,
+       STEDMA40_DEV_DST_SXA7_RX_TX = 47,
+       STEDMA40_DEV_CAC1_TX = 48,
+       STEDMA40_DEV_CAC1_TX_HAC1_TX = 49,
+       STEDMA40_DEV_HAC1_TX = 50,
+       STEDMA40_MEMXCPY_TX_0 = 51,
+       STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52,
+       STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53,
+       STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54,
+       STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55,
+       STEDMA40_MEMCPY_TX_1 = 56,
+       STEDMA40_MEMCPY_TX_2 = 57,
+       STEDMA40_MEMCPY_TX_3 = 58,
+       STEDMA40_MEMCPY_TX_4 = 59,
+       STEDMA40_MEMCPY_TX_5 = 60,
+       STEDMA40_DEV_CAC0_TX = 61,
+       STEDMA40_DEV_CAC0_TX_HAC0_TX = 62,
+       STEDMA40_DEV_HAC0_TX = 63,
+};
+
+#endif
index 24a931f..b5e2552 100644 (file)
@@ -148,6 +148,7 @@ static struct clk *s5p_clks[] __initdata = {
        &clk_fout_vpll,
        &clk_arm,
        &clk_vpll,
+       &clk_xusbxti,
 };
 
 void __init s5p_register_clocks(unsigned long xtal_freq)
index 34efdd2..db4112c 100644 (file)
@@ -43,6 +43,11 @@ struct s3c_gpio_chip;
  * layouts. Provide an point to vector control routine and provide any
  * per-bank configuration information that other systems such as the
  * external interrupt code will need.
+ *
+ * @sa s3c_gpio_cfgpin
+ * @sa s3c_gpio_getcfg
+ * @sa s3c_gpio_setpull
+ * @sa s3c_gpio_getpull
  */
 struct s3c_gpio_cfg {
        unsigned int    cfg_eint;
@@ -70,11 +75,25 @@ struct s3c_gpio_cfg {
 /**
  * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
  * @pin pin The pin number to configure.
- * @pin to The configuration for the pin's function.
+ * @to to The configuration for the pin's function.
  *
  * Configure which function is actually connected to the external
  * pin, such as an gpio input, output or some form of special function
  * connected to an internal peripheral block.
+ *
+ * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
+ * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
+ * will then generate the correct bit mask and shift for the configuration.
+ *
+ * If a bank of GPIOs all needs to be set to special-function 2, then
+ * the following code will work:
+ *
+ *     for (gpio = start; gpio < end; gpio++)
+ *             s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ *
+ * The @to parameter can also be a specific value already shifted to the
+ * correct position in the control register, although these are discouraged
+ * in newer kernels and are only being kept for compatibility.
  */
 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
 
@@ -108,6 +127,8 @@ extern unsigned s3c_gpio_getcfg(unsigned int pin);
  * This function sets the state of the pull-{up,down} resistor for the
  * specified pin. It will return 0 if successfull, or a negative error
  * code if the pin cannot support the requested pull setting.
+ *
+ * @pull is one of S3C_GPIO_PULL_NONE, S3C_GPIO_PULL_DOWN or S3C_GPIO_PULL_UP.
 */
 extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
 
index 7dc0f0f..2797163 100644 (file)
@@ -17,8 +17,6 @@
 #define L1_CACHE_SHIFT         (CONFIG_FRV_L1_CACHE_SHIFT)
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
-
 #define __cacheline_aligned    __attribute__((aligned(L1_CACHE_BYTES)))
 #define ____cacheline_aligned  __attribute__((aligned(L1_CACHE_BYTES)))
 
index 2947764..ccae981 100644 (file)
@@ -35,8 +35,8 @@
  * the slab must be aligned such that load- and store-double instructions don't
  * fault if used
  */
-#define        ARCH_KMALLOC_MINALIGN           8
-#define        ARCH_SLAB_MINALIGN              8
+#define        ARCH_KMALLOC_MINALIGN           L1_CACHE_BYTES
+#define        ARCH_SLAB_MINALIGN              L1_CACHE_BYTES
 
 /*****************************************************************************/
 /*
index 21adbd7..837dc82 100644 (file)
@@ -94,7 +94,6 @@ ia64_acpi_release_global_lock (unsigned int *lock)
 #define acpi_noirq 0   /* ACPI always enabled on IA64 */
 #define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */
 #define acpi_strict 1  /* no ACPI spec workarounds on IA64 */
-#define acpi_ht 0      /* no HT-only mode on IA64 */
 #endif
 #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
 static inline void disable_acpi(void) { }
index 518e876..6a1380e 100644 (file)
@@ -390,11 +390,13 @@ smp_callin (void)
 
        fix_b0_for_bsp();
 
+#ifdef CONFIG_NUMA
        /*
         * numa_node_id() works after this.
         */
        set_numa_node(cpu_to_node_map[cpuid]);
        set_numa_mem(local_memory_node(cpu_to_node_map[cpuid]));
+#endif
 
        ipi_call_lock_irq();
        spin_lock(&vector_lock);
@@ -638,7 +640,9 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callin_map);
+#ifdef CONFIG_NUMA
        set_numa_node(cpu_to_node_map[smp_processor_id()]);
+#endif
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
        paravirt_post_smp_prepare_boot_cpu();
 }
index 3efea7d..2437718 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/random.h>
 #include <asm/mmzone.h>
 #include <asm/numa.h>
 
@@ -50,6 +51,22 @@ paddr_to_nid(unsigned long paddr)
        return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
 }
 
+/*
+ * Return the bit number of a random bit set in the nodemask.
+ *   (returns -1 if nodemask is empty)
+ */
+int __node_random(const nodemask_t *maskp)
+{
+       int w, bit = -1;
+
+       w = nodes_weight(*maskp);
+       if (w)
+               bit = bitmap_ord_to_pos(maskp->bits,
+                       get_random_int() % w, MAX_NUMNODES);
+       return bit;
+}
+EXPORT_SYMBOL(__node_random);
+
 #if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)
 /*
  * Because of holes evaluate on section limits.
index 64aff52..aa2533a 100644 (file)
@@ -335,8 +335,11 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
 }
 
 struct pci_bus * __devinit
-pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
+pci_acpi_scan_root(struct acpi_pci_root *root)
 {
+       struct acpi_device *device = root->device;
+       int domain = root->segment;
+       int bus = root->secondary.start;
        struct pci_controller *controller;
        unsigned int windows = 0;
        struct pci_bus *pbus;
index 4772777..4556d82 100644 (file)
@@ -2,6 +2,7 @@
 #define _PARISC_CACHEFLUSH_H
 
 #include <linux/mm.h>
+#include <linux/uaccess.h>
 
 /* The usual comment is "Caches aren't brain-dead on the <architecture>".
  * Unfortunately, that doesn't apply to PA-RISC. */
@@ -125,11 +126,20 @@ static inline void *kmap(struct page *page)
 
 #define kunmap(page)                   kunmap_parisc(page_address(page))
 
-#define kmap_atomic(page, idx)         page_address(page)
+static inline void *kmap_atomic(struct page *page, enum km_type idx)
+{
+       pagefault_disable();
+       return page_address(page);
+}
 
-#define kunmap_atomic(addr, idx)       kunmap_parisc(addr)
+static inline void kunmap_atomic(void *addr, enum km_type idx)
+{
+       kunmap_parisc(addr);
+       pagefault_enable();
+}
 
-#define kmap_atomic_pfn(pfn, idx)      page_address(pfn_to_page(pfn))
+#define kmap_atomic_prot(page, idx, prot)      kmap_atomic(page, idx)
+#define kmap_atomic_pfn(pfn, idx)      kmap_atomic(pfn_to_page(pfn), (idx))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
 #endif
 
index ec787b4..dcd5510 100644 (file)
 #else
 #define FRAME_SIZE     64
 #endif
+#define FRAME_ALIGN    64
 
-#define align(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
+/* Add FRAME_SIZE to the size x and align it to y. All definitions
+ * that use align_frame will include space for a frame.
+ */
+#define align_frame(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
 
 int main(void)
 {
@@ -146,7 +150,8 @@ int main(void)
        DEFINE(TASK_PT_IOR, offsetof(struct task_struct, thread.regs.ior));
        BLANK();
        DEFINE(TASK_SZ, sizeof(struct task_struct));
-       DEFINE(TASK_SZ_ALGN, align(sizeof(struct task_struct), 64));
+       /* TASK_SZ_ALGN includes space for a stack frame. */
+       DEFINE(TASK_SZ_ALGN, align_frame(sizeof(struct task_struct), FRAME_ALIGN));
        BLANK();
        DEFINE(PT_PSW, offsetof(struct pt_regs, gr[ 0]));
        DEFINE(PT_GR1, offsetof(struct pt_regs, gr[ 1]));
@@ -233,7 +238,8 @@ int main(void)
        DEFINE(PT_ISR, offsetof(struct pt_regs, isr));
        DEFINE(PT_IOR, offsetof(struct pt_regs, ior));
        DEFINE(PT_SIZE, sizeof(struct pt_regs));
-       DEFINE(PT_SZ_ALGN, align(sizeof(struct pt_regs), 64));
+       /* PT_SZ_ALGN includes space for a stack frame. */
+       DEFINE(PT_SZ_ALGN, align_frame(sizeof(struct pt_regs), FRAME_ALIGN));
        BLANK();
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
        DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
@@ -242,7 +248,8 @@ int main(void)
        DEFINE(TI_SEGMENT, offsetof(struct thread_info, addr_limit));
        DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
        DEFINE(THREAD_SZ, sizeof(struct thread_info));
-       DEFINE(THREAD_SZ_ALGN, align(sizeof(struct thread_info), 64));
+       /* THREAD_SZ_ALGN includes space for a stack frame. */
+       DEFINE(THREAD_SZ_ALGN, align_frame(sizeof(struct thread_info), FRAME_ALIGN));
        BLANK();
        DEFINE(ICACHE_BASE, offsetof(struct pdc_cache_info, ic_base));
        DEFINE(ICACHE_STRIDE, offsetof(struct pdc_cache_info, ic_stride));
index 3a44f7f..6337ade 100644 (file)
        .align          32
        .endm
 
-       /* The following are simple 32 vs 64 bit instruction
-        * abstractions for the macros */
-       .macro          EXTR    reg1,start,length,reg2
-#ifdef CONFIG_64BIT
-       extrd,u         \reg1,32+(\start),\length,\reg2
-#else
-       extrw,u         \reg1,\start,\length,\reg2
-#endif
-       .endm
-
-       .macro          DEP     reg1,start,length,reg2
-#ifdef CONFIG_64BIT
-       depd            \reg1,32+(\start),\length,\reg2
-#else
-       depw            \reg1,\start,\length,\reg2
-#endif
-       .endm
-
-       .macro          DEPI    val,start,length,reg
-#ifdef CONFIG_64BIT
-       depdi           \val,32+(\start),\length,\reg
-#else
-       depwi           \val,\start,\length,\reg
-#endif
-       .endm
-
        /* In LP64, the space contains part of the upper 32 bits of the
         * fault.  We have to extract this and place it in the va,
         * zeroing the corresponding bits in the space register */
         */
        .macro          L2_ptep pmd,pte,index,va,fault
 #if PT_NLEVELS == 3
-       EXTR            \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
+       extru           \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
 #else
-       EXTR            \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+       extru           \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
 #endif
-       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       dep             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
        copy            %r0,\pte
        ldw,s           \index(\pmd),\pmd
        bb,>=,n         \pmd,_PxD_PRESENT_BIT,\fault
-       DEP             %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
+       dep             %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
        copy            \pmd,%r9
        SHLREG          %r9,PxD_VALUE_SHIFT,\pmd
-       EXTR            \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
-       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       extru           \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+       dep             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
        shladd          \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
        LDREG           %r0(\pmd),\pte          /* pmd is now pte */
        bb,>=,n         \pte,_PAGE_PRESENT_BIT,\fault
        depdi           0,31,32,\tmp
 #endif
        copy            \va,\tmp1
-       DEPI            0,31,23,\tmp1
+       depi            0,31,23,\tmp1
        cmpb,COND(<>),n \tmp,\tmp1,\fault
        ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
        depd,z          \prot,8,7,\prot
@@ -997,13 +971,6 @@ intr_restore:
 
        rfi
        nop
-       nop
-       nop
-       nop
-       nop
-       nop
-       nop
-       nop
 
 #ifndef CONFIG_PREEMPT
 # define intr_do_preempt       intr_restore
@@ -2076,9 +2043,10 @@ syscall_restore:
        LDREG   TASK_PT_GR31(%r1),%r31     /* restore syscall rp */
 
        /* NOTE: We use rsm/ssm pair to make this operation atomic */
+       LDREG   TASK_PT_GR30(%r1),%r1              /* Get user sp */
        rsm     PSW_SM_I, %r0
-       LDREG   TASK_PT_GR30(%r1),%r30             /* restore user sp */
-       mfsp    %sr3,%r1                           /* Get users space id */
+       copy    %r1,%r30                           /* Restore user sp */
+       mfsp    %sr3,%r1                           /* Get user space id */
        mtsp    %r1,%sr7                           /* Restore sr7 */
        ssm     PSW_SM_I, %r0
 
index f5f9602..68e75ce 100644 (file)
@@ -47,18 +47,17 @@ ENTRY(linux_gateway_page)
        KILL_INSN
        .endr
 
-       /* ADDRESS 0xb0 to 0xb4, lws uses 1 insns for entry */
+       /* ADDRESS 0xb0 to 0xb8, lws uses two insns for entry */
        /* Light-weight-syscall entry must always be located at 0xb0 */
        /* WARNING: Keep this number updated with table size changes */
 #define __NR_lws_entries (2)
 
 lws_entry:
-       /* Unconditional branch to lws_start, located on the 
-          same gateway page */
-       b,n     lws_start
+       gate    lws_start, %r0          /* increase privilege */
+       depi    3, 31, 2, %r31          /* Ensure we return into user mode. */
 
-       /* Fill from 0xb4 to 0xe0 */
-       .rept 11
+       /* Fill from 0xb8 to 0xe0 */
+       .rept 10
        KILL_INSN
        .endr
 
@@ -423,9 +422,6 @@ tracesys_sigexit:
 
        *********************************************************/
 lws_start:
-       /* Gate and ensure we return to userspace */
-       gate    .+8, %r0
-       depi    3, 31, 2, %r31  /* Ensure we return to userspace */
 
 #ifdef CONFIG_64BIT
        /* FIXME: If we are a 64-bit kernel just
@@ -442,7 +438,7 @@ lws_start:
 #endif 
 
         /* Is the lws entry number valid? */
-       comiclr,>>=     __NR_lws_entries, %r20, %r0
+       comiclr,>>      __NR_lws_entries, %r20, %r0
        b,n     lws_exit_nosys
 
        /* WARNING: Trashing sr2 and sr3 */
@@ -473,7 +469,7 @@ lws_exit:
        /* now reset the lowest bit of sp if it was set */
        xor     %r30,%r1,%r30
 #endif
-       be,n    0(%sr3, %r31)
+       be,n    0(%sr7, %r31)
 
 
        
@@ -529,7 +525,6 @@ lws_compare_and_swap32:
 #endif
 
 lws_compare_and_swap:
-#ifdef CONFIG_SMP
        /* Load start of lock table */
        ldil    L%lws_lock_start, %r20
        ldo     R%lws_lock_start(%r20), %r28
@@ -572,8 +567,6 @@ cas_wouldblock:
        ldo     2(%r0), %r28                            /* 2nd case */
        b       lws_exit                                /* Contended... */
        ldo     -EAGAIN(%r0), %r21                      /* Spin in userspace */
-#endif
-/* CONFIG_SMP */
 
        /*
                prev = *addr;
@@ -601,13 +594,11 @@ cas_action:
 1:     ldw     0(%sr3,%r26), %r28
        sub,<>  %r28, %r25, %r0
 2:     stw     %r24, 0(%sr3,%r26)
-#ifdef CONFIG_SMP
        /* Free lock */
        stw     %r20, 0(%sr2,%r20)
-# if ENABLE_LWS_DEBUG
+#if ENABLE_LWS_DEBUG
        /* Clear thread register indicator */
        stw     %r0, 4(%sr2,%r20)
-# endif
 #endif
        /* Return to userspace, set no error */
        b       lws_exit
@@ -615,12 +606,10 @@ cas_action:
 
 3:             
        /* Error occured on load or store */
-#ifdef CONFIG_SMP
        /* Free lock */
        stw     %r20, 0(%sr2,%r20)
-# if ENABLE_LWS_DEBUG
+#if ENABLE_LWS_DEBUG
        stw     %r0, 4(%sr2,%r20)
-# endif
 #endif
        b       lws_exit
        ldo     -EFAULT(%r0),%r21       /* set errno */
@@ -672,7 +661,6 @@ ENTRY(sys_call_table64)
 END(sys_call_table64)
 #endif
 
-#ifdef CONFIG_SMP
        /*
                All light-weight-syscall atomic operations 
                will use this set of locks 
@@ -694,8 +682,6 @@ ENTRY(lws_lock_start)
        .endr
 END(lws_lock_start)
        .previous
-#endif
-/* CONFIG_SMP for lws_lock_start */
 
 .end
 
index 3ca1c61..27a7492 100644 (file)
@@ -342,6 +342,7 @@ decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
                return SIGNALCODE(SIGFPE, FPE_FLTINV);
          case DIVISIONBYZEROEXCEPTION:
                update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+               Clear_excp_register(exception_index);
                return SIGNALCODE(SIGFPE, FPE_FLTDIV);
          case INEXACTEXCEPTION:
                update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
index c6afbfc..18162ce 100644 (file)
@@ -264,8 +264,7 @@ no_context:
 
   out_of_memory:
        up_read(&mm->mmap_sem);
-       printk(KERN_CRIT "VM: killing process %s\n", current->comm);
-       if (user_mode(regs))
-               do_group_exit(SIGKILL);
-       goto no_context;
+       if (!user_mode(regs))
+               goto no_context;
+       pagefault_out_of_memory();
 }
index 5c28082..1a40da9 100644 (file)
@@ -1849,8 +1849,7 @@ out:
        return ret;
 }
 
-static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
-                          int datasync)
+static int spufs_mfc_fsync(struct file *file, int datasync)
 {
        return spufs_mfc_flush(file, NULL);
 }
index fc1b1c4..e5e5f82 100644 (file)
@@ -251,7 +251,7 @@ const struct file_operations spufs_context_fops = {
        .llseek         = dcache_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
 };
 EXPORT_SYMBOL_GPL(spufs_context_fops);
 
index 1fefae7..e19ff02 100644 (file)
@@ -102,7 +102,7 @@ static const struct file_operations hcall_inst_seq_fops = {
 #define CPU_NAME_BUF_SIZE      32
 
 
-static void probe_hcall_entry(unsigned long opcode, unsigned long *args)
+static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long *args)
 {
        struct hcall_stats *h;
 
@@ -114,7 +114,7 @@ static void probe_hcall_entry(unsigned long opcode, unsigned long *args)
        h->purr_start = mfspr(SPRN_PURR);
 }
 
-static void probe_hcall_exit(unsigned long opcode, unsigned long retval,
+static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long retval,
                             unsigned long *retbuf)
 {
        struct hcall_stats *h;
@@ -140,11 +140,11 @@ static int __init hcall_inst_init(void)
        if (!firmware_has_feature(FW_FEATURE_LPAR))
                return 0;
 
-       if (register_trace_hcall_entry(probe_hcall_entry))
+       if (register_trace_hcall_entry(probe_hcall_entry, NULL))
                return -EINVAL;
 
-       if (register_trace_hcall_exit(probe_hcall_exit)) {
-               unregister_trace_hcall_entry(probe_hcall_entry);
+       if (register_trace_hcall_exit(probe_hcall_exit, NULL)) {
+               unregister_trace_hcall_entry(probe_hcall_entry, NULL);
                return -EINVAL;
        }
 
index 56f462c..aa2c39d 100644 (file)
@@ -85,7 +85,6 @@ extern int acpi_ioapic;
 extern int acpi_noirq;
 extern int acpi_strict;
 extern int acpi_disabled;
-extern int acpi_ht;
 extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
@@ -97,7 +96,6 @@ void acpi_pic_sci_set_trigger(unsigned int, u16);
 static inline void disable_acpi(void)
 {
        acpi_disabled = 1;
-       acpi_ht = 0;
        acpi_pci_disabled = 1;
        acpi_noirq = 1;
 }
index dca9c54..4681459 100644 (file)
@@ -332,6 +332,7 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
 #endif
 }
 
+#if __GNUC__ >= 4
 #define static_cpu_has(bit)                                    \
 (                                                              \
        __builtin_constant_p(boot_cpu_has(bit)) ?               \
@@ -340,6 +341,12 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
                __static_cpu_has(bit) :                         \
                boot_cpu_has(bit)                               \
 )
+#else
+/*
+ * gcc 3.x is too stupid to do the static test; fall back to dynamic.
+ */
+#define static_cpu_has(bit) boot_cpu_has(bit)
+#endif
 
 #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
 
index 6c3fdd6..f32a430 100644 (file)
@@ -225,5 +225,13 @@ extern void mcheck_intel_therm_init(void);
 static inline void mcheck_intel_therm_init(void) { }
 #endif
 
+/*
+ * Used by APEI to report memory error via /dev/mcelog
+ */
+
+struct cper_sec_mem_err;
+extern void apei_mce_report_mem_error(int corrected,
+                                     struct cper_sec_mem_err *mem_err);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_MCE_H */
index 62ba940..f0b6e5d 100644 (file)
@@ -239,8 +239,8 @@ static inline struct thread_info *current_thread_info(void)
 #define TS_USEDFPU             0x0001  /* FPU was used by this task
                                           this quantum (SMP) */
 #define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
-#define TS_POLLING             0x0004  /* true if in idle loop
-                                          and not sleeping */
+#define TS_POLLING             0x0004  /* idle task polling need_resched,
+                                          skip sending interrupt */
 #define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
 
 #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
index 488be46..60cc405 100644 (file)
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(acpi_disabled);
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
 int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
-int acpi_ht __initdata = 1;    /* enable HT */
 
 int acpi_lapic;
 int acpi_ioapic;
@@ -1501,9 +1500,8 @@ void __init acpi_boot_table_init(void)
 
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return; 
 
        /*
@@ -1534,9 +1532,8 @@ int __init early_acpi_boot_init(void)
 {
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return 1;
 
        /*
@@ -1554,9 +1551,8 @@ int __init acpi_boot_init(void)
 
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return 1;
 
        acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
@@ -1591,21 +1587,12 @@ static int __init parse_acpi(char *arg)
        /* acpi=force to over-ride black-list */
        else if (strcmp(arg, "force") == 0) {
                acpi_force = 1;
-               acpi_ht = 1;
                acpi_disabled = 0;
        }
        /* acpi=strict disables out-of-spec workarounds */
        else if (strcmp(arg, "strict") == 0) {
                acpi_strict = 1;
        }
-       /* Limit ACPI just to boot-time to enable HT */
-       else if (strcmp(arg, "ht") == 0) {
-               if (!acpi_force) {
-                       printk(KERN_WARNING "acpi=ht will be removed in Linux-2.6.35\n");
-                       disable_acpi();
-               }
-               acpi_ht = 1;
-       }
        /* acpi=rsdt use RSDT instead of XSDT */
        else if (strcmp(arg, "rsdt") == 0) {
                acpi_rsdt_forced = 1;
index f996103..82e5086 100644 (file)
@@ -162,8 +162,6 @@ static int __init acpi_sleep_setup(char *str)
 #endif
                if (strncmp(str, "old_ordering", 12) == 0)
                        acpi_old_suspend_ordering();
-               if (strncmp(str, "sci_force_enable", 16) == 0)
-                       acpi_set_sci_en_on_resume();
                str = strchr(str, ',');
                if (str != NULL)
                        str += strspn(str, ", \t");
index e5a4a1e..c02cc69 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/smp.h>
 #include <asm/mce.h>
 #include <asm/kvm_para.h>
+#include <asm/tsc.h>
 
 unsigned int num_processors;
 
@@ -1151,8 +1152,13 @@ static void __cpuinit lapic_setup_esr(void)
  */
 void __cpuinit setup_local_APIC(void)
 {
-       unsigned int value;
-       int i, j;
+       unsigned int value, queued;
+       int i, j, acked = 0;
+       unsigned long long tsc = 0, ntsc;
+       long long max_loops = cpu_khz;
+
+       if (cpu_has_tsc)
+               rdtscll(tsc);
 
        if (disable_apic) {
                arch_disable_smp_support();
@@ -1204,13 +1210,32 @@ void __cpuinit setup_local_APIC(void)
         * the interrupt. Hence a vector might get locked. It was noticed
         * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
         */
-       for (i = APIC_ISR_NR - 1; i >= 0; i--) {
-               value = apic_read(APIC_ISR + i*0x10);
-               for (j = 31; j >= 0; j--) {
-                       if (value & (1<<j))
-                               ack_APIC_irq();
+       do {
+               queued = 0;
+               for (i = APIC_ISR_NR - 1; i >= 0; i--)
+                       queued |= apic_read(APIC_IRR + i*0x10);
+
+               for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+                       value = apic_read(APIC_ISR + i*0x10);
+                       for (j = 31; j >= 0; j--) {
+                               if (value & (1<<j)) {
+                                       ack_APIC_irq();
+                                       acked++;
+                               }
+                       }
                }
-       }
+               if (acked > 256) {
+                       printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
+                              acked);
+                       break;
+               }
+               if (cpu_has_tsc) {
+                       rdtscll(ntsc);
+                       max_loops = (cpu_khz << 10) - (ntsc - tsc);
+               } else
+                       max_loops--;
+       } while (queued && max_loops > 0);
+       WARN_ON(max_loops <= 0);
 
        /*
         * Now that we are all set up, enable the APIC
index 6f3dc8f..7ec2123 100644 (file)
@@ -1497,8 +1497,8 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
  * simply keep the boost-disable flag in sync with the current global
  * state.
  */
-static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
-                               void *hcpu)
+static int cpb_notify(struct notifier_block *nb, unsigned long action,
+                     void *hcpu)
 {
        unsigned cpu = (long)hcpu;
        u32 lo, hi;
@@ -1528,7 +1528,7 @@ static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpb_nb = {
+static struct notifier_block cpb_nb = {
        .notifier_call          = cpb_notify,
 };
 
index 4ac6d48..bb34b03 100644 (file)
@@ -7,3 +7,5 @@ obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
 obj-$(CONFIG_X86_MCE_INJECT)   += mce-inject.o
 
 obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
+
+obj-$(CONFIG_ACPI_APEI)                += mce-apei.o
diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c
new file mode 100644 (file)
index 0000000..745b54f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Bridge between MCE and APEI
+ *
+ * On some machine, corrected memory errors are reported via APEI
+ * generic hardware error source (GHES) instead of corrected Machine
+ * Check. These corrected memory errors can be reported to user space
+ * through /dev/mcelog via faking a corrected Machine Check, so that
+ * the error memory page can be offlined by /sbin/mcelog if the error
+ * count for one page is beyond the threshold.
+ *
+ * For fatal MCE, save MCE record into persistent storage via ERST, so
+ * that the MCE record can be logged after reboot via ERST.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/cper.h>
+#include <acpi/apei.h>
+#include <asm/mce.h>
+
+#include "mce-internal.h"
+
+void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err)
+{
+       struct mce m;
+
+       /* Only corrected MC is reported */
+       if (!corrected)
+               return;
+
+       mce_setup(&m);
+       m.bank = 1;
+       /* Fake a memory read corrected error with unknown channel */
+       m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f;
+       m.addr = mem_err->physical_addr;
+       mce_log(&m);
+       mce_notify_irq();
+}
+EXPORT_SYMBOL_GPL(apei_mce_report_mem_error);
+
+#define CPER_CREATOR_MCE                                               \
+       UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c,     \
+               0x64, 0x90, 0xb8, 0x9d)
+#define CPER_SECTION_TYPE_MCE                                          \
+       UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96,     \
+               0x04, 0x4a, 0x38, 0xfc)
+
+/*
+ * CPER specification (in UEFI specification 2.3 appendix N) requires
+ * byte-packed.
+ */
+struct cper_mce_record {
+       struct cper_record_header hdr;
+       struct cper_section_descriptor sec_hdr;
+       struct mce mce;
+} __packed;
+
+int apei_write_mce(struct mce *m)
+{
+       struct cper_mce_record rcd;
+
+       memset(&rcd, 0, sizeof(rcd));
+       memcpy(rcd.hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
+       rcd.hdr.revision = CPER_RECORD_REV;
+       rcd.hdr.signature_end = CPER_SIG_END;
+       rcd.hdr.section_count = 1;
+       rcd.hdr.error_severity = CPER_SER_FATAL;
+       /* timestamp, platform_id, partition_id are all invalid */
+       rcd.hdr.validation_bits = 0;
+       rcd.hdr.record_length = sizeof(rcd);
+       rcd.hdr.creator_id = CPER_CREATOR_MCE;
+       rcd.hdr.notification_type = CPER_NOTIFY_MCE;
+       rcd.hdr.record_id = cper_next_record_id();
+       rcd.hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
+
+       rcd.sec_hdr.section_offset = (void *)&rcd.mce - (void *)&rcd;
+       rcd.sec_hdr.section_length = sizeof(rcd.mce);
+       rcd.sec_hdr.revision = CPER_SEC_REV;
+       /* fru_id and fru_text is invalid */
+       rcd.sec_hdr.validation_bits = 0;
+       rcd.sec_hdr.flags = CPER_SEC_PRIMARY;
+       rcd.sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
+       rcd.sec_hdr.section_severity = CPER_SER_FATAL;
+
+       memcpy(&rcd.mce, m, sizeof(*m));
+
+       return erst_write(&rcd.hdr);
+}
+
+ssize_t apei_read_mce(struct mce *m, u64 *record_id)
+{
+       struct cper_mce_record rcd;
+       ssize_t len;
+
+       len = erst_read_next(&rcd.hdr, sizeof(rcd));
+       if (len <= 0)
+               return len;
+       /* Can not skip other records in storage via ERST unless clear them */
+       else if (len != sizeof(rcd) ||
+                uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
+               if (printk_ratelimit())
+                       pr_warning(
+                       "MCE-APEI: Can not skip the unknown record in ERST");
+               return -EIO;
+       }
+
+       memcpy(m, &rcd.mce, sizeof(*m));
+       *record_id = rcd.hdr.record_id;
+
+       return sizeof(*m);
+}
+
+/* Check whether there is record in ERST */
+int apei_check_mce(void)
+{
+       return erst_get_record_count();
+}
+
+int apei_clear_mce(u64 record_id)
+{
+       return erst_clear(record_id);
+}
index 32996f9..fefcc69 100644 (file)
@@ -28,3 +28,26 @@ extern int mce_ser;
 
 extern struct mce_bank *mce_banks;
 
+#ifdef CONFIG_ACPI_APEI
+int apei_write_mce(struct mce *m);
+ssize_t apei_read_mce(struct mce *m, u64 *record_id);
+int apei_check_mce(void);
+int apei_clear_mce(u64 record_id);
+#else
+static inline int apei_write_mce(struct mce *m)
+{
+       return -EINVAL;
+}
+static inline ssize_t apei_read_mce(struct mce *m, u64 *record_id)
+{
+       return 0;
+}
+static inline int apei_check_mce(void)
+{
+       return 0;
+}
+static inline int apei_clear_mce(u64 record_id)
+{
+       return -EINVAL;
+}
+#endif
index 7a355dd..707165d 100644 (file)
@@ -264,7 +264,7 @@ static void wait_for_panic(void)
 
 static void mce_panic(char *msg, struct mce *final, char *exp)
 {
-       int i;
+       int i, apei_err = 0;
 
        if (!fake_panic) {
                /*
@@ -287,8 +287,11 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
                struct mce *m = &mcelog.entry[i];
                if (!(m->status & MCI_STATUS_VAL))
                        continue;
-               if (!(m->status & MCI_STATUS_UC))
+               if (!(m->status & MCI_STATUS_UC)) {
                        print_mce(m);
+                       if (!apei_err)
+                               apei_err = apei_write_mce(m);
+               }
        }
        /* Now print uncorrected but with the final one last */
        for (i = 0; i < MCE_LOG_LEN; i++) {
@@ -297,11 +300,17 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
                        continue;
                if (!(m->status & MCI_STATUS_UC))
                        continue;
-               if (!final || memcmp(m, final, sizeof(struct mce)))
+               if (!final || memcmp(m, final, sizeof(struct mce))) {
                        print_mce(m);
+                       if (!apei_err)
+                               apei_err = apei_write_mce(m);
+               }
        }
-       if (final)
+       if (final) {
                print_mce(final);
+               if (!apei_err)
+                       apei_err = apei_write_mce(final);
+       }
        if (cpu_missing)
                printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
        print_mce_tail();
@@ -1493,6 +1502,43 @@ static void collect_tscs(void *data)
        rdtscll(cpu_tsc[smp_processor_id()]);
 }
 
+static int mce_apei_read_done;
+
+/* Collect MCE record of previous boot in persistent storage via APEI ERST. */
+static int __mce_read_apei(char __user **ubuf, size_t usize)
+{
+       int rc;
+       u64 record_id;
+       struct mce m;
+
+       if (usize < sizeof(struct mce))
+               return -EINVAL;
+
+       rc = apei_read_mce(&m, &record_id);
+       /* Error or no more MCE record */
+       if (rc <= 0) {
+               mce_apei_read_done = 1;
+               return rc;
+       }
+       rc = -EFAULT;
+       if (copy_to_user(*ubuf, &m, sizeof(struct mce)))
+               return rc;
+       /*
+        * In fact, we should have cleared the record after that has
+        * been flushed to the disk or sent to network in
+        * /sbin/mcelog, but we have no interface to support that now,
+        * so just clear it to avoid duplication.
+        */
+       rc = apei_clear_mce(record_id);
+       if (rc) {
+               mce_apei_read_done = 1;
+               return rc;
+       }
+       *ubuf += sizeof(struct mce);
+
+       return 0;
+}
+
 static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
                        loff_t *off)
 {
@@ -1506,15 +1552,19 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
                return -ENOMEM;
 
        mutex_lock(&mce_read_mutex);
+
+       if (!mce_apei_read_done) {
+               err = __mce_read_apei(&buf, usize);
+               if (err || buf != ubuf)
+                       goto out;
+       }
+
        next = rcu_dereference_check_mce(mcelog.next);
 
        /* Only supports full reads right now */
-       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
-               mutex_unlock(&mce_read_mutex);
-               kfree(cpu_tsc);
-
-               return -EINVAL;
-       }
+       err = -EINVAL;
+       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce))
+               goto out;
 
        err = 0;
        prev = 0;
@@ -1562,10 +1612,15 @@ timeout:
                        memset(&mcelog.entry[i], 0, sizeof(struct mce));
                }
        }
+
+       if (err)
+               err = -EFAULT;
+
+out:
        mutex_unlock(&mce_read_mutex);
        kfree(cpu_tsc);
 
-       return err ? -EFAULT : buf - ubuf;
+       return err ? err : buf - ubuf;
 }
 
 static unsigned int mce_poll(struct file *file, poll_table *wait)
@@ -1573,6 +1628,8 @@ static unsigned int mce_poll(struct file *file, poll_table *wait)
        poll_wait(file, &mce_wait, wait);
        if (rcu_dereference_check_mce(mcelog.next))
                return POLLIN | POLLRDNORM;
+       if (!mce_apei_read_done && apei_check_mce())
+               return POLLIN | POLLRDNORM;
        return 0;
 }
 
index e802989..b4ae4ac 100644 (file)
@@ -676,6 +676,17 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "DG45FC"),
                },
        },
+       /*
+        * The Dell Inspiron Mini 1012 has DMI_BIOS_VENDOR = "Dell Inc.", so
+        * match on the product name.
+        */
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "Phoenix BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
+               },
+       },
 #endif
        {}
 };
index 763d815..37462f1 100644 (file)
@@ -1215,9 +1215,17 @@ __init void prefill_possible_map(void)
        if (!num_processors)
                num_processors = 1;
 
-       if (setup_possible_cpus == -1)
-               possible = num_processors + disabled_cpus;
-       else
+       i = setup_max_cpus ?: 1;
+       if (setup_possible_cpus == -1) {
+               possible = num_processors;
+#ifdef CONFIG_HOTPLUG_CPU
+               if (setup_max_cpus)
+                       possible += disabled_cpus;
+#else
+               if (possible > i)
+                       possible = i;
+#endif
+       } else
                possible = setup_possible_cpus;
 
        total_cpus = max_t(int, possible, num_processors + disabled_cpus);
@@ -1230,11 +1238,23 @@ __init void prefill_possible_map(void)
                possible = nr_cpu_ids;
        }
 
+#ifdef CONFIG_HOTPLUG_CPU
+       if (!setup_max_cpus)
+#endif
+       if (possible > i) {
+               printk(KERN_WARNING
+                       "%d Processors exceeds max_cpus limit of %u\n",
+                       possible, setup_max_cpus);
+               possible = i;
+       }
+
        printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
                possible, max_t(int, possible - num_processors, 0));
 
        for (i = 0; i < possible; i++)
                set_cpu_possible(i, true);
+       for (; i < NR_CPUS; i++)
+               set_cpu_possible(i, false);
 
        nr_cpu_ids = possible;
 }
index 2bdf628..9257510 100644 (file)
@@ -1390,7 +1390,6 @@ __init void lguest_init(void)
 #endif
 #ifdef CONFIG_ACPI
        acpi_disabled = 1;
-       acpi_ht = 0;
 #endif
 
        /*
index 10c27bb..550df48 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/topology.h>
 #include <linux/module.h>
 #include <linux/bootmem.h>
-#include <linux/random.h>
 
 #ifdef CONFIG_DEBUG_PER_CPU_MAPS
 # define DBG(x...) printk(KERN_DEBUG x)
@@ -66,19 +65,3 @@ const struct cpumask *cpumask_of_node(int node)
 }
 EXPORT_SYMBOL(cpumask_of_node);
 #endif
-
-/*
- * Return the bit number of a random bit set in the nodemask.
- *   (returns -1 if nodemask is empty)
- */
-int __node_random(const nodemask_t *maskp)
-{
-       int w, bit = -1;
-
-       w = nodes_weight(*maskp);
-       if (w)
-               bit = bitmap_ord_to_pos(maskp->bits,
-                       get_random_int() % w, MAX_NUMNODES);
-       return bit;
-}
-EXPORT_SYMBOL(__node_random);
index bbe5502..acc15b2 100644 (file)
@@ -336,6 +336,7 @@ int free_memtype(u64 start, u64 end)
 {
        int err = -EINVAL;
        int is_range_ram;
+       struct memtype *entry;
 
        if (!pat_enabled)
                return 0;
@@ -355,17 +356,20 @@ int free_memtype(u64 start, u64 end)
        }
 
        spin_lock(&memtype_lock);
-       err = rbt_memtype_erase(start, end);
+       entry = rbt_memtype_erase(start, end);
        spin_unlock(&memtype_lock);
 
-       if (err) {
+       if (!entry) {
                printk(KERN_INFO "%s:%d freeing invalid memtype %Lx-%Lx\n",
                        current->comm, current->pid, start, end);
+               return -EINVAL;
        }
 
+       kfree(entry);
+
        dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end);
 
-       return err;
+       return 0;
 }
 
 
index 4f39eef..77e5ba1 100644 (file)
@@ -28,15 +28,15 @@ static inline char *cattr_name(unsigned long flags)
 #ifdef CONFIG_X86_PAT
 extern int rbt_memtype_check_insert(struct memtype *new,
                                        unsigned long *new_type);
-extern int rbt_memtype_erase(u64 start, u64 end);
+extern struct memtype *rbt_memtype_erase(u64 start, u64 end);
 extern struct memtype *rbt_memtype_lookup(u64 addr);
 extern int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos);
 #else
 static inline int rbt_memtype_check_insert(struct memtype *new,
                                        unsigned long *new_type)
 { return 0; }
-static inline int rbt_memtype_erase(u64 start, u64 end)
-{ return 0; }
+static inline struct memtype *rbt_memtype_erase(u64 start, u64 end)
+{ return NULL; }
 static inline struct memtype *rbt_memtype_lookup(u64 addr)
 { return NULL; }
 static inline int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos)
index 07de4cb..f537087 100644 (file)
@@ -231,16 +231,17 @@ int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type)
        return err;
 }
 
-int rbt_memtype_erase(u64 start, u64 end)
+struct memtype *rbt_memtype_erase(u64 start, u64 end)
 {
        struct memtype *data;
 
        data = memtype_rb_exact_match(&memtype_rbroot, start, end);
        if (!data)
-               return -EINVAL;
+               goto out;
 
        rb_erase(&data->rb, &memtype_rbroot);
-       return 0;
+out:
+       return data;
 }
 
 struct memtype *rbt_memtype_lookup(u64 addr)
index 7928540..cac7184 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/pagemap.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
-#include <linux/quicklist.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 31930fd..2ec04c4 100644 (file)
@@ -207,10 +207,9 @@ get_current_resources(struct acpi_device *device, int busnum,
        if (!info.res)
                goto res_alloc_fail;
 
-       info.name = kmalloc(16, GFP_KERNEL);
+       info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
        if (!info.name)
                goto name_alloc_fail;
-       sprintf(info.name, "PCI Bus %04x:%02x", domain, busnum);
 
        info.res_num = 0;
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
@@ -224,8 +223,11 @@ res_alloc_fail:
        return;
 }
 
-struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
+struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 {
+       struct acpi_device *device = root->device;
+       int domain = root->segment;
+       int busnum = root->secondary.start;
        struct pci_bus *bus;
        struct pci_sysdata *sd;
        int node;
index f42a030..91874e0 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PCI)             += pci/
 obj-$(CONFIG_PARISC)           += parisc/
 obj-$(CONFIG_RAPIDIO)          += rapidio/
 obj-y                          += video/
+obj-y                          += idle/
 obj-$(CONFIG_ACPI)             += acpi/
 obj-$(CONFIG_SFI)              += sfi/
 # PnP must come after ACPI since it will eventually need to check if acpi
@@ -91,7 +92,6 @@ obj-$(CONFIG_EISA)            += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
-obj-y                          += idle/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-$(CONFIG_NEW_LEDS)         += leds/
index 93d2c79..7464115 100644 (file)
@@ -360,4 +360,13 @@ config ACPI_SBS
          To compile this driver as a module, choose M here:
          the modules will be called sbs and sbshc.
 
+config ACPI_HED
+       tristate "Hardware Error Device"
+       help
+         This driver supports the Hardware Error Device (PNP0C33),
+         which is used to report some hardware errors notified via
+         SCI, mainly the corrected errors.
+
+source "drivers/acpi/apei/Kconfig"
+
 endif  # ACPI
index a8d8998..6ee3316 100644 (file)
@@ -19,7 +19,7 @@ obj-y                         += acpi.o \
 
 # All the builtin files are in the "acpi." module_param namespace.
 acpi-y                         += osl.o utils.o reboot.o
-acpi-y                         += hest.o
+acpi-y                         += atomicio.o
 
 # sleep related files
 acpi-y                         += wakeup.o
@@ -59,6 +59,7 @@ obj-$(CONFIG_ACPI_BATTERY)    += battery.o
 obj-$(CONFIG_ACPI_SBS)         += sbshc.o
 obj-$(CONFIG_ACPI_SBS)         += sbs.o
 obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
+obj-$(CONFIG_ACPI_HED)         += hed.o
 
 # processor has its own "processor." module_param namespace
 processor-y                    := processor_driver.o processor_throttling.o
@@ -66,3 +67,5 @@ processor-y                   += processor_idle.o processor_thermal.o
 processor-$(CONFIG_CPU_FREQ)   += processor_perflib.o
 
 obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
+
+obj-$(CONFIG_ACPI_APEI)                += apei/
index 6212213..d269a8f 100644 (file)
@@ -43,6 +43,10 @@ static DEFINE_MUTEX(isolated_cpus_lock);
 #define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
 #define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
 static unsigned long power_saving_mwait_eax;
+
+static unsigned char tsc_detected_unstable;
+static unsigned char tsc_marked_unstable;
+
 static void power_saving_mwait_init(void)
 {
        unsigned int eax, ebx, ecx, edx;
@@ -87,8 +91,8 @@ static void power_saving_mwait_init(void)
 
                /*FALL THROUGH*/
        default:
-               /* TSC could halt in idle, so notify users */
-               mark_tsc_unstable("TSC halts in idle");
+               /* TSC could halt in idle */
+               tsc_detected_unstable = 1;
        }
 #endif
 }
@@ -168,16 +172,14 @@ static int power_saving_thread(void *data)
 
                do_sleep = 0;
 
-               current_thread_info()->status &= ~TS_POLLING;
-               /*
-                * TS_POLLING-cleared state must be visible before we test
-                * NEED_RESCHED:
-                */
-               smp_mb();
-
                expire_time = jiffies + HZ * (100 - idle_pct) / 100;
 
                while (!need_resched()) {
+                       if (tsc_detected_unstable && !tsc_marked_unstable) {
+                               /* TSC could halt in idle, so notify users */
+                               mark_tsc_unstable("TSC halts in idle");
+                               tsc_marked_unstable = 1;
+                       }
                        local_irq_disable();
                        cpu = smp_processor_id();
                        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
@@ -200,8 +202,6 @@ static int power_saving_thread(void *data)
                        }
                }
 
-               current_thread_info()->status |= TS_POLLING;
-
                /*
                 * current sched_rt has threshold for rt task running time.
                 * When a rt task uses 95% CPU time, the rt thread will be
index 7c7bbb4..d5a5efc 100644 (file)
@@ -69,7 +69,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
 acpi_status acpi_enable(void)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_enable);
 
@@ -84,21 +84,30 @@ acpi_status acpi_enable(void)
        if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "System is already in ACPI mode\n"));
-       } else {
-               /* Transition to ACPI mode */
+               return_ACPI_STATUS(AE_OK);
+       }
 
-               status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not transition to ACPI mode"));
-                       return_ACPI_STATUS(status);
-               }
+       /* Transition to ACPI mode */
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INIT,
-                                 "Transition to ACPI mode successful\n"));
+       status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not transition to ACPI mode"));
+               return_ACPI_STATUS(status);
        }
 
-       return_ACPI_STATUS(status);
+       /* Sanity check that transition succeeded */
+
+       if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) {
+               ACPI_ERROR((AE_INFO,
+                           "Hardware did not enter ACPI mode"));
+               return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INIT,
+                         "Transition to ACPI mode successful\n"));
+
+       return_ACPI_STATUS(AE_OK);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_enable)
index 679a112..b44274a 100644 (file)
@@ -63,7 +63,6 @@ acpi_status acpi_hw_set_mode(u32 mode)
 {
 
        acpi_status status;
-       u32 retry;
 
        ACPI_FUNCTION_TRACE(hw_set_mode);
 
@@ -125,24 +124,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
                return_ACPI_STATUS(status);
        }
 
-       /*
-        * Some hardware takes a LONG time to switch modes. Give them 3 sec to
-        * do so, but allow faster systems to proceed more quickly.
-        */
-       retry = 3000;
-       while (retry) {
-               if (acpi_hw_get_mode() == mode) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Mode %X successfully enabled\n",
-                                         mode));
-                       return_ACPI_STATUS(AE_OK);
-               }
-               acpi_os_stall(1000);
-               retry--;
-       }
-
-       ACPI_ERROR((AE_INFO, "Hardware did not change modes"));
-       return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+       return_ACPI_STATUS(AE_OK);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
new file mode 100644 (file)
index 0000000..f8c668f
--- /dev/null
@@ -0,0 +1,30 @@
+config ACPI_APEI
+       bool "ACPI Platform Error Interface (APEI)"
+       depends on X86
+       help
+         APEI allows to report errors (for example from the chipset)
+         to the operating system. This improves NMI handling
+         especially. In addition it supports error serialization and
+         error injection.
+
+config ACPI_APEI_GHES
+       tristate "APEI Generic Hardware Error Source"
+       depends on ACPI_APEI && X86
+       select ACPI_HED
+       help
+         Generic Hardware Error Source provides a way to report
+         platform hardware errors (such as that from chipset). It
+         works in so called "Firmware First" mode, that is, hardware
+         errors are reported to firmware firstly, then reported to
+         Linux by firmware. This way, some non-standard hardware
+         error registers or non-standard hardware link can be checked
+         by firmware to produce more valuable hardware error
+         information for Linux.
+
+config ACPI_APEI_EINJ
+       tristate "APEI Error INJection (EINJ)"
+       depends on ACPI_APEI && DEBUG_FS
+       help
+         EINJ provides a hardware error injection mechanism, it is
+         mainly used for debugging and testing the other parts of
+         APEI and some other RAS features.
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
new file mode 100644 (file)
index 0000000..b13b03a
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_ACPI_APEI)                += apei.o
+obj-$(CONFIG_ACPI_APEI_GHES)   += ghes.o
+obj-$(CONFIG_ACPI_APEI_EINJ)   += einj.o
+
+apei-y := apei-base.o hest.o cper.o erst.o
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
new file mode 100644 (file)
index 0000000..db3946e
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * apei-base.c - ACPI Platform Error Interface (APEI) supporting
+ * infrastructure
+ *
+ * APEI allows to report errors (for example from the chipset) to the
+ * the operating system. This improves NMI handling especially. In
+ * addition it supports error serialization and error injection.
+ *
+ * For more information about APEI, please refer to ACPI Specification
+ * version 4.0, chapter 17.
+ *
+ * This file has Common functions used by more than one APEI table,
+ * including framework of interpreter for ERST and EINJ; resource
+ * management for APEI registers.
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/kref.h>
+#include <linux/rculist.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <acpi/atomicio.h>
+
+#include "apei-internal.h"
+
+#define APEI_PFX "APEI: "
+
+/*
+ * APEI ERST (Error Record Serialization Table) and EINJ (Error
+ * INJection) interpreter framework.
+ */
+
+#define APEI_EXEC_PRESERVE_REGISTER    0x1
+
+void apei_exec_ctx_init(struct apei_exec_context *ctx,
+                       struct apei_exec_ins_type *ins_table,
+                       u32 instructions,
+                       struct acpi_whea_header *action_table,
+                       u32 entries)
+{
+       ctx->ins_table = ins_table;
+       ctx->instructions = instructions;
+       ctx->action_table = action_table;
+       ctx->entries = entries;
+}
+EXPORT_SYMBOL_GPL(apei_exec_ctx_init);
+
+int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
+{
+       int rc;
+
+       rc = acpi_atomic_read(val, &entry->register_region);
+       if (rc)
+               return rc;
+       *val >>= entry->register_region.bit_offset;
+       *val &= entry->mask;
+
+       return 0;
+}
+
+int apei_exec_read_register(struct apei_exec_context *ctx,
+                           struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val = 0;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       ctx->value = val;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_read_register);
+
+int apei_exec_read_register_value(struct apei_exec_context *ctx,
+                                 struct acpi_whea_header *entry)
+{
+       int rc;
+
+       rc = apei_exec_read_register(ctx, entry);
+       if (rc)
+               return rc;
+       ctx->value = (ctx->value == entry->value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_read_register_value);
+
+int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
+{
+       int rc;
+
+       val &= entry->mask;
+       val <<= entry->register_region.bit_offset;
+       if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
+               u64 valr = 0;
+               rc = acpi_atomic_read(&valr, &entry->register_region);
+               if (rc)
+                       return rc;
+               valr &= ~(entry->mask << entry->register_region.bit_offset);
+               val |= valr;
+       }
+       rc = acpi_atomic_write(val, &entry->register_region);
+
+       return rc;
+}
+
+int apei_exec_write_register(struct apei_exec_context *ctx,
+                            struct acpi_whea_header *entry)
+{
+       return __apei_exec_write_register(entry, ctx->value);
+}
+EXPORT_SYMBOL_GPL(apei_exec_write_register);
+
+int apei_exec_write_register_value(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry)
+{
+       int rc;
+
+       ctx->value = entry->value;
+       rc = apei_exec_write_register(ctx, entry);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(apei_exec_write_register_value);
+
+int apei_exec_noop(struct apei_exec_context *ctx,
+                  struct acpi_whea_header *entry)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_noop);
+
+/*
+ * Interpret the specified action. Go through whole action table,
+ * execute all instructions belong to the action.
+ */
+int apei_exec_run(struct apei_exec_context *ctx, u8 action)
+{
+       int rc;
+       u32 i, ip;
+       struct acpi_whea_header *entry;
+       apei_exec_ins_func_t run;
+
+       ctx->ip = 0;
+
+       /*
+        * "ip" is the instruction pointer of current instruction,
+        * "ctx->ip" specifies the next instruction to executed,
+        * instruction "run" function may change the "ctx->ip" to
+        * implement "goto" semantics.
+        */
+rewind:
+       ip = 0;
+       for (i = 0; i < ctx->entries; i++) {
+               entry = &ctx->action_table[i];
+               if (entry->action != action)
+                       continue;
+               if (ip == ctx->ip) {
+                       if (entry->instruction >= ctx->instructions ||
+                           !ctx->ins_table[entry->instruction].run) {
+                               pr_warning(FW_WARN APEI_PFX
+                       "Invalid action table, unknown instruction type: %d\n",
+                                          entry->instruction);
+                               return -EINVAL;
+                       }
+                       run = ctx->ins_table[entry->instruction].run;
+                       rc = run(ctx, entry);
+                       if (rc < 0)
+                               return rc;
+                       else if (rc != APEI_EXEC_SET_IP)
+                               ctx->ip++;
+               }
+               ip++;
+               if (ctx->ip < ip)
+                       goto rewind;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_run);
+
+typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx,
+                                     struct acpi_whea_header *entry,
+                                     void *data);
+
+static int apei_exec_for_each_entry(struct apei_exec_context *ctx,
+                                   apei_exec_entry_func_t func,
+                                   void *data,
+                                   int *end)
+{
+       u8 ins;
+       int i, rc;
+       struct acpi_whea_header *entry;
+       struct apei_exec_ins_type *ins_table = ctx->ins_table;
+
+       for (i = 0; i < ctx->entries; i++) {
+               entry = ctx->action_table + i;
+               ins = entry->instruction;
+               if (end)
+                       *end = i;
+               if (ins >= ctx->instructions || !ins_table[ins].run) {
+                       pr_warning(FW_WARN APEI_PFX
+                       "Invalid action table, unknown instruction type: %d\n",
+                                  ins);
+                       return -EINVAL;
+               }
+               rc = func(ctx, entry, data);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int pre_map_gar_callback(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry,
+                               void *data)
+{
+       u8 ins = entry->instruction;
+
+       if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
+               return acpi_pre_map_gar(&entry->register_region);
+
+       return 0;
+}
+
+/*
+ * Pre-map all GARs in action table to make it possible to access them
+ * in NMI handler.
+ */
+int apei_exec_pre_map_gars(struct apei_exec_context *ctx)
+{
+       int rc, end;
+
+       rc = apei_exec_for_each_entry(ctx, pre_map_gar_callback,
+                                     NULL, &end);
+       if (rc) {
+               struct apei_exec_context ctx_unmap;
+               memcpy(&ctx_unmap, ctx, sizeof(*ctx));
+               ctx_unmap.entries = end;
+               apei_exec_post_unmap_gars(&ctx_unmap);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(apei_exec_pre_map_gars);
+
+static int post_unmap_gar_callback(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry,
+                                  void *data)
+{
+       u8 ins = entry->instruction;
+
+       if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
+               acpi_post_unmap_gar(&entry->register_region);
+
+       return 0;
+}
+
+/* Post-unmap all GAR in action table. */
+int apei_exec_post_unmap_gars(struct apei_exec_context *ctx)
+{
+       return apei_exec_for_each_entry(ctx, post_unmap_gar_callback,
+                                       NULL, NULL);
+}
+EXPORT_SYMBOL_GPL(apei_exec_post_unmap_gars);
+
+/*
+ * Resource management for GARs in APEI
+ */
+struct apei_res {
+       struct list_head list;
+       unsigned long start;
+       unsigned long end;
+};
+
+/* Collect all resources requested, to avoid conflict */
+struct apei_resources apei_resources_all = {
+       .iomem = LIST_HEAD_INIT(apei_resources_all.iomem),
+       .ioport = LIST_HEAD_INIT(apei_resources_all.ioport),
+};
+
+static int apei_res_add(struct list_head *res_list,
+                       unsigned long start, unsigned long size)
+{
+       struct apei_res *res, *resn, *res_ins = NULL;
+       unsigned long end = start + size;
+
+       if (end <= start)
+               return 0;
+repeat:
+       list_for_each_entry_safe(res, resn, res_list, list) {
+               if (res->start > end || res->end < start)
+                       continue;
+               else if (end <= res->end && start >= res->start) {
+                       kfree(res_ins);
+                       return 0;
+               }
+               list_del(&res->list);
+               res->start = start = min(res->start, start);
+               res->end = end = max(res->end, end);
+               kfree(res_ins);
+               res_ins = res;
+               goto repeat;
+       }
+
+       if (res_ins)
+               list_add(&res_ins->list, res_list);
+       else {
+               res_ins = kmalloc(sizeof(*res), GFP_KERNEL);
+               if (!res_ins)
+                       return -ENOMEM;
+               res_ins->start = start;
+               res_ins->end = end;
+               list_add(&res_ins->list, res_list);
+       }
+
+       return 0;
+}
+
+static int apei_res_sub(struct list_head *res_list1,
+                       struct list_head *res_list2)
+{
+       struct apei_res *res1, *resn1, *res2, *res;
+       res1 = list_entry(res_list1->next, struct apei_res, list);
+       resn1 = list_entry(res1->list.next, struct apei_res, list);
+       while (&res1->list != res_list1) {
+               list_for_each_entry(res2, res_list2, list) {
+                       if (res1->start >= res2->end ||
+                           res1->end <= res2->start)
+                               continue;
+                       else if (res1->end <= res2->end &&
+                                res1->start >= res2->start) {
+                               list_del(&res1->list);
+                               kfree(res1);
+                               break;
+                       } else if (res1->end > res2->end &&
+                                  res1->start < res2->start) {
+                               res = kmalloc(sizeof(*res), GFP_KERNEL);
+                               if (!res)
+                                       return -ENOMEM;
+                               res->start = res2->end;
+                               res->end = res1->end;
+                               res1->end = res2->start;
+                               list_add(&res->list, &res1->list);
+                               resn1 = res;
+                       } else {
+                               if (res1->start < res2->start)
+                                       res1->end = res2->start;
+                               else
+                                       res1->start = res2->end;
+                       }
+               }
+               res1 = resn1;
+               resn1 = list_entry(resn1->list.next, struct apei_res, list);
+       }
+
+       return 0;
+}
+
+static void apei_res_clean(struct list_head *res_list)
+{
+       struct apei_res *res, *resn;
+
+       list_for_each_entry_safe(res, resn, res_list, list) {
+               list_del(&res->list);
+               kfree(res);
+       }
+}
+
+void apei_resources_fini(struct apei_resources *resources)
+{
+       apei_res_clean(&resources->iomem);
+       apei_res_clean(&resources->ioport);
+}
+EXPORT_SYMBOL_GPL(apei_resources_fini);
+
+static int apei_resources_merge(struct apei_resources *resources1,
+                               struct apei_resources *resources2)
+{
+       int rc;
+       struct apei_res *res;
+
+       list_for_each_entry(res, &resources2->iomem, list) {
+               rc = apei_res_add(&resources1->iomem, res->start,
+                                 res->end - res->start);
+               if (rc)
+                       return rc;
+       }
+       list_for_each_entry(res, &resources2->ioport, list) {
+               rc = apei_res_add(&resources1->ioport, res->start,
+                                 res->end - res->start);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/*
+ * EINJ has two groups of GARs (EINJ table entry and trigger table
+ * entry), so common resources are subtracted from the trigger table
+ * resources before the second requesting.
+ */
+int apei_resources_sub(struct apei_resources *resources1,
+                      struct apei_resources *resources2)
+{
+       int rc;
+
+       rc = apei_res_sub(&resources1->iomem, &resources2->iomem);
+       if (rc)
+               return rc;
+       return apei_res_sub(&resources1->ioport, &resources2->ioport);
+}
+EXPORT_SYMBOL_GPL(apei_resources_sub);
+
+/*
+ * IO memory/port rersource management mechanism is used to check
+ * whether memory/port area used by GARs conflicts with normal memory
+ * or IO memory/port of devices.
+ */
+int apei_resources_request(struct apei_resources *resources,
+                          const char *desc)
+{
+       struct apei_res *res, *res_bak;
+       struct resource *r;
+
+       apei_resources_sub(resources, &apei_resources_all);
+
+       list_for_each_entry(res, &resources->iomem, list) {
+               r = request_mem_region(res->start, res->end - res->start,
+                                      desc);
+               if (!r) {
+                       pr_err(APEI_PFX
+               "Can not request iomem region <%016llx-%016llx> for GARs.\n",
+                              (unsigned long long)res->start,
+                              (unsigned long long)res->end);
+                       res_bak = res;
+                       goto err_unmap_iomem;
+               }
+       }
+
+       list_for_each_entry(res, &resources->ioport, list) {
+               r = request_region(res->start, res->end - res->start, desc);
+               if (!r) {
+                       pr_err(APEI_PFX
+               "Can not request ioport region <%016llx-%016llx> for GARs.\n",
+                              (unsigned long long)res->start,
+                              (unsigned long long)res->end);
+                       res_bak = res;
+                       goto err_unmap_ioport;
+               }
+       }
+
+       apei_resources_merge(&apei_resources_all, resources);
+
+       return 0;
+err_unmap_ioport:
+       list_for_each_entry(res, &resources->ioport, list) {
+               if (res == res_bak)
+                       break;
+               release_mem_region(res->start, res->end - res->start);
+       }
+       res_bak = NULL;
+err_unmap_iomem:
+       list_for_each_entry(res, &resources->iomem, list) {
+               if (res == res_bak)
+                       break;
+               release_region(res->start, res->end - res->start);
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(apei_resources_request);
+
+void apei_resources_release(struct apei_resources *resources)
+{
+       struct apei_res *res;
+
+       list_for_each_entry(res, &resources->iomem, list)
+               release_mem_region(res->start, res->end - res->start);
+       list_for_each_entry(res, &resources->ioport, list)
+               release_region(res->start, res->end - res->start);
+
+       apei_resources_sub(&apei_resources_all, resources);
+}
+EXPORT_SYMBOL_GPL(apei_resources_release);
+
+static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
+{
+       u32 width, space_id;
+
+       width = reg->bit_width;
+       space_id = reg->space_id;
+       /* Handle possible alignment issues */
+       memcpy(paddr, &reg->address, sizeof(*paddr));
+       if (!*paddr) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid physical address in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid bit width in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+           space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid address space type in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int collect_res_callback(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry,
+                               void *data)
+{
+       struct apei_resources *resources = data;
+       struct acpi_generic_address *reg = &entry->register_region;
+       u8 ins = entry->instruction;
+       u64 paddr;
+       int rc;
+
+       if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER))
+               return 0;
+
+       rc = apei_check_gar(reg, &paddr);
+       if (rc)
+               return rc;
+
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return apei_res_add(&resources->iomem, paddr,
+                                   reg->bit_width / 8);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return apei_res_add(&resources->ioport, paddr,
+                                   reg->bit_width / 8);
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * Same register may be used by multiple instructions in GARs, so
+ * resources are collected before requesting.
+ */
+int apei_exec_collect_resources(struct apei_exec_context *ctx,
+                               struct apei_resources *resources)
+{
+       return apei_exec_for_each_entry(ctx, collect_res_callback,
+                                       resources, NULL);
+}
+EXPORT_SYMBOL_GPL(apei_exec_collect_resources);
+
+struct dentry *apei_get_debugfs_dir(void)
+{
+       static struct dentry *dapei;
+
+       if (!dapei)
+               dapei = debugfs_create_dir("apei", NULL);
+
+       return dapei;
+}
+EXPORT_SYMBOL_GPL(apei_get_debugfs_dir);
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
new file mode 100644 (file)
index 0000000..18df1e9
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * apei-internal.h - ACPI Platform Error Interface internal
+ * definations.
+ */
+
+#ifndef APEI_INTERNAL_H
+#define APEI_INTERNAL_H
+
+#include <linux/cper.h>
+
+struct apei_exec_context;
+
+typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx,
+                                   struct acpi_whea_header *entry);
+
+#define APEI_EXEC_INS_ACCESS_REGISTER  0x0001
+
+struct apei_exec_ins_type {
+       u32 flags;
+       apei_exec_ins_func_t run;
+};
+
+struct apei_exec_context {
+       u32 ip;
+       u64 value;
+       u64 var1;
+       u64 var2;
+       u64 src_base;
+       u64 dst_base;
+       struct apei_exec_ins_type *ins_table;
+       u32 instructions;
+       struct acpi_whea_header *action_table;
+       u32 entries;
+};
+
+void apei_exec_ctx_init(struct apei_exec_context *ctx,
+                       struct apei_exec_ins_type *ins_table,
+                       u32 instructions,
+                       struct acpi_whea_header *action_table,
+                       u32 entries);
+
+static inline void apei_exec_ctx_set_input(struct apei_exec_context *ctx,
+                                          u64 input)
+{
+       ctx->value = input;
+}
+
+static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx)
+{
+       return ctx->value;
+}
+
+int apei_exec_run(struct apei_exec_context *ctx, u8 action);
+
+/* Common instruction implementation */
+
+/* IP has been set in instruction function */
+#define APEI_EXEC_SET_IP       1
+
+int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val);
+int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val);
+int apei_exec_read_register(struct apei_exec_context *ctx,
+                           struct acpi_whea_header *entry);
+int apei_exec_read_register_value(struct apei_exec_context *ctx,
+                                 struct acpi_whea_header *entry);
+int apei_exec_write_register(struct apei_exec_context *ctx,
+                            struct acpi_whea_header *entry);
+int apei_exec_write_register_value(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry);
+int apei_exec_noop(struct apei_exec_context *ctx,
+                  struct acpi_whea_header *entry);
+int apei_exec_pre_map_gars(struct apei_exec_context *ctx);
+int apei_exec_post_unmap_gars(struct apei_exec_context *ctx);
+
+struct apei_resources {
+       struct list_head iomem;
+       struct list_head ioport;
+};
+
+static inline void apei_resources_init(struct apei_resources *resources)
+{
+       INIT_LIST_HEAD(&resources->iomem);
+       INIT_LIST_HEAD(&resources->ioport);
+}
+
+void apei_resources_fini(struct apei_resources *resources);
+int apei_resources_sub(struct apei_resources *resources1,
+                      struct apei_resources *resources2);
+int apei_resources_request(struct apei_resources *resources,
+                          const char *desc);
+void apei_resources_release(struct apei_resources *resources);
+int apei_exec_collect_resources(struct apei_exec_context *ctx,
+                               struct apei_resources *resources);
+
+struct dentry;
+struct dentry *apei_get_debugfs_dir(void);
+
+#define apei_estatus_for_each_section(estatus, section)                        \
+       for (section = (struct acpi_hest_generic_data *)(estatus + 1);  \
+            (void *)section - (void *)estatus < estatus->data_length;  \
+            section = (void *)(section+1) + section->error_data_length)
+
+static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
+{
+       if (estatus->raw_data_length)
+               return estatus->raw_data_offset + \
+                       estatus->raw_data_length;
+       else
+               return sizeof(*estatus) + estatus->data_length;
+}
+
+int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
+int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
+#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
new file mode 100644 (file)
index 0000000..f4cf2fc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * UEFI Common Platform Error Record (CPER) support
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * CPER is the format used to describe platform hardware error by
+ * various APEI tables, such as ERST, BERT and HEST etc.
+ *
+ * For more information about CPER, please refer to Appendix N of UEFI
+ * Specification version 2.3.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/cper.h>
+#include <linux/acpi.h>
+
+/*
+ * CPER record ID need to be unique even after reboot, because record
+ * ID is used as index for ERST storage, while CPER records from
+ * multiple boot may co-exist in ERST.
+ */
+u64 cper_next_record_id(void)
+{
+       static atomic64_t seq;
+
+       if (!atomic64_read(&seq))
+               atomic64_set(&seq, ((u64)get_seconds()) << 32);
+
+       return atomic64_inc_return(&seq);
+}
+EXPORT_SYMBOL_GPL(cper_next_record_id);
+
+int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
+{
+       if (estatus->data_length &&
+           estatus->data_length < sizeof(struct acpi_hest_generic_data))
+               return -EINVAL;
+       if (estatus->raw_data_length &&
+           estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_estatus_check_header);
+
+int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
+{
+       struct acpi_hest_generic_data *gdata;
+       unsigned int data_len, gedata_len;
+       int rc;
+
+       rc = apei_estatus_check_header(estatus);
+       if (rc)
+               return rc;
+       data_len = estatus->data_length;
+       gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+       while (data_len > sizeof(*gdata)) {
+               gedata_len = gdata->error_data_length;
+               if (gedata_len > data_len - sizeof(*gdata))
+                       return -EINVAL;
+               data_len -= gedata_len + sizeof(*gdata);
+       }
+       if (data_len)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_estatus_check);
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
new file mode 100644 (file)
index 0000000..465c885
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * APEI Error INJection support
+ *
+ * EINJ provides a hardware error injection mechanism, this is useful
+ * for debugging and testing of other APEI and RAS features.
+ *
+ * For more information about EINJ, please refer to ACPI Specification
+ * version 4.0, section 17.5.
+ *
+ * Copyright 2009-2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/nmi.h>
+#include <linux/delay.h>
+#include <acpi/acpi.h>
+
+#include "apei-internal.h"
+
+#define EINJ_PFX "EINJ: "
+
+#define SPIN_UNIT              100                     /* 100ns */
+/* Firmware should respond within 1 miliseconds */
+#define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
+
+/*
+ * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
+ * EINJ table through an unpublished extension. Use with caution as
+ * most will ignore the parameter and make their own choice of address
+ * for error injection.
+ */
+struct einj_parameter {
+       u64 type;
+       u64 reserved1;
+       u64 reserved2;
+       u64 param1;
+       u64 param2;
+};
+
+#define EINJ_OP_BUSY                   0x1
+#define EINJ_STATUS_SUCCESS            0x0
+#define EINJ_STATUS_FAIL               0x1
+#define EINJ_STATUS_INVAL              0x2
+
+#define EINJ_TAB_ENTRY(tab)                                            \
+       ((struct acpi_whea_header *)((char *)(tab) +                    \
+                                   sizeof(struct acpi_table_einj)))
+
+static struct acpi_table_einj *einj_tab;
+
+static struct apei_resources einj_resources;
+
+static struct apei_exec_ins_type einj_ins_type[] = {
+       [ACPI_EINJ_READ_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_read_register,
+       },
+       [ACPI_EINJ_READ_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_read_register_value,
+       },
+       [ACPI_EINJ_WRITE_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_write_register,
+       },
+       [ACPI_EINJ_WRITE_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_write_register_value,
+       },
+       [ACPI_EINJ_NOOP] = {
+               .flags = 0,
+               .run   = apei_exec_noop,
+       },
+};
+
+/*
+ * Prevent EINJ interpreter to run simultaneously, because the
+ * corresponding firmware implementation may not work properly when
+ * invoked simultaneously.
+ */
+static DEFINE_MUTEX(einj_mutex);
+
+static struct einj_parameter *einj_param;
+
+static void einj_exec_ctx_init(struct apei_exec_context *ctx)
+{
+       apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
+                          EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);
+}
+
+static int __einj_get_available_error_type(u32 *type)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       einj_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE);
+       if (rc)
+               return rc;
+       *type = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+/* Get error injection capabilities of the platform */
+static int einj_get_available_error_type(u32 *type)
+{
+       int rc;
+
+       mutex_lock(&einj_mutex);
+       rc = __einj_get_available_error_type(type);
+       mutex_unlock(&einj_mutex);
+
+       return rc;
+}
+
+static int einj_timedout(u64 *t)
+{
+       if ((s64)*t < SPIN_UNIT) {
+               pr_warning(FW_WARN EINJ_PFX
+                          "Firmware does not respond in time\n");
+               return 1;
+       }
+       *t -= SPIN_UNIT;
+       ndelay(SPIN_UNIT);
+       touch_nmi_watchdog();
+       return 0;
+}
+
+static u64 einj_get_parameter_address(void)
+{
+       int i;
+       u64 paddr = 0;
+       struct acpi_whea_header *entry;
+
+       entry = EINJ_TAB_ENTRY(einj_tab);
+       for (i = 0; i < einj_tab->entries; i++) {
+               if (entry->action == ACPI_EINJ_SET_ERROR_TYPE &&
+                   entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
+                   entry->register_region.space_id ==
+                   ACPI_ADR_SPACE_SYSTEM_MEMORY)
+                       memcpy(&paddr, &entry->register_region.address,
+                              sizeof(paddr));
+               entry++;
+       }
+
+       return paddr;
+}
+
+/* do sanity check to trigger table */
+static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
+{
+       if (trigger_tab->header_size != sizeof(struct acpi_einj_trigger))
+               return -EINVAL;
+       if (trigger_tab->table_size > PAGE_SIZE ||
+           trigger_tab->table_size <= trigger_tab->header_size)
+               return -EINVAL;
+       if (trigger_tab->entry_count !=
+           (trigger_tab->table_size - trigger_tab->header_size) /
+           sizeof(struct acpi_einj_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Execute instructions in trigger error action table */
+static int __einj_error_trigger(u64 trigger_paddr)
+{
+       struct acpi_einj_trigger *trigger_tab = NULL;
+       struct apei_exec_context trigger_ctx;
+       struct apei_resources trigger_resources;
+       struct acpi_whea_header *trigger_entry;
+       struct resource *r;
+       u32 table_size;
+       int rc = -EIO;
+
+       r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
+                              "APEI EINJ Trigger Table");
+       if (!r) {
+               pr_err(EINJ_PFX
+       "Can not request iomem region <%016llx-%016llx> for Trigger table.\n",
+                      (unsigned long long)trigger_paddr,
+                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab));
+               goto out;
+       }
+       trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
+       if (!trigger_tab) {
+               pr_err(EINJ_PFX "Failed to map trigger table!\n");
+               goto out_rel_header;
+       }
+       rc = einj_check_trigger_header(trigger_tab);
+       if (rc) {
+               pr_warning(FW_BUG EINJ_PFX
+                          "The trigger error action table is invalid\n");
+               goto out_rel_header;
+       }
+       rc = -EIO;
+       table_size = trigger_tab->table_size;
+       r = request_mem_region(trigger_paddr + sizeof(*trigger_tab),
+                              table_size - sizeof(*trigger_tab),
+                              "APEI EINJ Trigger Table");
+       if (!r) {
+               pr_err(EINJ_PFX
+"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n",
+                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab),
+                      (unsigned long long)trigger_paddr + table_size);
+               goto out_rel_header;
+       }
+       iounmap(trigger_tab);
+       trigger_tab = ioremap_cache(trigger_paddr, table_size);
+       if (!trigger_tab) {
+               pr_err(EINJ_PFX "Failed to map trigger table!\n");
+               goto out_rel_entry;
+       }
+       trigger_entry = (struct acpi_whea_header *)
+               ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
+       apei_resources_init(&trigger_resources);
+       apei_exec_ctx_init(&trigger_ctx, einj_ins_type,
+                          ARRAY_SIZE(einj_ins_type),
+                          trigger_entry, trigger_tab->entry_count);
+       rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);
+       if (rc)
+               goto out_fini;
+       rc = apei_resources_sub(&trigger_resources, &einj_resources);
+       if (rc)
+               goto out_fini;
+       rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
+       if (rc)
+               goto out_fini;
+       rc = apei_exec_pre_map_gars(&trigger_ctx);
+       if (rc)
+               goto out_release;
+
+       rc = apei_exec_run(&trigger_ctx, ACPI_EINJ_TRIGGER_ERROR);
+
+       apei_exec_post_unmap_gars(&trigger_ctx);
+out_release:
+       apei_resources_release(&trigger_resources);
+out_fini:
+       apei_resources_fini(&trigger_resources);
+out_rel_entry:
+       release_mem_region(trigger_paddr + sizeof(*trigger_tab),
+                          table_size - sizeof(*trigger_tab));
+out_rel_header:
+       release_mem_region(trigger_paddr, sizeof(*trigger_tab));
+out:
+       if (trigger_tab)
+               iounmap(trigger_tab);
+
+       return rc;
+}
+
+static int __einj_error_inject(u32 type, u64 param1, u64 param2)
+{
+       struct apei_exec_context ctx;
+       u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
+       int rc;
+
+       einj_exec_ctx_init(&ctx);
+
+       rc = apei_exec_run(&ctx, ACPI_EINJ_BEGIN_OPERATION);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, type);
+       rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
+       if (rc)
+               return rc;
+       if (einj_param) {
+               writeq(param1, &einj_param->param1);
+               writeq(param2, &einj_param->param2);
+       }
+       rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_EINJ_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!(val & EINJ_OP_BUSY))
+                       break;
+               if (einj_timedout(&timeout))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       if (val != EINJ_STATUS_SUCCESS)
+               return -EBUSY;
+
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_TRIGGER_TABLE);
+       if (rc)
+               return rc;
+       trigger_paddr = apei_exec_ctx_get_output(&ctx);
+       rc = __einj_error_trigger(trigger_paddr);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_EINJ_END_OPERATION);
+
+       return rc;
+}
+
+/* Inject the specified hardware error */
+static int einj_error_inject(u32 type, u64 param1, u64 param2)
+{
+       int rc;
+
+       mutex_lock(&einj_mutex);
+       rc = __einj_error_inject(type, param1, param2);
+       mutex_unlock(&einj_mutex);
+
+       return rc;
+}
+
+static u32 error_type;
+static u64 error_param1;
+static u64 error_param2;
+static struct dentry *einj_debug_dir;
+
+static int available_error_type_show(struct seq_file *m, void *v)
+{
+       int rc;
+       u32 available_error_type = 0;
+
+       rc = einj_get_available_error_type(&available_error_type);
+       if (rc)
+               return rc;
+       if (available_error_type & 0x0001)
+               seq_printf(m, "0x00000001\tProcessor Correctable\n");
+       if (available_error_type & 0x0002)
+               seq_printf(m, "0x00000002\tProcessor Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0004)
+               seq_printf(m, "0x00000004\tProcessor Uncorrectable fatal\n");
+       if (available_error_type & 0x0008)
+               seq_printf(m, "0x00000008\tMemory Correctable\n");
+       if (available_error_type & 0x0010)
+               seq_printf(m, "0x00000010\tMemory Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0020)
+               seq_printf(m, "0x00000020\tMemory Uncorrectable fatal\n");
+       if (available_error_type & 0x0040)
+               seq_printf(m, "0x00000040\tPCI Express Correctable\n");
+       if (available_error_type & 0x0080)
+               seq_printf(m, "0x00000080\tPCI Express Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0100)
+               seq_printf(m, "0x00000100\tPCI Express Uncorrectable fatal\n");
+       if (available_error_type & 0x0200)
+               seq_printf(m, "0x00000200\tPlatform Correctable\n");
+       if (available_error_type & 0x0400)
+               seq_printf(m, "0x00000400\tPlatform Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0800)
+               seq_printf(m, "0x00000800\tPlatform Uncorrectable fatal\n");
+
+       return 0;
+}
+
+static int available_error_type_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, available_error_type_show, NULL);
+}
+
+static const struct file_operations available_error_type_fops = {
+       .open           = available_error_type_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int error_type_get(void *data, u64 *val)
+{
+       *val = error_type;
+
+       return 0;
+}
+
+static int error_type_set(void *data, u64 val)
+{
+       int rc;
+       u32 available_error_type = 0;
+
+       /* Only one error type can be specified */
+       if (val & (val - 1))
+               return -EINVAL;
+       rc = einj_get_available_error_type(&available_error_type);
+       if (rc)
+               return rc;
+       if (!(val & available_error_type))
+               return -EINVAL;
+       error_type = val;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get,
+                       error_type_set, "0x%llx\n");
+
+static int error_inject_set(void *data, u64 val)
+{
+       if (!error_type)
+               return -EINVAL;
+
+       return einj_error_inject(error_type, error_param1, error_param2);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
+                       error_inject_set, "%llu\n");
+
+static int einj_check_table(struct acpi_table_einj *einj_tab)
+{
+       if (einj_tab->header_length != sizeof(struct acpi_table_einj))
+               return -EINVAL;
+       if (einj_tab->header.length < sizeof(struct acpi_table_einj))
+               return -EINVAL;
+       if (einj_tab->entries !=
+           (einj_tab->header.length - sizeof(struct acpi_table_einj)) /
+           sizeof(struct acpi_einj_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init einj_init(void)
+{
+       int rc;
+       u64 param_paddr;
+       acpi_status status;
+       struct dentry *fentry;
+       struct apei_exec_context ctx;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       status = acpi_get_table(ACPI_SIG_EINJ, 0,
+                               (struct acpi_table_header **)&einj_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_info(EINJ_PFX "Table is not found!\n");
+               return -ENODEV;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
+               return -EINVAL;
+       }
+
+       rc = einj_check_table(einj_tab);
+       if (rc) {
+               pr_warning(FW_BUG EINJ_PFX "EINJ table is invalid\n");
+               return -EINVAL;
+       }
+
+       rc = -ENOMEM;
+       einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir());
+       if (!einj_debug_dir)
+               goto err_cleanup;
+       fentry = debugfs_create_file("available_error_type", S_IRUSR,
+                                    einj_debug_dir, NULL,
+                                    &available_error_type_fops);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR,
+                                    einj_debug_dir, NULL, &error_type_fops);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
+                                   einj_debug_dir, &error_param1);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
+                                   einj_debug_dir, &error_param2);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_file("error_inject", S_IWUSR,
+                                    einj_debug_dir, NULL, &error_inject_fops);
+       if (!fentry)
+               goto err_cleanup;
+
+       apei_resources_init(&einj_resources);
+       einj_exec_ctx_init(&ctx);
+       rc = apei_exec_collect_resources(&ctx, &einj_resources);
+       if (rc)
+               goto err_fini;
+       rc = apei_resources_request(&einj_resources, "APEI EINJ");
+       if (rc)
+               goto err_fini;
+       rc = apei_exec_pre_map_gars(&ctx);
+       if (rc)
+               goto err_release;
+       param_paddr = einj_get_parameter_address();
+       if (param_paddr) {
+               einj_param = ioremap(param_paddr, sizeof(*einj_param));
+               rc = -ENOMEM;
+               if (!einj_param)
+                       goto err_unmap;
+       }
+
+       pr_info(EINJ_PFX "Error INJection is initialized.\n");
+
+       return 0;
+
+err_unmap:
+       apei_exec_post_unmap_gars(&ctx);
+err_release:
+       apei_resources_release(&einj_resources);
+err_fini:
+       apei_resources_fini(&einj_resources);
+err_cleanup:
+       debugfs_remove_recursive(einj_debug_dir);
+
+       return rc;
+}
+
+static void __exit einj_exit(void)
+{
+       struct apei_exec_context ctx;
+
+       if (einj_param)
+               iounmap(einj_param);
+       einj_exec_ctx_init(&ctx);
+       apei_exec_post_unmap_gars(&ctx);
+       apei_resources_release(&einj_resources);
+       apei_resources_fini(&einj_resources);
+       debugfs_remove_recursive(einj_debug_dir);
+}
+
+module_init(einj_init);
+module_exit(einj_exit);
+
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("APEI Error INJection support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
new file mode 100644 (file)
index 0000000..2ebc391
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * APEI Error Record Serialization Table support
+ *
+ * ERST is a way provided by APEI to save and retrieve hardware error
+ * infomation to and from a persistent store.
+ *
+ * For more information about ERST, please refer to ACPI Specification
+ * version 4.0, section 17.4.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/uaccess.h>
+#include <linux/cper.h>
+#include <linux/nmi.h>
+#include <acpi/apei.h>
+
+#include "apei-internal.h"
+
+#define ERST_PFX "ERST: "
+
+/* ERST command status */
+#define ERST_STATUS_SUCCESS                    0x0
+#define ERST_STATUS_NOT_ENOUGH_SPACE           0x1
+#define ERST_STATUS_HARDWARE_NOT_AVAILABLE     0x2
+#define ERST_STATUS_FAILED                     0x3
+#define ERST_STATUS_RECORD_STORE_EMPTY         0x4
+#define ERST_STATUS_RECORD_NOT_FOUND           0x5
+
+#define ERST_TAB_ENTRY(tab)                                            \
+       ((struct acpi_whea_header *)((char *)(tab) +                    \
+                                    sizeof(struct acpi_table_erst)))
+
+#define SPIN_UNIT              100                     /* 100ns */
+/* Firmware should respond within 1 miliseconds */
+#define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
+#define FIRMWARE_MAX_STALL     50                      /* 50us */
+
+int erst_disable;
+EXPORT_SYMBOL_GPL(erst_disable);
+
+static struct acpi_table_erst *erst_tab;
+
+/* ERST Error Log Address Range atrributes */
+#define ERST_RANGE_RESERVED    0x0001
+#define ERST_RANGE_NVRAM       0x0002
+#define ERST_RANGE_SLOW                0x0004
+
+/*
+ * ERST Error Log Address Range, used as buffer for reading/writing
+ * error records.
+ */
+static struct erst_erange {
+       u64 base;
+       u64 size;
+       void __iomem *vaddr;
+       u32 attr;
+} erst_erange;
+
+/*
+ * Prevent ERST interpreter to run simultaneously, because the
+ * corresponding firmware implementation may not work properly when
+ * invoked simultaneously.
+ *
+ * It is used to provide exclusive accessing for ERST Error Log
+ * Address Range too.
+ */
+static DEFINE_SPINLOCK(erst_lock);
+
+static inline int erst_errno(int command_status)
+{
+       switch (command_status) {
+       case ERST_STATUS_SUCCESS:
+               return 0;
+       case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
+               return -ENODEV;
+       case ERST_STATUS_NOT_ENOUGH_SPACE:
+               return -ENOSPC;
+       case ERST_STATUS_RECORD_STORE_EMPTY:
+       case ERST_STATUS_RECORD_NOT_FOUND:
+               return -ENOENT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int erst_timedout(u64 *t, u64 spin_unit)
+{
+       if ((s64)*t < spin_unit) {
+               pr_warning(FW_WARN ERST_PFX
+                          "Firmware does not respond in time\n");
+               return 1;
+       }
+       *t -= spin_unit;
+       ndelay(spin_unit);
+       touch_nmi_watchdog();
+       return 0;
+}
+
+static int erst_exec_load_var1(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->var1);
+}
+
+static int erst_exec_load_var2(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->var2);
+}
+
+static int erst_exec_store_var1(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry)
+{
+       return __apei_exec_write_register(entry, ctx->var1);
+}
+
+static int erst_exec_add(struct apei_exec_context *ctx,
+                        struct acpi_whea_header *entry)
+{
+       ctx->var1 += ctx->var2;
+       return 0;
+}
+
+static int erst_exec_subtract(struct apei_exec_context *ctx,
+                             struct acpi_whea_header *entry)
+{
+       ctx->var1 -= ctx->var2;
+       return 0;
+}
+
+static int erst_exec_add_value(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       val += ctx->value;
+       rc = __apei_exec_write_register(entry, val);
+       return rc;
+}
+
+static int erst_exec_subtract_value(struct apei_exec_context *ctx,
+                                   struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       val -= ctx->value;
+       rc = __apei_exec_write_register(entry, val);
+       return rc;
+}
+
+static int erst_exec_stall(struct apei_exec_context *ctx,
+                          struct acpi_whea_header *entry)
+{
+       u64 stall_time;
+
+       if (ctx->value > FIRMWARE_MAX_STALL) {
+               if (!in_nmi())
+                       pr_warning(FW_WARN ERST_PFX
+                       "Too long stall time for stall instruction: %llx.\n",
+                                  ctx->value);
+               stall_time = FIRMWARE_MAX_STALL;
+       } else
+               stall_time = ctx->value;
+       udelay(stall_time);
+       return 0;
+}
+
+static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
+                                     struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 stall_time;
+
+       if (ctx->var1 > FIRMWARE_MAX_STALL) {
+               if (!in_nmi())
+                       pr_warning(FW_WARN ERST_PFX
+               "Too long stall time for stall while true instruction: %llx.\n",
+                                  ctx->var1);
+               stall_time = FIRMWARE_MAX_STALL;
+       } else
+               stall_time = ctx->var1;
+
+       for (;;) {
+               rc = __apei_exec_read_register(entry, &val);
+               if (rc)
+                       return rc;
+               if (val != ctx->value)
+                       break;
+               if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
+                       return -EIO;
+       }
+       return 0;
+}
+
+static int erst_exec_skip_next_instruction_if_true(
+       struct apei_exec_context *ctx,
+       struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       if (val == ctx->value) {
+               ctx->ip += 2;
+               return APEI_EXEC_SET_IP;
+       }
+
+       return 0;
+}
+
+static int erst_exec_goto(struct apei_exec_context *ctx,
+                         struct acpi_whea_header *entry)
+{
+       ctx->ip = ctx->value;
+       return APEI_EXEC_SET_IP;
+}
+
+static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
+                                         struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->src_base);
+}
+
+static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
+                                         struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->dst_base);
+}
+
+static int erst_exec_move_data(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 offset;
+
+       rc = __apei_exec_read_register(entry, &offset);
+       if (rc)
+               return rc;
+       memmove((void *)ctx->dst_base + offset,
+               (void *)ctx->src_base + offset,
+               ctx->var2);
+
+       return 0;
+}
+
+static struct apei_exec_ins_type erst_ins_type[] = {
+       [ACPI_ERST_READ_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_read_register,
+       },
+       [ACPI_ERST_READ_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_read_register_value,
+       },
+       [ACPI_ERST_WRITE_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_write_register,
+       },
+       [ACPI_ERST_WRITE_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_write_register_value,
+       },
+       [ACPI_ERST_NOOP] = {
+               .flags = 0,
+               .run = apei_exec_noop,
+       },
+       [ACPI_ERST_LOAD_VAR1] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_load_var1,
+       },
+       [ACPI_ERST_LOAD_VAR2] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_load_var2,
+       },
+       [ACPI_ERST_STORE_VAR1] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_store_var1,
+       },
+       [ACPI_ERST_ADD] = {
+               .flags = 0,
+               .run = erst_exec_add,
+       },
+       [ACPI_ERST_SUBTRACT] = {
+               .flags = 0,
+               .run = erst_exec_subtract,
+       },
+       [ACPI_ERST_ADD_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_add_value,
+       },
+       [ACPI_ERST_SUBTRACT_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_subtract_value,
+       },
+       [ACPI_ERST_STALL] = {
+               .flags = 0,
+               .run = erst_exec_stall,
+       },
+       [ACPI_ERST_STALL_WHILE_TRUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_stall_while_true,
+       },
+       [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_skip_next_instruction_if_true,
+       },
+       [ACPI_ERST_GOTO] = {
+               .flags = 0,
+               .run = erst_exec_goto,
+       },
+       [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_set_src_address_base,
+       },
+       [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_set_dst_address_base,
+       },
+       [ACPI_ERST_MOVE_DATA] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_move_data,
+       },
+};
+
+static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
+{
+       apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
+                          ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
+}
+
+static int erst_get_erange(struct erst_erange *range)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
+       if (rc)
+               return rc;
+       range->base = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
+       if (rc)
+               return rc;
+       range->size = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
+       if (rc)
+               return rc;
+       range->attr = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+static ssize_t __erst_get_record_count(void)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
+       if (rc)
+               return rc;
+       return apei_exec_ctx_get_output(&ctx);
+}
+
+ssize_t erst_get_record_count(void)
+{
+       ssize_t count;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       count = __erst_get_record_count();
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(erst_get_record_count);
+
+static int __erst_get_next_record_id(u64 *record_id)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
+       if (rc)
+               return rc;
+       *record_id = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+/*
+ * Get the record ID of an existing error record on the persistent
+ * storage. If there is no error record on the persistent storage, the
+ * returned record_id is APEI_ERST_INVALID_RECORD_ID.
+ */
+int erst_get_next_record_id(u64 *record_id)
+{
+       int rc;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       rc = __erst_get_next_record_id(record_id);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_get_next_record_id);
+
+static int __erst_write_to_storage(u64 offset)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, offset);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+static int __erst_read_from_storage(u64 record_id, u64 offset)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, offset);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, record_id);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       };
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+static int __erst_clear_from_storage(u64 record_id)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, record_id);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+/* NVRAM ERST Error Log Address Range is not supported yet */
+static void pr_unimpl_nvram(void)
+{
+       if (printk_ratelimit())
+               pr_warning(ERST_PFX
+               "NVRAM ERST Log Address Range is not implemented yet\n");
+}
+
+static int __erst_write_to_nvram(const struct cper_record_header *record)
+{
+       /* do not print message, because printk is not safe for NMI */
+       return -ENOSYS;
+}
+
+static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
+{
+       pr_unimpl_nvram();
+       return -ENOSYS;
+}
+
+static int __erst_clear_from_nvram(u64 record_id)
+{
+       pr_unimpl_nvram();
+       return -ENOSYS;
+}
+
+int erst_write(const struct cper_record_header *record)
+{
+       int rc;
+       unsigned long flags;
+       struct cper_record_header *rcd_erange;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
+               return -EINVAL;
+
+       if (erst_erange.attr & ERST_RANGE_NVRAM) {
+               if (!spin_trylock_irqsave(&erst_lock, flags))
+                       return -EBUSY;
+               rc = __erst_write_to_nvram(record);
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return rc;
+       }
+
+       if (record->record_length > erst_erange.size)
+               return -EINVAL;
+
+       if (!spin_trylock_irqsave(&erst_lock, flags))
+               return -EBUSY;
+       memcpy(erst_erange.vaddr, record, record->record_length);
+       rcd_erange = erst_erange.vaddr;
+       /* signature for serialization system */
+       memcpy(&rcd_erange->persistence_information, "ER", 2);
+
+       rc = __erst_write_to_storage(0);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_write);
+
+static int __erst_read_to_erange(u64 record_id, u64 *offset)
+{
+       int rc;
+
+       if (erst_erange.attr & ERST_RANGE_NVRAM)
+               return __erst_read_to_erange_from_nvram(
+                       record_id, offset);
+
+       rc = __erst_read_from_storage(record_id, 0);
+       if (rc)
+               return rc;
+       *offset = 0;
+
+       return 0;
+}
+
+static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
+                          size_t buflen)
+{
+       int rc;
+       u64 offset, len = 0;
+       struct cper_record_header *rcd_tmp;
+
+       rc = __erst_read_to_erange(record_id, &offset);
+       if (rc)
+               return rc;
+       rcd_tmp = erst_erange.vaddr + offset;
+       len = rcd_tmp->record_length;
+       if (len <= buflen)
+               memcpy(record, rcd_tmp, len);
+
+       return len;
+}
+
+/*
+ * If return value > buflen, the buffer size is not big enough,
+ * else if return value < 0, something goes wrong,
+ * else everything is OK, and return value is record length
+ */
+ssize_t erst_read(u64 record_id, struct cper_record_header *record,
+                 size_t buflen)
+{
+       ssize_t len;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       len = __erst_read(record_id, record, buflen);
+       spin_unlock_irqrestore(&erst_lock, flags);
+       return len;
+}
+EXPORT_SYMBOL_GPL(erst_read);
+
+/*
+ * If return value > buflen, the buffer size is not big enough,
+ * else if return value = 0, there is no more record to read,
+ * else if return value < 0, something goes wrong,
+ * else everything is OK, and return value is record length
+ */
+ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
+{
+       int rc;
+       ssize_t len;
+       unsigned long flags;
+       u64 record_id;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       rc = __erst_get_next_record_id(&record_id);
+       if (rc) {
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return rc;
+       }
+       /* no more record */
+       if (record_id == APEI_ERST_INVALID_RECORD_ID) {
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return 0;
+       }
+
+       len = __erst_read(record_id, record, buflen);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(erst_read_next);
+
+int erst_clear(u64 record_id)
+{
+       int rc;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       if (erst_erange.attr & ERST_RANGE_NVRAM)
+               rc = __erst_clear_from_nvram(record_id);
+       else
+               rc = __erst_clear_from_storage(record_id);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_clear);
+
+static int __init setup_erst_disable(char *str)
+{
+       erst_disable = 1;
+       return 0;
+}
+
+__setup("erst_disable", setup_erst_disable);
+
+static int erst_check_table(struct acpi_table_erst *erst_tab)
+{
+       if (erst_tab->header_length != sizeof(struct acpi_table_erst))
+               return -EINVAL;
+       if (erst_tab->header.length < sizeof(struct acpi_table_erst))
+               return -EINVAL;
+       if (erst_tab->entries !=
+           (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
+           sizeof(struct acpi_erst_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init erst_init(void)
+{
+       int rc = 0;
+       acpi_status status;
+       struct apei_exec_context ctx;
+       struct apei_resources erst_resources;
+       struct resource *r;
+
+       if (acpi_disabled)
+               goto err;
+
+       if (erst_disable) {
+               pr_info(ERST_PFX
+       "Error Record Serialization Table (ERST) support is disabled.\n");
+               goto err;
+       }
+
+       status = acpi_get_table(ACPI_SIG_ERST, 0,
+                               (struct acpi_table_header **)&erst_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_err(ERST_PFX "Table is not found!\n");
+               goto err;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(ERST_PFX "Failed to get table, %s\n", msg);
+               rc = -EINVAL;
+               goto err;
+       }
+
+       rc = erst_check_table(erst_tab);
+       if (rc) {
+               pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
+               goto err;
+       }
+
+       apei_resources_init(&erst_resources);
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_collect_resources(&ctx, &erst_resources);
+       if (rc)
+               goto err_fini;
+       rc = apei_resources_request(&erst_resources, "APEI ERST");
+       if (rc)
+               goto err_fini;
+       rc = apei_exec_pre_map_gars(&ctx);
+       if (rc)
+               goto err_release;
+       rc = erst_get_erange(&erst_erange);
+       if (rc) {
+               if (rc == -ENODEV)
+                       pr_info(ERST_PFX
+       "The corresponding hardware device or firmware implementation "
+       "is not available.\n");
+               else
+                       pr_err(ERST_PFX
+                              "Failed to get Error Log Address Range.\n");
+               goto err_unmap_reg;
+       }
+
+       r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
+       if (!r) {
+               pr_err(ERST_PFX
+               "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
+               (unsigned long long)erst_erange.base,
+               (unsigned long long)erst_erange.base + erst_erange.size);
+               rc = -EIO;
+               goto err_unmap_reg;
+       }
+       rc = -ENOMEM;
+       erst_erange.vaddr = ioremap_cache(erst_erange.base,
+                                         erst_erange.size);
+       if (!erst_erange.vaddr)
+               goto err_release_erange;
+
+       pr_info(ERST_PFX
+       "Error Record Serialization Table (ERST) support is initialized.\n");
+
+       return 0;
+
+err_release_erange:
+       release_mem_region(erst_erange.base, erst_erange.size);
+err_unmap_reg:
+       apei_exec_post_unmap_gars(&ctx);
+err_release:
+       apei_resources_release(&erst_resources);
+err_fini:
+       apei_resources_fini(&erst_resources);
+err:
+       erst_disable = 1;
+       return rc;
+}
+
+device_initcall(erst_init);
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
new file mode 100644 (file)
index 0000000..fd0cc01
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * APEI Generic Hardware Error Source support
+ *
+ * Generic Hardware Error Source provides a way to report platform
+ * hardware errors (such as that from chipset). It works in so called
+ * "Firmware First" mode, that is, hardware errors are reported to
+ * firmware firstly, then reported to Linux by firmware. This way,
+ * some non-standard hardware error registers or non-standard hardware
+ * link can be checked by firmware to produce more hardware error
+ * information for Linux.
+ *
+ * For more information about Generic Hardware Error Source, please
+ * refer to ACPI Specification version 4.0, section 17.3.2.6
+ *
+ * Now, only SCI notification type and memory errors are
+ * supported. More notification type and hardware error type will be
+ * added later.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/cper.h>
+#include <linux/kdebug.h>
+#include <acpi/apei.h>
+#include <acpi/atomicio.h>
+#include <acpi/hed.h>
+#include <asm/mce.h>
+
+#include "apei-internal.h"
+
+#define GHES_PFX       "GHES: "
+
+#define GHES_ESTATUS_MAX_SIZE          65536
+
+/*
+ * One struct ghes is created for each generic hardware error
+ * source.
+ *
+ * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
+ * handler. Handler for one generic hardware error source is only
+ * triggered after the previous one is done. So handler can uses
+ * struct ghes without locking.
+ *
+ * estatus: memory buffer for error status block, allocated during
+ * HEST parsing.
+ */
+#define GHES_TO_CLEAR          0x0001
+
+struct ghes {
+       struct acpi_hest_generic *generic;
+       struct acpi_hest_generic_status *estatus;
+       struct list_head list;
+       u64 buffer_paddr;
+       unsigned long flags;
+};
+
+/*
+ * Error source lists, one list for each notification method. The
+ * members in lists are struct ghes.
+ *
+ * The list members are only added in HEST parsing and deleted during
+ * module_exit, that is, single-threaded. So no lock is needed for
+ * that.
+ *
+ * But the mutual exclusion is needed between members adding/deleting
+ * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
+ * used for that.
+ */
+static LIST_HEAD(ghes_sci);
+
+static struct ghes *ghes_new(struct acpi_hest_generic *generic)
+{
+       struct ghes *ghes;
+       unsigned int error_block_length;
+       int rc;
+
+       ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
+       if (!ghes)
+               return ERR_PTR(-ENOMEM);
+       ghes->generic = generic;
+       INIT_LIST_HEAD(&ghes->list);
+       rc = acpi_pre_map_gar(&generic->error_status_address);
+       if (rc)
+               goto err_free;
+       error_block_length = generic->error_block_length;
+       if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
+               pr_warning(FW_WARN GHES_PFX
+                          "Error status block length is too long: %u for "
+                          "generic hardware error source: %d.\n",
+                          error_block_length, generic->header.source_id);
+               error_block_length = GHES_ESTATUS_MAX_SIZE;
+       }
+       ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
+       if (!ghes->estatus) {
+               rc = -ENOMEM;
+               goto err_unmap;
+       }
+
+       return ghes;
+
+err_unmap:
+       acpi_post_unmap_gar(&generic->error_status_address);
+err_free:
+       kfree(ghes);
+       return ERR_PTR(rc);
+}
+
+static void ghes_fini(struct ghes *ghes)
+{
+       kfree(ghes->estatus);
+       acpi_post_unmap_gar(&ghes->generic->error_status_address);
+}
+
+enum {
+       GHES_SER_NO = 0x0,
+       GHES_SER_CORRECTED = 0x1,
+       GHES_SER_RECOVERABLE = 0x2,
+       GHES_SER_PANIC = 0x3,
+};
+
+static inline int ghes_severity(int severity)
+{
+       switch (severity) {
+       case CPER_SER_INFORMATIONAL:
+               return GHES_SER_NO;
+       case CPER_SER_CORRECTED:
+               return GHES_SER_CORRECTED;
+       case CPER_SER_RECOVERABLE:
+               return GHES_SER_RECOVERABLE;
+       case CPER_SER_FATAL:
+               return GHES_SER_PANIC;
+       default:
+               /* Unkown, go panic */
+               return GHES_SER_PANIC;
+       }
+}
+
+/* SCI handler run in work queue, so ioremap can be used here */
+static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
+                                int from_phys)
+{
+       void *vaddr;
+
+       vaddr = ioremap_cache(paddr, len);
+       if (!vaddr)
+               return -ENOMEM;
+       if (from_phys)
+               memcpy(buffer, vaddr, len);
+       else
+               memcpy(vaddr, buffer, len);
+       iounmap(vaddr);
+
+       return 0;
+}
+
+static int ghes_read_estatus(struct ghes *ghes, int silent)
+{
+       struct acpi_hest_generic *g = ghes->generic;
+       u64 buf_paddr;
+       u32 len;
+       int rc;
+
+       rc = acpi_atomic_read(&buf_paddr, &g->error_status_address);
+       if (rc) {
+               if (!silent && printk_ratelimit())
+                       pr_warning(FW_WARN GHES_PFX
+"Failed to read error status block address for hardware error source: %d.\n",
+                                  g->header.source_id);
+               return -EIO;
+       }
+       if (!buf_paddr)
+               return -ENOENT;
+
+       rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
+                                  sizeof(*ghes->estatus), 1);
+       if (rc)
+               return rc;
+       if (!ghes->estatus->block_status)
+               return -ENOENT;
+
+       ghes->buffer_paddr = buf_paddr;
+       ghes->flags |= GHES_TO_CLEAR;
+
+       rc = -EIO;
+       len = apei_estatus_len(ghes->estatus);
+       if (len < sizeof(*ghes->estatus))
+               goto err_read_block;
+       if (len > ghes->generic->error_block_length)
+               goto err_read_block;
+       if (apei_estatus_check_header(ghes->estatus))
+               goto err_read_block;
+       rc = ghes_copy_tofrom_phys(ghes->estatus + 1,
+                                  buf_paddr + sizeof(*ghes->estatus),
+                                  len - sizeof(*ghes->estatus), 1);
+       if (rc)
+               return rc;
+       if (apei_estatus_check(ghes->estatus))
+               goto err_read_block;
+       rc = 0;
+
+err_read_block:
+       if (rc && !silent)
+               pr_warning(FW_WARN GHES_PFX
+                          "Failed to read error status block!\n");
+       return rc;
+}
+
+static void ghes_clear_estatus(struct ghes *ghes)
+{
+       ghes->estatus->block_status = 0;
+       if (!(ghes->flags & GHES_TO_CLEAR))
+               return;
+       ghes_copy_tofrom_phys(ghes->estatus, ghes->buffer_paddr,
+                             sizeof(ghes->estatus->block_status), 0);
+       ghes->flags &= ~GHES_TO_CLEAR;
+}
+
+static void ghes_do_proc(struct ghes *ghes)
+{
+       int ser, processed = 0;
+       struct acpi_hest_generic_data *gdata;
+
+       ser = ghes_severity(ghes->estatus->error_severity);
+       apei_estatus_for_each_section(ghes->estatus, gdata) {
+#ifdef CONFIG_X86_MCE
+               if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
+                                CPER_SEC_PLATFORM_MEM)) {
+                       apei_mce_report_mem_error(
+                               ser == GHES_SER_CORRECTED,
+                               (struct cper_sec_mem_err *)(gdata+1));
+                       processed = 1;
+               }
+#endif
+       }
+
+       if (!processed && printk_ratelimit())
+               pr_warning(GHES_PFX
+               "Unknown error record from generic hardware error source: %d\n",
+                          ghes->generic->header.source_id);
+}
+
+static int ghes_proc(struct ghes *ghes)
+{
+       int rc;
+
+       rc = ghes_read_estatus(ghes, 0);
+       if (rc)
+               goto out;
+       ghes_do_proc(ghes);
+
+out:
+       ghes_clear_estatus(ghes);
+       return 0;
+}
+
+static int ghes_notify_sci(struct notifier_block *this,
+                                 unsigned long event, void *data)
+{
+       struct ghes *ghes;
+       int ret = NOTIFY_DONE;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ghes, &ghes_sci, list) {
+               if (!ghes_proc(ghes))
+                       ret = NOTIFY_OK;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+static struct notifier_block ghes_notifier_sci = {
+       .notifier_call = ghes_notify_sci,
+};
+
+static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       struct acpi_hest_generic *generic;
+       struct ghes *ghes = NULL;
+       int rc = 0;
+
+       if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
+               return 0;
+
+       generic = (struct acpi_hest_generic *)hest_hdr;
+       if (!generic->enabled)
+               return 0;
+
+       if (generic->error_block_length <
+           sizeof(struct acpi_hest_generic_status)) {
+               pr_warning(FW_BUG GHES_PFX
+"Invalid error block length: %u for generic hardware error source: %d\n",
+                          generic->error_block_length,
+                          generic->header.source_id);
+               goto err;
+       }
+       if (generic->records_to_preallocate == 0) {
+               pr_warning(FW_BUG GHES_PFX
+"Invalid records to preallocate: %u for generic hardware error source: %d\n",
+                          generic->records_to_preallocate,
+                          generic->header.source_id);
+               goto err;
+       }
+       ghes = ghes_new(generic);
+       if (IS_ERR(ghes)) {
+               rc = PTR_ERR(ghes);
+               ghes = NULL;
+               goto err;
+       }
+       switch (generic->notify.type) {
+       case ACPI_HEST_NOTIFY_POLLED:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via POLL is not supported!\n",
+                          generic->header.source_id);
+               break;
+       case ACPI_HEST_NOTIFY_EXTERNAL:
+       case ACPI_HEST_NOTIFY_LOCAL:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via IRQ is not supported!\n",
+                          generic->header.source_id);
+               break;
+       case ACPI_HEST_NOTIFY_SCI:
+               if (list_empty(&ghes_sci))
+                       register_acpi_hed_notifier(&ghes_notifier_sci);
+               list_add_rcu(&ghes->list, &ghes_sci);
+               break;
+       case ACPI_HEST_NOTIFY_NMI:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via NMI is not supported!\n",
+                          generic->header.source_id);
+               break;
+       default:
+               pr_warning(FW_WARN GHES_PFX
+       "Unknown notification type: %u for generic hardware error source: %d\n",
+                          generic->notify.type, generic->header.source_id);
+               break;
+       }
+
+       return 0;
+err:
+       if (ghes)
+               ghes_fini(ghes);
+       return rc;
+}
+
+static void ghes_cleanup(void)
+{
+       struct ghes *ghes, *nghes;
+
+       if (!list_empty(&ghes_sci))
+               unregister_acpi_hed_notifier(&ghes_notifier_sci);
+
+       synchronize_rcu();
+
+       list_for_each_entry_safe(ghes, nghes, &ghes_sci, list) {
+               list_del(&ghes->list);
+               ghes_fini(ghes);
+               kfree(ghes);
+       }
+}
+
+static int __init ghes_init(void)
+{
+       int rc;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (hest_disable) {
+               pr_info(GHES_PFX "HEST is not enabled!\n");
+               return -EINVAL;
+       }
+
+       rc = apei_hest_parse(hest_ghes_parse, NULL);
+       if (rc) {
+               pr_err(GHES_PFX
+               "Error during parsing HEST generic hardware error sources.\n");
+               goto err_cleanup;
+       }
+
+       if (list_empty(&ghes_sci)) {
+               pr_info(GHES_PFX
+                       "No functional generic hardware error sources.\n");
+               rc = -ENODEV;
+               goto err_cleanup;
+       }
+
+       pr_info(GHES_PFX
+               "Generic Hardware Error Source support is initialized.\n");
+
+       return 0;
+err_cleanup:
+       ghes_cleanup();
+       return rc;
+}
+
+static void __exit ghes_exit(void)
+{
+       ghes_cleanup();
+}
+
+module_init(ghes_init);
+module_exit(ghes_exit);
+
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("APEI Generic Hardware Error Source support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
new file mode 100644 (file)
index 0000000..e7f40d3
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * APEI Hardware Error Souce Table support
+ *
+ * HEST describes error sources in detail; communicates operational
+ * parameters (i.e. severity levels, masking bits, and threshold
+ * values) to Linux as necessary. It also allows the BIOS to report
+ * non-standard error sources to Linux (for example, chipset-specific
+ * error registers).
+ *
+ * For more information about HEST, please refer to ACPI Specification
+ * version 4.0, section 17.3.2.
+ *
+ * Copyright 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/kdebug.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <acpi/apei.h>
+
+#include "apei-internal.h"
+
+#define HEST_PFX "HEST: "
+
+int hest_disable;
+EXPORT_SYMBOL_GPL(hest_disable);
+
+/* HEST table parsing */
+
+static struct acpi_table_hest *hest_tab;
+
+static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       return 0;
+}
+
+static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
+       [ACPI_HEST_TYPE_IA32_CHECK] = -1,       /* need further calculation */
+       [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
+       [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
+       [ACPI_HEST_TYPE_AER_ROOT_PORT] = sizeof(struct acpi_hest_aer_root),
+       [ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer),
+       [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge),
+       [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic),
+};
+
+static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
+{
+       u16 hest_type = hest_hdr->type;
+       int len;
+
+       if (hest_type >= ACPI_HEST_TYPE_RESERVED)
+               return 0;
+
+       len = hest_esrc_len_tab[hest_type];
+
+       if (hest_type == ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) {
+               struct acpi_hest_ia_corrected *cmc;
+               cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
+               len = sizeof(*cmc) + cmc->num_hardware_banks *
+                       sizeof(struct acpi_hest_ia_error_bank);
+       } else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) {
+               struct acpi_hest_ia_machine_check *mc;
+               mc = (struct acpi_hest_ia_machine_check *)hest_hdr;
+               len = sizeof(*mc) + mc->num_hardware_banks *
+                       sizeof(struct acpi_hest_ia_error_bank);
+       }
+       BUG_ON(len == -1);
+
+       return len;
+};
+
+int apei_hest_parse(apei_hest_func_t func, void *data)
+{
+       struct acpi_hest_header *hest_hdr;
+       int i, rc, len;
+
+       if (hest_disable)
+               return -EINVAL;
+
+       hest_hdr = (struct acpi_hest_header *)(hest_tab + 1);
+       for (i = 0; i < hest_tab->error_source_count; i++) {
+               len = hest_esrc_len(hest_hdr);
+               if (!len) {
+                       pr_warning(FW_WARN HEST_PFX
+                                  "Unknown or unused hardware error source "
+                                  "type: %d for hardware error source: %d.\n",
+                                  hest_hdr->type, hest_hdr->source_id);
+                       return -EINVAL;
+               }
+               if ((void *)hest_hdr + len >
+                   (void *)hest_tab + hest_tab->header.length) {
+                       pr_warning(FW_BUG HEST_PFX
+               "Table contents overflow for hardware error source: %d.\n",
+                               hest_hdr->source_id);
+                       return -EINVAL;
+               }
+
+               rc = func(hest_hdr, data);
+               if (rc)
+                       return rc;
+
+               hest_hdr = (void *)hest_hdr + len;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_hest_parse);
+
+static int __init setup_hest_disable(char *str)
+{
+       hest_disable = 1;
+       return 0;
+}
+
+__setup("hest_disable", setup_hest_disable);
+
+static int __init hest_init(void)
+{
+       acpi_status status;
+       int rc = -ENODEV;
+
+       if (acpi_disabled)
+               goto err;
+
+       if (hest_disable) {
+               pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
+               goto err;
+       }
+
+       status = acpi_get_table(ACPI_SIG_HEST, 0,
+                               (struct acpi_table_header **)&hest_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_info(HEST_PFX "Table is not found!\n");
+               goto err;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(HEST_PFX "Failed to get table, %s\n", msg);
+               rc = -EINVAL;
+               goto err;
+       }
+
+       rc = apei_hest_parse(hest_void_parse, NULL);
+       if (rc)
+               goto err;
+
+       pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+
+       return 0;
+err:
+       hest_disable = 1;
+       return rc;
+}
+
+subsys_initcall(hest_init);
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
new file mode 100644 (file)
index 0000000..814b192
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * atomicio.c - ACPI IO memory pre-mapping/post-unmapping, then
+ * accessing in atomic context.
+ *
+ * This is used for NMI handler to access IO memory area, because
+ * ioremap/iounmap can not be used in NMI handler. The IO memory area
+ * is pre-mapped in process context and accessed in NMI handler.
+ *
+ * Copyright (C) 2009-2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/kref.h>
+#include <linux/rculist.h>
+#include <linux/interrupt.h>
+#include <acpi/atomicio.h>
+
+#define ACPI_PFX "ACPI: "
+
+static LIST_HEAD(acpi_iomaps);
+/*
+ * Used for mutual exclusion between writers of acpi_iomaps list, for
+ * synchronization between readers and writer, RCU is used.
+ */
+static DEFINE_SPINLOCK(acpi_iomaps_lock);
+
+struct acpi_iomap {
+       struct list_head list;
+       void __iomem *vaddr;
+       unsigned long size;
+       phys_addr_t paddr;
+       struct kref ref;
+};
+
+/* acpi_iomaps_lock or RCU read lock must be held before calling */
+static struct acpi_iomap *__acpi_find_iomap(phys_addr_t paddr,
+                                           unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       list_for_each_entry_rcu(map, &acpi_iomaps, list) {
+               if (map->paddr + map->size >= paddr + size &&
+                   map->paddr <= paddr)
+                       return map;
+       }
+       return NULL;
+}
+
+/*
+ * Atomic "ioremap" used by NMI handler, if the specified IO memory
+ * area is not pre-mapped, NULL will be returned.
+ *
+ * acpi_iomaps_lock or RCU read lock must be held before calling
+ */
+static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr,
+                                        unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       map = __acpi_find_iomap(paddr, size);
+       if (map)
+               return map->vaddr + (paddr - map->paddr);
+       else
+               return NULL;
+}
+
+/* acpi_iomaps_lock must be held before calling */
+static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
+                                       unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       map = __acpi_find_iomap(paddr, size);
+       if (map) {
+               kref_get(&map->ref);
+               return map->vaddr + (paddr - map->paddr);
+       } else
+               return NULL;
+}
+
+/*
+ * Used to pre-map the specified IO memory area. First try to find
+ * whether the area is already pre-mapped, if it is, increase the
+ * reference count (in __acpi_try_ioremap) and return; otherwise, do
+ * the real ioremap, and add the mapping into acpi_iomaps list.
+ */
+static void __iomem *acpi_pre_map(phys_addr_t paddr,
+                                 unsigned long size)
+{
+       void __iomem *vaddr;
+       struct acpi_iomap *map;
+       unsigned long pg_sz, flags;
+       phys_addr_t pg_off;
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       vaddr = __acpi_try_ioremap(paddr, size);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+       if (vaddr)
+               return vaddr;
+
+       pg_off = paddr & PAGE_MASK;
+       pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off;
+       vaddr = ioremap(pg_off, pg_sz);
+       if (!vaddr)
+               return NULL;
+       map = kmalloc(sizeof(*map), GFP_KERNEL);
+       if (!map)
+               goto err_unmap;
+       INIT_LIST_HEAD(&map->list);
+       map->paddr = pg_off;
+       map->size = pg_sz;
+       map->vaddr = vaddr;
+       kref_init(&map->ref);
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       vaddr = __acpi_try_ioremap(paddr, size);
+       if (vaddr) {
+               spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+               iounmap(map->vaddr);
+               kfree(map);
+               return vaddr;
+       }
+       list_add_tail_rcu(&map->list, &acpi_iomaps);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+
+       return vaddr + (paddr - pg_off);
+err_unmap:
+       iounmap(vaddr);
+       return NULL;
+}
+
+/* acpi_iomaps_lock must be held before calling */
+static void __acpi_kref_del_iomap(struct kref *ref)
+{
+       struct acpi_iomap *map;
+
+       map = container_of(ref, struct acpi_iomap, ref);
+       list_del_rcu(&map->list);
+}
+
+/*
+ * Used to post-unmap the specified IO memory area. The iounmap is
+ * done only if the reference count goes zero.
+ */
+static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
+{
+       struct acpi_iomap *map;
+       unsigned long flags;
+       int del;
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       map = __acpi_find_iomap(paddr, size);
+       BUG_ON(!map);
+       del = kref_put(&map->ref, __acpi_kref_del_iomap);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+
+       if (!del)
+               return;
+
+       synchronize_rcu();
+       iounmap(map->vaddr);
+       kfree(map);
+}
+
+/* In NMI handler, should set silent = 1 */
+static int acpi_check_gar(struct acpi_generic_address *reg,
+                         u64 *paddr, int silent)
+{
+       u32 width, space_id;
+
+       width = reg->bit_width;
+       space_id = reg->space_id;
+       /* Handle possible alignment issues */
+       memcpy(paddr, &reg->address, sizeof(*paddr));
+       if (!*paddr) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                       "Invalid physical address in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                                  "Invalid bit width in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+           space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                       "Invalid address space type in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Pre-map, working on GAR */
+int acpi_pre_map_gar(struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       void __iomem *vaddr;
+       int rc;
+
+       if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return 0;
+
+       rc = acpi_check_gar(reg, &paddr, 0);
+       if (rc)
+               return rc;
+
+       vaddr = acpi_pre_map(paddr, reg->bit_width / 8);
+       if (!vaddr)
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_pre_map_gar);
+
+/* Post-unmap, working on GAR */
+int acpi_post_unmap_gar(struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return 0;
+
+       rc = acpi_check_gar(reg, &paddr, 0);
+       if (rc)
+               return rc;
+
+       acpi_post_unmap(paddr, reg->bit_width / 8);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_post_unmap_gar);
+
+/*
+ * Can be used in atomic (including NMI) or process context. RCU read
+ * lock can only be released after the IO memory area accessing.
+ */
+static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
+{
+       void __iomem *addr;
+
+       rcu_read_lock();
+       addr = __acpi_ioremap_fast(paddr, width);
+       switch (width) {
+       case 8:
+               *val = readb(addr);
+               break;
+       case 16:
+               *val = readw(addr);
+               break;
+       case 32:
+               *val = readl(addr);
+               break;
+       case 64:
+               *val = readq(addr);
+               break;
+       default:
+               return -EINVAL;
+       }
+       rcu_read_unlock();
+
+       return 0;
+}
+
+static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
+{
+       void __iomem *addr;
+
+       rcu_read_lock();
+       addr = __acpi_ioremap_fast(paddr, width);
+       switch (width) {
+       case 8:
+               writeb(val, addr);
+               break;
+       case 16:
+               writew(val, addr);
+               break;
+       case 32:
+               writel(val, addr);
+               break;
+       case 64:
+               writeq(val, addr);
+               break;
+       default:
+               return -EINVAL;
+       }
+       rcu_read_unlock();
+
+       return 0;
+}
+
+/* GAR accessing in atomic (including NMI) or process context */
+int acpi_atomic_read(u64 *val, struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       rc = acpi_check_gar(reg, &paddr, 1);
+       if (rc)
+               return rc;
+
+       *val = 0;
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return acpi_atomic_read_mem(paddr, val, reg->bit_width);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return acpi_os_read_port(paddr, (u32 *)val, reg->bit_width);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(acpi_atomic_read);
+
+int acpi_atomic_write(u64 val, struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       rc = acpi_check_gar(reg, &paddr, 1);
+       if (rc)
+               return rc;
+
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return acpi_atomic_write_mem(paddr, val, reg->bit_width);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return acpi_os_write_port(paddr, val, reg->bit_width);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(acpi_atomic_write);
index f2234db..e61d4f8 100644 (file)
@@ -1027,10 +1027,9 @@ int __init acpi_ec_ecdt_probe(void)
                /* Don't trust ECDT, which comes from ASUSTek */
                if (!EC_FLAGS_VALIDATE_ECDT)
                        goto install;
-               saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+               saved_ec = kmemdup(boot_ec, sizeof(struct acpi_ec), GFP_KERNEL);
                if (!saved_ec)
                        return -ENOMEM;
-               memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec));
        /* fall through */
        }
 
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
new file mode 100644 (file)
index 0000000..d0c1967
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * ACPI Hardware Error Device (PNP0C33) Driver
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * ACPI Hardware Error Device is used to report some hardware errors
+ * notified via SCI, mainly the corrected errors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/hed.h>
+
+static struct acpi_device_id acpi_hed_ids[] = {
+       {"PNP0C33", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_hed_ids);
+
+static acpi_handle hed_handle;
+
+static BLOCKING_NOTIFIER_HEAD(acpi_hed_notify_list);
+
+int register_acpi_hed_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&acpi_hed_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_hed_notifier);
+
+void unregister_acpi_hed_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&acpi_hed_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier);
+
+/*
+ * SCI to report hardware error is forwarded to the listeners of HED,
+ * it is used by HEST Generic Hardware Error Source with notify type
+ * SCI.
+ */
+static void acpi_hed_notify(struct acpi_device *device, u32 event)
+{
+       blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL);
+}
+
+static int __devinit acpi_hed_add(struct acpi_device *device)
+{
+       /* Only one hardware error device */
+       if (hed_handle)
+               return -EINVAL;
+       hed_handle = device->handle;
+       return 0;
+}
+
+static int __devexit acpi_hed_remove(struct acpi_device *device, int type)
+{
+       hed_handle = NULL;
+       return 0;
+}
+
+static struct acpi_driver acpi_hed_driver = {
+       .name = "hardware_error_device",
+       .class = "hardware_error",
+       .ids = acpi_hed_ids,
+       .ops = {
+               .add = acpi_hed_add,
+               .remove = acpi_hed_remove,
+               .notify = acpi_hed_notify,
+       },
+};
+
+static int __init acpi_hed_init(void)
+{
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (acpi_bus_register_driver(&acpi_hed_driver) < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit acpi_hed_exit(void)
+{
+       acpi_bus_unregister_driver(&acpi_hed_driver);
+}
+
+module_init(acpi_hed_init);
+module_exit(acpi_hed_exit);
+
+ACPI_MODULE_NAME("hed");
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("ACPI Hardware Error Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c
deleted file mode 100644 (file)
index 1c527a1..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <linux/acpi.h>
-#include <linux/pci.h>
-
-#define PREFIX "ACPI: "
-
-static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p)
-{
-       return sizeof(*p) +
-               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
-}
-
-static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p)
-{
-       return sizeof(*p) +
-               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
-}
-
-static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p)
-{
-       return sizeof(*p);
-}
-
-static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p)
-{
-       return sizeof(*p);
-}
-
-static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci)
-{
-       return  (0           == pci_domain_nr(pci->bus) &&
-                p->bus      == pci->bus->number &&
-                p->device   == PCI_SLOT(pci->devfn) &&
-                p->function == PCI_FUNC(pci->devfn));
-}
-
-static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first)
-{
-       struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header);
-       unsigned long rc=0;
-       u8 pcie_type = 0;
-       u8 bridge = 0;
-       switch (type) {
-       case ACPI_HEST_TYPE_AER_ROOT_PORT:
-               rc = sizeof(struct acpi_hest_aer_root);
-               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
-               break;
-       case ACPI_HEST_TYPE_AER_ENDPOINT:
-               rc = sizeof(struct acpi_hest_aer);
-               pcie_type = PCI_EXP_TYPE_ENDPOINT;
-               break;
-       case ACPI_HEST_TYPE_AER_BRIDGE:
-               rc = sizeof(struct acpi_hest_aer_bridge);
-               if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE)
-                       bridge = 1;
-               break;
-       }
-
-       if (p->flags & ACPI_HEST_GLOBAL) {
-               if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge)
-                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
-       }
-       else
-               if (hest_match_pci(p, pci))
-                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
-       return rc;
-}
-
-static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci)
-{
-       struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader;
-       void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */
-       struct acpi_hest_header *hdr = p;
-
-       int i;
-       int firmware_first = 0;
-       static unsigned char printed_unused = 0;
-       static unsigned char printed_reserved = 0;
-
-       for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) {
-               switch (hdr->type) {
-               case ACPI_HEST_TYPE_IA32_CHECK:
-                       p += parse_acpi_hest_ia_machine_check(p);
-                       break;
-               case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK:
-                       p += parse_acpi_hest_ia_corrected(p);
-                       break;
-               case ACPI_HEST_TYPE_IA32_NMI:
-                       p += parse_acpi_hest_ia_nmi(p);
-                       break;
-               /* These three should never appear */
-               case ACPI_HEST_TYPE_NOT_USED3:
-               case ACPI_HEST_TYPE_NOT_USED4:
-               case ACPI_HEST_TYPE_NOT_USED5:
-                       if (!printed_unused) {
-                               printk(KERN_DEBUG PREFIX
-                                      "HEST Error Source list contains an obsolete type (%d).\n", hdr->type);
-                               printed_unused = 1;
-                       }
-                       break;
-               case ACPI_HEST_TYPE_AER_ROOT_PORT:
-               case ACPI_HEST_TYPE_AER_ENDPOINT:
-               case ACPI_HEST_TYPE_AER_BRIDGE:
-                       p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first);
-                       break;
-               case ACPI_HEST_TYPE_GENERIC_ERROR:
-                       p += parse_acpi_hest_generic(p);
-                       break;
-               /* These should never appear either */
-               case ACPI_HEST_TYPE_RESERVED:
-               default:
-                       if (!printed_reserved) {
-                               printk(KERN_DEBUG PREFIX
-                                      "HEST Error Source list contains a reserved type (%d).\n", hdr->type);
-                               printed_reserved = 1;
-                       }
-                       break;
-               }
-       }
-       return firmware_first;
-}
-
-int acpi_hest_firmware_first_pci(struct pci_dev *pci)
-{
-       acpi_status status = AE_NOT_FOUND;
-       struct acpi_table_header *hest = NULL;
-
-       if (acpi_disabled)
-               return 0;
-
-       status = acpi_get_table(ACPI_SIG_HEST, 1, &hest);
-
-       if (ACPI_SUCCESS(status)) {
-               if (acpi_hest_firmware_first(hest, pci)) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci);
index aefce33..4eac593 100644 (file)
@@ -120,7 +120,8 @@ acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
        struct acpi_pci_root *root;
        
        list_for_each_entry(root, &acpi_pci_roots, node)
-               if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
+               if ((root->segment == (u16) seg) &&
+                   (root->secondary.start == (u16) bus))
                        return root->device->handle;
        return NULL;            
 }
@@ -154,7 +155,7 @@ EXPORT_SYMBOL_GPL(acpi_is_root_bridge);
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
-       int *busnr = data;
+       struct resource *res = data;
        struct acpi_resource_address64 address;
 
        if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -164,28 +165,27 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 
        acpi_resource_to_address64(resource, &address);
        if ((address.address_length > 0) &&
-           (address.resource_type == ACPI_BUS_NUMBER_RANGE))
-               *busnr = address.minimum;
+           (address.resource_type == ACPI_BUS_NUMBER_RANGE)) {
+               res->start = address.minimum;
+               res->end = address.minimum + address.address_length - 1;
+       }
 
        return AE_OK;
 }
 
 static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
-                                            unsigned long long *bus)
+                                            struct resource *res)
 {
        acpi_status status;
-       int busnum;
 
-       busnum = -1;
+       res->start = -1;
        status =
            acpi_walk_resources(handle, METHOD_NAME__CRS,
-                               get_root_bridge_busnr_callback, &busnum);
+                               get_root_bridge_busnr_callback, res);
        if (ACPI_FAILURE(status))
                return status;
-       /* Check if we really get a bus number from _CRS */
-       if (busnum == -1)
+       if (res->start == -1)
                return AE_ERROR;
-       *bus = busnum;
        return AE_OK;
 }
 
@@ -429,34 +429,47 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        struct acpi_device *child;
        u32 flags, base_flags;
 
+       root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+       if (!root)
+               return -ENOMEM;
+
        segment = 0;
        status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
                                       &segment);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
-               return -ENODEV;
+               result = -ENODEV;
+               goto end;
        }
 
        /* Check _CRS first, then _BBN.  If no _BBN, default to zero. */
-       bus = 0;
-       status = try_get_root_bridge_busnr(device->handle, &bus);
+       root->secondary.flags = IORESOURCE_BUS;
+       status = try_get_root_bridge_busnr(device->handle, &root->secondary);
        if (ACPI_FAILURE(status)) {
+               /*
+                * We need both the start and end of the downstream bus range
+                * to interpret _CBA (MMCONFIG base address), so it really is
+                * supposed to be in _CRS.  If we don't find it there, all we
+                * can do is assume [_BBN-0xFF] or [0-0xFF].
+                */
+               root->secondary.end = 0xFF;
+               printk(KERN_WARNING FW_BUG PREFIX
+                      "no secondary bus range in _CRS\n");
                status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,                                               NULL, &bus);
-               if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-                       printk(KERN_ERR PREFIX
-                            "no bus number in _CRS and can't evaluate _BBN\n");
-                       return -ENODEV;
+               if (ACPI_SUCCESS(status))
+                       root->secondary.start = bus;
+               else if (status == AE_NOT_FOUND)
+                       root->secondary.start = 0;
+               else {
+                       printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
+                       result = -ENODEV;
+                       goto end;
                }
        }
 
-       root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
-       if (!root)
-               return -ENOMEM;
-
        INIT_LIST_HEAD(&root->node);
        root->device = device;
        root->segment = segment & 0xFFFF;
-       root->bus_nr = bus & 0xFF;
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
        device->driver_data = root;
@@ -475,9 +488,9 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        /* TBD: Locking */
        list_add_tail(&root->node, &acpi_pci_roots);
 
-       printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
+       printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
               acpi_device_name(device), acpi_device_bid(device),
-              root->segment, root->bus_nr);
+              root->segment, &root->secondary);
 
        /*
         * Scan the Root Bridge
@@ -486,11 +499,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * PCI namespace does not get created until this call is made (and 
         * thus the root bridge's pci_dev does not exist).
         */
-       root->bus = pci_acpi_scan_root(device, segment, bus);
+       root->bus = pci_acpi_scan_root(root);
        if (!root->bus) {
                printk(KERN_ERR PREFIX
                            "Bus %04x:%02x not present in PCI namespace\n",
-                           root->segment, root->bus_nr);
+                           root->segment, (unsigned int)root->secondary.start);
                result = -ENODEV;
                goto end;
        }
index 5675d97..b1034a9 100644 (file)
@@ -616,7 +616,8 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
        acpi_processor_get_limit_info(pr);
 
 
-       acpi_processor_power_init(pr, device);
+       if (cpuidle_get_driver() == &acpi_idle_driver)
+               acpi_processor_power_init(pr, device);
 
        pr->cdev = thermal_cooling_device_register("Processor", device,
                                                &processor_cooling_ops);
@@ -920,9 +921,14 @@ static int __init acpi_processor_init(void)
        if (!acpi_processor_dir)
                return -ENOMEM;
 #endif
-       result = cpuidle_register_driver(&acpi_idle_driver);
-       if (result < 0)
-               goto out_proc;
+
+       if (!cpuidle_register_driver(&acpi_idle_driver)) {
+               printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
+                       acpi_idle_driver.name);
+       } else {
+               printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s",
+                       cpuidle_get_driver()->name);
+       }
 
        result = acpi_bus_register_driver(&acpi_processor_driver);
        if (result < 0)
@@ -941,7 +947,6 @@ static int __init acpi_processor_init(void)
 out_cpuidle:
        cpuidle_unregister_driver(&acpi_idle_driver);
 
-out_proc:
 #ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 #endif
index c3817e1..2e8c27d 100644 (file)
@@ -727,19 +727,9 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
                        break;
                }
 
-               if (pr->power.states[i].promotion.state)
-                       seq_printf(seq, "promotion[C%zd] ",
-                                  (pr->power.states[i].promotion.state -
-                                   pr->power.states));
-               else
-                       seq_puts(seq, "promotion[--] ");
-
-               if (pr->power.states[i].demotion.state)
-                       seq_printf(seq, "demotion[C%zd] ",
-                                  (pr->power.states[i].demotion.state -
-                                   pr->power.states));
-               else
-                       seq_puts(seq, "demotion[--] ");
+               seq_puts(seq, "promotion[--] ");
+
+               seq_puts(seq, "demotion[--] ");
 
                seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
                           pr->power.states[i].latency,
@@ -869,6 +859,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        ktime_t  kt1, kt2;
+       s64 idle_time_ns;
        s64 idle_time;
        s64 sleep_ticks = 0;
 
@@ -881,6 +872,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                return(acpi_idle_enter_c1(dev, state));
 
        local_irq_disable();
+
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
@@ -888,12 +880,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                 * NEED_RESCHED:
                 */
                smp_mb();
-       }
 
-       if (unlikely(need_resched())) {
-               current_thread_info()->status |= TS_POLLING;
-               local_irq_enable();
-               return 0;
+               if (unlikely(need_resched())) {
+                       current_thread_info()->status |= TS_POLLING;
+                       local_irq_enable();
+                       return 0;
+               }
        }
 
        /*
@@ -910,15 +902,18 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        sched_clock_idle_sleep_event();
        acpi_idle_do_entry(cx);
        kt2 = ktime_get_real();
-       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
+       idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
+       idle_time = idle_time_ns;
+       do_div(idle_time, NSEC_PER_USEC);
 
        sleep_ticks = us_to_pm_timer_ticks(idle_time);
 
        /* Tell the scheduler how much we idled: */
-       sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+       sched_clock_idle_wakeup_event(idle_time_ns);
 
        local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
+       if (cx->entry_method != ACPI_CSTATE_FFH)
+               current_thread_info()->status |= TS_POLLING;
 
        cx->usage++;
 
@@ -943,6 +938,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        ktime_t  kt1, kt2;
+       s64 idle_time_ns;
        s64 idle_time;
        s64 sleep_ticks = 0;
 
@@ -968,6 +964,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        }
 
        local_irq_disable();
+
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
@@ -975,12 +972,12 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                 * NEED_RESCHED:
                 */
                smp_mb();
-       }
 
-       if (unlikely(need_resched())) {
-               current_thread_info()->status |= TS_POLLING;
-               local_irq_enable();
-               return 0;
+               if (unlikely(need_resched())) {
+                       current_thread_info()->status |= TS_POLLING;
+                       local_irq_enable();
+                       return 0;
+               }
        }
 
        acpi_unlazy_tlb(smp_processor_id());
@@ -1025,14 +1022,17 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                spin_unlock(&c3_lock);
        }
        kt2 = ktime_get_real();
-       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
+       idle_time_ns = ktime_to_us(ktime_sub(kt2, kt1));
+       idle_time = idle_time_ns;
+       do_div(idle_time, NSEC_PER_USEC);
 
        sleep_ticks = us_to_pm_timer_ticks(idle_time);
        /* Tell the scheduler how much we idled: */
-       sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+       sched_clock_idle_wakeup_event(idle_time_ns);
 
        local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
+       if (cx->entry_method != ACPI_CSTATE_FFH)
+               current_thread_info()->status |= TS_POLLING;
 
        cx->usage++;
 
index baa76bb..4ab2275 100644 (file)
@@ -80,22 +80,6 @@ static int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-/*
- * According to the ACPI specification the BIOS should make sure that ACPI is
- * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states.  Still,
- * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
- * on such systems during resume.  Unfortunately that doesn't help in
- * particularly pathological cases in which SCI_EN has to be set directly on
- * resume, although the specification states very clearly that this flag is
- * owned by the hardware.  The set_sci_en_on_resume variable will be set in such
- * cases.
- */
-static bool set_sci_en_on_resume;
-
-void __init acpi_set_sci_en_on_resume(void)
-{
-       set_sci_en_on_resume = true;
-}
 
 /*
  * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
@@ -253,11 +237,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
        }
 
-       /* If ACPI is not enabled by the BIOS, we need to enable it here. */
-       if (set_sci_en_on_resume)
-               acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
-       else
-               acpi_enable();
+       /* This violates the spec but is required for bug compatibility. */
+       acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 
        /* Reprogram control registers and execute _BFS */
        acpi_leave_sleep_state_prep(acpi_state);
@@ -346,12 +327,6 @@ static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
        return 0;
 }
 
-static int __init init_set_sci_en_on_resume(const struct dmi_system_id *d)
-{
-       set_sci_en_on_resume = true;
-       return 0;
-}
-
 static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
        {
        .callback = init_old_suspend_ordering,
@@ -370,22 +345,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                },
        },
        {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Apple MacBook 1,1",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Apple MacMini 1,1",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
-               },
-       },
-       {
        .callback = init_old_suspend_ordering,
        .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
        .matches = {
@@ -394,94 +353,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                },
        },
        {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Toshiba Satellite L300",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard HP G7000 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP G7000 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard HP Pavilion dv3 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Pavilion dv4",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Pavilion dv7",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Compaq Presario C700 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario C700 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Compaq Presario CQ40 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario CQ40 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad T410",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T410"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad T510",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T510"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad W510",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W510"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad X201[s]",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201"),
-               },
-       },
-       {
        .callback = init_old_suspend_ordering,
        .ident = "Panasonic CF51-2L",
        .matches = {
@@ -490,30 +361,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
                },
        },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1558",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1558"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1557",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1555",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1555"),
-               },
-       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
index 8a8f3b3..25b8bd1 100644 (file)
@@ -1,6 +1,6 @@
 
 extern u8 sleep_states[];
-extern int acpi_suspend (u32 state);
+extern int acpi_suspend(u32 state);
 
 extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
index 8a0ed28..f336bca 100644 (file)
@@ -213,7 +213,7 @@ acpi_table_parse_entries(char *id,
        unsigned long table_end;
        acpi_size tbl_size;
 
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return -ENODEV;
 
        if (!handler)
@@ -280,7 +280,7 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler)
        struct acpi_table_header *table = NULL;
        acpi_size tbl_size;
 
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return -ENODEV;
 
        if (!handler)
index a0c93b3..9865d46 100644 (file)
@@ -45,6 +45,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/suspend.h>
+#include <acpi/video.h>
 
 #define PREFIX "ACPI: "
 
 
 #define MAX_NAME_LEN   20
 
-#define ACPI_VIDEO_DISPLAY_CRT 1
-#define ACPI_VIDEO_DISPLAY_TV  2
-#define ACPI_VIDEO_DISPLAY_DVI 3
-#define ACPI_VIDEO_DISPLAY_LCD 4
-
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
 ACPI_MODULE_NAME("video");
 
@@ -1007,11 +1003,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                result = acpi_video_init_brightness(device);
                if (result)
                        return;
-               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+               name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
                if (!name)
                        return;
+               count++;
 
-               sprintf(name, "acpi_video%d", count++);
                memset(&props, 0, sizeof(struct backlight_properties));
                props.max_brightness = device->brightness->count - 3;
                device->backlight = backlight_device_register(name, NULL, device,
@@ -1067,10 +1063,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                if (device->cap._DCS && device->cap._DSS) {
                        static int count;
                        char *name;
-                       name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+                       name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
                        if (!name)
                                return;
-                       sprintf(name, "acpi_video%d", count++);
+                       count++;
                        device->output_dev = video_output_register(name,
                                        NULL, device, &acpi_output_properties);
                        kfree(name);
@@ -1747,12 +1743,28 @@ acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id
        return NULL;
 }
 
+static int
+acpi_video_get_device_type(struct acpi_video_bus *video,
+                          unsigned long device_id)
+{
+       struct acpi_video_enumerated_device *ids;
+       int i;
+
+       for (i = 0; i < video->attached_count; i++) {
+               ids = &video->attached_array[i];
+               if ((ids->value.int_val & 0xffff) == device_id)
+                       return ids->value.int_val;
+       }
+
+       return 0;
+}
+
 static int
 acpi_video_bus_get_one_device(struct acpi_device *device,
                              struct acpi_video_bus *video)
 {
        unsigned long long device_id;
-       int status;
+       int status, device_type;
        struct acpi_video_device *data;
        struct acpi_video_device_attrib* attribute;
 
@@ -1797,8 +1809,25 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
                        }
                        if(attribute->bios_can_detect)
                                data->flags.bios = 1;
-               } else
-                       data->flags.unknown = 1;
+               } else {
+                       /* Check for legacy IDs */
+                       device_type = acpi_video_get_device_type(video,
+                                                                device_id);
+                       /* Ignore bits 16 and 18-20 */
+                       switch (device_type & 0xffe2ffff) {
+                       case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+                               data->flags.crt = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+                               data->flags.lcd = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+                               data->flags.tvout = 1;
+                               break;
+                       default:
+                               data->flags.unknown = 1;
+                       }
+               }
 
                acpi_video_device_bind(video, data);
                acpi_video_device_find_cap(data);
@@ -2032,6 +2061,71 @@ out:
        return result;
 }
 
+int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
+                       void **edid)
+{
+       struct acpi_video_bus *video;
+       struct acpi_video_device *video_device;
+       union acpi_object *buffer = NULL;
+       acpi_status status;
+       int i, length;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       video = acpi_driver_data(device);
+
+       for (i = 0; i < video->attached_count; i++) {
+               video_device = video->attached_array[i].bind_info;
+               length = 256;
+
+               if (!video_device)
+                       continue;
+
+               if (type) {
+                       switch (type) {
+                       case ACPI_VIDEO_DISPLAY_CRT:
+                               if (!video_device->flags.crt)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_TV:
+                               if (!video_device->flags.tvout)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_DVI:
+                               if (!video_device->flags.dvi)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LCD:
+                               if (!video_device->flags.lcd)
+                                       continue;
+                               break;
+                       }
+               } else if (video_device->device_id != device_id) {
+                       continue;
+               }
+
+               status = acpi_video_device_EDID(video_device, &buffer, length);
+
+               if (ACPI_FAILURE(status) || !buffer ||
+                   buffer->type != ACPI_TYPE_BUFFER) {
+                       length = 128;
+                       status = acpi_video_device_EDID(video_device, &buffer,
+                                                       length);
+                       if (ACPI_FAILURE(status) || !buffer ||
+                           buffer->type != ACPI_TYPE_BUFFER) {
+                               continue;
+                       }
+               }
+
+               *edid = buffer->buffer.pointer;
+               return length;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_video_get_edid);
+
 static int
 acpi_video_bus_get_devices(struct acpi_video_bus *video,
                           struct acpi_device *device)
index fc2f26b..c5fef01 100644 (file)
@@ -250,7 +250,7 @@ static int __init acpi_backlight(char *str)
                                ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
                if (!strcmp("video", str))
                        acpi_video_support |=
-                               ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
+                               ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO;
        }
        return 1;
 }
index e68541f..73f8833 100644 (file)
@@ -57,6 +57,8 @@ config SATA_PMP
          This option adds support for SATA Port Multipliers
          (the SATA version of an ethernet hub, or SAS expander).
 
+comment "Controllers with non-SFF native interface"
+
 config SATA_AHCI
        tristate "AHCI SATA support"
        depends on PCI
@@ -73,11 +75,12 @@ config SATA_AHCI_PLATFORM
 
          If unsure, say N.
 
-config SATA_SIL24
-       tristate "Silicon Image 3124/3132 SATA support"
-       depends on PCI
+config SATA_FSL
+       tristate "Freescale 3.0Gbps SATA support"
+       depends on FSL_SOC
        help
-         This option enables support for Silicon Image 3124/3132 Serial ATA.
+         This option enables support for Freescale 3.0Gbps SATA controller.
+         It can be found on MPC837x and MPC8315.
 
          If unsure, say N.
 
@@ -87,12 +90,11 @@ config SATA_INIC162X
        help
          This option enables support for Initio 162x Serial ATA.
 
-config SATA_FSL
-       tristate "Freescale 3.0Gbps SATA support"
-       depends on FSL_SOC
+config SATA_SIL24
+       tristate "Silicon Image 3124/3132 SATA support"
+       depends on PCI
        help
-         This option enables support for Freescale 3.0Gbps SATA controller.
-         It can be found on MPC837x and MPC8315.
+         This option enables support for Silicon Image 3124/3132 Serial ATA.
 
          If unsure, say N.
 
@@ -116,15 +118,65 @@ config ATA_SFF
 
 if ATA_SFF
 
-config SATA_SVW
-       tristate "ServerWorks Frodo / Apple K2 SATA support"
+comment "SFF controllers with custom DMA interface"
+
+config PDC_ADMA
+       tristate "Pacific Digital ADMA support"
        depends on PCI
        help
-         This option enables support for Broadcom/Serverworks/Apple K2
-         SATA support.
+         This option enables support for Pacific Digital ADMA controllers
+
+         If unsure, say N.
+
+config PATA_MPC52xx
+       tristate "Freescale MPC52xx SoC internal IDE"
+       depends on PPC_MPC52xx && PPC_BESTCOMM
+       select PPC_BESTCOMM_ATA
+       help
+         This option enables support for integrated IDE controller
+         of the Freescale MPC52xx SoC.
+
+         If unsure, say N.
+
+config PATA_OCTEON_CF
+       tristate "OCTEON Boot Bus Compact Flash support"
+       depends on CPU_CAVIUM_OCTEON
+       help
+         This option enables a polled compact flash driver for use with
+         compact flash cards attached to the OCTEON boot bus.
+
+         If unsure, say N.
+
+config SATA_QSTOR
+       tristate "Pacific Digital SATA QStor support"
+       depends on PCI
+       help
+         This option enables support for Pacific Digital Serial ATA QStor.
+
+         If unsure, say N.
+
+config SATA_SX4
+       tristate "Promise SATA SX4 support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for Promise Serial ATA SX4.
 
          If unsure, say N.
 
+config ATA_BMDMA
+       bool "ATA BMDMA support"
+       default y
+       help
+         This option adds support for SFF ATA controllers with BMDMA
+         capability.  BMDMA stands for bus-master DMA and the
+         de-facto DMA interface for SFF controllers.
+
+         If unuser, say Y.
+
+if ATA_BMDMA
+
+comment "SATA SFF controllers with BMDMA"
+
 config ATA_PIIX
        tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
        depends on PCI
@@ -152,22 +204,6 @@ config SATA_NV
 
          If unsure, say N.
 
-config PDC_ADMA
-       tristate "Pacific Digital ADMA support"
-       depends on PCI
-       help
-         This option enables support for Pacific Digital ADMA controllers
-
-         If unsure, say N.
-
-config SATA_QSTOR
-       tristate "Pacific Digital SATA QStor support"
-       depends on PCI
-       help
-         This option enables support for Pacific Digital Serial ATA QStor.
-
-         If unsure, say N.
-
 config SATA_PROMISE
        tristate "Promise SATA TX2/TX4 support"
        depends on PCI
@@ -176,14 +212,6 @@ config SATA_PROMISE
 
          If unsure, say N.
 
-config SATA_SX4
-       tristate "Promise SATA SX4 support (Experimental)"
-       depends on PCI && EXPERIMENTAL
-       help
-         This option enables support for Promise Serial ATA SX4.
-
-         If unsure, say N.
-
 config SATA_SIL
        tristate "Silicon Image SATA support"
        depends on PCI
@@ -203,6 +231,15 @@ config SATA_SIS
          enable the PATA_SIS driver in the config.
          If unsure, say N.
 
+config SATA_SVW
+       tristate "ServerWorks Frodo / Apple K2 SATA support"
+       depends on PCI
+       help
+         This option enables support for Broadcom/Serverworks/Apple K2
+         SATA support.
+
+         If unsure, say N.
+
 config SATA_ULI
        tristate "ULi Electronics SATA support"
        depends on PCI
@@ -227,14 +264,7 @@ config SATA_VITESSE
 
          If unsure, say N.
 
-config PATA_ACPI
-       tristate "ACPI firmware driver for PATA"
-       depends on ATA_ACPI
-       help
-         This option enables an ACPI method driver which drives
-         motherboard PATA controller interfaces through the ACPI
-         firmware in the BIOS. This driver can sometimes handle
-         otherwise unsupported hardware.
+comment "PATA SFF controllers with BMDMA"
 
 config PATA_ALI
        tristate "ALi PATA support"
@@ -262,40 +292,30 @@ config PATA_ARTOP
 
          If unsure, say N.
 
-config PATA_ATP867X
-       tristate "ARTOP/Acard ATP867X PATA support"
+config PATA_ATIIXP
+       tristate "ATI PATA support"
        depends on PCI
        help
-         This option enables support for ARTOP/Acard ATP867X PATA
-         controllers.
-
-         If unsure, say N.
-
-config PATA_AT32
-       tristate "Atmel AVR32 PATA support (Experimental)"
-       depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
-       help
-         This option enables support for the IDE devices on the
-         Atmel AT32AP platform.
+         This option enables support for the ATI ATA interfaces
+         found on the many ATI chipsets.
 
          If unsure, say N.
 
-config PATA_ATIIXP
-       tristate "ATI PATA support"
+config PATA_ATP867X
+       tristate "ARTOP/Acard ATP867X PATA support"
        depends on PCI
        help
-         This option enables support for the ATI ATA interfaces
-         found on the many ATI chipsets.
+         This option enables support for ARTOP/Acard ATP867X PATA
+         controllers.
 
          If unsure, say N.
 
-config PATA_CMD640_PCI
-       tristate "CMD640 PCI PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+config PATA_BF54X
+       tristate "Blackfin 54x ATAPI support"
+       depends on BF542 || BF548 || BF549
        help
-         This option enables support for the CMD640 PCI IDE
-         interface chip. Only the primary channel is currently
-         supported.
+         This option enables support for the built-in ATAPI controller on
+         Blackfin 54x family chips.
 
          If unsure, say N.
 
@@ -362,15 +382,6 @@ config PATA_EFAR
 
          If unsure, say N.
 
-config ATA_GENERIC
-       tristate "Generic ATA support"
-       depends on PCI
-       help
-         This option enables support for generic BIOS configured
-         ATA controllers via the new ATA layer
-
-         If unsure, say N.
-
 config PATA_HPT366
        tristate "HPT 366/368 PATA support"
        depends on PCI
@@ -415,12 +426,20 @@ config PATA_HPT3X3_DMA
          controllers. Enable with care as there are still some
          problems with DMA on this chipset.
 
-config PATA_ISAPNP
-       tristate "ISA Plug and Play PATA support"
-       depends on ISAPNP
+config PATA_ICSIDE
+       tristate "Acorn ICS PATA support"
+       depends on ARM && ARCH_ACORN
        help
-         This option enables support for ISA plug & play ATA
-         controllers such as those found on old soundcards.
+         On Acorn systems, say Y here if you wish to use the ICS PATA
+         interface card.  This is not required for ICS partition support.
+         If you are unsure, say N to this.
+
+config PATA_IT8213
+       tristate "IT8213 PATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the ITE 821 PATA
+          controllers via the new ATA layer.
 
          If unsure, say N.
 
@@ -434,15 +453,6 @@ config PATA_IT821X
 
          If unsure, say N.
 
-config PATA_IT8213
-       tristate "IT8213 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
-       help
-         This option enables support for the ITE 821 PATA
-          controllers via the new ATA layer.
-
-         If unsure, say N.
-
 config PATA_JMICRON
        tristate "JMicron PATA support"
        depends on PCI
@@ -452,23 +462,14 @@ config PATA_JMICRON
 
          If unsure, say N.
 
-config PATA_LEGACY
-       tristate "Legacy ISA PATA support (Experimental)"
-       depends on (ISA || PCI)  && EXPERIMENTAL
-       help
-         This option enables support for ISA/VLB/PCI bus legacy PATA
-         ports and allows them to be accessed via the new ATA layer.
-
-         If unsure, say N.
-
-config PATA_TRIFLEX
-       tristate "Compaq Triflex PATA support"
-       depends on PCI
+config PATA_MACIO
+       tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
+       depends on PPC_PMAC
        help
-         Enable support for the Compaq 'Triflex' IDE controller as found
-         on many Compaq Pentium-Pro systems, via the new ATA layer.
-
-         If unsure, say N.
+         Most IDE capable PowerMacs have IDE busses driven by a variant
+          of this controller which is part of the Apple chipset used on
+          most PowerMac models. Some models have multiple busses using
+          different chipsets, though generally, MacIO is one of them.
 
 config PATA_MARVELL
        tristate "Marvell PATA support via legacy mode"
@@ -481,32 +482,6 @@ config PATA_MARVELL
 
          If unsure, say N.
 
-config PATA_MPC52xx
-       tristate "Freescale MPC52xx SoC internal IDE"
-       depends on PPC_MPC52xx && PPC_BESTCOMM
-       select PPC_BESTCOMM_ATA
-       help
-         This option enables support for integrated IDE controller
-         of the Freescale MPC52xx SoC.
-
-         If unsure, say N.
-
-config PATA_MPIIX
-       tristate "Intel PATA MPIIX support"
-       depends on PCI
-       help
-         This option enables support for MPIIX PATA support.
-
-         If unsure, say N.
-
-config PATA_OLDPIIX
-       tristate "Intel PATA old PIIX support"
-       depends on PCI
-       help
-         This option enables support for early PIIX PATA support.
-
-         If unsure, say N.
-
 config PATA_NETCELL
        tristate "NETCELL Revolution RAID support"
        depends on PCI
@@ -525,15 +500,6 @@ config PATA_NINJA32
 
          If unsure, say N.
 
-config PATA_NS87410
-       tristate "Nat Semi NS87410 PATA support"
-       depends on PCI
-       help
-         This option enables support for the National Semiconductor
-         NS87410 PCI-IDE controller.
-
-         If unsure, say N.
-
 config PATA_NS87415
        tristate "Nat Semi NS87415 PATA support"
        depends on PCI
@@ -543,12 +509,11 @@ config PATA_NS87415
 
          If unsure, say N.
 
-config PATA_OPTI
-       tristate "OPTI621/6215 PATA support (Very Experimental)"
-       depends on PCI && EXPERIMENTAL
+config PATA_OLDPIIX
+       tristate "Intel PATA old PIIX support"
+       depends on PCI
        help
-         This option enables full PIO support for the early Opti ATA
-         controllers found on some old motherboards.
+         This option enables support for early PIIX PATA support.
 
          If unsure, say N.
 
@@ -562,24 +527,6 @@ config PATA_OPTIDMA
 
          If unsure, say N.
 
-config PATA_PALMLD
-       tristate "Palm LifeDrive PATA support"
-       depends on MACH_PALMLD
-       help
-         This option enables support for Palm LifeDrive's internal ATA
-         port via the new ATA layer.
-
-         If unsure, say N.
-
-config PATA_PCMCIA
-       tristate "PCMCIA PATA support"
-       depends on PCMCIA
-       help
-         This option enables support for PCMCIA ATA interfaces, including
-         compact flash card adapters via the new ATA layer.
-
-         If unsure, say N.
-
 config PATA_PDC2027X
        tristate "Promise PATA 2027x support"
        depends on PCI
@@ -597,12 +544,6 @@ config PATA_PDC_OLD
 
          If unsure, say N.
 
-config PATA_QDI
-       tristate "QDI VLB PATA support"
-       depends on ISA
-       help
-         Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
-
 config PATA_RADISYS
        tristate "RADISYS 82600 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
@@ -612,15 +553,6 @@ config PATA_RADISYS
 
          If unsure, say N.
 
-config PATA_RB532
-       tristate "RouterBoard 532 PATA CompactFlash support"
-       depends on MIKROTIK_RB532
-       help
-         This option enables support for the RouterBoard 532
-         PATA CompactFlash controller.
-
-         If unsure, say N.
-
 config PATA_RDC
        tristate "RDC PATA support"
        depends on PCI
@@ -631,21 +563,30 @@ config PATA_RDC
 
          If unsure, say N.
 
-config PATA_RZ1000
-       tristate "PC Tech RZ1000 PATA support"
+config PATA_SC1200
+       tristate "SC1200 PATA support"
        depends on PCI
        help
-         This option enables basic support for the PC Tech RZ1000/1
-         PATA controllers via the new ATA layer
+         This option enables support for the NatSemi/AMD SC1200 SoC
+         companion chip used with the Geode processor family.
 
          If unsure, say N.
 
-config PATA_SC1200
-       tristate "SC1200 PATA support"
+config PATA_SCC
+       tristate "Toshiba's Cell Reference Set IDE support"
+       depends on PCI && PPC_CELLEB
+       help
+         This option enables support for the built-in IDE controller on
+         Toshiba Cell Reference Board.
+
+         If unsure, say N.
+
+config PATA_SCH
+       tristate "Intel SCH PATA support"
        depends on PCI
        help
-         This option enables support for the NatSemi/AMD SC1200 SoC
-         companion chip used with the Geode processor family.
+         This option enables support for Intel SCH PATA on the Intel
+         SCH (US15W, US15L, UL11L) series host controllers.
 
          If unsure, say N.
 
@@ -683,6 +624,15 @@ config PATA_TOSHIBA
 
          If unsure, say N.
 
+config PATA_TRIFLEX
+       tristate "Compaq Triflex PATA support"
+       depends on PCI
+       help
+         Enable support for the Compaq 'Triflex' IDE controller as found
+         on many Compaq Pentium-Pro systems, via the new ATA layer.
+
+         If unsure, say N.
+
 config PATA_VIA
        tristate "VIA PATA support"
        depends on PCI
@@ -701,12 +651,99 @@ config PATA_WINBOND
 
          If unsure, say N.
 
-config PATA_WINBOND_VLB
-       tristate "Winbond W83759A VLB PATA support (Experimental)"
-       depends on ISA && EXPERIMENTAL
+endif # ATA_BMDMA
+
+comment "PIO-only SFF controllers"
+
+config PATA_AT32
+       tristate "Atmel AVR32 PATA support (Experimental)"
+       depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
        help
-         Support for the Winbond W83759A controller on Vesa Local Bus
-         systems.
+         This option enables support for the IDE devices on the
+         Atmel AT32AP platform.
+
+         If unsure, say N.
+
+config PATA_AT91
+       tristate "PATA support for AT91SAM9260"
+       depends on ARM && ARCH_AT91
+       help
+         This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
+
+         If unsure, say N.
+
+config PATA_CMD640_PCI
+       tristate "CMD640 PCI PATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the CMD640 PCI IDE
+         interface chip. Only the primary channel is currently
+         supported.
+
+         If unsure, say N.
+
+config PATA_ISAPNP
+       tristate "ISA Plug and Play PATA support"
+       depends on ISAPNP
+       help
+         This option enables support for ISA plug & play ATA
+         controllers such as those found on old soundcards.
+
+         If unsure, say N.
+
+config PATA_IXP4XX_CF
+       tristate "IXP4XX Compact Flash support"
+       depends on ARCH_IXP4XX
+       help
+         This option enables support for a Compact Flash connected on
+         the ixp4xx expansion bus. This driver had been written for
+         Loft/Avila boards in mind but can work with others.
+
+         If unsure, say N.
+
+config PATA_MPIIX
+       tristate "Intel PATA MPIIX support"
+       depends on PCI
+       help
+         This option enables support for MPIIX PATA support.
+
+         If unsure, say N.
+
+config PATA_NS87410
+       tristate "Nat Semi NS87410 PATA support"
+       depends on PCI
+       help
+         This option enables support for the National Semiconductor
+         NS87410 PCI-IDE controller.
+
+         If unsure, say N.
+
+config PATA_OPTI
+       tristate "OPTI621/6215 PATA support (Very Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables full PIO support for the early Opti ATA
+         controllers found on some old motherboards.
+
+         If unsure, say N.
+
+config PATA_PALMLD
+       tristate "Palm LifeDrive PATA support"
+       depends on MACH_PALMLD
+       help
+         This option enables support for Palm LifeDrive's internal ATA
+         port via the new ATA layer.
+
+         If unsure, say N.
+
+config PATA_PCMCIA
+       tristate "PCMCIA PATA support"
+       depends on PCMCIA
+       help
+         This option enables support for PCMCIA ATA interfaces, including
+         compact flash card adapters via the new ATA layer.
+
+         If unsure, say N.
 
 config HAVE_PATA_PLATFORM
        bool
@@ -725,14 +762,6 @@ config PATA_PLATFORM
 
          If unsure, say N.
 
-config PATA_AT91
-       tristate "PATA support for AT91SAM9260"
-       depends on ARM && ARCH_AT91
-       help
-         This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
-
-         If unsure, say N.
-
 config PATA_OF_PLATFORM
        tristate "OpenFirmware platform device PATA support"
        depends on PATA_PLATFORM && PPC_OF
@@ -743,69 +772,65 @@ config PATA_OF_PLATFORM
 
          If unsure, say N.
 
-config PATA_ICSIDE
-       tristate "Acorn ICS PATA support"
-       depends on ARM && ARCH_ACORN
+config PATA_QDI
+       tristate "QDI VLB PATA support"
+       depends on ISA
        help
-         On Acorn systems, say Y here if you wish to use the ICS PATA
-         interface card.  This is not required for ICS partition support.
-         If you are unsure, say N to this.
+         Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
 
-config PATA_IXP4XX_CF
-       tristate "IXP4XX Compact Flash support"
-       depends on ARCH_IXP4XX
+config PATA_RB532
+       tristate "RouterBoard 532 PATA CompactFlash support"
+       depends on MIKROTIK_RB532
        help
-         This option enables support for a Compact Flash connected on
-         the ixp4xx expansion bus. This driver had been written for
-         Loft/Avila boards in mind but can work with others.
+         This option enables support for the RouterBoard 532
+         PATA CompactFlash controller.
 
          If unsure, say N.
 
-config PATA_OCTEON_CF
-       tristate "OCTEON Boot Bus Compact Flash support"
-       depends on CPU_CAVIUM_OCTEON
+config PATA_RZ1000
+       tristate "PC Tech RZ1000 PATA support"
+       depends on PCI
        help
-         This option enables a polled compact flash driver for use with
-         compact flash cards attached to the OCTEON boot bus.
+         This option enables basic support for the PC Tech RZ1000/1
+         PATA controllers via the new ATA layer
 
          If unsure, say N.
 
-config PATA_SCC
-       tristate "Toshiba's Cell Reference Set IDE support"
-       depends on PCI && PPC_CELLEB
+config PATA_WINBOND_VLB
+       tristate "Winbond W83759A VLB PATA support (Experimental)"
+       depends on ISA && EXPERIMENTAL
        help
-         This option enables support for the built-in IDE controller on
-         Toshiba Cell Reference Board.
+         Support for the Winbond W83759A controller on Vesa Local Bus
+         systems.
 
-         If unsure, say N.
+comment "Generic fallback / legacy drivers"
 
-config PATA_SCH
-       tristate "Intel SCH PATA support"
-       depends on PCI
+config PATA_ACPI
+       tristate "ACPI firmware driver for PATA"
+       depends on ATA_ACPI && ATA_BMDMA
        help
-         This option enables support for Intel SCH PATA on the Intel
-         SCH (US15W, US15L, UL11L) series host controllers.
-
-         If unsure, say N.
+         This option enables an ACPI method driver which drives
+         motherboard PATA controller interfaces through the ACPI
+         firmware in the BIOS. This driver can sometimes handle
+         otherwise unsupported hardware.
 
-config PATA_BF54X
-       tristate "Blackfin 54x ATAPI support"
-       depends on BF542 || BF548 || BF549
+config ATA_GENERIC
+       tristate "Generic ATA support"
+       depends on PCI && ATA_BMDMA
        help
-         This option enables support for the built-in ATAPI controller on
-         Blackfin 54x family chips.
+         This option enables support for generic BIOS configured
+         ATA controllers via the new ATA layer
 
          If unsure, say N.
 
-config PATA_MACIO
-       tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
-       depends on PPC_PMAC
+config PATA_LEGACY
+       tristate "Legacy ISA PATA support (Experimental)"
+       depends on (ISA || PCI) && EXPERIMENTAL
        help
-         Most IDE capable PowerMacs have IDE busses driven by a variant
-          of this controller which is part of the Apple chipset used on
-          most PowerMac models. Some models have multiple busses using
-          different chipsets, though generally, MacIO is one of them.
+         This option enables support for ISA/VLB/PCI bus legacy PATA
+         ports and allows them to be accessed via the new ATA layer.
 
+         If unsure, say N.
 
 endif # ATA_SFF
 endif # ATA
index d0a93c4..7ef89d7 100644 (file)
@@ -1,33 +1,39 @@
 
 obj-$(CONFIG_ATA)              += libata.o
 
+# non-SFF interface
 obj-$(CONFIG_SATA_AHCI)                += ahci.o libahci.o
 obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
-obj-$(CONFIG_SATA_SVW)         += sata_svw.o
+obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
+obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
+obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
+
+# SFF w/ custom DMA
+obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
+obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
+obj-$(CONFIG_PATA_OCTEON_CF)   += pata_octeon_cf.o
+obj-$(CONFIG_SATA_QSTOR)       += sata_qstor.o
+obj-$(CONFIG_SATA_SX4)         += sata_sx4.o
+
+# SFF SATA w/ BMDMA
 obj-$(CONFIG_ATA_PIIX)         += ata_piix.o
+obj-$(CONFIG_SATA_MV)          += sata_mv.o
+obj-$(CONFIG_SATA_NV)          += sata_nv.o
 obj-$(CONFIG_SATA_PROMISE)     += sata_promise.o
-obj-$(CONFIG_SATA_QSTOR)       += sata_qstor.o
 obj-$(CONFIG_SATA_SIL)         += sata_sil.o
-obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
-obj-$(CONFIG_SATA_VIA)         += sata_via.o
-obj-$(CONFIG_SATA_VITESSE)     += sata_vsc.o
 obj-$(CONFIG_SATA_SIS)         += sata_sis.o
-obj-$(CONFIG_SATA_SX4)         += sata_sx4.o
-obj-$(CONFIG_SATA_NV)          += sata_nv.o
+obj-$(CONFIG_SATA_SVW)         += sata_svw.o
 obj-$(CONFIG_SATA_ULI)         += sata_uli.o
-obj-$(CONFIG_SATA_MV)          += sata_mv.o
-obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
-obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
-obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
-obj-$(CONFIG_PATA_MACIO)       += pata_macio.o
+obj-$(CONFIG_SATA_VIA)         += sata_via.o
+obj-$(CONFIG_SATA_VITESSE)     += sata_vsc.o
 
+# SFF PATA w/ BMDMA
 obj-$(CONFIG_PATA_ALI)         += pata_ali.o
 obj-$(CONFIG_PATA_AMD)         += pata_amd.o
 obj-$(CONFIG_PATA_ARTOP)       += pata_artop.o
-obj-$(CONFIG_PATA_ATP867X)     += pata_atp867x.o
-obj-$(CONFIG_PATA_AT32)                += pata_at32.o
 obj-$(CONFIG_PATA_ATIIXP)      += pata_atiixp.o
-obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
+obj-$(CONFIG_PATA_ATP867X)     += pata_atp867x.o
+obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
 obj-$(CONFIG_PATA_CMD64X)      += pata_cmd64x.o
 obj-$(CONFIG_PATA_CS5520)      += pata_cs5520.o
 obj-$(CONFIG_PATA_CS5530)      += pata_cs5530.o
@@ -39,47 +45,50 @@ obj-$(CONFIG_PATA_HPT366)   += pata_hpt366.o
 obj-$(CONFIG_PATA_HPT37X)      += pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)     += pata_hpt3x2n.o
 obj-$(CONFIG_PATA_HPT3X3)      += pata_hpt3x3.o
-obj-$(CONFIG_PATA_ISAPNP)      += pata_isapnp.o
-obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
+obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
 obj-$(CONFIG_PATA_IT8213)      += pata_it8213.o
+obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
+obj-$(CONFIG_PATA_MACIO)       += pata_macio.o
+obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
 obj-$(CONFIG_PATA_NETCELL)     += pata_netcell.o
 obj-$(CONFIG_PATA_NINJA32)     += pata_ninja32.o
-obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
 obj-$(CONFIG_PATA_NS87415)     += pata_ns87415.o
-obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
-obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
-obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
-obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
-obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
 obj-$(CONFIG_PATA_OLDPIIX)     += pata_oldpiix.o
-obj-$(CONFIG_PATA_PALMLD)      += pata_palmld.o
-obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
+obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
 obj-$(CONFIG_PATA_PDC2027X)    += pata_pdc2027x.o
 obj-$(CONFIG_PATA_PDC_OLD)     += pata_pdc202xx_old.o
-obj-$(CONFIG_PATA_QDI)         += pata_qdi.o
 obj-$(CONFIG_PATA_RADISYS)     += pata_radisys.o
-obj-$(CONFIG_PATA_RB532)       += pata_rb532_cf.o
 obj-$(CONFIG_PATA_RDC)         += pata_rdc.o
-obj-$(CONFIG_PATA_RZ1000)      += pata_rz1000.o
 obj-$(CONFIG_PATA_SC1200)      += pata_sc1200.o
+obj-$(CONFIG_PATA_SCC)         += pata_scc.o
+obj-$(CONFIG_PATA_SCH)         += pata_sch.o
 obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
 obj-$(CONFIG_PATA_SIL680)      += pata_sil680.o
+obj-$(CONFIG_PATA_SIS)         += pata_sis.o
 obj-$(CONFIG_PATA_TOSHIBA)     += pata_piccolo.o
+obj-$(CONFIG_PATA_TRIFLEX)     += pata_triflex.o
 obj-$(CONFIG_PATA_VIA)         += pata_via.o
 obj-$(CONFIG_PATA_WINBOND)     += pata_sl82c105.o
-obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
-obj-$(CONFIG_PATA_SIS)         += pata_sis.o
-obj-$(CONFIG_PATA_TRIFLEX)     += pata_triflex.o
+
+# SFF PIO only
+obj-$(CONFIG_PATA_AT32)                += pata_at32.o
+obj-$(CONFIG_PATA_AT91)                += pata_at91.o
+obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
+obj-$(CONFIG_PATA_ISAPNP)      += pata_isapnp.o
 obj-$(CONFIG_PATA_IXP4XX_CF)   += pata_ixp4xx_cf.o
-obj-$(CONFIG_PATA_SCC)         += pata_scc.o
-obj-$(CONFIG_PATA_SCH)         += pata_sch.o
-obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
-obj-$(CONFIG_PATA_OCTEON_CF)   += pata_octeon_cf.o
+obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
+obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
+obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
+obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
+obj-$(CONFIG_PATA_PALMLD)      += pata_palmld.o
 obj-$(CONFIG_PATA_PLATFORM)    += pata_platform.o
-obj-$(CONFIG_PATA_AT91)        += pata_at91.o
 obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
-obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
+obj-$(CONFIG_PATA_QDI)         += pata_qdi.o
+obj-$(CONFIG_PATA_RB532)       += pata_rb532_cf.o
+obj-$(CONFIG_PATA_RZ1000)      += pata_rz1000.o
+obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
+
 # Should be last but two libata driver
 obj-$(CONFIG_PATA_ACPI)                += pata_acpi.o
 # Should be last but one libata driver
index 33fb614..573158a 100644 (file)
@@ -155,7 +155,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
                        return rc;
                pcim_pin_device(dev);
        }
-       return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &generic_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_generic[] = {
index ec52fc6..7409f98 100644 (file)
@@ -1589,7 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
                hpriv->map = piix_init_sata_map(pdev, port_info,
                                        piix_map_db_table[ent->driver_data]);
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        host->private_data = hpriv;
@@ -1626,7 +1626,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
        pci_set_master(pdev);
-       return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
+       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht);
 }
 
 static void piix_remove_one(struct pci_dev *pdev)
index c47373f..06b7e49 100644 (file)
@@ -160,6 +160,10 @@ int libata_allow_tpm = 0;
 module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
 MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands (0=off [default], 1=on)");
 
+static int atapi_an;
+module_param(atapi_an, int, 0444);
+MODULE_PARM_DESC(atapi_an, "Enable ATAPI AN media presence notification (0=0ff [default], 1=on)");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -2122,6 +2126,14 @@ retry:
                goto err_out;
        }
 
+       if (dev->horkage & ATA_HORKAGE_DUMP_ID) {
+               ata_dev_printk(dev, KERN_DEBUG, "dumping IDENTIFY data, "
+                              "class=%d may_fallback=%d tried_spinup=%d\n",
+                              class, may_fallback, tried_spinup);
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+                              16, 2, id, ATA_ID_WORDS * sizeof(*id), true);
+       }
+
        /* Falling back doesn't make sense if ID data was read
         * successfully at least once.
         */
@@ -2510,7 +2522,8 @@ int ata_dev_configure(struct ata_device *dev)
                 * to enable ATAPI AN to discern between PHY status
                 * changed notifications and ATAPI ANs.
                 */
-               if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+               if (atapi_an &&
+                   (ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
                    (!sata_pmp_attached(ap) ||
                     sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
                        unsigned int err_mask;
@@ -6372,6 +6385,7 @@ static int __init ata_parse_force_one(char **cur,
                { "3.0Gbps",    .spd_limit      = 2 },
                { "noncq",      .horkage_on     = ATA_HORKAGE_NONCQ },
                { "ncq",        .horkage_off    = ATA_HORKAGE_NONCQ },
+               { "dump_id",    .horkage_on     = ATA_HORKAGE_DUMP_ID },
                { "pio0",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 0) },
                { "pio1",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 1) },
                { "pio2",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 2) },
index 19ddf92..efa4a18 100644 (file)
@@ -63,7 +63,6 @@ const struct ata_port_operations ata_sff_port_ops = {
        .sff_tf_read            = ata_sff_tf_read,
        .sff_exec_command       = ata_sff_exec_command,
        .sff_data_xfer          = ata_sff_data_xfer,
-       .sff_irq_clear          = ata_sff_irq_clear,
        .sff_drain_fifo         = ata_sff_drain_fifo,
 
        .lost_interrupt         = ata_sff_lost_interrupt,
@@ -395,32 +394,11 @@ void ata_sff_irq_on(struct ata_port *ap)
                ata_sff_set_devctl(ap, ap->ctl);
        ata_wait_idle(ap);
 
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_irq_on);
 
-/**
- *     ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt.
- *     @ap: Port associated with this ATA transaction.
- *
- *     Clear interrupt and error flags in DMA status register.
- *
- *     May be used as the irq_clear() entry in ata_port_operations.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- */
-void ata_sff_irq_clear(struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       if (!mmio)
-               return;
-
-       iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
-}
-EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
-
 /**
  *     ata_sff_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
@@ -820,11 +798,15 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
        case ATAPI_PROT_NODATA:
                ap->hsm_task_state = HSM_ST_LAST;
                break;
+#ifdef CONFIG_ATA_BMDMA
        case ATAPI_PROT_DMA:
                ap->hsm_task_state = HSM_ST_LAST;
                /* initiate bmdma */
                ap->ops->bmdma_start(qc);
                break;
+#endif /* CONFIG_ATA_BMDMA */
+       default:
+               BUG();
        }
 }
 
@@ -1491,27 +1473,27 @@ bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
 
-/**
- *     ata_sff_host_intr - Handle host interrupt for given (port, task)
- *     @ap: Port on which interrupt arrived (possibly...)
- *     @qc: Taskfile currently active in engine
- *
- *     Handle host interrupt for given queued command.  Currently,
- *     only DMA interrupts are handled.  All other commands are
- *     handled via polling with interrupts disabled (nIEN bit).
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     One if interrupt was handled, zero if not (shared irq).
- */
-unsigned int ata_sff_host_intr(struct ata_port *ap,
-                                     struct ata_queued_cmd *qc)
+static unsigned int ata_sff_idle_irq(struct ata_port *ap)
 {
-       struct ata_eh_info *ehi = &ap->link.eh_info;
-       u8 status, host_stat = 0;
-       bool bmdma_stopped = false;
+       ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+       if ((ap->stats.idle_irq % 1000) == 0) {
+               ap->ops->sff_check_status(ap);
+               if (ap->ops->sff_irq_clear)
+                       ap->ops->sff_irq_clear(ap);
+               ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+               return 1;
+       }
+#endif
+       return 0;       /* irq not handled */
+}
+
+static unsigned int __ata_sff_port_intr(struct ata_port *ap,
+                                       struct ata_queued_cmd *qc,
+                                       bool hsmv_on_idle)
+{
+       u8 status;
 
        VPRINTK("ata%u: protocol %d task_state %d\n",
                ap->print_id, qc->tf.protocol, ap->hsm_task_state);
@@ -1528,90 +1510,56 @@ unsigned int ata_sff_host_intr(struct ata_port *ap,
                 * need to check ata_is_atapi(qc->tf.protocol) again.
                 */
                if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
-                       goto idle_irq;
-               break;
-       case HSM_ST_LAST:
-               if (qc->tf.protocol == ATA_PROT_DMA ||
-                   qc->tf.protocol == ATAPI_PROT_DMA) {
-                       /* check status of DMA engine */
-                       host_stat = ap->ops->bmdma_status(ap);
-                       VPRINTK("ata%u: host_stat 0x%X\n",
-                               ap->print_id, host_stat);
-
-                       /* if it's not our irq... */
-                       if (!(host_stat & ATA_DMA_INTR))
-                               goto idle_irq;
-
-                       /* before we do anything else, clear DMA-Start bit */
-                       ap->ops->bmdma_stop(qc);
-                       bmdma_stopped = true;
-
-                       if (unlikely(host_stat & ATA_DMA_ERR)) {
-                               /* error when transfering data to/from memory */
-                               qc->err_mask |= AC_ERR_HOST_BUS;
-                               ap->hsm_task_state = HSM_ST_ERR;
-                       }
-               }
+                       return ata_sff_idle_irq(ap);
                break;
        case HSM_ST:
+       case HSM_ST_LAST:
                break;
        default:
-               goto idle_irq;
+               return ata_sff_idle_irq(ap);
        }
 
-
        /* check main status, clearing INTRQ if needed */
        status = ata_sff_irq_status(ap);
        if (status & ATA_BUSY) {
-               if (bmdma_stopped) {
+               if (hsmv_on_idle) {
                        /* BMDMA engine is already stopped, we're screwed */
                        qc->err_mask |= AC_ERR_HSM;
                        ap->hsm_task_state = HSM_ST_ERR;
                } else
-                       goto idle_irq;
+                       return ata_sff_idle_irq(ap);
        }
 
        /* clear irq events */
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 
        ata_sff_hsm_move(ap, qc, status, 0);
 
-       if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-                                      qc->tf.protocol == ATAPI_PROT_DMA))
-               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
-
        return 1;       /* irq handled */
-
-idle_irq:
-       ap->stats.idle_irq++;
-
-#ifdef ATA_IRQ_TRAP
-       if ((ap->stats.idle_irq % 1000) == 0) {
-               ap->ops->sff_check_status(ap);
-               ap->ops->sff_irq_clear(ap);
-               ata_port_printk(ap, KERN_WARNING, "irq trap\n");
-               return 1;
-       }
-#endif
-       return 0;       /* irq not handled */
 }
-EXPORT_SYMBOL_GPL(ata_sff_host_intr);
 
 /**
- *     ata_sff_interrupt - Default ATA host interrupt handler
- *     @irq: irq line (unused)
- *     @dev_instance: pointer to our ata_host information structure
+ *     ata_sff_port_intr - Handle SFF port interrupt
+ *     @ap: Port on which interrupt arrived (possibly...)
+ *     @qc: Taskfile currently active in engine
  *
- *     Default interrupt handler for PCI IDE devices.  Calls
- *     ata_sff_host_intr() for each port that is not disabled.
+ *     Handle port interrupt for given queued command.
  *
  *     LOCKING:
- *     Obtains host lock during operation.
+ *     spin_lock_irqsave(host lock)
  *
  *     RETURNS:
- *     IRQ_NONE or IRQ_HANDLED.
+ *     One if interrupt was handled, zero if not (shared irq).
  */
-irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+unsigned int ata_sff_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       return __ata_sff_port_intr(ap, qc, false);
+}
+EXPORT_SYMBOL_GPL(ata_sff_port_intr);
+
+static inline irqreturn_t __ata_sff_interrupt(int irq, void *dev_instance,
+       unsigned int (*port_intr)(struct ata_port *, struct ata_queued_cmd *))
 {
        struct ata_host *host = dev_instance;
        bool retried = false;
@@ -1631,7 +1579,7 @@ retry:
                qc = ata_qc_from_tag(ap, ap->link.active_tag);
                if (qc) {
                        if (!(qc->tf.flags & ATA_TFLAG_POLLING))
-                               handled |= ata_sff_host_intr(ap, qc);
+                               handled |= port_intr(ap, qc);
                        else
                                polling |= 1 << i;
                } else
@@ -1658,7 +1606,8 @@ retry:
 
                        if (idle & (1 << i)) {
                                ap->ops->sff_check_status(ap);
-                               ap->ops->sff_irq_clear(ap);
+                               if (ap->ops->sff_irq_clear)
+                                       ap->ops->sff_irq_clear(ap);
                        } else {
                                /* clear INTRQ and check if BUSY cleared */
                                if (!(ap->ops->sff_check_status(ap) & ATA_BUSY))
@@ -1680,6 +1629,25 @@ retry:
 
        return IRQ_RETVAL(handled);
 }
+
+/**
+ *     ata_sff_interrupt - Default SFF ATA host interrupt handler
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host information structure
+ *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_sff_port_intr() for each port that is not disabled.
+ *
+ *     LOCKING:
+ *     Obtains host lock during operation.
+ *
+ *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+{
+       return __ata_sff_interrupt(irq, dev_instance, ata_sff_port_intr);
+}
 EXPORT_SYMBOL_GPL(ata_sff_interrupt);
 
 /**
@@ -1717,7 +1685,7 @@ void ata_sff_lost_interrupt(struct ata_port *ap)
                                                                status);
        /* Run the host interrupt logic as if the interrupt had not been
           lost */
-       ata_sff_host_intr(ap, qc);
+       ata_sff_port_intr(ap, qc);
 }
 EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
 
@@ -1744,7 +1712,8 @@ void ata_sff_freeze(struct ata_port *ap)
         */
        ap->ops->sff_check_status(ap);
 
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_freeze);
 
@@ -1761,7 +1730,8 @@ void ata_sff_thaw(struct ata_port *ap)
 {
        /* clear & re-enable interrupts */
        ap->ops->sff_check_status(ap);
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
        ata_sff_irq_on(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_thaw);
@@ -2349,13 +2319,13 @@ int ata_pci_sff_init_host(struct ata_host *host)
 EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
 
 /**
- *     ata_pci_sff_prepare_host - helper to prepare native PCI ATA host
+ *     ata_pci_sff_prepare_host - helper to prepare PCI PIO-only SFF ATA host
  *     @pdev: target PCI device
  *     @ppi: array of port_info, must be enough for two ports
  *     @r_host: out argument for the initialized ATA host
  *
- *     Helper to allocate ATA host for @pdev, acquire all native PCI
- *     resources and initialize it accordingly in one go.
+ *     Helper to allocate PIO-only SFF ATA host for @pdev, acquire
+ *     all PCI resources and initialize it accordingly in one go.
  *
  *     LOCKING:
  *     Inherited from calling layer (may sleep).
@@ -2385,9 +2355,6 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev,
        if (rc)
                goto err_out;
 
-       /* init DMA related stuff */
-       ata_pci_bmdma_init(host);
-
        devres_remove_group(&pdev->dev, NULL);
        *r_host = host;
        return 0;
@@ -2492,8 +2459,21 @@ out:
 }
 EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
 
+static const struct ata_port_info *ata_sff_find_valid_pi(
+                                       const struct ata_port_info * const *ppi)
+{
+       int i;
+
+       /* look up the first valid port_info */
+       for (i = 0; i < 2 && ppi[i]; i++)
+               if (ppi[i]->port_ops != &ata_dummy_port_ops)
+                       return ppi[i];
+
+       return NULL;
+}
+
 /**
- *     ata_pci_sff_init_one - Initialize/register PCI IDE host controller
+ *     ata_pci_sff_init_one - Initialize/register PIO-only PCI IDE controller
  *     @pdev: Controller to be initialized
  *     @ppi: array of port_info, must be enough for two ports
  *     @sht: scsi_host_template to use when registering the host
@@ -2502,11 +2482,7 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
  *
  *     This is a helper function which can be called from a driver's
  *     xxx_init_one() probe function if the hardware uses traditional
- *     IDE taskfile registers.
- *
- *     This function calls pci_enable_device(), reserves its register
- *     regions, sets the dma mask, enables bus master mode, and calls
- *     ata_device_add()
+ *     IDE taskfile registers and is PIO only.
  *
  *     ASSUMPTION:
  *     Nobody makes a single channel controller that appears solely as
@@ -2523,20 +2499,13 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
                 struct scsi_host_template *sht, void *host_priv, int hflag)
 {
        struct device *dev = &pdev->dev;
-       const struct ata_port_info *pi = NULL;
+       const struct ata_port_info *pi;
        struct ata_host *host = NULL;
-       int i, rc;
+       int rc;
 
        DPRINTK("ENTER\n");
 
-       /* look up the first valid port_info */
-       for (i = 0; i < 2 && ppi[i]; i++) {
-               if (ppi[i]->port_ops != &ata_dummy_port_ops) {
-                       pi = ppi[i];
-                       break;
-               }
-       }
-
+       pi = ata_sff_find_valid_pi(ppi);
        if (!pi) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "no valid port_info specified\n");
@@ -2557,7 +2526,6 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
        host->private_data = host_priv;
        host->flags |= hflag;
 
-       pci_set_master(pdev);
        rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
 out:
        if (rc == 0)
@@ -2571,6 +2539,12 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
 
 #endif /* CONFIG_PCI */
 
+/*
+ *     BMDMA support
+ */
+
+#ifdef CONFIG_ATA_BMDMA
+
 const struct ata_port_operations ata_bmdma_port_ops = {
        .inherits               = &ata_sff_port_ops,
 
@@ -2580,6 +2554,7 @@ const struct ata_port_operations ata_bmdma_port_ops = {
        .qc_prep                = ata_bmdma_qc_prep,
        .qc_issue               = ata_bmdma_qc_issue,
 
+       .sff_irq_clear          = ata_bmdma_irq_clear,
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
@@ -2803,6 +2778,75 @@ unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_qc_issue);
 
+/**
+ *     ata_bmdma_port_intr - Handle BMDMA port interrupt
+ *     @ap: Port on which interrupt arrived (possibly...)
+ *     @qc: Taskfile currently active in engine
+ *
+ *     Handle port interrupt for given queued command.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     One if interrupt was handled, zero if not (shared irq).
+ */
+unsigned int ata_bmdma_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u8 host_stat = 0;
+       bool bmdma_stopped = false;
+       unsigned int handled;
+
+       if (ap->hsm_task_state == HSM_ST_LAST && ata_is_dma(qc->tf.protocol)) {
+               /* check status of DMA engine */
+               host_stat = ap->ops->bmdma_status(ap);
+               VPRINTK("ata%u: host_stat 0x%X\n", ap->print_id, host_stat);
+
+               /* if it's not our irq... */
+               if (!(host_stat & ATA_DMA_INTR))
+                       return ata_sff_idle_irq(ap);
+
+               /* before we do anything else, clear DMA-Start bit */
+               ap->ops->bmdma_stop(qc);
+               bmdma_stopped = true;
+
+               if (unlikely(host_stat & ATA_DMA_ERR)) {
+                       /* error when transfering data to/from memory */
+                       qc->err_mask |= AC_ERR_HOST_BUS;
+                       ap->hsm_task_state = HSM_ST_ERR;
+               }
+       }
+
+       handled = __ata_sff_port_intr(ap, qc, bmdma_stopped);
+
+       if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
+               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+       return handled;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_port_intr);
+
+/**
+ *     ata_bmdma_interrupt - Default BMDMA ATA host interrupt handler
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host information structure
+ *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_bmdma_port_intr() for each port that is not disabled.
+ *
+ *     LOCKING:
+ *     Obtains host lock during operation.
+ *
+ *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance)
+{
+       return __ata_sff_interrupt(irq, dev_instance, ata_bmdma_port_intr);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_interrupt);
+
 /**
  *     ata_bmdma_error_handler - Stock error handler for BMDMA controller
  *     @ap: port to handle error for
@@ -2848,7 +2892,8 @@ void ata_bmdma_error_handler(struct ata_port *ap)
                /* if we're gonna thaw, make sure IRQ is clear */
                if (thaw) {
                        ap->ops->sff_check_status(ap);
-                       ap->ops->sff_irq_clear(ap);
+                       if (ap->ops->sff_irq_clear)
+                               ap->ops->sff_irq_clear(ap);
                }
        }
 
@@ -2881,6 +2926,28 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
 
+/**
+ *     ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clear interrupt and error flags in DMA status register.
+ *
+ *     May be used as the irq_clear() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_irq_clear(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+       if (!mmio)
+               return;
+
+       iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+
 /**
  *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
  *     @qc: Info associated with this ATA transaction.
@@ -3137,7 +3204,100 @@ void ata_pci_bmdma_init(struct ata_host *host)
 }
 EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
 
+/**
+ *     ata_pci_bmdma_prepare_host - helper to prepare PCI BMDMA ATA host
+ *     @pdev: target PCI device
+ *     @ppi: array of port_info, must be enough for two ports
+ *     @r_host: out argument for the initialized ATA host
+ *
+ *     Helper to allocate BMDMA ATA host for @pdev, acquire all PCI
+ *     resources and initialize it accordingly in one go.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_bmdma_prepare_host(struct pci_dev *pdev,
+                              const struct ata_port_info * const * ppi,
+                              struct ata_host **r_host)
+{
+       int rc;
+
+       rc = ata_pci_sff_prepare_host(pdev, ppi, r_host);
+       if (rc)
+               return rc;
+
+       ata_pci_bmdma_init(*r_host);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_prepare_host);
+
+/**
+ *     ata_pci_bmdma_init_one - Initialize/register BMDMA PCI IDE controller
+ *     @pdev: Controller to be initialized
+ *     @ppi: array of port_info, must be enough for two ports
+ *     @sht: scsi_host_template to use when registering the host
+ *     @host_priv: host private_data
+ *     @hflags: host flags
+ *
+ *     This function is similar to ata_pci_sff_init_one() but also
+ *     takes care of BMDMA initialization.
+ *
+ *     LOCKING:
+ *     Inherited from PCI layer (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, negative on errno-based value on error.
+ */
+int ata_pci_bmdma_init_one(struct pci_dev *pdev,
+                          const struct ata_port_info * const * ppi,
+                          struct scsi_host_template *sht, void *host_priv,
+                          int hflags)
+{
+       struct device *dev = &pdev->dev;
+       const struct ata_port_info *pi;
+       struct ata_host *host = NULL;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       pi = ata_sff_find_valid_pi(ppi);
+       if (!pi) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "no valid port_info specified\n");
+               return -EINVAL;
+       }
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               goto out;
+
+       /* prepare and activate BMDMA host */
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
+       if (rc)
+               goto out;
+       host->private_data = host_priv;
+       host->flags |= hflags;
+
+       pci_set_master(pdev);
+       rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(&pdev->dev, NULL);
+       else
+               devres_release_group(&pdev->dev, NULL);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_init_one);
+
 #endif /* CONFIG_PCI */
+#endif /* CONFIG_ATA_BMDMA */
 
 /**
  *     ata_sff_port_init - Initialize SFF/BMDMA ATA port
index 066b9f3..c8d4703 100644 (file)
@@ -260,7 +260,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
                        return rc;
                pcim_pin_device(pdev);
        }
-       return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
 }
 
 static const struct pci_device_id pacpi_pci_tbl[] = {
index f306e10..794ec6e 100644 (file)
@@ -583,7 +583,10 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                        ppi[0] = &info_20_udma;
        }
 
-       return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
+       if (!ppi[0]->mwdma_mask && !ppi[0]->udma_mask)
+               return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
+       else
+               return ata_pci_bmdma_init_one(pdev, ppi, &ali_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index d95eca9..620a07c 100644 (file)
@@ -574,7 +574,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* And fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &amd_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index 4d066d6..ba43f0f 100644 (file)
@@ -421,7 +421,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
 
        BUG_ON(ppi[0] == NULL);
 
-       return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &artop_sht, NULL, 0);
 }
 
 static const struct pci_device_id artop_pci_tbl[] = {
index 44d88b3..4375561 100644 (file)
@@ -246,8 +246,8 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (!pci_test_config_bits(pdev, &atiixp_enable_bits[i]))
                        ppi[i] = &ata_dummy_port_info;
 
-       return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL,
-                                               ATA_HOST_PARALLEL_SCAN);
+       return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
+                                     ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id atiixp[] = {
index bb6e074..9529593 100644 (file)
@@ -525,7 +525,7 @@ static int atp867x_init_one(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       rc = ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       rc = ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                IRQF_SHARED, &atp867x_sht);
        if (rc)
                dev_printk(KERN_ERR, &pdev->dev, "failed to activate host\n");
index 6422cfd..9cae65d 100644 (file)
@@ -1214,7 +1214,7 @@ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
  *     bfin_irq_clear - Clear ATAPI interrupt.
  *     @ap: Port associated with this ATA transaction.
  *
- *     Note: Original code is ata_sff_irq_clear().
+ *     Note: Original code is ata_bmdma_irq_clear().
  */
 
 static void bfin_irq_clear(struct ata_port *ap)
index 4c81a71..9f5da1c 100644 (file)
@@ -367,7 +367,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
 #endif
 
-       return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 17c5f34..030952f 100644 (file)
@@ -221,7 +221,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
                        continue;
 
                rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
-                                     ata_sff_interrupt, 0, DRV_NAME, host);
+                                     ata_bmdma_interrupt, 0, DRV_NAME, host);
                if (rc)
                        return rc;
 
index e809a42..f792330 100644 (file)
@@ -324,7 +324,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ppi[1] = &info_palmax_secondary;
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index a02e645..03a9318 100644 (file)
@@ -198,7 +198,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        rdmsr(ATAC_CH0D1_PIO, timings, dummy);
        if (CS5535_BAD_PIO(timings))
                wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
-       return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &cs5535_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5535[] = {
index 914ae35..21ee23f 100644 (file)
@@ -260,7 +260,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                return -ENODEV;
        }
 
-       return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &cs5536_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5536[] = {
index 0fcc096..6d915b0 100644 (file)
@@ -138,7 +138,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
        if (PCI_FUNC(pdev->devfn) != 1)
                return -ENODEV;
 
-       return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
 }
 
 static const struct pci_device_id cy82c693[] = {
index 3bac0e0..a088347 100644 (file)
@@ -277,8 +277,8 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL,
-                                       ATA_HOST_PARALLEL_SCAN);
+       return ata_pci_bmdma_init_one(pdev, ppi, &efar_sht, NULL,
+                                     ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id efar_pci_tbl[] = {
index 8580eb3..7688868 100644 (file)
@@ -361,7 +361,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        break;
        }
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index 98b498b..9ae4c08 100644 (file)
@@ -987,7 +987,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
 }
 
 static const struct pci_device_id hpt37x[] = {
index 8b95aeb..32f3463 100644 (file)
@@ -548,7 +548,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
 }
 
 static const struct pci_device_id hpt3x2n[] = {
index 727a81c..b63d5e2 100644 (file)
@@ -248,7 +248,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
        }
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &hpt3x3_sht);
 }
 
index b56e8f7..9f2889f 100644 (file)
@@ -470,7 +470,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
                pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
        }
 
-       return ata_host_activate(host, ec->irq, ata_sff_interrupt, 0,
+       return ata_host_activate(host, ec->irq, ata_bmdma_interrupt, 0,
                                 &pata_icside_sht);
 }
 
index f971f0d..4d142a2 100644 (file)
@@ -273,7 +273,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &it8213_sht, NULL, 0);
 }
 
 static const struct pci_device_id it8213_pci_tbl[] = {
index 2bd2b00..bf88f71 100644 (file)
@@ -933,7 +933,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                else
                        ppi[0] = &info_smart;
        }
-       return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &it821x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 565e01e..cb3babb 100644 (file)
@@ -144,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
index b5b48e7..76640ac 100644 (file)
@@ -1110,7 +1110,7 @@ static int __devinit pata_macio_common_init(struct pata_macio_priv        *priv,
 
        /* Start it up */
        priv->irq = irq;
-       return ata_host_activate(priv->host, irq, ata_sff_interrupt, 0,
+       return ata_host_activate(priv->host, irq, ata_bmdma_interrupt, 0,
                                 &pata_macio_sht);
 }
 
index e8ca02e..dd38083 100644 (file)
@@ -153,7 +153,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
                return -ENODEV;
        }
 #endif
-       return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &marvell_sht, NULL, 0);
 }
 
 static const struct pci_device_id marvell_pci_tbl[] = {
index 36afe2c..f087ab5 100644 (file)
@@ -659,7 +659,7 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
        ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
 
        /* activate host */
-       return ata_host_activate(host, priv->ata_irq, ata_sff_interrupt, 0,
+       return ata_host_activate(host, priv->ata_irq, ata_bmdma_interrupt, 0,
                                 &mpc52xx_ata_sht);
 }
 
index 94f979a..3eb921c 100644 (file)
@@ -82,7 +82,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        ata_pci_bmdma_clear_simplex(pdev);
 
        /* And let the library code do the work */
-       return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, port_info, &netcell_sht, NULL, 0);
 }
 
 static const struct pci_device_id netcell_pci_tbl[] = {
index dd53a66..cc50bd0 100644 (file)
@@ -149,7 +149,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        ninja32_program(base);
        /* FIXME: Should we disable them at remove ? */
-       return ata_host_activate(host, dev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, dev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &ninja32_sht);
 }
 
index fdbba2d..605f198 100644 (file)
@@ -380,7 +380,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        ns87415_fixup(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
 }
 
 static const struct pci_device_id ns87415_pci_tbl[] = {
index 3001109..06ddd91 100644 (file)
@@ -749,20 +749,6 @@ static void octeon_cf_dev_config(struct ata_device *dev)
        dev->max_sectors = min(dev->max_sectors, 4095U);
 }
 
-/*
- * Trap if driver tries to do standard bmdma commands.  They are not
- * supported.
- */
-static void unreachable_qc(struct ata_queued_cmd *qc)
-{
-       BUG();
-}
-
-static u8 unreachable_port(struct ata_port *ap)
-{
-       BUG();
-}
-
 /*
  * We don't do ATAPI DMA so return 0.
  */
@@ -804,10 +790,6 @@ static struct ata_port_operations octeon_cf_ops = {
        .sff_dev_select         = octeon_cf_dev_select,
        .sff_irq_on             = octeon_cf_irq_on,
        .sff_irq_clear          = octeon_cf_irq_clear,
-       .bmdma_setup            = unreachable_qc,
-       .bmdma_start            = unreachable_qc,
-       .bmdma_stop             = unreachable_qc,
-       .bmdma_status           = unreachable_port,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = octeon_cf_set_piomode,
        .set_dmamode            = octeon_cf_set_dmamode,
index 988ef26..b811c16 100644 (file)
@@ -248,7 +248,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
 }
 
 static const struct pci_device_id oldpiix_pci_tbl[] = {
index 76b7d12..0852cd0 100644 (file)
@@ -429,7 +429,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (optiplus_with_udma(dev))
                ppi[0] = &info_82c700_udma;
 
-       return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &optidma_sht, NULL, 0);
 }
 
 static const struct pci_device_id optidma[] = {
index 09f1f22..b183511 100644 (file)
@@ -754,7 +754,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
                return -EIO;
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &pdc2027x_sht);
 }
 
index fa1e2f3..c39f213 100644 (file)
@@ -337,7 +337,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
                                return -ENODEV;
                }
        }
-       return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
 }
 
 static const struct pci_device_id pdc202xx[] = {
index 9816154..cb01bf9 100644 (file)
@@ -95,7 +95,7 @@ static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id
        };
        const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
        /* Just one port for the moment */
-       return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &tosh_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_tosh[] = {
index a5fa388..8574b31 100644 (file)
@@ -227,7 +227,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &radisys_sht, NULL, 0);
 }
 
 static const struct pci_device_id radisys_pci_tbl[] = {
index 37092cf..5fbe9b1 100644 (file)
@@ -344,7 +344,7 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
         */
        pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg);
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        host->private_data = hpriv;
@@ -354,7 +354,7 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
        pci_set_master(pdev);
-       return ata_pci_sff_activate_host(host, ata_sff_interrupt, &rdc_sht);
+       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &rdc_sht);
 }
 
 static void rdc_remove_one(struct pci_dev *pdev)
index 6b5b63a..e2c1825 100644 (file)
@@ -237,7 +237,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &sc1200_sht, NULL, 0);
 }
 
 static const struct pci_device_id sc1200[] = {
index 6f6193b..d9db3f8 100644 (file)
@@ -875,7 +875,7 @@ static void scc_postreset(struct ata_link *link, unsigned int *classes)
  *     scc_irq_clear - Clear PCI IDE BMDMA interrupt.
  *     @ap: Port associated with this ATA transaction.
  *
- *     Note: Original code is ata_sff_irq_clear().
+ *     Note: Original code is ata_bmdma_irq_clear().
  */
 
 static void scc_irq_clear (struct ata_port *ap)
@@ -1105,7 +1105,7 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &scc_sht);
 }
 
index 86b3d01..e97b32f 100644 (file)
@@ -179,7 +179,7 @@ static int __devinit sch_init_one(struct pci_dev *pdev,
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &sch_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0);
 }
 
 static int __init sch_init(void)
index 43ea389..86dd714 100644 (file)
@@ -460,7 +460,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
        if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
                ata_pci_bmdma_clear_simplex(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 43faf10..d3190d7 100644 (file)
@@ -374,11 +374,11 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
        ata_sff_std_ports(&host->ports[1]->ioaddr);
 
        /* Register & activate */
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &sil680_sht);
 
 use_ioports:
-       return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index b670803..60cea13 100644 (file)
@@ -826,7 +826,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        sis_fixup(pdev, chipset);
 
-       return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sis_sht, chipset, 0);
 }
 
 #ifdef CONFIG_PM
index 733b042..98548f6 100644 (file)
@@ -316,7 +316,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
        val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
        pci_write_config_dword(dev, 0x40, val);
 
-       return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
 }
 
 static const struct pci_device_id sl82c105[] = {
index 48f5060..0d1f89e 100644 (file)
@@ -201,7 +201,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
 }
 
 static const struct pci_device_id triflex[] = {
index 7e3e0a5..5e65988 100644 (file)
@@ -627,7 +627,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* We have established the device type, now fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &via_sht, (void *)config, 0);
 }
 
 #ifdef CONFIG_PM
index f3471bc..a476cd9 100644 (file)
@@ -675,8 +675,6 @@ static struct ata_port_operations mv5_ops = {
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
        .hardreset              = mv_hardreset,
-       .error_handler          = ata_std_error_handler, /* avoid SFF EH */
-       .post_internal_cmd      = ATA_OP_NULL,
 
        .scr_read               = mv5_scr_read,
        .scr_write              = mv5_scr_write,
@@ -2813,7 +2811,7 @@ static void mv_port_intr(struct ata_port *ap, u32 port_cause)
        } else if (!edma_was_enabled) {
                struct ata_queued_cmd *qc = mv_get_active_qc(ap);
                if (qc)
-                       ata_sff_host_intr(ap, qc);
+                       ata_bmdma_port_intr(ap, qc);
                else
                        mv_unexpected_intr(ap, edma_was_enabled);
        }
index baa8f0d..6fd1147 100644 (file)
@@ -920,7 +920,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
        }
 
        /* handle interrupt */
-       return ata_sff_host_intr(ap, qc);
+       return ata_bmdma_port_intr(ap, qc);
 }
 
 static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -1100,7 +1100,7 @@ static void nv_adma_irq_clear(struct ata_port *ap)
        u32 notifier_clears[2];
 
        if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
-               ata_sff_irq_clear(ap);
+               ata_bmdma_irq_clear(ap);
                return;
        }
 
@@ -1505,7 +1505,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
 
                qc = ata_qc_from_tag(ap, ap->link.active_tag);
                if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-                       handled += ata_sff_host_intr(ap, qc);
+                       handled += ata_bmdma_port_intr(ap, qc);
                } else {
                        /*
                         * No request pending?  Clear interrupt status
@@ -2430,7 +2430,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        ppi[0] = &nv_port_info[type];
        ipriv = ppi[0]->private_data;
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
 
index d533b3d..daeebf1 100644 (file)
@@ -120,8 +120,6 @@ static void qs_host_stop(struct ata_host *host);
 static void qs_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
-static void qs_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 qs_bmdma_status(struct ata_port *ap);
 static void qs_freeze(struct ata_port *ap);
 static void qs_thaw(struct ata_port *ap);
 static int qs_prereset(struct ata_link *link, unsigned long deadline);
@@ -137,8 +135,6 @@ static struct ata_port_operations qs_ata_ops = {
        .inherits               = &ata_sff_port_ops,
 
        .check_atapi_dma        = qs_check_atapi_dma,
-       .bmdma_stop             = qs_bmdma_stop,
-       .bmdma_status           = qs_bmdma_status,
        .qc_prep                = qs_qc_prep,
        .qc_issue               = qs_qc_issue,
 
@@ -190,16 +186,6 @@ static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
        return 1;       /* ATAPI DMA not supported */
 }
 
-static void qs_bmdma_stop(struct ata_queued_cmd *qc)
-{
-       /* nothing */
-}
-
-static u8 qs_bmdma_status(struct ata_port *ap)
-{
-       return 0;
-}
-
 static inline void qs_enter_reg_mode(struct ata_port *ap)
 {
        u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
@@ -454,7 +440,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
                if (!pp || pp->state != qs_state_mmio)
                        continue;
                if (!(qc->tf.flags & ATA_TFLAG_POLLING))
-                       handled |= ata_sff_host_intr(ap, qc);
+                       handled |= ata_sff_port_intr(ap, qc);
        }
        return handled;
 }
index 2dda312..3a4f842 100644 (file)
@@ -503,7 +503,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                goto err_hsm;
 
        /* ack bmdma irq events */
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 
        /* kick HSM in the ass */
        ata_sff_hsm_move(ap, qc, status, 0);
@@ -584,7 +584,7 @@ static void sil_thaw(struct ata_port *ap)
 
        /* clear IRQ */
        ap->ops->sff_check_status(ap);
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 
        /* turn on SATA IRQ if supported */
        if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
index f8a91bf..2bfe3ae 100644 (file)
@@ -279,7 +279,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
 
@@ -308,7 +308,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &sis_sht);
 }
 
index 101fd6a..7d9db4a 100644 (file)
@@ -502,7 +502,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
        writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &k2_sata_sht);
 }
 
index d8dac17..b8578c3 100644 (file)
@@ -242,7 +242,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &uli_sht);
 }
 
index 08f6549..101d8c2 100644 (file)
@@ -308,7 +308,7 @@ static void svia_noop_freeze(struct ata_port *ap)
         * certain way.  Leave it alone and just clear pending IRQ.
         */
        ap->ops->sff_check_status(ap);
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 }
 
 /**
@@ -463,7 +463,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        struct ata_host *host;
        int rc;
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        *r_host = host;
@@ -520,7 +520,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        struct ata_host *host;
        int i, rc;
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        *r_host = host;
@@ -628,7 +628,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        svia_configure(pdev);
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &svia_sht);
 }
 
index 2107952..b777176 100644 (file)
@@ -245,7 +245,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
 
        qc = ata_qc_from_tag(ap, ap->link.active_tag);
        if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
-               handled = ata_sff_host_intr(ap, qc);
+               handled = ata_bmdma_port_intr(ap, qc);
 
        /* We received an interrupt during a polled command,
         * or some other spurious condition.  Interrupt reporting
index 606048b..85c004a 100644 (file)
@@ -305,8 +305,7 @@ static int ps3flash_flush(struct file *file, fl_owner_t id)
        return ps3flash_writeback(ps3flash_dev);
 }
 
-static int ps3flash_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int ps3flash_fsync(struct file *file, int datasync)
 {
        return ps3flash_writeback(ps3flash_dev);
 }
index 12fdd39..1994885 100644 (file)
@@ -156,7 +156,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 
        if (dev->enabled)
                return 0;
-       if (!cpuidle_curr_driver || !cpuidle_curr_governor)
+       if (!cpuidle_get_driver() || !cpuidle_curr_governor)
                return -EIO;
        if (!dev->state_count)
                return -EINVAL;
@@ -207,7 +207,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 {
        if (!dev->enabled)
                return;
-       if (!cpuidle_curr_driver || !cpuidle_curr_governor)
+       if (!cpuidle_get_driver() || !cpuidle_curr_governor)
                return;
 
        dev->enabled = 0;
@@ -271,10 +271,11 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 {
        int ret;
        struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        if (!sys_dev)
                return -EINVAL;
-       if (!try_module_get(cpuidle_curr_driver->owner))
+       if (!try_module_get(cpuidle_driver->owner))
                return -EINVAL;
 
        init_completion(&dev->kobj_unregister);
@@ -284,7 +285,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
        if ((ret = cpuidle_add_sysfs(sys_dev))) {
-               module_put(cpuidle_curr_driver->owner);
+               module_put(cpuidle_driver->owner);
                return ret;
        }
 
@@ -325,6 +326,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
 void cpuidle_unregister_device(struct cpuidle_device *dev)
 {
        struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        if (dev->registered == 0)
                return;
@@ -340,7 +342,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
 
        cpuidle_resume_and_unlock();
 
-       module_put(cpuidle_curr_driver->owner);
+       module_put(cpuidle_driver->owner);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
index 9476ba3..33e50d5 100644 (file)
@@ -9,7 +9,6 @@
 
 /* For internal use only */
 extern struct cpuidle_governor *cpuidle_curr_governor;
-extern struct cpuidle_driver *cpuidle_curr_driver;
 extern struct list_head cpuidle_governors;
 extern struct list_head cpuidle_detected_devices;
 extern struct mutex cpuidle_lock;
index 2257004..fd1601e 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "cpuidle.h"
 
-struct cpuidle_driver *cpuidle_curr_driver;
+static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
 
 /**
@@ -39,14 +39,26 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
 
 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 
+/**
+ * cpuidle_get_driver - return the current driver
+ */
+struct cpuidle_driver *cpuidle_get_driver(void)
+{
+       return cpuidle_curr_driver;
+}
+EXPORT_SYMBOL_GPL(cpuidle_get_driver);
+
 /**
  * cpuidle_unregister_driver - unregisters a driver
  * @drv: the driver
  */
 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 {
-       if (!drv)
+       if (drv != cpuidle_curr_driver) {
+               WARN(1, "invalid cpuidle_unregister_driver(%s)\n",
+                       drv->name);
                return;
+       }
 
        spin_lock(&cpuidle_driver_lock);
        cpuidle_curr_driver = NULL;
index 0ba9c8b..0310ffa 100644 (file)
@@ -47,10 +47,11 @@ static ssize_t show_current_driver(struct sysdev_class *class,
                                   char *buf)
 {
        ssize_t ret;
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        spin_lock(&cpuidle_driver_lock);
-       if (cpuidle_curr_driver)
-               ret = sprintf(buf, "%s\n", cpuidle_curr_driver->name);
+       if (cpuidle_driver)
+               ret = sprintf(buf, "%s\n", cpuidle_driver->name);
        else
                ret = sprintf(buf, "none\n");
        spin_unlock(&cpuidle_driver_lock);
index 1b88779..9e01e96 100644 (file)
@@ -166,6 +166,15 @@ config TIMB_DMA
 config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
        bool
 
+config PL330_DMA
+       tristate "DMA API Driver for PL330"
+       select DMA_ENGINE
+       depends on PL330
+       help
+         Select if your platform has one or more PL330 DMACs.
+         You need to provide platform specific settings via
+         platform_data for a dma-pl330 device.
+
 config DMA_ENGINE
        bool
 
index 2088142..0fe5ebb 100644 (file)
@@ -22,3 +22,4 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
 obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
+obj-$(CONFIG_PL330_DMA) += pl330.o
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
new file mode 100644 (file)
index 0000000..7c50f6d
--- /dev/null
@@ -0,0 +1,866 @@
+/* linux/drivers/dma/pl330.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
+
+#define NR_DEFAULT_DESC        16
+
+enum desc_status {
+       /* In the DMAC pool */
+       FREE,
+       /*
+        * Allocted to some channel during prep_xxx
+        * Also may be sitting on the work_list.
+        */
+       PREP,
+       /*
+        * Sitting on the work_list and already submitted
+        * to the PL330 core. Not more than two descriptors
+        * of a channel can be BUSY at any time.
+        */
+       BUSY,
+       /*
+        * Sitting on the channel work_list but xfer done
+        * by PL330 core
+        */
+       DONE,
+};
+
+struct dma_pl330_chan {
+       /* Schedule desc completion */
+       struct tasklet_struct task;
+
+       /* DMA-Engine Channel */
+       struct dma_chan chan;
+
+       /* Last completed cookie */
+       dma_cookie_t completed;
+
+       /* List of to be xfered descriptors */
+       struct list_head work_list;
+
+       /* Pointer to the DMAC that manages this channel,
+        * NULL if the channel is available to be acquired.
+        * As the parent, this DMAC also provides descriptors
+        * to the channel.
+        */
+       struct dma_pl330_dmac *dmac;
+
+       /* To protect channel manipulation */
+       spinlock_t lock;
+
+       /* Token of a hardware channel thread of PL330 DMAC
+        * NULL if the channel is available to be acquired.
+        */
+       void *pl330_chid;
+};
+
+struct dma_pl330_dmac {
+       struct pl330_info pif;
+
+       /* DMA-Engine Device */
+       struct dma_device ddma;
+
+       /* Pool of descriptors available for the DMAC's channels */
+       struct list_head desc_pool;
+       /* To protect desc_pool manipulation */
+       spinlock_t pool_lock;
+
+       /* Peripheral channels connected to this DMAC */
+       struct dma_pl330_chan peripherals[0]; /* keep at end */
+};
+
+struct dma_pl330_desc {
+       /* To attach to a queue as child */
+       struct list_head node;
+
+       /* Descriptor for the DMA Engine API */
+       struct dma_async_tx_descriptor txd;
+
+       /* Xfer for PL330 core */
+       struct pl330_xfer px;
+
+       struct pl330_reqcfg rqcfg;
+       struct pl330_req req;
+
+       enum desc_status status;
+
+       /* The channel which currently holds this desc */
+       struct dma_pl330_chan *pchan;
+};
+
+static inline struct dma_pl330_chan *
+to_pchan(struct dma_chan *ch)
+{
+       if (!ch)
+               return NULL;
+
+       return container_of(ch, struct dma_pl330_chan, chan);
+}
+
+static inline struct dma_pl330_desc *
+to_desc(struct dma_async_tx_descriptor *tx)
+{
+       return container_of(tx, struct dma_pl330_desc, txd);
+}
+
+static inline void free_desc_list(struct list_head *list)
+{
+       struct dma_pl330_dmac *pdmac;
+       struct dma_pl330_desc *desc;
+       struct dma_pl330_chan *pch;
+       unsigned long flags;
+
+       if (list_empty(list))
+               return;
+
+       /* Finish off the work list */
+       list_for_each_entry(desc, list, node) {
+               dma_async_tx_callback callback;
+               void *param;
+
+               /* All desc in a list belong to same channel */
+               pch = desc->pchan;
+               callback = desc->txd.callback;
+               param = desc->txd.callback_param;
+
+               if (callback)
+                       callback(param);
+
+               desc->pchan = NULL;
+       }
+
+       pdmac = pch->dmac;
+
+       spin_lock_irqsave(&pdmac->pool_lock, flags);
+       list_splice_tail_init(list, &pdmac->desc_pool);
+       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+}
+
+static inline void fill_queue(struct dma_pl330_chan *pch)
+{
+       struct dma_pl330_desc *desc;
+       int ret;
+
+       list_for_each_entry(desc, &pch->work_list, node) {
+
+               /* If already submitted */
+               if (desc->status == BUSY)
+                       break;
+
+               ret = pl330_submit_req(pch->pl330_chid,
+                                               &desc->req);
+               if (!ret) {
+                       desc->status = BUSY;
+                       break;
+               } else if (ret == -EAGAIN) {
+                       /* QFull or DMAC Dying */
+                       break;
+               } else {
+                       /* Unacceptable request */
+                       desc->status = DONE;
+                       dev_err(pch->dmac->pif.dev, "%s:%d Bad Desc(%d)\n",
+                                       __func__, __LINE__, desc->txd.cookie);
+                       tasklet_schedule(&pch->task);
+               }
+       }
+}
+
+static void pl330_tasklet(unsigned long data)
+{
+       struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+       struct dma_pl330_desc *desc, *_dt;
+       unsigned long flags;
+       LIST_HEAD(list);
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       /* Pick up ripe tomatoes */
+       list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+               if (desc->status == DONE) {
+                       pch->completed = desc->txd.cookie;
+                       list_move_tail(&desc->node, &list);
+               }
+
+       /* Try to submit a req imm. next to the last completed cookie */
+       fill_queue(pch);
+
+       /* Make sure the PL330 Channel thread is active */
+       pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       free_desc_list(&list);
+}
+
+static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
+{
+       struct dma_pl330_desc *desc = token;
+       struct dma_pl330_chan *pch = desc->pchan;
+       unsigned long flags;
+
+       /* If desc aborted */
+       if (!pch)
+               return;
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       desc->status = DONE;
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       tasklet_schedule(&pch->task);
+}
+
+static int pl330_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_dmac *pdmac = pch->dmac;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       pch->completed = chan->cookie = 1;
+
+       pch->pl330_chid = pl330_request_channel(&pdmac->pif);
+       if (!pch->pl330_chid) {
+               spin_unlock_irqrestore(&pch->lock, flags);
+               return 0;
+       }
+
+       tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       return 1;
+}
+
+static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
+{
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_desc *desc;
+       unsigned long flags;
+
+       /* Only supports DMA_TERMINATE_ALL */
+       if (cmd != DMA_TERMINATE_ALL)
+               return -ENXIO;
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       /* FLUSH the PL330 Channel thread */
+       pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+
+       /* Mark all desc done */
+       list_for_each_entry(desc, &pch->work_list, node)
+               desc->status = DONE;
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       pl330_tasklet((unsigned long) pch);
+
+       return 0;
+}
+
+static void pl330_free_chan_resources(struct dma_chan *chan)
+{
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       tasklet_kill(&pch->task);
+
+       pl330_release_channel(pch->pl330_chid);
+       pch->pl330_chid = NULL;
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+}
+
+static enum dma_status
+pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+                struct dma_tx_state *txstate)
+{
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       dma_cookie_t last_done, last_used;
+       int ret;
+
+       last_done = pch->completed;
+       last_used = chan->cookie;
+
+       ret = dma_async_is_complete(cookie, last_done, last_used);
+
+       dma_set_tx_state(txstate, last_done, last_used, 0);
+
+       return ret;
+}
+
+static void pl330_issue_pending(struct dma_chan *chan)
+{
+       pl330_tasklet((unsigned long) to_pchan(chan));
+}
+
+/*
+ * We returned the last one of the circular list of descriptor(s)
+ * from prep_xxx, so the argument to submit corresponds to the last
+ * descriptor of the list.
+ */
+static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct dma_pl330_desc *desc, *last = to_desc(tx);
+       struct dma_pl330_chan *pch = to_pchan(tx->chan);
+       dma_cookie_t cookie;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       /* Assign cookies to all nodes */
+       cookie = tx->chan->cookie;
+
+       while (!list_empty(&last->node)) {
+               desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+
+               if (++cookie < 0)
+                       cookie = 1;
+               desc->txd.cookie = cookie;
+
+               list_move_tail(&desc->node, &pch->work_list);
+       }
+
+       if (++cookie < 0)
+               cookie = 1;
+       last->txd.cookie = cookie;
+
+       list_add_tail(&last->node, &pch->work_list);
+
+       tx->chan->cookie = cookie;
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       return cookie;
+}
+
+static inline void _init_desc(struct dma_pl330_desc *desc)
+{
+       desc->pchan = NULL;
+       desc->req.x = &desc->px;
+       desc->req.token = desc;
+       desc->rqcfg.swap = SWAP_NO;
+       desc->rqcfg.privileged = 0;
+       desc->rqcfg.insnaccess = 0;
+       desc->rqcfg.scctl = SCCTRL0;
+       desc->rqcfg.dcctl = DCCTRL0;
+       desc->req.cfg = &desc->rqcfg;
+       desc->req.xfer_cb = dma_pl330_rqcb;
+       desc->txd.tx_submit = pl330_tx_submit;
+
+       INIT_LIST_HEAD(&desc->node);
+}
+
+/* Returns the number of descriptors added to the DMAC pool */
+int add_desc(struct dma_pl330_dmac *pdmac, gfp_t flg, int count)
+{
+       struct dma_pl330_desc *desc;
+       unsigned long flags;
+       int i;
+
+       if (!pdmac)
+               return 0;
+
+       desc = kmalloc(count * sizeof(*desc), flg);
+       if (!desc)
+               return 0;
+
+       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+       for (i = 0; i < count; i++) {
+               _init_desc(&desc[i]);
+               list_add_tail(&desc[i].node, &pdmac->desc_pool);
+       }
+
+       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+       return count;
+}
+
+static struct dma_pl330_desc *
+pluck_desc(struct dma_pl330_dmac *pdmac)
+{
+       struct dma_pl330_desc *desc = NULL;
+       unsigned long flags;
+
+       if (!pdmac)
+               return NULL;
+
+       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+       if (!list_empty(&pdmac->desc_pool)) {
+               desc = list_entry(pdmac->desc_pool.next,
+                               struct dma_pl330_desc, node);
+
+               list_del_init(&desc->node);
+
+               desc->status = PREP;
+               desc->txd.callback = NULL;
+       }
+
+       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+       return desc;
+}
+
+static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
+{
+       struct dma_pl330_dmac *pdmac = pch->dmac;
+       struct dma_pl330_peri *peri = pch->chan.private;
+       struct dma_pl330_desc *desc;
+
+       /* Pluck one desc from the pool of DMAC */
+       desc = pluck_desc(pdmac);
+
+       /* If the DMAC pool is empty, alloc new */
+       if (!desc) {
+               if (!add_desc(pdmac, GFP_ATOMIC, 1))
+                       return NULL;
+
+               /* Try again */
+               desc = pluck_desc(pdmac);
+               if (!desc) {
+                       dev_err(pch->dmac->pif.dev,
+                               "%s:%d ALERT!\n", __func__, __LINE__);
+                       return NULL;
+               }
+       }
+
+       /* Initialize the descriptor */
+       desc->pchan = pch;
+       desc->txd.cookie = 0;
+       async_tx_ack(&desc->txd);
+
+       desc->req.rqtype = peri->rqtype;
+       desc->req.peri = peri->peri_id;
+
+       dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
+
+       return desc;
+}
+
+static inline void fill_px(struct pl330_xfer *px,
+               dma_addr_t dst, dma_addr_t src, size_t len)
+{
+       px->next = NULL;
+       px->bytes = len;
+       px->dst_addr = dst;
+       px->src_addr = src;
+}
+
+static struct dma_pl330_desc *
+__pl330_prep_dma_memcpy(struct dma_pl330_chan *pch, dma_addr_t dst,
+               dma_addr_t src, size_t len)
+{
+       struct dma_pl330_desc *desc = pl330_get_desc(pch);
+
+       if (!desc) {
+               dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+                       __func__, __LINE__);
+               return NULL;
+       }
+
+       /*
+        * Ideally we should lookout for reqs bigger than
+        * those that can be programmed with 256 bytes of
+        * MC buffer, but considering a req size is seldom
+        * going to be word-unaligned and more than 200MB,
+        * we take it easy.
+        * Also, should the limit is reached we'd rather
+        * have the platform increase MC buffer size than
+        * complicating this API driver.
+        */
+       fill_px(&desc->px, dst, src, len);
+
+       return desc;
+}
+
+/* Call after fixing burst size */
+static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
+{
+       struct dma_pl330_chan *pch = desc->pchan;
+       struct pl330_info *pi = &pch->dmac->pif;
+       int burst_len;
+
+       burst_len = pi->pcfg.data_bus_width / 8;
+       burst_len *= pi->pcfg.data_buf_dep;
+       burst_len >>= desc->rqcfg.brst_size;
+
+       /* src/dst_burst_len can't be more than 16 */
+       if (burst_len > 16)
+               burst_len = 16;
+
+       while (burst_len > 1) {
+               if (!(len % (burst_len << desc->rqcfg.brst_size)))
+                       break;
+               burst_len--;
+       }
+
+       return burst_len;
+}
+
+static struct dma_async_tx_descriptor *
+pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
+               dma_addr_t src, size_t len, unsigned long flags)
+{
+       struct dma_pl330_desc *desc;
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_peri *peri = chan->private;
+       struct pl330_info *pi;
+       int burst;
+
+       if (unlikely(!pch || !len || !peri))
+               return NULL;
+
+       if (peri->rqtype != MEMTOMEM)
+               return NULL;
+
+       pi = &pch->dmac->pif;
+
+       desc = __pl330_prep_dma_memcpy(pch, dst, src, len);
+       if (!desc)
+               return NULL;
+
+       desc->rqcfg.src_inc = 1;
+       desc->rqcfg.dst_inc = 1;
+
+       /* Select max possible burst size */
+       burst = pi->pcfg.data_bus_width / 8;
+
+       while (burst > 1) {
+               if (!(len % burst))
+                       break;
+               burst /= 2;
+       }
+
+       desc->rqcfg.brst_size = 0;
+       while (burst != (1 << desc->rqcfg.brst_size))
+               desc->rqcfg.brst_size++;
+
+       desc->rqcfg.brst_len = get_burst_len(desc, len);
+
+       desc->txd.flags = flags;
+
+       return &desc->txd;
+}
+
+static struct dma_async_tx_descriptor *
+pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned long flg)
+{
+       struct dma_pl330_desc *first, *desc = NULL;
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_peri *peri = chan->private;
+       struct scatterlist *sg;
+       unsigned long flags;
+       int i, burst_size;
+       dma_addr_t addr;
+
+       if (unlikely(!pch || !sgl || !sg_len))
+               return NULL;
+
+       /* Make sure the direction is consistent */
+       if ((direction == DMA_TO_DEVICE &&
+                               peri->rqtype != MEMTODEV) ||
+                       (direction == DMA_FROM_DEVICE &&
+                               peri->rqtype != DEVTOMEM)) {
+               dev_err(pch->dmac->pif.dev, "%s:%d Invalid Direction\n",
+                               __func__, __LINE__);
+               return NULL;
+       }
+
+       addr = peri->fifo_addr;
+       burst_size = peri->burst_sz;
+
+       first = NULL;
+
+       for_each_sg(sgl, sg, sg_len, i) {
+
+               desc = pl330_get_desc(pch);
+               if (!desc) {
+                       struct dma_pl330_dmac *pdmac = pch->dmac;
+
+                       dev_err(pch->dmac->pif.dev,
+                               "%s:%d Unable to fetch desc\n",
+                               __func__, __LINE__);
+                       if (!first)
+                               return NULL;
+
+                       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+                       while (!list_empty(&first->node)) {
+                               desc = list_entry(first->node.next,
+                                               struct dma_pl330_desc, node);
+                               list_move_tail(&desc->node, &pdmac->desc_pool);
+                       }
+
+                       list_move_tail(&first->node, &pdmac->desc_pool);
+
+                       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+                       return NULL;
+               }
+
+               if (!first)
+                       first = desc;
+               else
+                       list_add_tail(&desc->node, &first->node);
+
+               if (direction == DMA_TO_DEVICE) {
+                       desc->rqcfg.src_inc = 1;
+                       desc->rqcfg.dst_inc = 0;
+                       fill_px(&desc->px,
+                               addr, sg_dma_address(sg), sg_dma_len(sg));
+               } else {
+                       desc->rqcfg.src_inc = 0;
+                       desc->rqcfg.dst_inc = 1;
+                       fill_px(&desc->px,
+                               sg_dma_address(sg), addr, sg_dma_len(sg));
+               }
+
+               desc->rqcfg.brst_size = burst_size;
+               desc->rqcfg.brst_len = 1;
+       }
+
+       /* Return the last desc in the chain */
+       desc->txd.flags = flg;
+       return &desc->txd;
+}
+
+static irqreturn_t pl330_irq_handler(int irq, void *data)
+{
+       if (pl330_update(data))
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static int __devinit
+pl330_probe(struct amba_device *adev, struct amba_id *id)
+{
+       struct dma_pl330_platdata *pdat;
+       struct dma_pl330_dmac *pdmac;
+       struct dma_pl330_chan *pch;
+       struct pl330_info *pi;
+       struct dma_device *pd;
+       struct resource *res;
+       int i, ret, irq;
+
+       pdat = adev->dev.platform_data;
+
+       if (!pdat || !pdat->nr_valid_peri) {
+               dev_err(&adev->dev, "platform data missing\n");
+               return -ENODEV;
+       }
+
+       /* Allocate a new DMAC and its Channels */
+       pdmac = kzalloc(pdat->nr_valid_peri * sizeof(*pch)
+                               + sizeof(*pdmac), GFP_KERNEL);
+       if (!pdmac) {
+               dev_err(&adev->dev, "unable to allocate mem\n");
+               return -ENOMEM;
+       }
+
+       pi = &pdmac->pif;
+       pi->dev = &adev->dev;
+       pi->pl330_data = NULL;
+       pi->mcbufsz = pdat->mcbuf_sz;
+
+       res = &adev->res;
+       request_mem_region(res->start, resource_size(res), "dma-pl330");
+
+       pi->base = ioremap(res->start, resource_size(res));
+       if (!pi->base) {
+               ret = -ENXIO;
+               goto probe_err1;
+       }
+
+       irq = adev->irq[0];
+       ret = request_irq(irq, pl330_irq_handler, 0,
+                       dev_name(&adev->dev), pi);
+       if (ret)
+               goto probe_err2;
+
+       ret = pl330_add(pi);
+       if (ret)
+               goto probe_err3;
+
+       INIT_LIST_HEAD(&pdmac->desc_pool);
+       spin_lock_init(&pdmac->pool_lock);
+
+       /* Create a descriptor pool of default size */
+       if (!add_desc(pdmac, GFP_KERNEL, NR_DEFAULT_DESC))
+               dev_warn(&adev->dev, "unable to allocate desc\n");
+
+       pd = &pdmac->ddma;
+       INIT_LIST_HEAD(&pd->channels);
+
+       /* Initialize channel parameters */
+       for (i = 0; i < pdat->nr_valid_peri; i++) {
+               struct dma_pl330_peri *peri = &pdat->peri[i];
+               pch = &pdmac->peripherals[i];
+
+               switch (peri->rqtype) {
+               case MEMTOMEM:
+                       dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+                       break;
+               case MEMTODEV:
+               case DEVTOMEM:
+                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
+                       break;
+               default:
+                       dev_err(&adev->dev, "DEVTODEV Not Supported\n");
+                       continue;
+               }
+
+               INIT_LIST_HEAD(&pch->work_list);
+               spin_lock_init(&pch->lock);
+               pch->pl330_chid = NULL;
+               pch->chan.private = peri;
+               pch->chan.device = pd;
+               pch->chan.chan_id = i;
+               pch->dmac = pdmac;
+
+               /* Add the channel to the DMAC list */
+               pd->chancnt++;
+               list_add_tail(&pch->chan.device_node, &pd->channels);
+       }
+
+       pd->dev = &adev->dev;
+
+       pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
+       pd->device_free_chan_resources = pl330_free_chan_resources;
+       pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
+       pd->device_tx_status = pl330_tx_status;
+       pd->device_prep_slave_sg = pl330_prep_slave_sg;
+       pd->device_control = pl330_control;
+       pd->device_issue_pending = pl330_issue_pending;
+
+       ret = dma_async_device_register(pd);
+       if (ret) {
+               dev_err(&adev->dev, "unable to register DMAC\n");
+               goto probe_err4;
+       }
+
+       amba_set_drvdata(adev, pdmac);
+
+       dev_info(&adev->dev,
+               "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
+       dev_info(&adev->dev,
+               "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
+               pi->pcfg.data_buf_dep,
+               pi->pcfg.data_bus_width / 8, pi->pcfg.num_chan,
+               pi->pcfg.num_peri, pi->pcfg.num_events);
+
+       return 0;
+
+probe_err4:
+       pl330_del(pi);
+probe_err3:
+       free_irq(irq, pi);
+probe_err2:
+       iounmap(pi->base);
+probe_err1:
+       release_mem_region(res->start, resource_size(res));
+       kfree(pdmac);
+
+       return ret;
+}
+
+static int __devexit pl330_remove(struct amba_device *adev)
+{
+       struct dma_pl330_dmac *pdmac = amba_get_drvdata(adev);
+       struct dma_pl330_chan *pch, *_p;
+       struct pl330_info *pi;
+       struct resource *res;
+       int irq;
+
+       if (!pdmac)
+               return 0;
+
+       amba_set_drvdata(adev, NULL);
+
+       /* Idle the DMAC */
+       list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
+                       chan.device_node) {
+
+               /* Remove the channel */
+               list_del(&pch->chan.device_node);
+
+               /* Flush the channel */
+               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+               pl330_free_chan_resources(&pch->chan);
+       }
+
+       pi = &pdmac->pif;
+
+       pl330_del(pi);
+
+       irq = adev->irq[0];
+       free_irq(irq, pi);
+
+       iounmap(pi->base);
+
+       res = &adev->res;
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(pdmac);
+
+       return 0;
+}
+
+static struct amba_id pl330_ids[] = {
+       {
+               .id     = 0x00041330,
+               .mask   = 0x000fffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl330_driver = {
+       .drv = {
+               .owner = THIS_MODULE,
+               .name = "dma-pl330",
+       },
+       .id_table = pl330_ids,
+       .probe = pl330_probe,
+       .remove = pl330_remove,
+};
+
+static int __init pl330_init(void)
+{
+       return amba_driver_register(&pl330_driver);
+}
+module_init(pl330_init);
+
+static void __exit pl330_exit(void)
+{
+       amba_driver_unregister(&pl330_driver);
+       return;
+}
+module_exit(pl330_exit);
+
+MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("API Driver for PL330 DMAC");
+MODULE_LICENSE("GPL");
index cc5316d..b3ba44c 100644 (file)
@@ -900,9 +900,10 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
                        flags |= RADEON_FRONT;
        }
        if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
-               if (!dev_priv->have_z_offset)
+               if (!dev_priv->have_z_offset) {
                        printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
-               flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+                       flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+               }
        }
 
        if (flags & (RADEON_FRONT | RADEON_BACK)) {
index f15e90a..fb5c518 100644 (file)
@@ -1,3 +1,14 @@
+config INTEL_IDLE
+       tristate "Cpuidle Driver for Intel Processors"
+       depends on CPU_IDLE
+       depends on X86
+       depends on CPU_SUP_INTEL
+       depends on EXPERIMENTAL
+       help
+         Enable intel_idle, a cpuidle driver that includes knowledge of
+         native Intel hardware idle features.  The acpi_idle driver
+         can be configured at the same time, in order to handle
+         processors intel_idle does not support.
 
 menu "Memory power savings"
 depends on X86_64
index 5f68fc3..23d295c 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_I7300_IDLE)                       += i7300_idle.o
+obj-$(CONFIG_INTEL_IDLE)                       += intel_idle.o
 
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
new file mode 100755 (executable)
index 0000000..54f0fb4
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * intel_idle.c - native hardware idle loop for modern Intel processors
+ *
+ * Copyright (c) 2010, Intel Corporation.
+ * Len Brown <len.brown@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * intel_idle is a cpuidle driver that loads on specific Intel processors
+ * in lieu of the legacy ACPI processor_idle driver.  The intent is to
+ * make Linux more efficient on these processors, as intel_idle knows
+ * more than ACPI, as well as make Linux more immune to ACPI BIOS bugs.
+ */
+
+/*
+ * Design Assumptions
+ *
+ * All CPUs have same idle states as boot CPU
+ *
+ * Chipset BM_STS (bus master status) bit is a NOP
+ *     for preventing entry into deep C-stats
+ */
+
+/*
+ * Known limitations
+ *
+ * The driver currently initializes for_each_online_cpu() upon modprobe.
+ * It it unaware of subsequent processors hot-added to the system.
+ * This means that if you boot with maxcpus=n and later online
+ * processors above n, those processors will use C1 only.
+ *
+ * ACPI has a .suspend hack to turn off deep c-statees during suspend
+ * to avoid complications with the lapic timer workaround.
+ * Have not seen issues with suspend, but may need same workaround here.
+ *
+ * There is currently no kernel-based automatic probing/loading mechanism
+ * if the driver is built as a module.
+ */
+
+/* un-comment DEBUG to enable pr_debug() statements */
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/clockchips.h>
+#include <linux/hrtimer.h>     /* ktime_get_real() */
+#include <trace/events/power.h>
+#include <linux/sched.h>
+
+#define INTEL_IDLE_VERSION "0.4"
+#define PREFIX "intel_idle: "
+
+#define MWAIT_SUBSTATE_MASK    (0xf)
+#define MWAIT_CSTATE_MASK      (0xf)
+#define MWAIT_SUBSTATE_SIZE    (4)
+#define MWAIT_MAX_NUM_CSTATES  8
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
+
+static struct cpuidle_driver intel_idle_driver = {
+       .name = "intel_idle",
+       .owner = THIS_MODULE,
+};
+/* intel_idle.max_cstate=0 disables driver */
+static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
+static int power_policy = 7; /* 0 = max perf; 15 = max powersave */
+
+static unsigned int substates;
+static int (*choose_substate)(int);
+
+/* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
+static unsigned int lapic_timer_reliable_states;
+
+static struct cpuidle_device *intel_idle_cpuidle_devices;
+static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
+
+static struct cpuidle_state *cpuidle_state_table;
+
+/*
+ * States are indexed by the cstate number,
+ * which is also the index into the MWAIT hint array.
+ * Thus C0 is a dummy.
+ */
+static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
+       { /* MWAIT C0 */ },
+       { /* MWAIT C1 */
+               .name = "NHM-C1",
+               .desc = "MWAIT 0x00",
+               .driver_data = (void *) 0x00,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 3,
+               .power_usage = 1000,
+               .target_residency = 6,
+               .enter = &intel_idle },
+       { /* MWAIT C2 */
+               .name = "NHM-C3",
+               .desc = "MWAIT 0x10",
+               .driver_data = (void *) 0x10,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 20,
+               .power_usage = 500,
+               .target_residency = 80,
+               .enter = &intel_idle },
+       { /* MWAIT C3 */
+               .name = "NHM-C6",
+               .desc = "MWAIT 0x20",
+               .driver_data = (void *) 0x20,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 200,
+               .power_usage = 350,
+               .target_residency = 800,
+               .enter = &intel_idle },
+};
+
+static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
+       { /* MWAIT C0 */ },
+       { /* MWAIT C1 */
+               .name = "ATM-C1",
+               .desc = "MWAIT 0x00",
+               .driver_data = (void *) 0x00,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 1,
+               .power_usage = 1000,
+               .target_residency = 4,
+               .enter = &intel_idle },
+       { /* MWAIT C2 */
+               .name = "ATM-C2",
+               .desc = "MWAIT 0x10",
+               .driver_data = (void *) 0x10,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 20,
+               .power_usage = 500,
+               .target_residency = 80,
+               .enter = &intel_idle },
+       { /* MWAIT C3 */ },
+       { /* MWAIT C4 */
+               .name = "ATM-C4",
+               .desc = "MWAIT 0x30",
+               .driver_data = (void *) 0x30,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 100,
+               .power_usage = 250,
+               .target_residency = 400,
+               .enter = &intel_idle },
+       { /* MWAIT C5 */ },
+       { /* MWAIT C6 */
+               .name = "ATM-C6",
+               .desc = "MWAIT 0x40",
+               .driver_data = (void *) 0x40,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 200,
+               .power_usage = 150,
+               .target_residency = 800,
+               .enter = NULL },        /* disabled */
+};
+
+/*
+ * choose_tunable_substate()
+ *
+ * Run-time decision on which C-state substate to invoke
+ * If power_policy = 0, choose shallowest substate (0)
+ * If power_policy = 15, choose deepest substate
+ * If power_policy = middle, choose middle substate etc.
+ */
+static int choose_tunable_substate(int cstate)
+{
+       unsigned int num_substates;
+       unsigned int substate_choice;
+
+       power_policy &= 0xF;    /* valid range: 0-15 */
+       cstate &= 7;    /* valid range: 0-7 */
+
+       num_substates = (substates >> ((cstate) * 4)) & MWAIT_SUBSTATE_MASK;
+
+       if (num_substates <= 1)
+               return 0;
+
+       substate_choice = ((power_policy + (power_policy + 1) *
+                               (num_substates - 1)) / 16);
+
+       return substate_choice;
+}
+
+/*
+ * choose_zero_substate()
+ */
+static int choose_zero_substate(int cstate)
+{
+       return 0;
+}
+
+/**
+ * intel_idle
+ * @dev: cpuidle_device
+ * @state: cpuidle state
+ *
+ */
+static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
+{
+       unsigned long ecx = 1; /* break on interrupt flag */
+       unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
+       unsigned int cstate;
+       ktime_t kt_before, kt_after;
+       s64 usec_delta;
+       int cpu = smp_processor_id();
+
+       cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
+
+       eax = eax + (choose_substate)(cstate);
+
+       local_irq_disable();
+
+       if (!(lapic_timer_reliable_states & (1 << (cstate))))
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+       kt_before = ktime_get_real();
+
+       stop_critical_timings();
+#ifndef MODULE
+       trace_power_start(POWER_CSTATE, (eax >> 4) + 1);
+#endif
+       if (!need_resched()) {
+
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __mwait(eax, ecx);
+       }
+
+       start_critical_timings();
+
+       kt_after = ktime_get_real();
+       usec_delta = ktime_to_us(ktime_sub(kt_after, kt_before));
+
+       local_irq_enable();
+
+       if (!(lapic_timer_reliable_states & (1 << (cstate))))
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+       return usec_delta;
+}
+
+/*
+ * intel_idle_probe()
+ */
+static int intel_idle_probe(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       if (max_cstate == 0) {
+               pr_debug(PREFIX "disabled\n");
+               return -EPERM;
+       }
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return -ENODEV;
+
+       if (!boot_cpu_has(X86_FEATURE_MWAIT))
+               return -ENODEV;
+
+       if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+               return -ENODEV;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+               !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+                       return -ENODEV;
+#ifdef DEBUG
+       if (substates == 0)     /* can over-ride via modparam */
+#endif
+               substates = edx;
+
+       pr_debug(PREFIX "MWAIT substates: 0x%x\n", substates);
+
+       if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
+               lapic_timer_reliable_states = 0xFFFFFFFF;
+
+       if (boot_cpu_data.x86 != 6)     /* family 6 */
+               return -ENODEV;
+
+       switch (boot_cpu_data.x86_model) {
+
+       case 0x1A:      /* Core i7, Xeon 5500 series */
+       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+       case 0x2E:      /* Nehalem-EX Xeon */
+               lapic_timer_reliable_states = (1 << 1);  /* C1 */
+
+       case 0x25:      /* Westmere */
+       case 0x2C:      /* Westmere */
+               cpuidle_state_table = nehalem_cstates;
+               choose_substate = choose_tunable_substate;
+               break;
+
+       case 0x1C:      /* 28 - Atom Processor */
+               lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+               cpuidle_state_table = atom_cstates;
+               choose_substate = choose_zero_substate;
+               break;
+#ifdef FUTURE_USE
+       case 0x17:      /* 23 - Core 2 Duo */
+               lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+#endif
+
+       default:
+               pr_debug(PREFIX "does not run on family %d model %d\n",
+                       boot_cpu_data.x86, boot_cpu_data.x86_model);
+               return -ENODEV;
+       }
+
+       pr_debug(PREFIX "v" INTEL_IDLE_VERSION
+               " model 0x%X\n", boot_cpu_data.x86_model);
+
+       pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n",
+               lapic_timer_reliable_states);
+       return 0;
+}
+
+/*
+ * intel_idle_cpuidle_devices_uninit()
+ * unregister, free cpuidle_devices
+ */
+static void intel_idle_cpuidle_devices_uninit(void)
+{
+       int i;
+       struct cpuidle_device *dev;
+
+       for_each_online_cpu(i) {
+               dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
+               cpuidle_unregister_device(dev);
+       }
+
+       free_percpu(intel_idle_cpuidle_devices);
+       return;
+}
+/*
+ * intel_idle_cpuidle_devices_init()
+ * allocate, initialize, register cpuidle_devices
+ */
+static int intel_idle_cpuidle_devices_init(void)
+{
+       int i, cstate;
+       struct cpuidle_device *dev;
+
+       intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+       if (intel_idle_cpuidle_devices == NULL)
+               return -ENOMEM;
+
+       for_each_online_cpu(i) {
+               dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
+
+               dev->state_count = 1;
+
+               for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+                       int num_substates;
+
+                       if (cstate > max_cstate) {
+                               printk(PREFIX "max_cstate %d reached\n",
+                                       max_cstate);
+                               break;
+                       }
+
+                       /* does the state exist in CPUID.MWAIT? */
+                       num_substates = (substates >> ((cstate) * 4))
+                                               & MWAIT_SUBSTATE_MASK;
+                       if (num_substates == 0)
+                               continue;
+                       /* is the state not enabled? */
+                       if (cpuidle_state_table[cstate].enter == NULL) {
+                               /* does the driver not know about the state? */
+                               if (*cpuidle_state_table[cstate].name == '\0')
+                                       pr_debug(PREFIX "unaware of model 0x%x"
+                                               " MWAIT %d please"
+                                               " contact lenb@kernel.org",
+                                       boot_cpu_data.x86_model, cstate);
+                               continue;
+                       }
+
+                       if ((cstate > 2) &&
+                               !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+                               mark_tsc_unstable("TSC halts in idle"
+                                       " states deeper than C2");
+
+                       dev->states[dev->state_count] = /* structure copy */
+                               cpuidle_state_table[cstate];
+
+                       dev->state_count += 1;
+               }
+
+               dev->cpu = i;
+               if (cpuidle_register_device(dev)) {
+                       pr_debug(PREFIX "cpuidle_register_device %d failed!\n",
+                                i);
+                       intel_idle_cpuidle_devices_uninit();
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+
+static int __init intel_idle_init(void)
+{
+       int retval;
+
+       retval = intel_idle_probe();
+       if (retval)
+               return retval;
+
+       retval = cpuidle_register_driver(&intel_idle_driver);
+       if (retval) {
+               printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
+                       cpuidle_get_driver()->name);
+               return retval;
+       }
+
+       retval = intel_idle_cpuidle_devices_init();
+       if (retval) {
+               cpuidle_unregister_driver(&intel_idle_driver);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void __exit intel_idle_exit(void)
+{
+       intel_idle_cpuidle_devices_uninit();
+       cpuidle_unregister_driver(&intel_idle_driver);
+
+       return;
+}
+
+module_init(intel_idle_init);
+module_exit(intel_idle_exit);
+
+module_param(power_policy, int, 0644);
+module_param(max_cstate, int, 0444);
+#ifdef DEBUG
+module_param(substates, int, 0444);
+#endif
+
+MODULE_AUTHOR("Len Brown <len.brown@intel.com>");
+MODULE_DESCRIPTION("Cpuidle driver for Intel Hardware v" INTEL_IDLE_VERSION);
+MODULE_LICENSE("GPL");
index 4647484..08f948d 100644 (file)
@@ -706,14 +706,9 @@ static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len)
        if (!len)
                return 0;
 
-       data = kmalloc(len, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       if (copy_from_user(data, (void __user *)(unsigned long)src, len)) {
-               kfree(data);
-               return -EFAULT;
-       }
+       data = memdup_user((void __user *)(unsigned long)src, len);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        *dest = data;
        return 0;
index 7554704..edef852 100644 (file)
@@ -144,10 +144,11 @@ static ssize_t dev_counters_read(struct file *file, char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        u64 *counters;
+       size_t avail;
        struct qib_devdata *dd = private2dd(file);
 
-       return simple_read_from_buffer(buf, count, ppos, counters,
-               dd->f_read_cntrs(dd, *ppos, NULL, &counters));
+       avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
 }
 
 /* read the per-device counters */
@@ -155,10 +156,11 @@ static ssize_t dev_names_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos)
 {
        char *names;
+       size_t avail;
        struct qib_devdata *dd = private2dd(file);
 
-       return simple_read_from_buffer(buf, count, ppos, names,
-               dd->f_read_cntrs(dd, *ppos, &names, NULL));
+       avail = dd->f_read_cntrs(dd, *ppos, &names, NULL);
+       return simple_read_from_buffer(buf, count, ppos, names, avail);
 }
 
 static const struct file_operations cntr_ops[] = {
@@ -176,10 +178,11 @@ static ssize_t portnames_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos)
 {
        char *names;
+       size_t avail;
        struct qib_devdata *dd = private2dd(file);
 
-       return simple_read_from_buffer(buf, count, ppos, names,
-               dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL));
+       avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL);
+       return simple_read_from_buffer(buf, count, ppos, names, avail);
 }
 
 /* read the per-port counters for port 1 (pidx 0) */
@@ -187,10 +190,11 @@ static ssize_t portcntrs_1_read(struct file *file, char __user *buf,
                                size_t count, loff_t *ppos)
 {
        u64 *counters;
+       size_t avail;
        struct qib_devdata *dd = private2dd(file);
 
-       return simple_read_from_buffer(buf, count, ppos, counters,
-               dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters));
+       avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
 }
 
 /* read the per-port counters for port 2 (pidx 1) */
@@ -198,10 +202,11 @@ static ssize_t portcntrs_2_read(struct file *file, char __user *buf,
                                size_t count, loff_t *ppos)
 {
        u64 *counters;
+       size_t avail;
        struct qib_devdata *dd = private2dd(file);
 
-       return simple_read_from_buffer(buf, count, ppos, counters,
-               dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters));
+       avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
 }
 
 static const struct file_operations portcntr_ops[] = {
index 7b6549f..1eadadc 100644 (file)
@@ -3475,14 +3475,6 @@ struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
        struct qib_devdata *dd;
        int ret;
 
-#ifndef CONFIG_PCI_MSI
-       qib_early_err(&pdev->dev, "QLogic PCIE device 0x%x cannot "
-             "work if CONFIG_PCI_MSI is not enabled\n",
-             ent->device);
-       dd = ERR_PTR(-ENODEV);
-       goto bail;
-#endif
-
        dd = qib_alloc_devdata(pdev, sizeof(struct qib_pportdata) +
                               sizeof(struct qib_chip_specific));
        if (IS_ERR(dd))
@@ -3554,10 +3546,6 @@ struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
        if (qib_mini_init)
                goto bail;
 
-#ifndef CONFIG_PCI_MSI
-       qib_dev_err(dd, "PCI_MSI not configured, NO interrupts\n");
-#endif
-
        if (qib_pcie_params(dd, 8, NULL, NULL))
                qib_dev_err(dd, "Failed to setup PCIe or interrupts; "
                            "continuing anyway\n");
index 2c24eab..503992d 100644 (file)
@@ -42,9 +42,6 @@
 #include <linux/jiffies.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_smi.h>
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-#include <linux/dca.h>
-#endif
 
 #include "qib.h"
 #include "qib_7322_regs.h"
@@ -114,40 +111,18 @@ static ushort qib_singleport;
 module_param_named(singleport, qib_singleport, ushort, S_IRUGO);
 MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space");
 
-
-/*
- * Setup QMH7342 receive and transmit parameters, necessary because
- * each bay, Mez connector, and IB port need different tuning, beyond
- * what the switch and HCA can do automatically.
- * It's expected to be done by cat'ing files to the modules file,
- * rather than setting up as a module parameter.
- * It's a "write-only" file, returns 0 when read back.
- * The unit, port, bay (if given), and values MUST be done as a single write.
- * The unit, port, and bay must precede the values to be effective.
- */
-static int setup_qmh_params(const char *, struct kernel_param *);
-static unsigned dummy_qmh_params;
-module_param_call(qmh_serdes_setup, setup_qmh_params, param_get_uint,
-                 &dummy_qmh_params, S_IWUSR | S_IRUGO);
-
-/* similarly for QME7342, but it's simpler */
-static int setup_qme_params(const char *, struct kernel_param *);
-static unsigned dummy_qme_params;
-module_param_call(qme_serdes_setup, setup_qme_params, param_get_uint,
-                 &dummy_qme_params, S_IWUSR | S_IRUGO);
-
 #define MAX_ATTEN_LEN 64 /* plenty for any real system */
 /* for read back, default index is ~5m copper cable */
-static char cable_atten_list[MAX_ATTEN_LEN] = "10";
-static struct kparam_string kp_cable_atten = {
-       .string = cable_atten_list,
+static char txselect_list[MAX_ATTEN_LEN] = "10";
+static struct kparam_string kp_txselect = {
+       .string = txselect_list,
        .maxlen = MAX_ATTEN_LEN
 };
-static int  setup_cable_atten(const char *, struct kernel_param *);
-module_param_call(cable_atten, setup_cable_atten, param_get_string,
-                 &kp_cable_atten, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(cable_atten, \
-                "cable attenuation indices for cables with invalid EEPROM");
+static int  setup_txselect(const char *, struct kernel_param *);
+module_param_call(txselect, setup_txselect, param_get_string,
+                 &kp_txselect, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(txselect, \
+                "Tx serdes indices (for no QSFP or invalid QSFP data)");
 
 #define BOARD_QME7342 5
 #define BOARD_QMH7342 6
@@ -540,12 +515,6 @@ struct qib_chip_specific {
        u32 lastbuf_for_pio;
        u32 stay_in_freeze;
        u32 recovery_ports_initted;
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       u32 dca_ctrl;
-       int rhdr_cpu[18];
-       int sdma_cpu[2];
-       u64 dca_rcvhdr_ctrl[5]; /* B, C, D, E, F */
-#endif
        struct msix_entry *msix_entries;
        void  **msix_arg;
        unsigned long *sendchkenable;
@@ -574,11 +543,12 @@ struct vendor_txdds_ent {
 static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
 
 #define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
+#define TXDDS_EXTRA_SZ 11 /* number of extra tx settings entries */
 #define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
 
 #define H1_FORCE_VAL 8
-#define H1_FORCE_QME 1 /*  may be overridden via setup_qme_params() */
-#define H1_FORCE_QMH 7 /*  may be overridden via setup_qmh_params() */
+#define H1_FORCE_QME 1 /*  may be overridden via setup_txselect() */
+#define H1_FORCE_QMH 7 /*  may be overridden via setup_txselect() */
 
 /* The static and dynamic registers are paired, and the pairs indexed by spd */
 #define krp_static_adapt_dis(spd) (KREG_IBPORT_IDX(ADAPT_DISABLE_STATIC_SDR) \
@@ -590,15 +560,6 @@ static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
 #define QDR_STATIC_ADAPT_INIT 0xffffffffffULL /* up, disable H0,H1-8, LE */
 #define QDR_STATIC_ADAPT_INIT_R1 0xf0ffffffffULL /* r1 up, disable H0,H1-8 */
 
-static const struct txdds_ent qmh_sdr_txdds =  { 11, 0,  5,  6 };
-static const struct txdds_ent qmh_ddr_txdds =  {  7, 0,  2,  8 };
-static const struct txdds_ent qmh_qdr_txdds =  {  0, 1,  3, 10 };
-
-/* this is used for unknown mez cards also */
-static const struct txdds_ent qme_sdr_txdds =  { 11, 0,  4,  4 };
-static const struct txdds_ent qme_ddr_txdds =  {  7, 0,  2,  7 };
-static const struct txdds_ent qme_qdr_txdds =  {  0, 1, 12, 11 };
-
 struct qib_chippport_specific {
        u64 __iomem *kpregbase;
        u64 __iomem *cpregbase;
@@ -637,12 +598,8 @@ struct qib_chippport_specific {
         * Per-bay per-channel rcv QMH H1 values and Tx values for QDR.
         * entry zero is unused, to simplify indexing
         */
-       u16 h1_val;
-       u8 amp[SERDES_CHANS];
-       u8 pre[SERDES_CHANS];
-       u8 mainv[SERDES_CHANS];
-       u8 post[SERDES_CHANS];
-       u8 no_eep;  /* attenuation index to use if no qsfp info */
+       u8 h1_val;
+       u8 no_eep;  /* txselect table index to use if no qsfp info */
        u8 ipg_tries;
        u8 ibmalfusesnap;
        struct qib_qsfp_data qsfp_data;
@@ -676,52 +633,6 @@ static struct {
                SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 },
 };
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-static const struct dca_reg_map {
-       int     shadow_inx;
-       int     lsb;
-       u64     mask;
-       u16     regno;
-} dca_rcvhdr_reg_map[] = {
-       { 0, SYM_LSB(DCACtrlB, RcvHdrq0DCAOPH),
-          ~SYM_MASK(DCACtrlB, RcvHdrq0DCAOPH) , KREG_IDX(DCACtrlB) },
-       { 0, SYM_LSB(DCACtrlB, RcvHdrq1DCAOPH),
-          ~SYM_MASK(DCACtrlB, RcvHdrq1DCAOPH) , KREG_IDX(DCACtrlB) },
-       { 0, SYM_LSB(DCACtrlB, RcvHdrq2DCAOPH),
-          ~SYM_MASK(DCACtrlB, RcvHdrq2DCAOPH) , KREG_IDX(DCACtrlB) },
-       { 0, SYM_LSB(DCACtrlB, RcvHdrq3DCAOPH),
-          ~SYM_MASK(DCACtrlB, RcvHdrq3DCAOPH) , KREG_IDX(DCACtrlB) },
-       { 1, SYM_LSB(DCACtrlC, RcvHdrq4DCAOPH),
-          ~SYM_MASK(DCACtrlC, RcvHdrq4DCAOPH) , KREG_IDX(DCACtrlC) },
-       { 1, SYM_LSB(DCACtrlC, RcvHdrq5DCAOPH),
-          ~SYM_MASK(DCACtrlC, RcvHdrq5DCAOPH) , KREG_IDX(DCACtrlC) },
-       { 1, SYM_LSB(DCACtrlC, RcvHdrq6DCAOPH),
-          ~SYM_MASK(DCACtrlC, RcvHdrq6DCAOPH) , KREG_IDX(DCACtrlC) },
-       { 1, SYM_LSB(DCACtrlC, RcvHdrq7DCAOPH),
-          ~SYM_MASK(DCACtrlC, RcvHdrq7DCAOPH) , KREG_IDX(DCACtrlC) },
-       { 2, SYM_LSB(DCACtrlD, RcvHdrq8DCAOPH),
-          ~SYM_MASK(DCACtrlD, RcvHdrq8DCAOPH) , KREG_IDX(DCACtrlD) },
-       { 2, SYM_LSB(DCACtrlD, RcvHdrq9DCAOPH),
-          ~SYM_MASK(DCACtrlD, RcvHdrq9DCAOPH) , KREG_IDX(DCACtrlD) },
-       { 2, SYM_LSB(DCACtrlD, RcvHdrq10DCAOPH),
-          ~SYM_MASK(DCACtrlD, RcvHdrq10DCAOPH) , KREG_IDX(DCACtrlD) },
-       { 2, SYM_LSB(DCACtrlD, RcvHdrq11DCAOPH),
-          ~SYM_MASK(DCACtrlD, RcvHdrq11DCAOPH) , KREG_IDX(DCACtrlD) },
-       { 3, SYM_LSB(DCACtrlE, RcvHdrq12DCAOPH),
-          ~SYM_MASK(DCACtrlE, RcvHdrq12DCAOPH) , KREG_IDX(DCACtrlE) },
-       { 3, SYM_LSB(DCACtrlE, RcvHdrq13DCAOPH),
-          ~SYM_MASK(DCACtrlE, RcvHdrq13DCAOPH) , KREG_IDX(DCACtrlE) },
-       { 3, SYM_LSB(DCACtrlE, RcvHdrq14DCAOPH),
-          ~SYM_MASK(DCACtrlE, RcvHdrq14DCAOPH) , KREG_IDX(DCACtrlE) },
-       { 3, SYM_LSB(DCACtrlE, RcvHdrq15DCAOPH),
-          ~SYM_MASK(DCACtrlE, RcvHdrq15DCAOPH) , KREG_IDX(DCACtrlE) },
-       { 4, SYM_LSB(DCACtrlF, RcvHdrq16DCAOPH),
-          ~SYM_MASK(DCACtrlF, RcvHdrq16DCAOPH) , KREG_IDX(DCACtrlF) },
-       { 4, SYM_LSB(DCACtrlF, RcvHdrq17DCAOPH),
-          ~SYM_MASK(DCACtrlF, RcvHdrq17DCAOPH) , KREG_IDX(DCACtrlF) },
-};
-#endif
-
 /* ibcctrl bits */
 #define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
 /* cycle through TS1/TS2 till OK */
@@ -2572,95 +2483,6 @@ static void qib_setup_7322_setextled(struct qib_pportdata *ppd, u32 on)
                qib_write_kreg_port(ppd, krp_rcvpktledcnt, ledblink);
 }
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-static void qib_update_rhdrq_dca(struct qib_ctxtdata *rcd)
-{
-       struct qib_devdata *dd = rcd->dd;
-       struct qib_chip_specific *cspec = dd->cspec;
-       int cpu = get_cpu();
-
-       if (cspec->rhdr_cpu[rcd->ctxt] != cpu) {
-               const struct dca_reg_map *rmp;
-
-               cspec->rhdr_cpu[rcd->ctxt] = cpu;
-               rmp = &dca_rcvhdr_reg_map[rcd->ctxt];
-               cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] &= rmp->mask;
-               cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] |=
-                       (u64) dca3_get_tag(&dd->pcidev->dev, cpu) << rmp->lsb;
-               qib_write_kreg(dd, rmp->regno,
-                              cspec->dca_rcvhdr_ctrl[rmp->shadow_inx]);
-               cspec->dca_ctrl |= SYM_MASK(DCACtrlA, RcvHdrqDCAEnable);
-               qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
-       }
-       put_cpu();
-}
-
-static void qib_update_sdma_dca(struct qib_pportdata *ppd)
-{
-       struct qib_devdata *dd = ppd->dd;
-       struct qib_chip_specific *cspec = dd->cspec;
-       int cpu = get_cpu();
-       unsigned pidx = ppd->port - 1;
-
-       if (cspec->sdma_cpu[pidx] != cpu) {
-               cspec->sdma_cpu[pidx] = cpu;
-               cspec->dca_rcvhdr_ctrl[4] &= ~(ppd->hw_pidx ?
-                       SYM_MASK(DCACtrlF, SendDma1DCAOPH) :
-                       SYM_MASK(DCACtrlF, SendDma0DCAOPH));
-               cspec->dca_rcvhdr_ctrl[4] |=
-                       (u64) dca3_get_tag(&dd->pcidev->dev, cpu) <<
-                               (ppd->hw_pidx ?
-                                       SYM_LSB(DCACtrlF, SendDma1DCAOPH) :
-                                       SYM_LSB(DCACtrlF, SendDma0DCAOPH));
-               qib_write_kreg(dd, KREG_IDX(DCACtrlF),
-                              cspec->dca_rcvhdr_ctrl[4]);
-               cspec->dca_ctrl |= ppd->hw_pidx ?
-                       SYM_MASK(DCACtrlA, SendDMAHead1DCAEnable) :
-                       SYM_MASK(DCACtrlA, SendDMAHead0DCAEnable);
-               qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
-       }
-       put_cpu();
-}
-
-static void qib_setup_dca(struct qib_devdata *dd)
-{
-       struct qib_chip_specific *cspec = dd->cspec;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(cspec->rhdr_cpu); i++)
-               cspec->rhdr_cpu[i] = -1;
-       for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
-               cspec->sdma_cpu[i] = -1;
-       cspec->dca_rcvhdr_ctrl[0] =
-               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq0DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq1DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq2DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq3DCAXfrCnt));
-       cspec->dca_rcvhdr_ctrl[1] =
-               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq4DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq5DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq6DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq7DCAXfrCnt));
-       cspec->dca_rcvhdr_ctrl[2] =
-               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq8DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq9DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq10DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq11DCAXfrCnt));
-       cspec->dca_rcvhdr_ctrl[3] =
-               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq12DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq13DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq14DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq15DCAXfrCnt));
-       cspec->dca_rcvhdr_ctrl[4] =
-               (1ULL << SYM_LSB(DCACtrlF, RcvHdrq16DCAXfrCnt)) |
-               (1ULL << SYM_LSB(DCACtrlF, RcvHdrq17DCAXfrCnt));
-       for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
-               qib_write_kreg(dd, KREG_IDX(DCACtrlB) + i,
-                              cspec->dca_rcvhdr_ctrl[i]);
-}
-
-#endif
-
 /*
  * Disable MSIx interrupt if enabled, call generic MSIx code
  * to cleanup, and clear pending MSIx interrupts.
@@ -2701,15 +2523,6 @@ static void qib_setup_7322_cleanup(struct qib_devdata *dd)
 {
        int i;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED) {
-               dca_remove_requester(&dd->pcidev->dev);
-               dd->flags &= ~QIB_DCA_ENABLED;
-               dd->cspec->dca_ctrl = 0;
-               qib_write_kreg(dd, KREG_IDX(DCACtrlA), dd->cspec->dca_ctrl);
-       }
-#endif
-
        qib_7322_free_irq(dd);
        kfree(dd->cspec->cntrs);
        kfree(dd->cspec->sendchkenable);
@@ -3017,11 +2830,6 @@ static irqreturn_t qib_7322pintr(int irq, void *data)
        if (dd->int_counter != (u32) -1)
                dd->int_counter++;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED)
-               qib_update_rhdrq_dca(rcd);
-#endif
-
        /* Clear the interrupt bit we expect to be set. */
        qib_write_kreg(dd, kr_intclear, ((1ULL << QIB_I_RCVAVAIL_LSB) |
                       (1ULL << QIB_I_RCVURG_LSB)) << rcd->ctxt);
@@ -3085,11 +2893,6 @@ static irqreturn_t sdma_intr(int irq, void *data)
        if (dd->int_counter != (u32) -1)
                dd->int_counter++;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED)
-               qib_update_sdma_dca(ppd);
-#endif
-
        /* Clear the interrupt bit we expect to be set. */
        qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
                       INT_MASK_P(SDma, 1) : INT_MASK_P(SDma, 0));
@@ -3119,11 +2922,6 @@ static irqreturn_t sdma_idle_intr(int irq, void *data)
        if (dd->int_counter != (u32) -1)
                dd->int_counter++;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED)
-               qib_update_sdma_dca(ppd);
-#endif
-
        /* Clear the interrupt bit we expect to be set. */
        qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
                       INT_MASK_P(SDmaIdle, 1) : INT_MASK_P(SDmaIdle, 0));
@@ -3153,11 +2951,6 @@ static irqreturn_t sdma_progress_intr(int irq, void *data)
        if (dd->int_counter != (u32) -1)
                dd->int_counter++;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED)
-               qib_update_sdma_dca(ppd);
-#endif
-
        /* Clear the interrupt bit we expect to be set. */
        qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
                       INT_MASK_P(SDmaProgress, 1) :
@@ -3188,11 +2981,6 @@ static irqreturn_t sdma_cleanup_intr(int irq, void *data)
        if (dd->int_counter != (u32) -1)
                dd->int_counter++;
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       if (dd->flags & QIB_DCA_ENABLED)
-               qib_update_sdma_dca(ppd);
-#endif
-
        /* Clear the interrupt bit we expect to be set. */
        qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
                       INT_MASK_PM(SDmaCleanupDone, 1) :
@@ -4299,10 +4087,6 @@ static void rcvctrl_7322_mod(struct qib_pportdata *ppd, unsigned int op,
                qib_write_kreg_ctxt(dd, krc_rcvhdraddr, ctxt,
                                    rcd->rcvhdrq_phys);
                rcd->seq_cnt = 1;
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-               if (dd->flags & QIB_DCA_ENABLED)
-                       qib_update_rhdrq_dca(rcd);
-#endif
        }
        if (op & QIB_RCVCTRL_CTXT_DIS)
                ppd->p_rcvctrl &=
@@ -5360,7 +5144,13 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
                                     QIBL_IB_AUTONEG_INPROG)))
                        set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled);
                if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+                       /* unlock the Tx settings, speed may change */
+                       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+                               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                               reset_tx_deemphasis_override));
                        qib_cancel_sends(ppd);
+                       /* on link down, ensure sane pcs state */
+                       qib_7322_mini_pcs_reset(ppd);
                        spin_lock_irqsave(&ppd->sdma_lock, flags);
                        if (__qib_sdma_running(ppd))
                                __qib_sdma_process_event(ppd,
@@ -5766,26 +5556,28 @@ static void qib_init_7322_qsfp(struct qib_pportdata *ppd)
 }
 
 /*
- * called at device initialization time, and also if the cable_atten
+ * called at device initialization time, and also if the txselect
  * module parameter is changed.  This is used for cables that don't
  * have valid QSFP EEPROMs (not present, or attenuation is zero).
  * We initialize to the default, then if there is a specific
- * unit,port match, we use that.
+ * unit,port match, we use that (and set it immediately, for the
+ * current speed, if the link is at INIT or better).
  * String format is "default# unit#,port#=# ... u,p=#", separators must
- * be a SPACE character.  A newline terminates.
+ * be a SPACE character.  A newline terminates.  The u,p=# tuples may
+ * optionally have "u,p=#,#", where the final # is the H1 value
  * The last specific match is used (actually, all are used, but last
  * one is the one that winds up set); if none at all, fall back on default.
  */
 static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
 {
        char *nxt, *str;
-       int pidx, unit, port, deflt;
+       u32 pidx, unit, port, deflt, h1;
        unsigned long val;
-       int any = 0;
+       int any = 0, seth1;
 
-       str = cable_atten_list;
+       str = txselect_list;
 
-       /* default number is validated in setup_cable_atten() */
+       /* default number is validated in setup_txselect() */
        deflt = simple_strtoul(str, &nxt, 0);
        for (pidx = 0; pidx < dd->num_pports; ++pidx)
                dd->pport[pidx].cpspec->no_eep = deflt;
@@ -5812,16 +5604,28 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
                                ;
                        continue;
                }
-               if (val >= TXDDS_TABLE_SZ)
+               if (val >= TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)
                        continue;
+               seth1 = 0;
+               h1 = 0; /* gcc thinks it might be used uninitted */
+               if (*nxt == ',' && nxt[1]) {
+                       str = ++nxt;
+                       h1 = (u32)simple_strtoul(str, &nxt, 0);
+                       if (nxt == str)
+                               while (*nxt && *nxt++ != ' ') /* skip */
+                                       ;
+                       else
+                               seth1 = 1;
+               }
                for (pidx = 0; dd->unit == unit && pidx < dd->num_pports;
                     ++pidx) {
-                       if (dd->pport[pidx].port != port ||
-                               !dd->pport[pidx].link_speed_supported)
+                       struct qib_pportdata *ppd = &dd->pport[pidx];
+
+                       if (ppd->port != port || !ppd->link_speed_supported)
                                continue;
-                       dd->pport[pidx].cpspec->no_eep = val;
+                       ppd->cpspec->no_eep = val;
                        /* now change the IBC and serdes, overriding generic */
-                       init_txdds_table(&dd->pport[pidx], 1);
+                       init_txdds_table(ppd, 1);
                        any++;
                }
                if (*nxt == '\n')
@@ -5832,35 +5636,35 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
                 * Change the IBC and serdes, but since it's
                 * general, don't override specific settings.
                 */
-               for (pidx = 0; pidx < dd->num_pports; ++pidx) {
-                       if (!dd->pport[pidx].link_speed_supported)
-                               continue;
-                       init_txdds_table(&dd->pport[pidx], 0);
-               }
+               for (pidx = 0; pidx < dd->num_pports; ++pidx)
+                       if (dd->pport[pidx].link_speed_supported)
+                               init_txdds_table(&dd->pport[pidx], 0);
        }
 }
 
-/* handle the cable_atten parameter changing */
-static int setup_cable_atten(const char *str, struct kernel_param *kp)
+/* handle the txselect parameter changing */
+static int setup_txselect(const char *str, struct kernel_param *kp)
 {
        struct qib_devdata *dd;
        unsigned long val;
        char *n;
        if (strlen(str) >= MAX_ATTEN_LEN) {
-               printk(KERN_INFO QIB_DRV_NAME " cable_atten_values string "
+               printk(KERN_INFO QIB_DRV_NAME " txselect_values string "
                       "too long\n");
                return -ENOSPC;
        }
        val = simple_strtoul(str, &n, 0);
-       if (n == str || val >= TXDDS_TABLE_SZ) {
+       if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
                printk(KERN_INFO QIB_DRV_NAME
-                      "cable_atten_values must start with a number\n");
+                      "txselect_values must start with a number < %d\n",
+                       TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
                return -EINVAL;
        }
-       strcpy(cable_atten_list, str);
+       strcpy(txselect_list, str);
 
        list_for_each_entry(dd, &qib_dev_list, list)
-               set_no_qsfp_atten(dd, 1);
+               if (dd->deviceid == PCI_DEVICE_ID_QLOGIC_IB_7322)
+                       set_no_qsfp_atten(dd, 1);
        return 0;
 }
 
@@ -6261,28 +6065,17 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
                 * in adapter-specific routines.
                 */
                if (!(ppd->dd->flags & QIB_HAS_QSFP)) {
-                       int i;
-                       const struct txdds_ent *txdds;
-
                        if (!IS_QMH(ppd->dd) && !IS_QME(ppd->dd))
                                qib_devinfo(ppd->dd->pcidev, "IB%u:%u: "
                                            "Unknown mezzanine card type\n",
-                                           ppd->dd->unit, ppd->port);
-                       txdds = IS_QMH(ppd->dd) ? &qmh_qdr_txdds :
-                               &qme_qdr_txdds;
-
+                                           dd->unit, ppd->port);
+                       cp->h1_val = IS_QMH(dd) ? H1_FORCE_QMH : H1_FORCE_QME;
                        /*
-                        * set values in case link comes up
-                        * before table is written to driver.
+                        * Choose center value as default tx serdes setting
+                        * until changed through module parameter.
                         */
-                       cp->h1_val = IS_QMH(ppd->dd) ? H1_FORCE_QMH :
-                               H1_FORCE_QME;
-                       for (i = 0; i < SERDES_CHANS; i++) {
-                               cp->amp[i] = txdds->amp;
-                               cp->pre[i] = txdds->pre;
-                               cp->mainv[i] = txdds->main;
-                               cp->post[i] = txdds->post;
-                       }
+                       ppd->cpspec->no_eep = IS_QMH(dd) ?
+                               TXDDS_TABLE_SZ + 2 : TXDDS_TABLE_SZ + 4;
                } else
                        cp->h1_val = H1_FORCE_VAL;
 
@@ -6299,8 +6092,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 
        dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
        dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
-       dd->rhf_offset =
-               dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
+       dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
 
        /* we always allocate at least 2048 bytes for eager buffers */
        dd->rcvegrbufsize = max(mtu, 2048);
@@ -6919,13 +6711,6 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
        /* clear diagctrl register, in case diags were running and crashed */
        qib_write_kreg(dd, kr_hwdiagctrl, 0);
 
-#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
-       ret = dca_add_requester(&pdev->dev);
-       if (!ret) {
-               dd->flags |= QIB_DCA_ENABLED;
-               qib_setup_dca(dd);
-       }
-#endif
        goto bail;
 
 bail_cleanup:
@@ -7111,8 +6896,8 @@ static const struct txdds_ent txdds_ddr[TXDDS_TABLE_SZ] = {
 static const struct txdds_ent txdds_qdr[TXDDS_TABLE_SZ] = {
        /* amp, pre, main, post */
        {  2, 2, 15,  6 },      /* Loopback */
-       {  0, 1,  0,  7 },      /*  2 dB */
-       {  0, 1,  0,  9 },      /*  3 dB */
+       {  0, 1,  0,  7 },      /*  2 dB (also QMH7342) */
+       {  0, 1,  0,  9 },      /*  3 dB (also QMH7342) */
        {  0, 1,  0, 11 },      /*  4 dB */
        {  0, 1,  0, 13 },      /*  5 dB */
        {  0, 1,  0, 15 },      /*  6 dB */
@@ -7128,6 +6913,57 @@ static const struct txdds_ent txdds_qdr[TXDDS_TABLE_SZ] = {
        {  0, 2,  9, 15 },      /* 16 dB */
 };
 
+/*
+ * extra entries for use with txselect, for indices >= TXDDS_TABLE_SZ.
+ * These are mostly used for mez cards going through connectors
+ * and backplane traces, but can be used to add other "unusual"
+ * table values as well.
+ */
+static const struct txdds_ent txdds_extra_sdr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 0, 0,  1 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  1 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+};
+
+static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 0, 0,  7 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  7 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+};
+
+static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 1,  0,  4 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  5 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  6 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  8 },      /* QMH7342 backplane settings */
+       {  0, 1, 12, 10 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 11 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 12 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 14 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  6 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  7 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  8 },      /* QME7342 backplane setting */
+};
+
 static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds,
                                               unsigned atten)
 {
@@ -7145,7 +6981,7 @@ static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds,
 }
 
 /*
- * if override is set, the module parameter cable_atten has a value
+ * if override is set, the module parameter txselect has a value
  * for this specific port, so use it, rather than our normal mechanism.
  */
 static void find_best_ent(struct qib_pportdata *ppd,
@@ -7184,15 +7020,28 @@ static void find_best_ent(struct qib_pportdata *ppd,
                *ddr_dds = get_atten_table(txdds_ddr, qd->atten[0]);
                *qdr_dds = get_atten_table(txdds_qdr, qd->atten[1]);
                return;
-       } else {
+       } else if (ppd->cpspec->no_eep < TXDDS_TABLE_SZ) {
                /*
                 * If we have no (or incomplete) data from the cable
-                * EEPROM, or no QSFP, use the module parameter value
-                * to index into the attentuation table.
+                * EEPROM, or no QSFP, or override is set, use the
+                * module parameter value to index into the attentuation
+                * table.
                 */
-               *sdr_dds = &txdds_sdr[ppd->cpspec->no_eep];
-               *ddr_dds = &txdds_ddr[ppd->cpspec->no_eep];
-               *qdr_dds = &txdds_qdr[ppd->cpspec->no_eep];
+               idx = ppd->cpspec->no_eep;
+               *sdr_dds = &txdds_sdr[idx];
+               *ddr_dds = &txdds_ddr[idx];
+               *qdr_dds = &txdds_qdr[idx];
+       } else if (ppd->cpspec->no_eep < (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
+               /* similar to above, but index into the "extra" table. */
+               idx = ppd->cpspec->no_eep - TXDDS_TABLE_SZ;
+               *sdr_dds = &txdds_extra_sdr[idx];
+               *ddr_dds = &txdds_extra_ddr[idx];
+               *qdr_dds = &txdds_extra_qdr[idx];
+       } else {
+               /* this shouldn't happen, it's range checked */
+               *sdr_dds = txdds_sdr + qib_long_atten;
+               *ddr_dds = txdds_ddr + qib_long_atten;
+               *qdr_dds = txdds_qdr + qib_long_atten;
        }
 }
 
@@ -7203,33 +7052,24 @@ static void init_txdds_table(struct qib_pportdata *ppd, int override)
        int idx;
        int single_ent = 0;
 
-       if (IS_QMH(ppd->dd)) {
-               /* normally will be overridden, via setup_qmh() */
-               sdr_dds = &qmh_sdr_txdds;
-               ddr_dds = &qmh_ddr_txdds;
-               qdr_dds = &qmh_qdr_txdds;
-               single_ent = 1;
-       } else if (IS_QME(ppd->dd)) {
-               sdr_dds = &qme_sdr_txdds;
-               ddr_dds = &qme_ddr_txdds;
-               qdr_dds = &qme_qdr_txdds;
+       find_best_ent(ppd, &sdr_dds, &ddr_dds, &qdr_dds, override);
+
+       /* for mez cards or override, use the selected value for all entries */
+       if (!(ppd->dd->flags & QIB_HAS_QSFP) || override)
                single_ent = 1;
-       } else
-               find_best_ent(ppd, &sdr_dds, &ddr_dds, &qdr_dds, override);
 
        /* Fill in the first entry with the best entry found. */
        set_txdds(ppd, 0, sdr_dds);
        set_txdds(ppd, TXDDS_TABLE_SZ, ddr_dds);
        set_txdds(ppd, 2 * TXDDS_TABLE_SZ, qdr_dds);
-
-       /*
-        * for our current speed, also write that value into the
-        * tx serdes registers.
-        */
-       dds = (struct txdds_ent *)(ppd->link_speed_active == QIB_IB_QDR ?
-                                  qdr_dds : (ppd->link_speed_active ==
-                                             QIB_IB_DDR ? ddr_dds : sdr_dds));
-       write_tx_serdes_param(ppd, dds);
+       if (ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED |
+               QIBL_LINKACTIVE)) {
+               dds = (struct txdds_ent *)(ppd->link_speed_active ==
+                                          QIB_IB_QDR ?  qdr_dds :
+                                          (ppd->link_speed_active ==
+                                           QIB_IB_DDR ? ddr_dds : sdr_dds));
+               write_tx_serdes_param(ppd, dds);
+       }
 
        /* Fill in the remaining entries with the default table values. */
        for (idx = 1; idx < ARRAY_SIZE(txdds_sdr); ++idx) {
@@ -7352,6 +7192,11 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
         */
        init_txdds_table(ppd, 0);
 
+       /* ensure no tx overrides from earlier driver loads */
+       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+               reset_tx_deemphasis_override));
+
        /* Patch some SerDes defaults to "Better for IB" */
        /* Timing Loop Bandwidth: cdr_timing[11:9] = 0 */
        ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9));
@@ -7421,7 +7266,7 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
                            QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN);
        ppd->cpspec->qdr_dfe_on = 1;
 
-       /* (FLoop LOS gate: PPM filter  enabled */
+       /* FLoop LOS gate: PPM filter  enabled */
        ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10);
 
        /* rx offset center enabled */
@@ -7486,68 +7331,39 @@ static void write_tx_serdes_param(struct qib_pportdata *ppd,
                    SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txc0_ena) |
                    SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txcp1_ena) |
                    SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txcn1_ena));
-       deemph |= 1ULL << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                                 tx_override_deemphasis_select);
-       deemph |= txdds->amp << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                                   txampcntl_d2a);
-       deemph |= txdds->main << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                                     txc0_ena);
-       deemph |= txdds->post << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                                    txcp1_ena);
-       deemph |= txdds->pre << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+
+       deemph |= SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                          tx_override_deemphasis_select);
+       deemph |= (txdds->amp & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                   txampcntl_d2a)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                      txampcntl_d2a);
+       deemph |= (txdds->main & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txc0_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                  txc0_ena);
+       deemph |= (txdds->post & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txcp1_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                   txcp1_ena);
+       deemph |= (txdds->pre & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txcn1_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
                                    txcn1_ena);
        qib_write_kreg_port(ppd, krp_tx_deemph_override, deemph);
 }
 
 /*
- * set per-bay, per channel parameters.  For now, we ignore
- * do_tx, and always set tx parameters, and set them with the same value
- * for all channels, using the channel 0 value.   We may switch to
- * per-channel settings in the future, and that method only needs
- * to be done once.
- * Because this also writes the IBC txdds table with a single set
- * of values, it should be called only for cases where we want to completely
- * force a specific setting, typically only for mez cards.
+ * Set the parameters for mez cards on link bounce, so they are
+ * always exactly what was requested.  Similar logic to init_txdds
+ * but does just the serdes.
  */
 static void adj_tx_serdes(struct qib_pportdata *ppd)
 {
-       struct txdds_ent txdds;
-       int i;
-       u8 *amp, *pre, *mainv, *post;
-
-       /*
-        * Because we use TX_DEEMPHASIS_OVERRIDE, we need to
-        * always do tx side, just like H1, since it is cleared
-        * by link down
-        */
-       amp = ppd->cpspec->amp;
-       pre = ppd->cpspec->pre;
-       mainv = ppd->cpspec->mainv;
-       post = ppd->cpspec->post;
-
-       amp[0] &= SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                           txampcntl_d2a);
-       mainv[0] &= SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                             txc0_ena);
-       post[0] &= SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                            txcp1_ena);
-       pre[0] &= SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
-                           txcn1_ena);
-
-       /*
-        * Use the channel zero values, only, for now, for
-        * all channels
-       */
-       txdds.amp = amp[0];
-       txdds.pre = pre[0];
-       txdds.main = mainv[0];
-       txdds.post = post[0];
-
-       /* write the QDR table for IBC use, as backup for link down */
-       for (i = 0; i < ARRAY_SIZE(txdds_qdr); ++i)
-               set_txdds(ppd, i + 32, &txdds);
+       const struct txdds_ent *sdr_dds, *ddr_dds, *qdr_dds;
+       struct txdds_ent *dds;
 
-       write_tx_serdes_param(ppd, &txdds);
+       find_best_ent(ppd, &sdr_dds, &ddr_dds, &qdr_dds, 1);
+       dds = (struct txdds_ent *)(ppd->link_speed_active == QIB_IB_QDR ?
+               qdr_dds : (ppd->link_speed_active == QIB_IB_DDR ?
+                               ddr_dds : sdr_dds));
+       write_tx_serdes_param(ppd, dds);
 }
 
 /* set QDR forced value for H1, if needed */
@@ -7567,235 +7383,6 @@ static void force_h1(struct qib_pportdata *ppd)
        }
 }
 
-/*
- * Parse the parameters for the QMH7342, to get rx and tx serdes
- * settings for that Bay, for both possible mez connectors (PCIe bus)
- * and IB link (one link on mez1, two possible on mez2).
- *
- * Data is comma or white space separated.
- *
- * A set of data has 7 groups, rx and tx groups have SERDES_CHANS values,
- * one per IB lane (serdes channel).
- * The groups are Bay, bus# H1 rcv, and amp, pre, post, main Tx values (QDR).
- * The Bay # is used only for debugging currently.
- * H1 values are set whenever the link goes down, or is at cfg_test or
- * cfg_wait_enh.  Tx values are programmed once, when this routine is called
- * (and with default values at chip initialization).  Values are any base, in
- * strtoul style, and values are seperated by comma, or any white space
- * (space, tab, newline).
- *
- * An example set might look like this (white space vs
- * comma used for human ease of reading)
- * The ordering is a set of Bay# Bus# H1, amp, pre, post, and main for mez1 IB1,
- * repeat for mez2 IB1, then mez2 IB2.
- *
- * B B H1:0       amp:0       pre:0        post: 0        main:0
- * a u H1:  1     amp:  1     pre:  1      post:   1      main:  1
- * y s H1:    2   amp:    2   pre:    2    post:      2   main:    2
- *     H1:      4 amp:      3 pre:      3  post:        3 main:      3
- * 1 3    8,6,5,6     0,0,0,0     1,1,1,1       10,10,10,10    3,3,3,3
- * 1 6    7,6,6,7     0,0,0,0     1,1,1,1       10,10,10,10    3,3,3,3
- * 1 6    9,7,7,8     0,0,0,0     1,1,1,1       10,10,10,10    3,3,3,3
- */
-#define N_QMH_FIELDS 22
-static int setup_qmh_params(const char *str, struct kernel_param *kp)
-{
-       char *abuf, *v, *nv, *nvp;
-       struct qib_devdata *dd;
-       struct qib_pportdata *ppd;
-       u32 mez, vlen, nf, port, bay;
-       int ret = 0, found = 0;
-
-       vlen = strlen(str) + 1;
-       abuf = kmalloc(vlen, GFP_KERNEL);
-       if (!abuf) {
-               printk(KERN_INFO QIB_DRV_NAME
-                      " Unable to allocate QMH param buffer; ignoring\n");
-               return 0;
-       }
-       memcpy(abuf, str, vlen);
-       v = abuf;
-
-       /* these 3 are because gcc can't know they are set before used */
-       port = 1;
-       mez = 1; /* used only for debugging */
-       bay = 0; /* used only for debugging */
-       ppd = NULL;
-       for (nf = 0; (nv = strsep(&v, ", \t\n\r")) &&
-            nf < (N_QMH_FIELDS * 3);) {
-               u32 val;
-
-               if (!*nv)
-                       /* allow for multiple separators */
-                       continue;
-
-               val = simple_strtoul(nv, &nvp, 0);
-               if (nv == nvp) {
-                       printk(KERN_INFO QIB_DRV_NAME
-                              " Bay%u, mez%u IB%u non-numeric value (%s) "
-                              "field #%u, ignoring rest\n", bay, mez,
-                              port, nv, nf % (N_QMH_FIELDS * 3));
-                       ret = -EINVAL;
-                       goto bail;
-               }
-               if (!(nf % N_QMH_FIELDS)) {
-                       ppd = NULL;
-                       bay = val;
-                       if (!bay || bay > 16) {
-                               printk(KERN_INFO QIB_DRV_NAME
-                                      " Invalid bay # %u, field %u, "
-                                      "ignoring rest\n", bay, nf);
-                               ret = -EINVAL;
-                               goto bail;
-                       }
-               } else if ((nf % N_QMH_FIELDS) == 1) {
-                       u32 bus = val;
-                       if (nf == 1) {
-                               mez = 1;
-                               port = 1;
-                       } else if (nf == (N_QMH_FIELDS + 1)) {
-                               mez = 2;
-                               port = 1;
-                       } else {
-                               mez = 2;
-                               port = 2;
-                       }
-                       list_for_each_entry(dd, &qib_dev_list, list) {
-                               if (dd->deviceid != PCI_DEVICE_ID_QLOGIC_IB_7322
-                                   || !IS_QMH(dd))
-                                       continue; /* only for QMH cards */
-                               if (dd->pcidev->bus->number == bus) {
-                                       found++;
-                                       ppd = &dd->pport[port - 1];
-                               }
-                       }
-               } else if (ppd) {
-                       u32 parm = (nf % N_QMH_FIELDS) - 2;
-                       if (parm < SERDES_CHANS && !(parm % SERDES_CHANS))
-                               ppd->cpspec->h1_val = val;
-                       else if (parm < (2 * SERDES_CHANS))
-                               ppd->cpspec->amp[parm % SERDES_CHANS] = val;
-                       else if (parm < (3 * SERDES_CHANS))
-                               ppd->cpspec->pre[parm % SERDES_CHANS] = val;
-                       else if (parm < (4 * SERDES_CHANS))
-                               ppd->cpspec->post[parm % SERDES_CHANS] = val;
-                       else {
-                               ppd->cpspec->mainv[parm % SERDES_CHANS] = val;
-                               /* At the end of a port, set params */
-                               if (parm == ((5 * SERDES_CHANS) - 1))
-                                       adj_tx_serdes(ppd);
-                       }
-               }
-               nf++;
-       }
-       if (!found) {
-               printk(KERN_ERR QIB_DRV_NAME
-                      ": No match found for qmh_serdes_setup parameter\n");
-               ret = -EINVAL;
-       }
-bail:
-       kfree(abuf);
-       return ret;
-}
-
-/*
- * Similarly for QME7342, but the format is simpler, values are the
- * same for all mez card positions in a blade (2 or 4 per blade), but
- * are different for some blades vs others, and we don't need to
- * specify different parameters for different serdes channels or different
- * IB ports.
- * Format is: h1 amp,pre,post,main
- * Alternate format (so ports can be different): Pport# h1 amp,pre,post,main
- */
-#define N_QME_FIELDS 5
-static int setup_qme_params(const char *str, struct kernel_param *kp)
-{
-       char *abuf, *v, *nv, *nvp;
-       struct qib_devdata *dd;
-       u32 vlen, nf, port = 0;
-       u8 h1, tx[4]; /* amp, pre, post, main */
-       int ret =  -EINVAL;
-       char *seplist;
-
-       vlen = strlen(str) + 1;
-       abuf = kmalloc(vlen, GFP_KERNEL);
-       if (!abuf) {
-               printk(KERN_INFO QIB_DRV_NAME
-                      " Unable to allocate QME param buffer; ignoring\n");
-               return 0;
-       }
-       strncpy(abuf, str, vlen);
-
-       v = abuf;
-       seplist = " \t";
-       h1 = H1_FORCE_QME; /* gcc can't figure out always set before used */
-
-       for (nf = 0; (nv = strsep(&v, seplist)); ) {
-               u32 val;
-
-               if (!*nv)
-                       /* allow for multiple separators */
-                       continue;
-
-               if (!nf && *nv == 'P') {
-                       /* alternate format with port */
-                       val = simple_strtoul(++nv, &nvp, 0);
-                       if (nv == nvp || port >= NUM_IB_PORTS) {
-                               printk(KERN_INFO QIB_DRV_NAME
-                                      " %s: non-numeric port value (%s) "
-                                      "ignoring rest\n", __func__, nv);
-                               goto done;
-                       }
-                       port = val;
-                       continue; /* without incrementing nf */
-               }
-               val = simple_strtoul(nv, &nvp, 0);
-               if (nv == nvp) {
-                       printk(KERN_INFO QIB_DRV_NAME
-                              " %s: non-numeric value (%s) "
-                              "field #%u, ignoring rest\n", __func__,
-                              nv, nf);
-                       goto done;
-               }
-               if (!nf) {
-                       h1 = val;
-                       seplist = ",";
-               } else
-                       tx[nf - 1] = val;
-               if (++nf == N_QME_FIELDS) {
-                       list_for_each_entry(dd, &qib_dev_list, list) {
-                               int pidx, i;
-                               if (dd->deviceid != PCI_DEVICE_ID_QLOGIC_IB_7322
-                                   || !IS_QME(dd))
-                                       continue; /* only for QME cards */
-                               for (pidx = 0; pidx < dd->num_pports; ++pidx) {
-                                       struct qib_pportdata *ppd;
-                                       ppd = &dd->pport[pidx];
-                                       if ((port && ppd->port != port) ||
-                                               !ppd->link_speed_supported)
-                                               continue;
-                                       ppd->cpspec->h1_val = h1;
-                                       for (i = 0; i < SERDES_CHANS; i++) {
-                                               ppd->cpspec->amp[i] = tx[0];
-                                               ppd->cpspec->pre[i] = tx[1];
-                                               ppd->cpspec->post[i] = tx[2];
-                                               ppd->cpspec->mainv[i] = tx[3];
-                                       }
-                                       adj_tx_serdes(ppd);
-                               }
-                       }
-                       ret = 0;
-                       goto done;
-               }
-       }
-       printk(KERN_INFO QIB_DRV_NAME
-              " %s: Only %u of %u fields provided, skipping\n",
-              __func__, nf, N_QME_FIELDS);
-done:
-       kfree(abuf);
-       return ret;
-}
-
 #define SJA_EN SYM_MASK(SPC_JTAG_ACCESS_REG, SPC_JTAG_ACCESS_EN)
 #define BISTEN_LSB SYM_LSB(SPC_JTAG_ACCESS_REG, bist_en)
 
index c0139c0..9b40f34 100644 (file)
@@ -1237,7 +1237,13 @@ static int __devinit qib_init_one(struct pci_dev *pdev,
         */
        switch (ent->device) {
        case PCI_DEVICE_ID_QLOGIC_IB_6120:
+#ifdef CONFIG_PCI_MSI
                dd = qib_init_iba6120_funcs(pdev, ent);
+#else
+               qib_early_err(&pdev->dev, "QLogic PCIE device 0x%x cannot "
+                     "work if CONFIG_PCI_MSI is not enabled\n",
+                     ent->device);
+#endif
                break;
 
        case PCI_DEVICE_ID_QLOGIC_IB_7220:
index f98d17a..81bf25e 100644 (file)
@@ -21,7 +21,7 @@ comment "LED drivers"
 
 config LEDS_88PM860X
        tristate "LED Support for Marvell 88PM860x PMIC"
-       depends on LEDS_CLASS && MFD_88PM860X
+       depends on MFD_88PM860X
        help
          This option enables support for on-chip LED drivers found on Marvell
          Semiconductor 88PM8606 PMIC.
@@ -69,8 +69,8 @@ config LEDS_NET48XX
 
 config LEDS_NET5501
        tristate "LED Support for Soekris net5501 series Error LED"
-       depends on LEDS_CLASS && LEDS_TRIGGERS
-       depends on LEDS_GPIO_PLATFORM && GPIO_CS5535
+       depends on LEDS_TRIGGERS
+       depends on X86 && LEDS_GPIO_PLATFORM && GPIO_CS5535
        select LEDS_TRIGGER_DEFAULT_ON
        default n
        help
index 26843dd..cc22eee 100644 (file)
@@ -250,7 +250,6 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
                led.gpio = of_get_gpio_flags(child, 0, &flags);
                led.active_low = flags & OF_GPIO_ACTIVE_LOW;
                led.name = of_get_property(child, "label", NULL) ? : child->name;
-               led.blinking = 0;
                led.default_trigger =
                        of_get_property(child, "linux,default-trigger", NULL);
                state = of_get_property(child, "default-state", NULL);
index 72ebb3f..4dfa6b9 100644 (file)
@@ -189,8 +189,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
        return new_offset;
 }
 
-static int vol_cdev_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int vol_cdev_fsync(struct file *file, int datasync)
 {
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_device *ubi = desc->vol->ubi;
index 82eaf65..ea9b7a0 100644 (file)
@@ -551,8 +551,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id)
        void __iomem *shmem;
 
        if (dev == NULL) {
-               pr_err("%s: net_interrupt(): irq %d for unknown device.\n",
-                       dev->name, irq);
+               pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
                return IRQ_NONE;
        }
 
index c911bfb..9d11dbf 100644 (file)
@@ -294,7 +294,7 @@ int be_cmd_POST(struct be_adapter *adapter)
                } else {
                        return 0;
                }
-       } while (timeout < 20);
+       } while (timeout < 40);
 
        dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
        return -1;
index aa065c7..54b1427 100644 (file)
@@ -1861,7 +1861,7 @@ static int be_setup(struct be_adapter *adapter)
                                goto if_destroy;
                        }
                        vf++;
-               } while (vf < num_vfs);
+               }
        } else if (!be_physfn(adapter)) {
                status = be_cmd_mac_addr_query(adapter, mac,
                        MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
index be90d35..fe92566 100644 (file)
@@ -3367,13 +3367,9 @@ static int cnic_cm_shutdown(struct cnic_dev *dev)
 
 static void cnic_init_context(struct cnic_dev *dev, u32 cid)
 {
-       struct cnic_local *cp = dev->cnic_priv;
        u32 cid_addr;
        int i;
 
-       if (CHIP_NUM(cp) == CHIP_NUM_5709)
-               return;
-
        cid_addr = GET_CID_ADDR(cid);
 
        for (i = 0; i < CTX_SIZE; i += 4)
@@ -3530,14 +3526,11 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
 
        sb_id = cp->status_blk_num;
        tx_cid = 20;
-       cnic_init_context(dev, tx_cid);
-       cnic_init_context(dev, tx_cid + 1);
        cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
        if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
                struct status_block_msix *sblk = cp->status_blk.bnx2;
 
                tx_cid = TX_TSS_CID + sb_id - 1;
-               cnic_init_context(dev, tx_cid);
                CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) |
                        (TX_TSS_CID << 7));
                cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index;
@@ -3556,6 +3549,9 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
                offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
                offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
        } else {
+               cnic_init_context(dev, tx_cid);
+               cnic_init_context(dev, tx_cid + 1);
+
                offset0 = BNX2_L2CTX_TYPE;
                offset1 = BNX2_L2CTX_CMD_TYPE;
                offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
index 110c620..0c55177 100644 (file)
@@ -12,8 +12,8 @@
 #ifndef CNIC_IF_H
 #define CNIC_IF_H
 
-#define CNIC_MODULE_VERSION    "2.1.1"
-#define CNIC_MODULE_RELDATE    "Feb 22, 2010"
+#define CNIC_MODULE_VERSION    "2.1.2"
+#define CNIC_MODULE_RELDATE    "May 26, 2010"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
index 326465f..ddf7a86 100644 (file)
@@ -681,6 +681,8 @@ static int fec_enet_mii_probe(struct net_device *dev)
        struct phy_device *phy_dev = NULL;
        int phy_addr;
 
+       fep->phy_dev = NULL;
+
        /* find the first phy */
        for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
                if (fep->mii_bus->phy_map[phy_addr]) {
@@ -711,6 +713,11 @@ static int fec_enet_mii_probe(struct net_device *dev)
        fep->link = 0;
        fep->full_duplex = 0;
 
+       printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
+               "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name,
+               fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
+               fep->phy_dev->irq);
+
        return 0;
 }
 
@@ -756,13 +763,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        if (mdiobus_register(fep->mii_bus))
                goto err_out_free_mdio_irq;
 
-       if (fec_enet_mii_probe(dev) != 0)
-               goto err_out_unregister_bus;
-
        return 0;
 
-err_out_unregister_bus:
-       mdiobus_unregister(fep->mii_bus);
 err_out_free_mdio_irq:
        kfree(fep->mii_bus->irq);
 err_out_free_mdiobus:
@@ -915,7 +917,12 @@ fec_enet_open(struct net_device *dev)
        if (ret)
                return ret;
 
-       /* schedule a link state check */
+       /* Probe and connect to PHY when open the interface */
+       ret = fec_enet_mii_probe(dev);
+       if (ret) {
+               fec_enet_free_buffers(dev);
+               return ret;
+       }
        phy_start(fep->phy_dev);
        netif_start_queue(dev);
        fep->opened = 1;
@@ -929,10 +936,12 @@ fec_enet_close(struct net_device *dev)
 
        /* Don't know what to do yet. */
        fep->opened = 0;
-       phy_stop(fep->phy_dev);
        netif_stop_queue(dev);
        fec_stop(dev);
 
+       if (fep->phy_dev)
+               phy_disconnect(fep->phy_dev);
+
         fec_enet_free_buffers(dev);
 
        return 0;
@@ -1316,11 +1325,6 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_register;
 
-       printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
-               "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name,
-               fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
-               fep->phy_dev->irq);
-
        return 0;
 
 failed_register:
index 694132e..4e7d1d0 100644 (file)
@@ -1151,8 +1151,7 @@ static int __init yam_init_driver(void)
                dev = alloc_netdev(sizeof(struct yam_port), name,
                                   yam_setup);
                if (!dev) {
-                       printk(KERN_ERR "yam: cannot allocate net device %s\n",
-                              dev->name);
+                       pr_err("yam: cannot allocate net device\n");
                        err = -ENOMEM;
                        goto error;
                }
index c033584..522abe2 100644 (file)
@@ -295,6 +295,10 @@ This option defaults to enabled (set) */
 
 #define MULTICAST_CAM_TABLE_NUM 4
 
+/* TEMAC Synthesis features */
+#define TEMAC_FEATURE_RX_CSUM  (1 << 0)
+#define TEMAC_FEATURE_TX_CSUM  (1 << 1)
+
 /* TX/RX CURDESC_PTR points to first descriptor */
 /* TX/RX TAILDESC_PTR points to last descriptor in linked list */
 
@@ -353,6 +357,7 @@ struct temac_local {
        struct mutex indirect_mutex;
        u32 options;                    /* Current options word */
        int last_link;
+       unsigned int temac_features;
 
        /* Buffer descriptors */
        struct cdmac_bd *tx_bd_v;
index fa7620e..52dcc84 100644 (file)
@@ -245,7 +245,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
                                          CHNL_CTRL_IRQ_COAL_EN);
        /* 0x10220483 */
        /* 0x00100483 */
-       lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
+       lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
                                          CHNL_CTRL_IRQ_EN |
                                          CHNL_CTRL_IRQ_DLY_EN |
                                          CHNL_CTRL_IRQ_COAL_EN |
@@ -574,6 +574,10 @@ static void temac_start_xmit_done(struct net_device *ndev)
                if (cur_p->app4)
                        dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
                cur_p->app0 = 0;
+               cur_p->app1 = 0;
+               cur_p->app2 = 0;
+               cur_p->app3 = 0;
+               cur_p->app4 = 0;
 
                ndev->stats.tx_packets++;
                ndev->stats.tx_bytes += cur_p->len;
@@ -589,6 +593,29 @@ static void temac_start_xmit_done(struct net_device *ndev)
        netif_wake_queue(ndev);
 }
 
+static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
+{
+       struct cdmac_bd *cur_p;
+       int tail;
+
+       tail = lp->tx_bd_tail;
+       cur_p = &lp->tx_bd_v[tail];
+
+       do {
+               if (cur_p->app0)
+                       return NETDEV_TX_BUSY;
+
+               tail++;
+               if (tail >= TX_BD_NUM)
+                       tail = 0;
+
+               cur_p = &lp->tx_bd_v[tail];
+               num_frag--;
+       } while (num_frag >= 0);
+
+       return 0;
+}
+
 static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct temac_local *lp = netdev_priv(ndev);
@@ -603,7 +630,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
        cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-       if (cur_p->app0 & STS_CTRL_APP0_CMPLT) {
+       if (temac_check_tx_bd_space(lp, num_frag)) {
                if (!netif_queue_stopped(ndev)) {
                        netif_stop_queue(ndev);
                        return NETDEV_TX_BUSY;
@@ -613,29 +640,14 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        cur_p->app0 = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               const struct iphdr *ip = ip_hdr(skb);
-               int length = 0, start = 0, insert = 0;
-
-               switch (ip->protocol) {
-               case IPPROTO_TCP:
-                       start = sizeof(struct iphdr) + ETH_HLEN;
-                       insert = sizeof(struct iphdr) + ETH_HLEN + 16;
-                       length = ip->tot_len - sizeof(struct iphdr);
-                       break;
-               case IPPROTO_UDP:
-                       start = sizeof(struct iphdr) + ETH_HLEN;
-                       insert = sizeof(struct iphdr) + ETH_HLEN + 6;
-                       length = ip->tot_len - sizeof(struct iphdr);
-                       break;
-               default:
-                       break;
-               }
-               cur_p->app1 = ((start << 16) | insert);
-               cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr,
-                                               length, ip->protocol, 0);
-               skb->data[insert] = 0;
-               skb->data[insert + 1] = 0;
+               unsigned int csum_start_off = skb_transport_offset(skb);
+               unsigned int csum_index_off = csum_start_off + skb->csum_offset;
+
+               cur_p->app0 |= 1; /* TX Checksum Enabled */
+               cur_p->app1 = (csum_start_off << 16) | csum_index_off;
+               cur_p->app2 = 0;  /* initial checksum seed */
        }
+
        cur_p->app0 |= STS_CTRL_APP0_SOP;
        cur_p->len = skb_headlen(skb);
        cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len,
@@ -699,6 +711,15 @@ static void ll_temac_recv(struct net_device *ndev)
                skb->protocol = eth_type_trans(skb, ndev);
                skb->ip_summed = CHECKSUM_NONE;
 
+               /* if we're doing rx csum offload, set it up */
+               if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
+                       (skb->protocol == __constant_htons(ETH_P_IP)) &&
+                       (skb->len > 64)) {
+
+                       skb->csum = cur_p->app3 & 0xFFFF;
+                       skb->ip_summed = CHECKSUM_COMPLETE;
+               }
+
                netif_rx(skb);
 
                ndev->stats.rx_packets++;
@@ -883,6 +904,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        struct temac_local *lp;
        struct net_device *ndev;
        const void *addr;
+       __be32 *p;
        int size, rc = 0;
 
        /* Init network device structure */
@@ -926,6 +948,18 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
                goto nodev;
        }
 
+       /* Setup checksum offload, but default to off if not specified */
+       lp->temac_features = 0;
+       p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
+       if (p && be32_to_cpu(*p)) {
+               lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+               /* Can checksum TCP/UDP over IPv4. */
+               ndev->features |= NETIF_F_IP_CSUM;
+       }
+       p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
+       if (p && be32_to_cpu(*p))
+               lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+
        /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
        np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
        if (!np) {
@@ -950,7 +984,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
 
        lp->rx_irq = irq_of_parse_and_map(np, 0);
        lp->tx_irq = irq_of_parse_and_map(np, 1);
-       if (!lp->rx_irq || !lp->tx_irq) {
+       if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {
                dev_err(&op->dev, "could not determine irqs\n");
                rc = -ENOMEM;
                goto nodev;
index 7aaae2d..80c11d1 100644 (file)
@@ -130,4 +130,21 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
 }
 #endif
 
+#ifdef CONFIG_ACPI_APEI
+extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
+#else
+static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
+{
+       if (pci_dev->__aer_firmware_first_valid)
+               return pci_dev->__aer_firmware_first;
+       return 0;
+}
+#endif
+
+static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
+                                                int enable)
+{
+       pci_dev->__aer_firmware_first = !!enable;
+       pci_dev->__aer_firmware_first_valid = 1;
+}
 #endif /* _AERDRV_H_ */
index 0481408..f278d7b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 #include <linux/pci-acpi.h>
 #include <linux/delay.h>
+#include <acpi/apei.h>
 #include "aerdrv.h"
 
 /**
@@ -53,3 +54,79 @@ int aer_osc_setup(struct pcie_device *pciedev)
 
        return 0;
 }
+
+#ifdef CONFIG_ACPI_APEI
+static inline int hest_match_pci(struct acpi_hest_aer_common *p,
+                                struct pci_dev *pci)
+{
+       return  (0           == pci_domain_nr(pci->bus) &&
+                p->bus      == pci->bus->number &&
+                p->device   == PCI_SLOT(pci->devfn) &&
+                p->function == PCI_FUNC(pci->devfn));
+}
+
+struct aer_hest_parse_info {
+       struct pci_dev *pci_dev;
+       int firmware_first;
+};
+
+static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       struct aer_hest_parse_info *info = data;
+       struct acpi_hest_aer_common *p;
+       u8 pcie_type = 0;
+       u8 bridge = 0;
+       int ff = 0;
+
+       switch (hest_hdr->type) {
+       case ACPI_HEST_TYPE_AER_ROOT_PORT:
+               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
+               break;
+       case ACPI_HEST_TYPE_AER_ENDPOINT:
+               pcie_type = PCI_EXP_TYPE_ENDPOINT;
+               break;
+       case ACPI_HEST_TYPE_AER_BRIDGE:
+               if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
+                       bridge = 1;
+               break;
+       default:
+               return 0;
+       }
+
+       p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
+       if (p->flags & ACPI_HEST_GLOBAL) {
+               if ((info->pci_dev->is_pcie &&
+                    info->pci_dev->pcie_type == pcie_type) || bridge)
+                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       } else
+               if (hest_match_pci(p, info->pci_dev))
+                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       info->firmware_first = ff;
+
+       return 0;
+}
+
+static void aer_set_firmware_first(struct pci_dev *pci_dev)
+{
+       int rc;
+       struct aer_hest_parse_info info = {
+               .pci_dev        = pci_dev,
+               .firmware_first = 0,
+       };
+
+       rc = apei_hest_parse(aer_hest_parse, &info);
+
+       if (rc)
+               pci_dev->__aer_firmware_first = 0;
+       else
+               pci_dev->__aer_firmware_first = info.firmware_first;
+       pci_dev->__aer_firmware_first_valid = 1;
+}
+
+int pcie_aer_get_firmware_first(struct pci_dev *dev)
+{
+       if (!dev->__aer_firmware_first_valid)
+               aer_set_firmware_first(dev);
+       return dev->__aer_firmware_first;
+}
+#endif
index df2d686..8af4f61 100644 (file)
@@ -36,7 +36,7 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
        u16 reg16 = 0;
        int pos;
 
-       if (dev->aer_firmware_first)
+       if (pcie_aer_get_firmware_first(dev))
                return -EIO;
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@@ -63,7 +63,7 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev)
        u16 reg16 = 0;
        int pos;
 
-       if (dev->aer_firmware_first)
+       if (pcie_aer_get_firmware_first(dev))
                return -EIO;
 
        pos = pci_pcie_cap(dev);
@@ -771,7 +771,7 @@ void aer_isr(struct work_struct *work)
  */
 int aer_init(struct pcie_device *dev)
 {
-       if (dev->port->aer_firmware_first) {
+       if (pcie_aer_get_firmware_first(dev->port)) {
                dev_printk(KERN_DEBUG, &dev->device,
                           "PCIe errors handled by platform firmware.\n");
                goto out;
@@ -785,7 +785,7 @@ out:
        if (forceload) {
                dev_printk(KERN_DEBUG, &dev->device,
                           "aerdrv forceload requested.\n");
-               dev->port->aer_firmware_first = 0;
+               pcie_aer_force_firmware_first(dev->port, 0);
                return 0;
        }
        return -ENXIO;
index c82548a..f4adba2 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
-#include <acpi/acpi_hest.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -904,12 +903,6 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev)
                pdev->is_hotplug_bridge = 1;
 }
 
-static void set_pci_aer_firmware_first(struct pci_dev *pdev)
-{
-       if (acpi_hest_firmware_first_pci(pdev))
-               pdev->aer_firmware_first = 1;
-}
-
 #define LEGACY_IO_RESOURCE     (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
 
 /**
@@ -939,7 +932,6 @@ int pci_setup_device(struct pci_dev *dev)
        dev->multifunction = !!(hdr_type & 0x80);
        dev->error_state = pci_channel_io_normal;
        set_pcie_port_type(dev);
-       set_pci_aer_firmware_first(dev);
 
        list_for_each_entry(slot, &dev->bus->slots, list)
                if (PCI_SLOT(dev->devfn) == slot->number)
index 5664321..8070e07 100644 (file)
@@ -1124,7 +1124,7 @@ static void rio_update_route_tables(struct rio_mport *port)
 
 /**
  * rio_init_em - Initializes RIO Error Management (for switches)
- * @port: Master port associated with the RIO network
+ * @rdev: RIO device
  *
  * For each enumerated switch, call device-specific error management
  * initialization routine (if supplied by the switch driver).
index 777e099..08fa453 100644 (file)
@@ -338,7 +338,7 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
 
 /**
  * rio_request_inb_pwrite - request inbound port-write message service
- * @mport: RIO device to which register inbound port-write callback routine
+ * @rdev: RIO device to which register inbound port-write callback routine
  * @pwcback: Callback routine to execute when port-write is received
  *
  * Binds a port-write callback function to the RapidIO device.
@@ -385,7 +385,10 @@ EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
 /**
  * rio_mport_get_physefb - Helper function that returns register offset
  *                      for Physical Layer Extended Features Block.
- * @rdev: RIO device
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
  */
 u32
 rio_mport_get_physefb(struct rio_mport *port, int local,
@@ -430,7 +433,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
 
 /**
  * rio_get_comptag - Begin or continue searching for a RIO device by component tag
- * @comp_tag: RIO component tad to match
+ * @comp_tag: RIO component tag to match
  * @from: Previous RIO device found in search, or %NULL for new search
  *
  * Iterates through the list of known RIO devices. If a RIO device is
@@ -835,7 +838,6 @@ int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  * rio_std_route_clr_table - Clear swotch route table using standard registers
  *   defined in RIO specification rev.1.3.
  * @mport: Master port to issue transaction
- * @local: Indicate a local master port or remote device access
  * @destid: Destination ID of the device
  * @hopcount: Number of switch hops to the device
  * @table: routing table ID (global or port-specific)
index 8dc0383..4a789e5 100644 (file)
@@ -119,7 +119,7 @@ static int s5p_serial_probe(struct platform_device *pdev)
        return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
 }
 
-static struct platform_driver s5p_serial_drv = {
+static struct platform_driver s5p_serial_driver = {
        .probe          = s5p_serial_probe,
        .remove         = __devexit_p(s3c24xx_serial_remove),
        .driver         = {
@@ -130,19 +130,19 @@ static struct platform_driver s5p_serial_drv = {
 
 static int __init s5pv210_serial_console_init(void)
 {
-       return s3c24xx_serial_initconsole(&s5p_serial_drv, s5p_uart_inf);
+       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
 }
 
 console_initcall(s5pv210_serial_console_init);
 
 static int __init s5p_serial_init(void)
 {
-       return s3c24xx_serial_init(&s5p_serial_drv, *s5p_uart_inf);
+       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
 }
 
 static void __exit s5p_serial_exit(void)
 {
-       platform_driver_unregister(&s5p_serial_drv);
+       platform_driver_unregister(&s5p_serial_driver);
 }
 
 module_init(s5p_serial_init);
index 9286e86..643b413 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 
 #include "netfs.h"
 
@@ -880,7 +879,7 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
 /*
  * We want fsync() to work on POHMELFS.
  */
-static int pohmelfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int pohmelfs_fsync(struct file *file, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct writeback_control wbc = {
@@ -969,13 +968,6 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
                goto err_out_exit;
        }
 
-       if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-           (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               err = dquot_transfer(inode, attr);
-               if (err)
-                       goto err_out_exit;
-       }
-
        err = inode_setattr(inode, attr);
        if (err) {
                dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
index 6b8bf8c..43abf55 100644 (file)
@@ -794,7 +794,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 }
 
 static int
-printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
+printer_fsync(struct file *fd, int datasync)
 {
        struct printer_dev      *dev = fd->private_data;
        unsigned long           flags;
index aa88911..0f41c91 100644 (file)
@@ -593,17 +593,17 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
        int r;
        switch (ioctl) {
        case VHOST_NET_SET_BACKEND:
-               r = copy_from_user(&backend, argp, sizeof backend);
-               if (r < 0)
-                       return r;
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
                return vhost_net_set_backend(n, backend.index, backend.fd);
        case VHOST_GET_FEATURES:
                features = VHOST_FEATURES;
-               return copy_to_user(featurep, &features, sizeof features);
+               if (copy_to_user(featurep, &features, sizeof features))
+                       return -EFAULT;
+               return 0;
        case VHOST_SET_FEATURES:
-               r = copy_from_user(&features, featurep, sizeof features);
-               if (r < 0)
-                       return r;
+               if (copy_from_user(&features, featurep, sizeof features))
+                       return -EFAULT;
                if (features & ~VHOST_FEATURES)
                        return -EOPNOTSUPP;
                return vhost_net_set_features(n, features);
index c6fb8e9..3b83382 100644 (file)
@@ -320,10 +320,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem, *oldmem;
        unsigned long size = offsetof(struct vhost_memory, regions);
-       long r;
-       r = copy_from_user(&mem, m, size);
-       if (r)
-               return r;
+       if (copy_from_user(&mem, m, size))
+               return -EFAULT;
        if (mem.padding)
                return -EOPNOTSUPP;
        if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
@@ -333,15 +331,16 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -ENOMEM;
 
        memcpy(newmem, &mem, size);
-       r = copy_from_user(newmem->regions, m->regions,
-                          mem.nregions * sizeof *m->regions);
-       if (r) {
+       if (copy_from_user(newmem->regions, m->regions,
+                          mem.nregions * sizeof *m->regions)) {
                kfree(newmem);
-               return r;
+               return -EFAULT;
        }
 
-       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL)))
+       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) {
+               kfree(newmem);
                return -EFAULT;
+       }
        oldmem = d->memory;
        rcu_assign_pointer(d->memory, newmem);
        synchronize_rcu();
@@ -374,7 +373,7 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
        r = get_user(idx, idxp);
        if (r < 0)
                return r;
-       if (idx > d->nvqs)
+       if (idx >= d->nvqs)
                return -ENOBUFS;
 
        vq = d->vqs + idx;
@@ -389,9 +388,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EBUSY;
                        break;
                }
-               r = copy_from_user(&s, argp, sizeof s);
-               if (r < 0)
+               if (copy_from_user(&s, argp, sizeof s)) {
+                       r = -EFAULT;
                        break;
+               }
                if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
                        r = -EINVAL;
                        break;
@@ -405,9 +405,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EBUSY;
                        break;
                }
-               r = copy_from_user(&s, argp, sizeof s);
-               if (r < 0)
+               if (copy_from_user(&s, argp, sizeof s)) {
+                       r = -EFAULT;
                        break;
+               }
                if (s.num > 0xffff) {
                        r = -EINVAL;
                        break;
@@ -419,12 +420,14 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
        case VHOST_GET_VRING_BASE:
                s.index = idx;
                s.num = vq->last_avail_idx;
-               r = copy_to_user(argp, &s, sizeof s);
+               if (copy_to_user(argp, &s, sizeof s))
+                       r = -EFAULT;
                break;
        case VHOST_SET_VRING_ADDR:
-               r = copy_from_user(&a, argp, sizeof a);
-               if (r < 0)
+               if (copy_from_user(&a, argp, sizeof a)) {
+                       r = -EFAULT;
                        break;
+               }
                if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
                        r = -EOPNOTSUPP;
                        break;
@@ -477,9 +480,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                vq->used = (void __user *)(unsigned long)a.used_user_addr;
                break;
        case VHOST_SET_VRING_KICK:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -492,9 +496,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        filep = eventfp;
                break;
        case VHOST_SET_VRING_CALL:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -510,9 +515,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        filep = eventfp;
                break;
        case VHOST_SET_VRING_ERR:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -575,9 +581,10 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
                r = vhost_set_memory(d, argp);
                break;
        case VHOST_SET_LOG_BASE:
-               r = copy_from_user(&p, argp, sizeof p);
-               if (r < 0)
+               if (copy_from_user(&p, argp, sizeof p)) {
+                       r = -EFAULT;
                        break;
+               }
                if ((u64)(unsigned long)p != p) {
                        r = -EFAULT;
                        break;
index 1105a59..073c9b4 100644 (file)
@@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
        return 0;
 }
 
-int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
+int fb_deferred_io_fsync(struct file *file, int datasync)
 {
        struct fb_info *info = file->private_data;
 
index 25b300e..2bedc6c 100644 (file)
@@ -257,15 +257,13 @@ v9fs_file_write(struct file *filp, const char __user * data,
        return total;
 }
 
-static int v9fs_file_fsync(struct file *filp, struct dentry *dentry,
-                                       int datasync)
+static int v9fs_file_fsync(struct file *filp, int datasync)
 {
        struct p9_fid *fid;
        struct p9_wstat wstat;
        int retval;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "filp %p dentry %p datasync %x\n", filp,
-                                               dentry, datasync);
+       P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 
        fid = filp->private_data;
        v9fs_blank_wstat(&wstat);
index 23aa52f..f4287e4 100644 (file)
@@ -197,7 +197,7 @@ const struct file_operations adfs_dir_operations = {
        .read           = generic_read_dir,
        .llseek         = generic_file_llseek,
        .readdir        = adfs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static int
index 005ea34..a36da53 100644 (file)
@@ -26,7 +26,7 @@ const struct file_operations adfs_file_operations = {
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .splice_read    = generic_file_splice_read,
index 0f5e309..6f850b0 100644 (file)
@@ -322,8 +322,9 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
        if (error)
                goto out;
 
+       /* XXX: this is missing some actual on-disk truncation.. */
        if (ia_valid & ATTR_SIZE)
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
 
        if (error)
                goto out;
index 861dae6..f05b615 100644 (file)
@@ -183,7 +183,7 @@ extern int                   affs_add_entry(struct inode *dir, struct inode *inode, struct dent
 
 void           affs_free_prealloc(struct inode *inode);
 extern void    affs_truncate(struct inode *);
-int            affs_file_fsync(struct file *, struct dentry *, int);
+int            affs_file_fsync(struct file *, int);
 
 /* dir.c */
 
index 184e55c..322710c 100644 (file)
@@ -916,9 +916,9 @@ affs_truncate(struct inode *inode)
        affs_free_prealloc(inode);
 }
 
-int affs_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int affs_file_fsync(struct file *filp, int datasync)
 {
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int ret, err;
 
        ret = write_inode_now(inode, 0);
index 807f284..5f679b7 100644 (file)
@@ -740,7 +740,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
                              unsigned long, loff_t);
 extern int afs_writeback_all(struct afs_vnode *);
-extern int afs_fsync(struct file *, struct dentry *, int);
+extern int afs_fsync(struct file *, int);
 
 
 /*****************************************************************************/
index 3bed54a..3dab9e9 100644 (file)
@@ -701,8 +701,9 @@ int afs_writeback_all(struct afs_vnode *vnode)
  * - the return status from this call provides a reliable indication of
  *   whether any write errors occurred for this process.
  */
-int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int afs_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct afs_writeback *wb, *xwb;
        struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
        int ret;
index 48fdeeb..1ccf25c 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -527,7 +527,7 @@ static void aio_fput_routine(struct work_struct *data)
 
                /* Complete the fput(s) */
                if (req->ki_filp != NULL)
-                       __fput(req->ki_filp);
+                       fput(req->ki_filp);
 
                /* Link the iocb into the context's free list */
                spin_lock_irq(&ctx->ctx_lock);
@@ -560,11 +560,11 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
 
        /*
         * Try to optimize the aio and eventfd file* puts, by avoiding to
-        * schedule work in case it is not __fput() time. In normal cases,
+        * schedule work in case it is not final fput() time. In normal cases,
         * we would not be holding the last reference to the file*, so
         * this function will be executed w/out any aio kthread wakeup.
         */
-       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
+       if (unlikely(!fput_atomic(req->ki_filp))) {
                get_ioctx(ctx);
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
index 9bd4b38..e4b75d6 100644 (file)
@@ -205,7 +205,7 @@ static struct inode *anon_inode_mkinode(void)
         * that it already _is_ on the dirty list.
         */
        inode->i_state = I_DIRTY;
-       inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+       inode->i_mode = S_IRUSR | S_IWUSR;
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
        inode->i_flags |= S_PRIVATE;
index 0815e93..b4fa3b0 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -67,14 +67,14 @@ EXPORT_SYMBOL(inode_change_ok);
  * @offset:    the new size to assign to the inode
  * @Returns:   0 on success, -ve errno on failure
  *
+ * inode_newsize_ok must be called with i_mutex held.
+ *
  * inode_newsize_ok will check filesystem limits and ulimits to check that the
  * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
  * when necessary. Caller must not proceed with inode size change if failure is
  * returned. @inode must be a file (not directory), with appropriate
  * permissions to allow truncate (inode_newsize_ok does NOT check these
  * conditions).
- *
- * inode_newsize_ok must be called with i_mutex held.
  */
 int inode_newsize_ok(const struct inode *inode, loff_t offset)
 {
@@ -104,17 +104,25 @@ out_big:
 }
 EXPORT_SYMBOL(inode_newsize_ok);
 
-int inode_setattr(struct inode * inode, struct iattr * attr)
+/**
+ * generic_setattr - copy simple metadata updates into the generic inode
+ * @inode:     the inode to be updated
+ * @attr:      the new attributes
+ *
+ * generic_setattr must be called with i_mutex held.
+ *
+ * generic_setattr updates the inode's metadata with that specified
+ * in attr. Noticably missing is inode size update, which is more complex
+ * as it requires pagecache updates. See simple_setsize.
+ *
+ * The inode is not marked as dirty after this operation. The rationale is
+ * that for "simple" filesystems, the struct inode is the inode storage.
+ * The caller is free to mark the inode dirty afterwards if needed.
+ */
+void generic_setattr(struct inode *inode, const struct iattr *attr)
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       if (ia_valid & ATTR_SIZE &&
-           attr->ia_size != i_size_read(inode)) {
-               int error = vmtruncate(inode, attr->ia_size);
-               if (error)
-                       return error;
-       }
-
        if (ia_valid & ATTR_UID)
                inode->i_uid = attr->ia_uid;
        if (ia_valid & ATTR_GID)
@@ -135,6 +143,28 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
                        mode &= ~S_ISGID;
                inode->i_mode = mode;
        }
+}
+EXPORT_SYMBOL(generic_setattr);
+
+/*
+ * note this function is deprecated, the new truncate sequence should be
+ * used instead -- see eg. simple_setsize, generic_setattr.
+ */
+int inode_setattr(struct inode *inode, const struct iattr *attr)
+{
+       unsigned int ia_valid = attr->ia_valid;
+
+       if (ia_valid & ATTR_SIZE &&
+           attr->ia_size != i_size_read(inode)) {
+               int error;
+
+               error = vmtruncate(inode, attr->ia_size);
+               if (error)
+                       return error;
+       }
+
+       generic_setattr(inode, attr);
+
        mark_inode_dirty(inode);
 
        return 0;
index a05287a..52e59bf 100644 (file)
@@ -93,8 +93,7 @@ static int bad_file_release(struct inode *inode, struct file *filp)
        return -EIO;
 }
 
-static int bad_file_fsync(struct file *file, struct dentry *dentry,
-                       int datasync)
+static int bad_file_fsync(struct file *file, int datasync)
 {
        return -EIO;
 }
index 8f73841..d967e05 100644 (file)
@@ -78,7 +78,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir)
 const struct file_operations bfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = bfs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .llseek         = generic_file_llseek,
 };
 
index 26e5f50..7346c96 100644 (file)
@@ -172,8 +172,9 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
 
-       return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode),
-                               iov, offset, nr_segs, blkdev_get_blocks, NULL);
+       return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
+                               I_BDEV(inode), iov, offset, nr_segs,
+                               blkdev_get_blocks, NULL);
 }
 
 int __sync_blockdev(struct block_device *bdev, int wait)
@@ -309,8 +310,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping,
                        struct page **pagep, void **fsdata)
 {
        *pagep = NULL;
-       return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               blkdev_get_block);
+       return block_write_begin_newtrunc(file, mapping, pos, len, flags,
+                               pagep, fsdata, blkdev_get_block);
 }
 
 static int blkdev_write_end(struct file *file, struct address_space *mapping,
@@ -358,12 +359,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
        return retval;
 }
        
-/*
- *     Filp is never NULL; the only case when ->fsync() is called with
- *     NULL first argument is nfsd_sync_dir() and that's not a directory.
- */
-int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int blkdev_fsync(struct file *filp, int datasync)
 {
        struct inode *bd_inode = filp->f_mapping->host;
        struct block_device *bdev = I_BDEV(bd_inode);
index e9bf864..29c2009 100644 (file)
@@ -2434,7 +2434,7 @@ void btrfs_update_iflags(struct inode *inode);
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
 
 /* file.c */
-int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
+int btrfs_sync_file(struct file *file, int datasync);
 int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
 int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
index 79437c5..787b50a 100644 (file)
@@ -1101,8 +1101,9 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
  * important optimization for directories because holding the mutex prevents
  * new operations on the dir while we write to disk.
  */
-int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int btrfs_sync_file(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret = 0;
index e8aa708..d54812b 100644 (file)
@@ -1949,14 +1949,11 @@ static int __block_commit_write(struct inode *inode, struct page *page,
 }
 
 /*
- * block_write_begin takes care of the basic task of block allocation and
- * bringing partial write blocks uptodate first.
- *
- * If *pagep is not NULL, then block_write_begin uses the locked page
- * at *pagep rather than allocating its own. In this case, the page will
- * not be unlocked or deallocated on failure.
+ * Filesystems implementing the new truncate sequence should use the
+ * _newtrunc postfix variant which won't incorrectly call vmtruncate.
+ * The filesystem needs to handle block truncation upon failure.
  */
-int block_write_begin(struct file *file, struct address_space *mapping,
+int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata,
                        get_block_t *get_block)
@@ -1992,20 +1989,50 @@ int block_write_begin(struct file *file, struct address_space *mapping,
                        unlock_page(page);
                        page_cache_release(page);
                        *pagep = NULL;
-
-                       /*
-                        * prepare_write() may have instantiated a few blocks
-                        * outside i_size.  Trim these off again. Don't need
-                        * i_size_read because we hold i_mutex.
-                        */
-                       if (pos + len > inode->i_size)
-                               vmtruncate(inode, inode->i_size);
                }
        }
 
 out:
        return status;
 }
+EXPORT_SYMBOL(block_write_begin_newtrunc);
+
+/*
+ * block_write_begin takes care of the basic task of block allocation and
+ * bringing partial write blocks uptodate first.
+ *
+ * If *pagep is not NULL, then block_write_begin uses the locked page
+ * at *pagep rather than allocating its own. In this case, the page will
+ * not be unlocked or deallocated on failure.
+ */
+int block_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata,
+                       get_block_t *get_block)
+{
+       int ret;
+
+       ret = block_write_begin_newtrunc(file, mapping, pos, len, flags,
+                                       pagep, fsdata, get_block);
+
+       /*
+        * prepare_write() may have instantiated a few blocks
+        * outside i_size.  Trim these off again. Don't need
+        * i_size_read because we hold i_mutex.
+        *
+        * Filesystems which pass down their own page also cannot
+        * call into vmtruncate here because it would lead to lock
+        * inversion problems (*pagep is locked). This is a further
+        * example of where the old truncate sequence is inadequate.
+        */
+       if (unlikely(ret) && *pagep == NULL) {
+               loff_t isize = mapping->host->i_size;
+               if (pos + len > isize)
+                       vmtruncate(mapping->host, isize);
+       }
+
+       return ret;
+}
 EXPORT_SYMBOL(block_write_begin);
 
 int block_write_end(struct file *file, struct address_space *mapping,
@@ -2324,7 +2351,7 @@ out:
  * For moronic filesystems that do not allow holes in file.
  * We may have to extend the file.
  */
-int cont_write_begin(struct file *file, struct address_space *mapping,
+int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata,
                        get_block_t *get_block, loff_t *bytes)
@@ -2345,11 +2372,30 @@ int cont_write_begin(struct file *file, struct address_space *mapping,
        }
 
        *pagep = NULL;
-       err = block_write_begin(file, mapping, pos, len,
+       err = block_write_begin_newtrunc(file, mapping, pos, len,
                                flags, pagep, fsdata, get_block);
 out:
        return err;
 }
+EXPORT_SYMBOL(cont_write_begin_newtrunc);
+
+int cont_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata,
+                       get_block_t *get_block, loff_t *bytes)
+{
+       int ret;
+
+       ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
+                                       pagep, fsdata, get_block, bytes);
+       if (unlikely(ret)) {
+               loff_t isize = mapping->host->i_size;
+               if (pos + len > isize)
+                       vmtruncate(mapping->host, isize);
+       }
+
+       return ret;
+}
 EXPORT_SYMBOL(cont_write_begin);
 
 int block_prepare_write(struct page *page, unsigned from, unsigned to,
@@ -2381,7 +2427,7 @@ EXPORT_SYMBOL(block_commit_write);
  *
  * We are not allowed to take the i_mutex here so we have to play games to
  * protect against truncate races as the page could now be beyond EOF.  Because
- * vmtruncate() writes the inode size before removing pages, once we have the
+ * truncate writes the inode size before removing pages, once we have the
  * page lock we can determine safely if the page is beyond EOF. If it is not
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
@@ -2464,10 +2510,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
 }
 
 /*
- * On entry, the page is fully not uptodate.
- * On exit the page is fully uptodate in the areas outside (from,to)
+ * Filesystems implementing the new truncate sequence should use the
+ * _newtrunc postfix variant which won't incorrectly call vmtruncate.
+ * The filesystem needs to handle block truncation upon failure.
  */
-int nobh_write_begin(struct file *file, struct address_space *mapping,
+int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata,
                        get_block_t *get_block)
@@ -2500,8 +2547,8 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
                unlock_page(page);
                page_cache_release(page);
                *pagep = NULL;
-               return block_write_begin(file, mapping, pos, len, flags, pagep,
-                                       fsdata, get_block);
+               return block_write_begin_newtrunc(file, mapping, pos, len,
+                                       flags, pagep, fsdata, get_block);
        }
 
        if (PageMappedToDisk(page))
@@ -2605,8 +2652,34 @@ out_release:
        page_cache_release(page);
        *pagep = NULL;
 
-       if (pos + len > inode->i_size)
-               vmtruncate(inode, inode->i_size);
+       return ret;
+}
+EXPORT_SYMBOL(nobh_write_begin_newtrunc);
+
+/*
+ * On entry, the page is fully not uptodate.
+ * On exit the page is fully uptodate in the areas outside (from,to)
+ */
+int nobh_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata,
+                       get_block_t *get_block)
+{
+       int ret;
+
+       ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags,
+                                       pagep, fsdata, get_block);
+
+       /*
+        * prepare_write() may have instantiated a few blocks
+        * outside i_size.  Trim these off again. Don't need
+        * i_size_read because we hold i_mutex.
+        */
+       if (unlikely(ret)) {
+               loff_t isize = mapping->host->i_size;
+               if (pos + len > isize)
+                       vmtruncate(mapping->host, isize);
+       }
 
        return ret;
 }
index 9f46de2..89490be 100644 (file)
@@ -1,7 +1,6 @@
 #include "ceph_debug.h"
 
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 
@@ -217,8 +216,8 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
                if (ac->protocol != protocol) {
                        ret = ceph_auth_init_protocol(ac, protocol);
                        if (ret) {
-                               pr_err("error %d on auth method %s init\n",
-                                      ret, ac->ops->name);
+                               pr_err("error %d on auth protocol %d init\n",
+                                      ret, protocol);
                                goto out;
                        }
                }
@@ -247,7 +246,7 @@ int ceph_build_auth(struct ceph_auth_client *ac,
        if (!ac->protocol)
                return ceph_auth_build_hello(ac, msg_buf, msg_len);
        BUG_ON(!ac->ops);
-       if (!ac->ops->is_authenticated(ac))
+       if (ac->ops->should_authenticate(ac))
                return ceph_build_auth_request(ac, msg_buf, msg_len);
        return 0;
 }
index 4429a70..d38a2fb 100644 (file)
@@ -23,6 +23,12 @@ struct ceph_auth_client_ops {
         */
        int (*is_authenticated)(struct ceph_auth_client *ac);
 
+       /*
+        * true if we should (re)authenticate, e.g., when our tickets
+        * are getting old and crusty.
+        */
+       int (*should_authenticate)(struct ceph_auth_client *ac);
+
        /*
         * build requests and process replies during monitor
         * handshake.  if handle_reply returns -EAGAIN, we build
index 24407c1..ad1dc21 100644 (file)
@@ -31,6 +31,13 @@ static int is_authenticated(struct ceph_auth_client *ac)
        return !xi->starting;
 }
 
+static int should_authenticate(struct ceph_auth_client *ac)
+{
+       struct ceph_auth_none_info *xi = ac->private;
+
+       return xi->starting;
+}
+
 /*
  * the generic auth code decode the global_id, and we carry no actual
  * authenticate state, so nothing happens here.
@@ -98,6 +105,7 @@ static const struct ceph_auth_client_ops ceph_auth_none_ops = {
        .reset = reset,
        .destroy = destroy,
        .is_authenticated = is_authenticated,
+       .should_authenticate = should_authenticate,
        .handle_reply = handle_reply,
        .create_authorizer = ceph_auth_none_create_authorizer,
        .destroy_authorizer = ceph_auth_none_destroy_authorizer,
index 7b20623..83d4d27 100644 (file)
@@ -27,6 +27,17 @@ static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
        return (ac->want_keys & xi->have_keys) == ac->want_keys;
 }
 
+static int ceph_x_should_authenticate(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi = ac->private;
+       int need;
+
+       ceph_x_validate_tickets(ac, &need);
+       dout("ceph_x_should_authenticate want=%d need=%d have=%d\n",
+            ac->want_keys, need, xi->have_keys);
+       return need != 0;
+}
+
 static int ceph_x_encrypt_buflen(int ilen)
 {
        return sizeof(struct ceph_x_encrypt_header) + ilen + 16 +
@@ -620,6 +631,7 @@ static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
 static const struct ceph_auth_client_ops ceph_x_ops = {
        .name = "x",
        .is_authenticated = ceph_x_is_authenticated,
+       .should_authenticate = ceph_x_should_authenticate,
        .build_request = ceph_x_build_request,
        .handle_reply = ceph_x_handle_reply,
        .create_authorizer = ceph_x_create_authorizer,
index 0dd0b81..ae3e3a3 100644 (file)
@@ -1776,9 +1776,9 @@ out:
        spin_unlock(&ci->i_unsafe_lock);
 }
 
-int ceph_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ceph_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ceph_inode_info *ci = ceph_inode(inode);
        unsigned flush_tid;
        int ret;
index 3b9eeed..2fa992e 100644 (file)
@@ -265,16 +265,17 @@ extern const char *ceph_mds_state_name(int s);
  *  - they also define the lock ordering by the MDS
  *  - a few of these are internal to the mds
  */
-#define CEPH_LOCK_DN          1
-#define CEPH_LOCK_ISNAP       2
-#define CEPH_LOCK_IVERSION    4     /* mds internal */
-#define CEPH_LOCK_IFILE       8     /* mds internal */
-#define CEPH_LOCK_IAUTH       32
-#define CEPH_LOCK_ILINK       64
-#define CEPH_LOCK_IDFT        128   /* dir frag tree */
-#define CEPH_LOCK_INEST       256   /* mds internal */
-#define CEPH_LOCK_IXATTR      512
-#define CEPH_LOCK_INO         2048  /* immutable inode bits; not a lock */
+#define CEPH_LOCK_DVERSION    1
+#define CEPH_LOCK_DN          2
+#define CEPH_LOCK_ISNAP       16
+#define CEPH_LOCK_IVERSION    32    /* mds internal */
+#define CEPH_LOCK_IFILE       64
+#define CEPH_LOCK_IAUTH       128
+#define CEPH_LOCK_ILINK       256
+#define CEPH_LOCK_IDFT        512   /* dir frag tree */
+#define CEPH_LOCK_INEST       1024  /* mds internal */
+#define CEPH_LOCK_IXATTR      2048
+#define CEPH_LOCK_INO         8192  /* immutable inode bits; not a lock */
 
 /* client_session ops */
 enum {
index 4fd3090..f857193 100644 (file)
@@ -587,7 +587,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
        req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        /* we only need inode linkage */
@@ -1107,10 +1107,9 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
  * an fsync() on a dir will wait for any uncommitted directory
  * operations to commit.
  */
-static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int ceph_dir_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct list_head *head = &ci->i_unsafe_dirops;
        struct ceph_mds_request *req;
index 1744764..4480cb1 100644 (file)
@@ -133,7 +133,7 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,
                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
                                               USE_ANY_MDS);
                if (IS_ERR(req))
-                       return ERR_PTR(PTR_ERR(req));
+                       return ERR_CAST(req);
 
                req->r_ino1 = vino;
                req->r_ino2.ino = cfh->parent_ino;
index 6512b67..6251a15 100644 (file)
@@ -230,7 +230,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
        /* do the open */
        req = prepare_open_request(dir->i_sb, flags, mode);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        if (flags & O_CREAT) {
index a81b8b6..226f5a5 100644 (file)
@@ -69,7 +69,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
 
        BUG_ON(!S_ISDIR(parent->i_mode));
        if (IS_ERR(inode))
-               return ERR_PTR(PTR_ERR(inode));
+               return inode;
        inode->i_mode = parent->i_mode;
        inode->i_uid = parent->i_uid;
        inode->i_gid = parent->i_gid;
index 885aa57..b49f128 100644 (file)
@@ -1768,12 +1768,12 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
        mutex_unlock(&mdsc->mutex);
        dout("do_request waiting\n");
        if (req->r_timeout) {
-               err = (long)wait_for_completion_interruptible_timeout(
+               err = (long)wait_for_completion_killable_timeout(
                        &req->r_completion, req->r_timeout);
                if (err == 0)
                        err = -EIO;
        } else {
-               err = wait_for_completion_interruptible(&req->r_completion);
+               err = wait_for_completion_killable(&req->r_completion);
        }
        dout("do_request waited, got %d\n", err);
        mutex_lock(&mdsc->mutex);
@@ -2014,16 +2014,21 @@ static void handle_forward(struct ceph_mds_client *mdsc,
        mutex_lock(&mdsc->mutex);
        req = __lookup_request(mdsc, tid);
        if (!req) {
-               dout("forward %llu to mds%d - req dne\n", tid, next_mds);
+               dout("forward tid %llu to mds%d - req dne\n", tid, next_mds);
                goto out;  /* dup reply? */
        }
 
-       if (fwd_seq <= req->r_num_fwd) {
-               dout("forward %llu to mds%d - old seq %d <= %d\n",
+       if (req->r_aborted) {
+               dout("forward tid %llu aborted, unregistering\n", tid);
+               __unregister_request(mdsc, req);
+       } else if (fwd_seq <= req->r_num_fwd) {
+               dout("forward tid %llu to mds%d - old seq %d <= %d\n",
                     tid, next_mds, req->r_num_fwd, fwd_seq);
        } else {
                /* resend. forward race not possible; mds would drop */
-               dout("forward %llu to mds%d (we resend)\n", tid, next_mds);
+               dout("forward tid %llu to mds%d (we resend)\n", tid, next_mds);
+               BUG_ON(req->r_err);
+               BUG_ON(req->r_got_result);
                req->r_num_fwd = fwd_seq;
                req->r_resend_mds = next_mds;
                put_request_session(req);
@@ -2541,7 +2546,7 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
                return;
        lease = msg->front.iov_base;
        lease->action = action;
-       lease->mask = cpu_to_le16(CEPH_LOCK_DN);
+       lease->mask = cpu_to_le16(1);
        lease->ino = cpu_to_le64(ceph_vino(inode).ino);
        lease->first = lease->last = cpu_to_le64(ceph_vino(inode).snap);
        lease->seq = cpu_to_le32(seq);
@@ -2571,7 +2576,7 @@ void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc, struct inode *inode,
 
        BUG_ON(inode == NULL);
        BUG_ON(dentry == NULL);
-       BUG_ON(mask != CEPH_LOCK_DN);
+       BUG_ON(mask == 0);
 
        /* is dentry lease valid? */
        spin_lock(&dentry->d_lock);
index 60b7483..64b8b1f 100644 (file)
@@ -120,6 +120,12 @@ void ceph_msgr_exit(void)
        destroy_workqueue(ceph_msgr_wq);
 }
 
+void ceph_msgr_flush()
+{
+       flush_workqueue(ceph_msgr_wq);
+}
+
+
 /*
  * socket callback functions
  */
index 00a9430..76fbc95 100644 (file)
@@ -213,6 +213,7 @@ extern int ceph_parse_ips(const char *c, const char *end,
 
 extern int ceph_msgr_init(void);
 extern void ceph_msgr_exit(void);
+extern void ceph_msgr_flush(void);
 
 extern struct ceph_messenger *ceph_messenger_create(
        struct ceph_entity_addr *myaddr);
index f6510a4..21c62e9 100644 (file)
@@ -704,8 +704,11 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                              struct ceph_msg *msg)
 {
        int ret;
+       int was_auth = 0;
 
        mutex_lock(&monc->mutex);
+       if (monc->auth->ops)
+               was_auth = monc->auth->ops->is_authenticated(monc->auth);
        monc->pending_auth = 0;
        ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
                                     msg->front.iov_len,
@@ -716,7 +719,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                wake_up(&monc->client->auth_wq);
        } else if (ret > 0) {
                __send_prepared_auth_request(monc, ret);
-       } else if (monc->auth->ops->is_authenticated(monc->auth)) {
+       } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) {
                dout("authenticated, starting session\n");
 
                monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
index afa7bb3..d25b4ad 100644 (file)
@@ -361,8 +361,13 @@ static void put_osd(struct ceph_osd *osd)
 {
        dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref),
             atomic_read(&osd->o_ref) - 1);
-       if (atomic_dec_and_test(&osd->o_ref))
+       if (atomic_dec_and_test(&osd->o_ref)) {
+               struct ceph_auth_client *ac = osd->o_osdc->client->monc.auth;
+
+               if (osd->o_authorizer)
+                       ac->ops->destroy_authorizer(ac, osd->o_authorizer);
                kfree(osd);
+       }
 }
 
 /*
index cfdd8f4..ddc656f 100644 (file)
@@ -706,7 +706,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                     len, *p, end);
                newcrush = crush_decode(*p, min(*p+len, end));
                if (IS_ERR(newcrush))
-                       return ERR_PTR(PTR_ERR(newcrush));
+                       return ERR_CAST(newcrush);
        }
 
        /* new flags? */
index 7c663d9..4e0bee2 100644 (file)
@@ -669,9 +669,17 @@ static void ceph_destroy_client(struct ceph_client *client)
 
        /* unmount */
        ceph_mdsc_stop(&client->mdsc);
-       ceph_monc_stop(&client->monc);
        ceph_osdc_stop(&client->osdc);
 
+       /*
+        * make sure mds and osd connections close out before destroying
+        * the auth module, which is needed to free those connections'
+        * ceph_authorizers.
+        */
+       ceph_msgr_flush();
+
+       ceph_monc_stop(&client->monc);
+
        ceph_adjust_min_caps(-client->min_caps);
 
        ceph_debugfs_client_cleanup(client);
@@ -738,7 +746,7 @@ static struct dentry *open_root_dentry(struct ceph_client *client,
        dout("open_root_inode opening '%s'\n", path);
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_path1 = kstrdup(path, GFP_NOFS);
        req->r_ino1.ino = CEPH_INO_ROOT;
        req->r_ino1.snap = CEPH_NOSNAP;
index 3725c9e..10a4a40 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/fs.h>
 #include <linux/mempool.h>
 #include <linux/pagemap.h>
-#include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/writeback.h>
 #include <linux/slab.h>
@@ -811,7 +810,7 @@ extern void ceph_put_cap(struct ceph_cap *cap);
 
 extern void ceph_queue_caps_release(struct inode *inode);
 extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc);
-extern int ceph_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern int ceph_fsync(struct file *file, int datasync);
 extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
 extern int ceph_get_cap_mds(struct inode *inode);
index 0242ff9..a7eb65c 100644 (file)
@@ -84,7 +84,7 @@ extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
 extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                         size_t write_size, loff_t *poffset);
 extern int cifs_lock(struct file *, int, struct file_lock *);
-extern int cifs_fsync(struct file *, struct dentry *, int);
+extern int cifs_fsync(struct file *, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
 extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
 extern const struct file_operations cifs_dir_ops;
index a83541e..f1ff785 100644 (file)
@@ -1676,7 +1676,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
        return rc;
 }
 
-int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int cifs_fsync(struct file *file, int datasync)
 {
        int xid;
        int rc = 0;
@@ -1688,7 +1688,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        xid = GetXid();
 
        cFYI(1, "Sync file - name: %s datasync: 0x%x",
-               dentry->d_name.name, datasync);
+               file->f_path.dentry->d_name.name, datasync);
 
        rc = filemap_write_and_wait(inode->i_mapping);
        if (rc == 0) {
index d99860a..6b443ff 100644 (file)
@@ -11,8 +11,7 @@ extern int coda_fake_statfs;
 
 void coda_destroy_inodecache(void);
 int coda_init_inodecache(void);
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
-              int datasync);
+int coda_fsync(struct file *coda_file, int datasync);
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
 
index 7196077..ad3cd2a 100644 (file)
@@ -202,10 +202,10 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        return 0;
 }
 
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
+int coda_fsync(struct file *coda_file, int datasync)
 {
        struct file *host_file;
-       struct inode *coda_inode = coda_dentry->d_inode;
+       struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
        struct coda_file_info *cfi;
        int err = 0;
 
index c8af2d9..4164514 100644 (file)
@@ -72,16 +72,11 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
        if (!sd)
                return -EINVAL;
 
-       sd_iattr = sd->s_iattr;
-
-       error = inode_change_ok(inode, iattr);
-       if (error)
-               return error;
-
-       error = inode_setattr(inode, iattr);
+       error = simple_setattr(dentry, iattr);
        if (error)
                return error;
 
+       sd_iattr = sd->s_iattr;
        if (!sd_iattr) {
                /* setting attributes for the first time, allocate now */
                sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
index 4d74fc7..0210898 100644 (file)
@@ -277,8 +277,10 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
 
+DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
+
 /*
- * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value
+ * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value
  *
  * These functions are exactly the same as the above functions (but use a hex
  * output for the decimal challenged). For details look at the above unsigned
@@ -357,6 +359,23 @@ struct dentry *debugfs_create_x32(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
 
+/**
+ * debugfs_create_x64 - create a debugfs file that is used to read and write an unsigned 64-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is %NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ *         from.
+ */
+struct dentry *debugfs_create_x64(const char *name, mode_t mode,
+                                struct dentry *parent, u64 *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_x64);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x64);
+
 
 static int debugfs_size_t_set(void *data, u64 val)
 {
index da111aa..7600aac 100644 (file)
@@ -1134,27 +1134,8 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        return ret;
 }
 
-/*
- * This is a library function for use by filesystem drivers.
- *
- * The locking rules are governed by the flags parameter:
- *  - if the flags value contains DIO_LOCKING we use a fancy locking
- *    scheme for dumb filesystems.
- *    For writes this function is called under i_mutex and returns with
- *    i_mutex held, for reads, i_mutex is not held on entry, but it is
- *    taken and dropped again before returning.
- *    For reads and writes i_alloc_sem is taken in shared mode and released
- *    on I/O completion (which may happen asynchronously after returning to
- *    the caller).
- *
- *  - if the flags value does NOT contain DIO_LOCKING we don't use any
- *    internal locking but rather rely on the filesystem to synchronize
- *    direct I/O reads/writes versus each other and truncate.
- *    For reads and writes both i_mutex and i_alloc_sem are not held on
- *    entry and are never taken.
- */
 ssize_t
-__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
        struct block_device *bdev, const struct iovec *iov, loff_t offset, 
        unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags)
@@ -1247,9 +1228,46 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                                nr_segs, blkbits, get_block, end_io,
                                submit_io, dio);
 
+out:
+       return retval;
+}
+EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);
+
+/*
+ * This is a library function for use by filesystem drivers.
+ *
+ * The locking rules are governed by the flags parameter:
+ *  - if the flags value contains DIO_LOCKING we use a fancy locking
+ *    scheme for dumb filesystems.
+ *    For writes this function is called under i_mutex and returns with
+ *    i_mutex held, for reads, i_mutex is not held on entry, but it is
+ *    taken and dropped again before returning.
+ *    For reads and writes i_alloc_sem is taken in shared mode and released
+ *    on I/O completion (which may happen asynchronously after returning to
+ *    the caller).
+ *
+ *  - if the flags value does NOT contain DIO_LOCKING we don't use any
+ *    internal locking but rather rely on the filesystem to synchronize
+ *    direct I/O reads/writes versus each other and truncate.
+ *    For reads and writes both i_mutex and i_alloc_sem are not held on
+ *    entry and are never taken.
+ */
+ssize_t
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset,
+       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       dio_submit_t submit_io, int flags)
+{
+       ssize_t retval;
+
+       retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
+                       offset, nr_segs, get_block, end_io, submit_io, flags);
        /*
         * In case of error extending write may have instantiated a few
         * blocks outside i_size. Trim these off again for DIO_LOCKING.
+        * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
+        * their own manner. This is a further example of where the old
+        * truncate sequence is inadequate.
         *
         * NOTE: filesystems with their own locking have to handle this
         * on their own.
@@ -1257,12 +1275,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (flags & DIO_LOCKING) {
                if (unlikely((rw & WRITE) && retval < 0)) {
                        loff_t isize = i_size_read(inode);
+                       loff_t end = offset + iov_length(iov, nr_segs);
+
                        if (end > isize)
                                vmtruncate(inode, isize);
                }
        }
 
-out:
        return retval;
 }
 EXPORT_SYMBOL(__blockdev_direct_IO);
index 3bdddbc..e8fcf4e 100644 (file)
@@ -274,7 +274,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
 }
 
 static int
-ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+ecryptfs_fsync(struct file *file, int datasync)
 {
        return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
 }
index 65dee2f..31ef525 100644 (file)
@@ -805,7 +805,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                                    - (ia->ia_size & ~PAGE_CACHE_MASK));
 
                if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
-                       rc = vmtruncate(inode, ia->ia_size);
+                       rc = simple_setsize(inode, ia->ia_size);
                        if (rc)
                                goto out;
                        lower_ia->ia_size = ia->ia_size;
@@ -830,7 +830,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                                goto out;
                        }
                }
-               vmtruncate(inode, ia->ia_size);
+               simple_setsize(inode, ia->ia_size);
                rc = ecryptfs_write_inode_size_to_metadata(inode);
                if (rc) {
                        printk(KERN_ERR "Problem with "
index 839b9dc..fef6899 100644 (file)
@@ -40,12 +40,11 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
-                           int datasync)
+static int exofs_file_fsync(struct file *filp, int datasync)
 {
        int ret;
        struct address_space *mapping = filp->f_mapping;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = mapping->host;
        struct super_block *sb;
 
        ret = filemap_write_and_wait(mapping);
@@ -66,7 +65,7 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
 
 static int exofs_flush(struct file *file, fl_owner_t id)
 {
-       exofs_file_fsync(file, file->f_path.dentry, 1);
+       exofs_file_fsync(file, 1);
        /* TODO: Flush the OSD target */
        return 0;
 }
index 0b038e4..52b34f1 100644 (file)
@@ -122,7 +122,6 @@ extern int ext2_write_inode (struct inode *, struct writeback_control *);
 extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
-extern void ext2_truncate (struct inode *);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
 extern void ext2_get_inode_flags(struct ext2_inode_info *);
@@ -155,7 +154,7 @@ extern void ext2_write_super (struct super_block *);
 extern const struct file_operations ext2_dir_operations;
 
 /* file.c */
-extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern int ext2_fsync(struct file *file, int datasync);
 extern const struct inode_operations ext2_file_inode_operations;
 extern const struct file_operations ext2_file_operations;
 extern const struct file_operations ext2_xip_file_operations;
index 5d198d0..49eec94 100644 (file)
@@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
        return 0;
 }
 
-int ext2_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ext2_fsync(struct file *file, int datasync)
 {
        int ret;
-       struct super_block *sb = dentry->d_inode->i_sb;
+       struct super_block *sb = file->f_mapping->host->i_sb;
        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
 
-       ret = simple_fsync(file, dentry, datasync);
+       ret = generic_file_fsync(file, datasync);
        if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) {
                /* We don't really know where the IO error happened... */
                ext2_error(sb, __func__,
@@ -95,7 +95,6 @@ const struct file_operations ext2_xip_file_operations = {
 #endif
 
 const struct inode_operations ext2_file_inode_operations = {
-       .truncate       = ext2_truncate,
 #ifdef CONFIG_EXT2_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index 527c46d..1921443 100644 (file)
@@ -54,6 +54,18 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
                inode->i_blocks - ea_blocks == 0);
 }
 
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
+
+static void ext2_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               ext2_truncate_blocks(inode, inode->i_size);
+       }
+}
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -71,7 +83,7 @@ void ext2_delete_inode (struct inode * inode)
 
        inode->i_size = 0;
        if (inode->i_blocks)
-               ext2_truncate (inode);
+               ext2_truncate_blocks(inode, 0);
        ext2_free_inode (inode);
 
        return;
@@ -757,8 +769,8 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata)
 {
-       return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext2_get_block);
+       return block_write_begin_newtrunc(file, mapping, pos, len, flags,
+                                       pagep, fsdata, ext2_get_block);
 }
 
 static int
@@ -766,8 +778,25 @@ ext2_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata)
 {
+       int ret;
+
        *pagep = NULL;
-       return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+       ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+       if (ret < 0)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
+}
+
+static int ext2_write_end(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned copied,
+                       struct page *page, void *fsdata)
+{
+       int ret;
+
+       ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+       if (ret < len)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
 }
 
 static int
@@ -775,13 +804,18 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata)
 {
+       int ret;
+
        /*
         * Dir-in-pagecache still uses ext2_write_begin. Would have to rework
         * directory handling code to pass around offsets rather than struct
         * pages in order to make this work easily.
         */
-       return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext2_get_block);
+       ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
+                                               fsdata, ext2_get_block);
+       if (ret < 0)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
 }
 
 static int ext2_nobh_writepage(struct page *page,
@@ -800,10 +834,15 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
-
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                               offset, nr_segs, ext2_get_block, NULL);
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       ssize_t ret;
+
+       ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
+                               iov, offset, nr_segs, ext2_get_block, NULL);
+       if (ret < 0 && (rw & WRITE))
+               ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
+       return ret;
 }
 
 static int
@@ -818,7 +857,7 @@ const struct address_space_operations ext2_aops = {
        .writepage              = ext2_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext2_write_begin,
-       .write_end              = generic_write_end,
+       .write_end              = ext2_write_end,
        .bmap                   = ext2_bmap,
        .direct_IO              = ext2_direct_IO,
        .writepages             = ext2_writepages,
@@ -1027,7 +1066,7 @@ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int de
                ext2_free_data(inode, p, q);
 }
 
-void ext2_truncate(struct inode *inode)
+static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
 {
        __le32 *i_data = EXT2_I(inode)->i_data;
        struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1039,27 +1078,8 @@ void ext2_truncate(struct inode *inode)
        int n;
        long iblock;
        unsigned blocksize;
-
-       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-           S_ISLNK(inode->i_mode)))
-               return;
-       if (ext2_inode_is_fast_symlink(inode))
-               return;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return;
-
        blocksize = inode->i_sb->s_blocksize;
-       iblock = (inode->i_size + blocksize-1)
-                                       >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-
-       if (mapping_is_xip(inode->i_mapping))
-               xip_truncate_page(inode->i_mapping, inode->i_size);
-       else if (test_opt(inode->i_sb, NOBH))
-               nobh_truncate_page(inode->i_mapping,
-                               inode->i_size, ext2_get_block);
-       else
-               block_truncate_page(inode->i_mapping,
-                               inode->i_size, ext2_get_block);
+       iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 
        n = ext2_block_to_path(inode, iblock, offsets, NULL);
        if (n == 0)
@@ -1127,6 +1147,62 @@ do_indirects:
        ext2_discard_reservation(inode);
 
        mutex_unlock(&ei->truncate_mutex);
+}
+
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
+{
+       /*
+        * XXX: it seems like a bug here that we don't allow
+        * IS_APPEND inode to have blocks-past-i_size trimmed off.
+        * review and fix this.
+        *
+        * Also would be nice to be able to handle IO errors and such,
+        * but that's probably too much to ask.
+        */
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+           S_ISLNK(inode->i_mode)))
+               return;
+       if (ext2_inode_is_fast_symlink(inode))
+               return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+       __ext2_truncate_blocks(inode, offset);
+}
+
+int ext2_setsize(struct inode *inode, loff_t newsize)
+{
+       loff_t oldsize;
+       int error;
+
+       error = inode_newsize_ok(inode, newsize);
+       if (error)
+               return error;
+
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+           S_ISLNK(inode->i_mode)))
+               return -EINVAL;
+       if (ext2_inode_is_fast_symlink(inode))
+               return -EINVAL;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return -EPERM;
+
+       if (mapping_is_xip(inode->i_mapping))
+               error = xip_truncate_page(inode->i_mapping, newsize);
+       else if (test_opt(inode->i_sb, NOBH))
+               error = nobh_truncate_page(inode->i_mapping,
+                               newsize, ext2_get_block);
+       else
+               error = block_truncate_page(inode->i_mapping,
+                               newsize, ext2_get_block);
+       if (error)
+               return error;
+
+       oldsize = inode->i_size;
+       i_size_write(inode, newsize);
+       truncate_pagecache(inode, oldsize, newsize);
+
+       __ext2_truncate_blocks(inode, newsize);
+
        inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
        if (inode_needs_sync(inode)) {
                sync_mapping_buffers(inode->i_mapping);
@@ -1134,6 +1210,8 @@ do_indirects:
        } else {
                mark_inode_dirty(inode);
        }
+
+       return 0;
 }
 
 static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
@@ -1474,8 +1552,15 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
                if (error)
                        return error;
        }
-       error = inode_setattr(inode, iattr);
-       if (!error && (iattr->ia_valid & ATTR_MODE))
+       if (iattr->ia_valid & ATTR_SIZE) {
+               error = ext2_setsize(inode, iattr->ia_size);
+               if (error)
+                       return error;
+       }
+       generic_setattr(inode, iattr);
+       if (iattr->ia_valid & ATTR_MODE)
                error = ext2_acl_chmod(inode);
+       mark_inode_dirty(inode);
+
        return error;
 }
index 71e9eb1..7ff43f4 100644 (file)
@@ -119,6 +119,8 @@ static void ext2_put_super (struct super_block * sb)
        int i;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        if (sb->s_dirt)
                ext2_write_super(sb);
 
@@ -1063,6 +1065,12 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ext2_sops;
        sb->s_export_op = &ext2_export_ops;
        sb->s_xattr = ext2_xattr_handlers;
+
+#ifdef CONFIG_QUOTA
+       sb->dq_op = &dquot_operations;
+       sb->s_qcop = &dquot_quotactl_ops;
+#endif
+
        root = ext2_iget(sb, EXT2_ROOT_INO);
        if (IS_ERR(root)) {
                ret = PTR_ERR(root);
@@ -1241,6 +1249,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                        spin_unlock(&sbi->s_lock);
                        return 0;
                }
+
                /*
                 * OK, we are remounting a valid rw partition rdonly, so set
                 * the rdonly flag and then mark the partition as valid again.
@@ -1248,6 +1257,13 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                es->s_state = cpu_to_le16(sbi->s_mount_state);
                es->s_mtime = cpu_to_le32(get_seconds());
                spin_unlock(&sbi->s_lock);
+
+               err = dquot_suspend(sb, -1);
+               if (err < 0) {
+                       spin_lock(&sbi->s_lock);
+                       goto restore_opts;
+               }
+
                ext2_sync_super(sb, es, 1);
        } else {
                __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
@@ -1269,8 +1285,12 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                if (!ext2_setup_super (sb, es, 0))
                        sb->s_flags &= ~MS_RDONLY;
                spin_unlock(&sbi->s_lock);
+
                ext2_write_super(sb);
+
+               dquot_resume(sb, -1);
        }
+
        return 0;
 restore_opts:
        sbi->s_mount_opt = old_opts.s_mount_opt;
index 373fa90..e2e72c3 100644 (file)
@@ -297,7 +297,7 @@ static void free_rb_tree_fname(struct rb_root *root)
                        kfree (old);
                }
                if (!parent)
-                       root->rb_node = NULL;
+                       *root = RB_ROOT;
                else if (parent->rb_left == n)
                        parent->rb_left = NULL;
                else if (parent->rb_right == n)
index fcf7487..d7e9f74 100644 (file)
@@ -43,9 +43,9 @@
  * inode to disk.
  */
 
-int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
+int ext3_sync_file(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ext3_inode_info *ei = EXT3_I(inode);
        journal_t *journal = EXT3_SB(inode->i_sb)->s_journal;
        int ret, needs_barrier = 0;
index 0fc1293..6c953bb 100644 (file)
@@ -410,6 +410,8 @@ static void ext3_put_super (struct super_block * sb)
        struct ext3_super_block *es = sbi->s_es;
        int i, err;
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        lock_kernel();
 
        ext3_xattr_put_super(sb);
@@ -748,7 +750,7 @@ static int ext3_release_dquot(struct dquot *dquot);
 static int ext3_mark_dquot_dirty(struct dquot *dquot);
 static int ext3_write_info(struct super_block *sb, int type);
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path, int remount);
+                               char *path);
 static int ext3_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -767,12 +769,12 @@ static const struct dquot_operations ext3_quota_operations = {
 
 static const struct quotactl_ops ext3_qctl_operations = {
        .quota_on       = ext3_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
 #endif
 
@@ -1527,7 +1529,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
-                       vfs_quota_off(sb, i, 0);
+                       dquot_quota_off(sb, i);
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2551,6 +2553,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        ext3_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext3_mount_options old_opts;
+       int enable_quota = 0;
        int err;
 #ifdef CONFIG_QUOTA
        int i;
@@ -2597,6 +2600,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                }
 
                if (*flags & MS_RDONLY) {
+                       err = dquot_suspend(sb, -1);
+                       if (err < 0)
+                               goto restore_opts;
+
                        /*
                         * First of all, the unconditional stuff we have to do
                         * to disable replay of the journal when we next remount
@@ -2651,6 +2658,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                                goto restore_opts;
                        if (!ext3_setup_super (sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       enable_quota = 1;
                }
        }
 #ifdef CONFIG_QUOTA
@@ -2662,6 +2670,9 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+
+       if (enable_quota)
+               dquot_resume(sb, -1);
        return 0;
 restore_opts:
        sb->s_flags = old_sb_flags;
@@ -2851,24 +2862,21 @@ static int ext3_write_info(struct super_block *sb, int type)
  */
 static int ext3_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
-                       EXT3_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
+                                       EXT3_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name, int remount)
+                        char *name)
 {
        int err;
        struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, name is NULL */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, remount);
 
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
@@ -2906,7 +2914,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
                }
        }
 
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
        path_put(&path);
        return err;
 }
index 60bd310..19a4de5 100644 (file)
@@ -1519,7 +1519,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext4_sync_file(struct file *, struct dentry *, int);
+extern int ext4_sync_file(struct file *, int);
 
 /* hash.c */
 extern int ext4fs_dirhash(const char *name, int len, struct
index b6a74f9..592adf2 100644 (file)
@@ -71,9 +71,9 @@ static void ext4_sync_parent(struct inode *inode)
  * i_mutex lock is held when entering and exiting this function
  */
 
-int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int ext4_sync_file(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ext4_inode_info *ei = EXT4_I(inode);
        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
        int ret;
@@ -81,7 +81,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
 
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
-       trace_ext4_sync_file(file, dentry, datasync);
+       trace_ext4_sync_file(file, datasync);
 
        if (inode->i_sb->s_flags & MS_RDONLY)
                return 0;
@@ -91,7 +91,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
                return ret;
 
        if (!journal) {
-               ret = simple_fsync(file, dentry, datasync);
+               ret = generic_file_fsync(file, datasync);
                if (!ret && !list_empty(&inode->i_dentry))
                        ext4_sync_parent(inode);
                return ret;
index 49d88c0..4e8983a 100644 (file)
@@ -646,6 +646,8 @@ static void ext4_put_super(struct super_block *sb)
        struct ext4_super_block *es = sbi->s_es;
        int i, err;
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        flush_workqueue(sbi->dio_unwritten_wq);
        destroy_workqueue(sbi->dio_unwritten_wq);
 
@@ -1062,7 +1064,7 @@ static int ext4_release_dquot(struct dquot *dquot);
 static int ext4_mark_dquot_dirty(struct dquot *dquot);
 static int ext4_write_info(struct super_block *sb, int type);
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path, int remount);
+                               char *path);
 static int ext4_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -1084,12 +1086,12 @@ static const struct dquot_operations ext4_quota_operations = {
 
 static const struct quotactl_ops ext4_qctl_operations = {
        .quota_on       = ext4_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
 #endif
 
@@ -2054,7 +2056,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
-                       vfs_quota_off(sb, i, 0);
+                       dquot_quota_off(sb, i);
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -3576,6 +3578,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        ext4_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext4_mount_options old_opts;
+       int enable_quota = 0;
        ext4_group_t g;
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
        int err;
@@ -3633,6 +3636,10 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                }
 
                if (*flags & MS_RDONLY) {
+                       err = dquot_suspend(sb, -1);
+                       if (err < 0)
+                               goto restore_opts;
+
                        /*
                         * First of all, the unconditional stuff we have to do
                         * to disable replay of the journal when we next remount
@@ -3701,6 +3708,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       enable_quota = 1;
                }
        }
        ext4_setup_system_zone(sb);
@@ -3716,6 +3724,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+       if (enable_quota)
+               dquot_resume(sb, -1);
 
        ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
        kfree(orig_data);
@@ -3913,24 +3923,21 @@ static int ext4_write_info(struct super_block *sb, int type)
  */
 static int ext4_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
-                                 EXT4_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
+                                       EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name, int remount)
+                        char *name)
 {
        int err;
        struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, name is NULL */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, remount);
 
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
@@ -3969,7 +3976,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                }
        }
 
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
        path_put(&path);
        return err;
 }
index 53dba57..27ac257 100644 (file)
@@ -306,11 +306,11 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
 extern const struct file_operations fat_file_operations;
 extern const struct inode_operations fat_file_inode_operations;
 extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
-extern void fat_truncate(struct inode *inode);
+extern int fat_setsize(struct inode *inode, loff_t offset);
+extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
 extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
                       struct kstat *stat);
-extern int fat_file_fsync(struct file *file, struct dentry *dentry,
-                         int datasync);
+extern int fat_file_fsync(struct file *file, int datasync);
 
 /* fat/inode.c */
 extern void fat_attach(struct inode *inode, loff_t i_pos);
index a14c2f6..990dfae 100644 (file)
@@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int fat_file_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int res, err;
 
-       res = simple_fsync(filp, dentry, datasync);
+       res = generic_file_fsync(filp, datasync);
        err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
 
        return res ? res : err;
@@ -283,7 +283,7 @@ static int fat_free(struct inode *inode, int skip)
        return fat_free_clusters(inode, free_start);
 }
 
-void fat_truncate(struct inode *inode)
+void fat_truncate_blocks(struct inode *inode, loff_t offset)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
        const unsigned int cluster_size = sbi->cluster_size;
@@ -293,10 +293,10 @@ void fat_truncate(struct inode *inode)
         * This protects against truncating a file bigger than it was then
         * trying to write into the hole.
         */
-       if (MSDOS_I(inode)->mmu_private > inode->i_size)
-               MSDOS_I(inode)->mmu_private = inode->i_size;
+       if (MSDOS_I(inode)->mmu_private > offset)
+               MSDOS_I(inode)->mmu_private = offset;
 
-       nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
+       nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;
 
        fat_free(inode, nr_clusters);
        fat_flush_inodes(inode->i_sb, inode, NULL);
@@ -364,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
        return 0;
 }
 
+int fat_setsize(struct inode *inode, loff_t offset)
+{
+       int error;
+
+       error = simple_setsize(inode, offset);
+       if (error)
+               return error;
+       fat_truncate_blocks(inode, offset);
+
+       return error;
+}
+
 #define TIMES_SET_FLAGS        (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
 /* valid file mode bits */
 #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
@@ -378,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
        /*
         * Expand the file. Since inode_setattr() updates ->i_size
         * before calling the ->truncate(), but FAT needs to fill the
-        * hole before it.
+        * hole before it. XXX: this is no longer true with new truncate
+        * sequence.
         */
        if (attr->ia_valid & ATTR_SIZE) {
                if (attr->ia_size > inode->i_size) {
@@ -427,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
                        attr->ia_valid &= ~ATTR_MODE;
        }
 
-       if (attr->ia_valid)
-               error = inode_setattr(inode, attr);
+       if (attr->ia_valid & ATTR_SIZE) {
+               error = fat_setsize(inode, attr->ia_size);
+               if (error)
+                       goto out;
+       }
+
+       generic_setattr(inode, attr);
+       mark_inode_dirty(inode);
 out:
        return error;
 }
 EXPORT_SYMBOL_GPL(fat_setattr);
 
 const struct inode_operations fat_file_inode_operations = {
-       .truncate       = fat_truncate,
        .setattr        = fat_setattr,
        .getattr        = fat_getattr,
 };
index ed33904..7bf45ae 100644 (file)
@@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping,
        return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
 }
 
+static void fat_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               fat_truncate_blocks(inode, inode->i_size);
+       }
+}
+
 static int fat_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
 {
+       int err;
+
        *pagep = NULL;
-       return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               fat_get_block,
+       err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
+                               pagep, fsdata, fat_get_block,
                                &MSDOS_I(mapping->host)->mmu_private);
+       if (err < 0)
+               fat_write_failed(mapping, pos + len);
+       return err;
 }
 
 static int fat_write_end(struct file *file, struct address_space *mapping,
@@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
        struct inode *inode = mapping->host;
        int err;
        err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
+       if (err < len)
+               fat_write_failed(mapping, pos + len);
        if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
                MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
                             loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       ssize_t ret;
 
        if (rw == WRITE) {
                /*
@@ -193,8 +212,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
         * FAT need to use the DIO_LOCKING for avoiding the race
         * condition of fat_get_block() and ->truncate().
         */
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                                 offset, nr_segs, fat_get_block, NULL);
+       ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
+                               iov, offset, nr_segs, fat_get_block, NULL);
+       if (ret < 0 && (rw & WRITE))
+               fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
+
+       return ret;
 }
 
 static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
@@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
        inode->i_size = 0;
-       fat_truncate(inode);
+       fat_truncate_blocks(inode, 0);
        clear_inode(inode);
 }
 
index 32d12b7..5c7d10e 100644 (file)
@@ -194,14 +194,6 @@ struct file *alloc_file(struct path *path, fmode_t mode,
 }
 EXPORT_SYMBOL(alloc_file);
 
-void fput(struct file *file)
-{
-       if (atomic_long_dec_and_test(&file->f_count))
-               __fput(file);
-}
-
-EXPORT_SYMBOL(fput);
-
 /**
  * drop_file_write_access - give up ability to write to a file
  * @file: the file to which we will stop writing
@@ -227,10 +219,9 @@ void drop_file_write_access(struct file *file)
 }
 EXPORT_SYMBOL_GPL(drop_file_write_access);
 
-/* __fput is called from task context when aio completion releases the last
- * last use of a struct file *.  Do not use otherwise.
+/* the real guts of fput() - releasing the last reference to file
  */
-void __fput(struct file *file)
+static void __fput(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct vfsmount *mnt = file->f_path.mnt;
@@ -268,6 +259,14 @@ void __fput(struct file *file)
        mntput(mnt);
 }
 
+void fput(struct file *file)
+{
+       if (atomic_long_dec_and_test(&file->f_count))
+               __fput(file);
+}
+
+EXPORT_SYMBOL(fput);
+
 struct file *fget(unsigned int fd)
 {
        struct file *file;
index 4787ae6..3cdc5f7 100644 (file)
@@ -1156,10 +1156,9 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
+static int fuse_dir_fsync(struct file *file, int datasync)
 {
-       /* nfsd can call this with no file */
-       return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
+       return fuse_fsync_common(file, datasync, 1);
 }
 
 static bool update_mtime(unsigned ivalid)
index a9f5e13..b5fd6f9 100644 (file)
@@ -351,10 +351,9 @@ static void fuse_sync_writes(struct inode *inode)
        fuse_release_nowrite(inode);
 }
 
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
-                     int isdir)
+int fuse_fsync_common(struct file *file, int datasync, int isdir)
 {
-       struct inode *inode = de->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_file *ff = file->private_data;
        struct fuse_req *req;
@@ -403,9 +402,9 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
        return err;
 }
 
-static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
+static int fuse_fsync(struct file *file, int datasync)
 {
-       return fuse_fsync_common(file, de, datasync, 0);
+       return fuse_fsync_common(file, datasync, 0);
 }
 
 void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
index 01cc462..2c0d14a 100644 (file)
@@ -568,8 +568,7 @@ void fuse_release_common(struct file *file, int opcode);
 /**
  * Send FSYNC or FSYNCDIR request
  */
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
-                     int isdir);
+int fuse_fsync_common(struct file *file, int datasync, int isdir);
 
 /**
  * Notify poll wakeup
index a739a0a..9f8b525 100644 (file)
@@ -700,8 +700,14 @@ out:
                return 0;
 
        page_cache_release(page);
+
+       /*
+        * XXX(hch): the call below should probably be replaced with
+        * a call to the gfs2-specific truncate blocks helper to actually
+        * release disk blocks..
+        */
        if (pos + len > ip->i_inode.i_size)
-               vmtruncate(&ip->i_inode, ip->i_inode.i_size);
+               simple_setsize(&ip->i_inode, ip->i_inode.i_size);
 out_endtrans:
        gfs2_trans_end(sdp);
 out_trans_fail:
index b20bfcc..ed9a94f 100644 (file)
@@ -554,9 +554,9 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * Returns: errno
  */
 
-static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int gfs2_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        int ret = 0;
 
index 4e64352..98cdd05 100644 (file)
@@ -1071,6 +1071,9 @@ int gfs2_permission(struct inode *inode, int mask)
        return error;
 }
 
+/*
+ * XXX: should be changed to have proper ordering by opencoding simple_setsize
+ */
 static int setattr_size(struct inode *inode, struct iattr *attr)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -1081,7 +1084,7 @@ static int setattr_size(struct inode *inode, struct iattr *attr)
                error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
                if (error)
                        return error;
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                gfs2_trans_end(sdp);
                if (error) 
                        return error;
index 3a029d8..87ac189 100644 (file)
@@ -411,9 +411,9 @@ int hostfs_file_open(struct inode *ino, struct file *file)
        return 0;
 }
 
-int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int hostfs_fsync(struct file *file, int datasync)
 {
-       return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
+       return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
 }
 
 static const struct file_operations hostfs_file_fops = {
index 3efabff..a9ae9bf 100644 (file)
@@ -19,9 +19,9 @@ static int hpfs_file_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
+int hpfs_file_fsync(struct file *file, int datasync)
 {
-       /*return file_fsync(file, dentry);*/
+       /*return file_fsync(file, datasync);*/
        return 0; /* Don't fsync :-) */
 }
 
index 97bf738..75f9d43 100644 (file)
@@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *,
 
 /* file.c */
 
-int hpfs_file_fsync(struct file *, struct dentry *, int);
+int hpfs_file_fsync(struct file *, int);
 extern const struct file_operations hpfs_file_ops;
 extern const struct inode_operations hpfs_file_iops;
 extern const struct address_space_operations hpfs_aops;
index 2e4dfa8..826c3f9 100644 (file)
@@ -587,7 +587,7 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
        return err;
 }
 
-static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int hppfs_fsync(struct file *file, int datasync)
 {
        return 0;
 }
index a0bbd3d..a4e9a7e 100644 (file)
@@ -688,7 +688,7 @@ static void init_once(void *foo)
 const struct file_operations hugetlbfs_file_operations = {
        .read                   = hugetlbfs_read,
        .mmap                   = hugetlbfs_file_mmap,
-       .fsync                  = simple_sync_file,
+       .fsync                  = noop_fsync,
        .get_unmapped_area      = hugetlb_get_unmapped_area,
 };
 
index e7291c1..8134970 100644 (file)
@@ -26,9 +26,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
                        struct page **pagep, void **fsdata);
 static int jffs2_readpage (struct file *filp, struct page *pg);
 
-int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int jffs2_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
 
        /* Trigger GC to flush any pending writes for this inode */
index 86e0821..8bc2c80 100644 (file)
@@ -169,13 +169,13 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        mutex_unlock(&f->sem);
        jffs2_complete_reservation(c);
 
-       /* We have to do the vmtruncate() without f->sem held, since
+       /* We have to do the simple_setsize() without f->sem held, since
           some pages may be locked and waiting for it in readpage().
           We are protected from a simultaneous write() extending i_size
           back past iattr->ia_size, because do_truncate() holds the
           generic inode semaphore. */
        if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
-               vmtruncate(inode, iattr->ia_size);      
+               simple_setsize(inode, iattr->ia_size);
                inode->i_blocks = (inode->i_size + 511) >> 9;
        }       
 
index 035a767..4791aac 100644 (file)
@@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations;
 extern const struct file_operations jffs2_file_operations;
 extern const struct inode_operations jffs2_file_inode_operations;
 extern const struct address_space_operations jffs2_file_address_operations;
-int jffs2_fsync(struct file *, struct dentry *, int);
+int jffs2_fsync(struct file *, int);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 
 /* ioctl.c */
index 85d9ec6..127263c 100644 (file)
@@ -27,9 +27,9 @@
 #include "jfs_acl.h"
 #include "jfs_debug.h"
 
-int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int jfs_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int rc = 0;
 
        if (!(inode->i_state & I_DIRTY) ||
index 9e6bda3..11042b1 100644 (file)
@@ -21,7 +21,7 @@
 struct fid;
 
 extern struct inode *ialloc(struct inode *, umode_t);
-extern int jfs_fsync(struct file *, struct dentry *, int);
+extern int jfs_fsync(struct file *, int);
 extern long jfs_ioctl(struct file *, unsigned int, unsigned long);
 extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long);
 extern struct inode *jfs_iget(struct super_block *, unsigned long);
index b66832a..b38f96b 100644 (file)
@@ -179,6 +179,8 @@ static void jfs_put_super(struct super_block *sb)
 
        jfs_info("In jfs_put_super");
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        lock_kernel();
 
        rc = jfs_umount(sb);
@@ -396,10 +398,20 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 
                JFS_SBI(sb)->flag = flag;
                ret = jfs_mount_rw(sb, 1);
+
+               /* mark the fs r/w for quota activity */
+               sb->s_flags &= ~MS_RDONLY;
+
                unlock_kernel();
+               dquot_resume(sb, -1);
                return ret;
        }
        if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
+               rc = dquot_suspend(sb, -1);
+               if (rc < 0) {
+                       unlock_kernel();
+                       return rc;
+               }
                rc = jfs_umount_rw(sb);
                JFS_SBI(sb)->flag = flag;
                unlock_kernel();
@@ -469,6 +481,10 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
         */
        sb->s_op = &jfs_super_operations;
        sb->s_export_op = &jfs_export_operations;
+#ifdef CONFIG_QUOTA
+       sb->dq_op = &dquot_operations;
+       sb->s_qcop = &dquot_quotactl_ops;
+#endif
 
        /*
         * Initialize direct-mapping inode/address-space
index 232bea4..09e1016 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/quotaops.h>
 #include <linux/mutex.h>
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
@@ -58,11 +59,6 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na
        return NULL;
 }
 
-int simple_sync_file(struct file * file, struct dentry *dentry, int datasync)
-{
-       return 0;
-}
 int dcache_dir_open(struct inode *inode, struct file *file)
 {
        static struct qstr cursor_name = {.len = 1, .name = "."};
@@ -190,7 +186,7 @@ const struct file_operations simple_dir_operations = {
        .llseek         = dcache_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
 };
 
 const struct inode_operations simple_dir_inode_operations = {
@@ -330,6 +326,81 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
        return 0;
 }
 
+/**
+ * simple_setsize - handle core mm and vfs requirements for file size change
+ * @inode: inode
+ * @newsize: new file size
+ *
+ * Returns 0 on success, -error on failure.
+ *
+ * simple_setsize must be called with inode_mutex held.
+ *
+ * simple_setsize will check that the requested new size is OK (see
+ * inode_newsize_ok), and then will perform the necessary i_size update
+ * and pagecache truncation (if necessary). It will be typically be called
+ * from the filesystem's setattr function when ATTR_SIZE is passed in.
+ *
+ * The inode itself must have correct permissions and attributes to allow
+ * i_size to be changed, this function then just checks that the new size
+ * requested is valid.
+ *
+ * In the case of simple in-memory filesystems with inodes stored solely
+ * in the inode cache, and file data in the pagecache, nothing more needs
+ * to be done to satisfy a truncate request. Filesystems with on-disk
+ * blocks for example will need to free them in the case of truncate, in
+ * that case it may be easier not to use simple_setsize (but each of its
+ * components will likely be required at some point to update pagecache
+ * and inode etc).
+ */
+int simple_setsize(struct inode *inode, loff_t newsize)
+{
+       loff_t oldsize;
+       int error;
+
+       error = inode_newsize_ok(inode, newsize);
+       if (error)
+               return error;
+
+       oldsize = inode->i_size;
+       i_size_write(inode, newsize);
+       truncate_pagecache(inode, oldsize, newsize);
+
+       return error;
+}
+EXPORT_SYMBOL(simple_setsize);
+
+/**
+ * simple_setattr - setattr for simple in-memory filesystem
+ * @dentry: dentry
+ * @iattr: iattr structure
+ *
+ * Returns 0 on success, -error on failure.
+ *
+ * simple_setattr implements setattr for an in-memory filesystem which
+ * does not store its own file data or metadata (eg. uses the page cache
+ * and inode cache as its data store).
+ */
+int simple_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       error = inode_change_ok(inode, iattr);
+       if (error)
+               return error;
+
+       if (iattr->ia_valid & ATTR_SIZE) {
+               error = simple_setsize(inode, iattr->ia_size);
+               if (error)
+                       return error;
+       }
+
+       generic_setattr(inode, iattr);
+
+       return error;
+}
+EXPORT_SYMBOL(simple_setattr);
+
 int simple_readpage(struct file *file, struct page *page)
 {
        clear_highpage(page);
@@ -851,13 +922,22 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
 }
 EXPORT_SYMBOL_GPL(generic_fh_to_parent);
 
-int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
+/**
+ * generic_file_fsync - generic fsync implementation for simple filesystems
+ * @file:      file to synchronize
+ * @datasync:  only synchronize essential metadata if true
+ *
+ * This is a generic implementation of the fsync method for simple
+ * filesystems which track all non-inode metadata in the buffers list
+ * hanging off the address_space structure.
+ */
+int generic_file_fsync(struct file *file, int datasync)
 {
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,
                .nr_to_write = 0, /* metadata-only; caller takes care of data */
        };
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int err;
        int ret;
 
@@ -872,7 +952,15 @@ int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
                ret = err;
        return ret;
 }
-EXPORT_SYMBOL(simple_fsync);
+EXPORT_SYMBOL(generic_file_fsync);
+
+/*
+ * No-op implementation of ->fsync for in-memory filesystems.
+ */
+int noop_fsync(struct file *file, int datasync)
+{
+       return 0;
+}
 
 EXPORT_SYMBOL(dcache_dir_close);
 EXPORT_SYMBOL(dcache_dir_lseek);
@@ -895,7 +983,7 @@ EXPORT_SYMBOL(simple_release_fs);
 EXPORT_SYMBOL(simple_rename);
 EXPORT_SYMBOL(simple_rmdir);
 EXPORT_SYMBOL(simple_statfs);
-EXPORT_SYMBOL(simple_sync_file);
+EXPORT_SYMBOL(noop_fsync);
 EXPORT_SYMBOL(simple_unlink);
 EXPORT_SYMBOL(simple_read_from_buffer);
 EXPORT_SYMBOL(simple_write_to_buffer);
index 0de5240..abe1caf 100644 (file)
@@ -219,9 +219,9 @@ int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        }
 }
 
-int logfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int logfs_fsync(struct file *file, int datasync)
 {
-       struct super_block *sb = dentry->d_inode->i_sb;
+       struct super_block *sb = file->f_mapping->host->i_sb;
 
        logfs_write_anchor(sb);
        return 0;
index 1a9db84..c838c4d 100644 (file)
@@ -506,7 +506,7 @@ extern const struct address_space_operations logfs_reg_aops;
 int logfs_readpage(struct file *file, struct page *page);
 int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                unsigned long arg);
-int logfs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int logfs_fsync(struct file *file, int datasync);
 
 /* gc.c */
 u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec);
index 6198731..9196958 100644 (file)
@@ -22,7 +22,7 @@ const struct file_operations minix_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = minix_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static inline void dir_put_page(struct page *page)
@@ -72,11 +72,8 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
 {
        struct address_space *mapping = dir->i_mapping;
        struct page *page = read_mapping_page(mapping, n, NULL);
-       if (!IS_ERR(page)) {
+       if (!IS_ERR(page))
                kmap(page);
-               if (!PageUptodate(page))
-                       goto fail;
-       }
        return page;
 
 fail:
index 3eec3e6..d5320ff 100644 (file)
@@ -19,7 +19,7 @@ const struct file_operations minix_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
 
index f230109..13487ad 100644 (file)
@@ -20,6 +20,9 @@ static inline block_t *i_data(struct inode *inode)
        return (block_t *)minix_i(inode)->u.i2_data;
 }
 
+#define DIRCOUNT 7
+#define INDIRCOUNT(sb) (1 << ((sb)->s_blocksize_bits - 2))
+
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
 {
        int n = 0;
@@ -34,21 +37,21 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
                        printk("MINIX-fs: block_to_path: "
                               "block %ld too big on dev %s\n",
                                block, bdevname(sb->s_bdev, b));
-       } else if (block < 7) {
+       } else if (block < DIRCOUNT) {
                offsets[n++] = block;
-       } else if ((block -= 7) < 256) {
-               offsets[n++] = 7;
+       } else if ((block -= DIRCOUNT) < INDIRCOUNT(sb)) {
+               offsets[n++] = DIRCOUNT;
                offsets[n++] = block;
-       } else if ((block -= 256) < 256*256) {
-               offsets[n++] = 8;
-               offsets[n++] = block>>8;
-               offsets[n++] = block & 255;
+       } else if ((block -= INDIRCOUNT(sb)) < INDIRCOUNT(sb) * INDIRCOUNT(sb)) {
+               offsets[n++] = DIRCOUNT + 1;
+               offsets[n++] = block / INDIRCOUNT(sb);
+               offsets[n++] = block % INDIRCOUNT(sb);
        } else {
-               block -= 256*256;
-               offsets[n++] = 9;
-               offsets[n++] = block>>16;
-               offsets[n++] = (block>>8) & 255;
-               offsets[n++] = block & 255;
+               block -= INDIRCOUNT(sb) * INDIRCOUNT(sb);
+               offsets[n++] = DIRCOUNT + 2;
+               offsets[n++] = (block / INDIRCOUNT(sb)) / INDIRCOUNT(sb);
+               offsets[n++] = (block / INDIRCOUNT(sb)) % INDIRCOUNT(sb);
+               offsets[n++] = block % INDIRCOUNT(sb);
        }
        return n;
 }
index 48e1f60..868d0cb 100644 (file)
@@ -1621,6 +1621,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        case LAST_DOTDOT:
                follow_dotdot(nd);
                dir = nd->path.dentry;
+       case LAST_DOT:
                if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {
                        if (!dir->d_op->d_revalidate(dir, nd)) {
                                error = -ESTALE;
@@ -1628,7 +1629,6 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                        }
                }
                /* fallthrough */
-       case LAST_DOT:
        case LAST_ROOT:
                if (open_flag & O_CREAT)
                        goto exit;
index b938708..3639cc5 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
 
-static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int ncp_fsync(struct file *file, int datasync)
 {
        return 0;
 }
index db64854..782b431 100644 (file)
@@ -53,7 +53,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *);
 static int nfs_mknod(struct inode *, struct dentry *, int, dev_t);
 static int nfs_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
-static int nfs_fsync_dir(struct file *, struct dentry *, int);
+static int nfs_fsync_dir(struct file *, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 
 const struct file_operations nfs_dir_operations = {
@@ -641,8 +641,10 @@ out:
  * All directory operations under NFS are synchronous, so fsync()
  * is a dummy operation.
  */
-static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
+static int nfs_fsync_dir(struct file *filp, int datasync)
 {
+       struct dentry *dentry = filp->f_path.dentry;
+
        dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        datasync);
index cac96bc..36a5e74 100644 (file)
@@ -53,7 +53,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
 static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
 static int  nfs_file_flush(struct file *, fl_owner_t id);
-static int  nfs_file_fsync(struct file *, struct dentry *dentry, int datasync);
+static int  nfs_file_fsync(struct file *, int datasync);
 static int nfs_check_flags(int flags);
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
@@ -322,8 +322,9 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
  * whether any write errors occurred for this process.
  */
 static int
-nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
+nfs_file_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = dentry->d_inode;
 
index 30292df..c9a30d7 100644 (file)
@@ -27,7 +27,7 @@
 #include "nilfs.h"
 #include "segment.h"
 
-int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int nilfs_sync_file(struct file *file, int datasync)
 {
        /*
         * Called from fsync() system call
@@ -37,7 +37,7 @@ int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
         * This function should be implemented when the writeback function
         * will be implemented.
         */
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int err;
 
        if (!nilfs_inode_dirty(inode))
index 8723e5b..47d6d79 100644 (file)
@@ -228,7 +228,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *,
                           struct page *, struct inode *);
 
 /* file.c */
-extern int nilfs_sync_file(struct file *, struct dentry *, int);
+extern int nilfs_sync_file(struct file *, int);
 
 /* ioctl.c */
 long nilfs_ioctl(struct file *, unsigned int, unsigned long);
index fe44d3f..0f48e7c 100644 (file)
@@ -1527,10 +1527,9 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
  * this problem for now.  We do write the $BITMAP attribute if it is present
  * which is the important one for a directory so things are not too bad.
  */
-static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
-               int datasync)
+static int ntfs_dir_fsync(struct file *filp, int datasync)
 {
-       struct inode *bmp_vi, *vi = dentry->d_inode;
+       struct inode *bmp_vi, *vi = filp->f_mapping->host;
        int err, ret;
        ntfs_attr na;
 
index a1924a0..113ebd9 100644 (file)
@@ -2133,7 +2133,6 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 /**
  * ntfs_file_fsync - sync a file to disk
  * @filp:      file to be synced
- * @dentry:    dentry describing the file to sync
  * @datasync:  if non-zero only flush user data and not metadata
  *
  * Data integrity sync of a file to disk.  Used for fsync, fdatasync, and msync
@@ -2149,19 +2148,15 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  * Also, if @datasync is true, we do not wait on the inode to be written out
  * but we always wait on the page cache pages to be written out.
  *
- * Note: In the past @filp could be NULL so we ignore it as we don't need it
- * anyway.
- *
  * Locking: Caller must hold i_mutex on the inode.
  *
  * TODO: We should probably also write all attribute/index inodes associated
  * with this inode but since we have no simple way of getting to them we ignore
  * this problem for now.
  */
-static int ntfs_file_fsync(struct file *filp, struct dentry *dentry,
-               int datasync)
+static int ntfs_file_fsync(struct file *filp, int datasync)
 {
-       struct inode *vi = dentry->d_inode;
+       struct inode *vi = filp->f_mapping->host;
        int err, ret = 0;
 
        ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
index 97e54b9..6a13ea6 100644 (file)
@@ -175,13 +175,12 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int ocfs2_sync_file(struct file *file,
-                          struct dentry *dentry,
-                          int datasync)
+static int ocfs2_sync_file(struct file *file, int datasync)
 {
        int err = 0;
        journal_t *journal;
-       struct inode *inode = dentry->d_inode;
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,
@@ -1053,7 +1052,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        /*
-        * This will intentionally not wind up calling vmtruncate(),
+        * This will intentionally not wind up calling simple_setsize(),
         * since all the work for a size change has been done above.
         * Otherwise, we could get into problems with truncate as
         * ip_alloc_sem is used there to protect against i_size
@@ -2119,9 +2118,13 @@ relock:
                         * direct write may have instantiated a few
                         * blocks outside i_size. Trim these off again.
                         * Don't need i_size_read because we hold i_mutex.
+                        *
+                        * XXX(hch): this looks buggy because ocfs2 did not
+                        * actually implement ->truncate.  Take a look at
+                        * the new truncate sequence and update this accordingly
                         */
                        if (*ppos + count > inode->i_size)
-                               vmtruncate(inode, inode->i_size);
+                               simple_setsize(inode, inode->i_size);
                        ret = written;
                        goto out_dio;
                }
index 2c26ce2..0eaa929 100644 (file)
@@ -879,13 +879,15 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
                if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                        continue;
                if (unsuspend)
-                       status = vfs_quota_enable(
-                                       sb_dqopt(sb)->files[type],
-                                       type, QFMT_OCFS2,
-                                       DQUOT_SUSPENDED);
-               else
-                       status = vfs_quota_disable(sb, type,
-                                                  DQUOT_SUSPENDED);
+                       status = dquot_resume(sb, type);
+               else {
+                       struct ocfs2_mem_dqinfo *oinfo;
+
+                       /* Cancel periodic syncing before suspending */
+                       oinfo = sb_dqinfo(sb, type)->dqi_priv;
+                       cancel_delayed_work_sync(&oinfo->dqi_sync_work);
+                       status = dquot_suspend(sb, type);
+               }
                if (status < 0)
                        break;
        }
@@ -916,8 +918,8 @@ static int ocfs2_enable_quotas(struct ocfs2_super *osb)
                        status = -ENOENT;
                        goto out_quota_off;
                }
-               status = vfs_quota_enable(inode[type], type, QFMT_OCFS2,
-                                               DQUOT_USAGE_ENABLED);
+               status = dquot_enable(inode[type], type, QFMT_OCFS2,
+                                     DQUOT_USAGE_ENABLED);
                if (status < 0)
                        goto out_quota_off;
        }
@@ -952,8 +954,8 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
                /* Turn off quotas. This will remove all dquot structures from
                 * memory and so they will be automatically synced to global
                 * quota files */
-               vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED |
-                                           DQUOT_LIMITS_ENABLED);
+               dquot_disable(sb, type, DQUOT_USAGE_ENABLED |
+                                       DQUOT_LIMITS_ENABLED);
                if (!inode)
                        continue;
                iput(inode);
@@ -962,7 +964,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 
 /* Handle quota on quotactl */
 static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
-                         char *path, int remount)
+                         char *path)
 {
        unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
                                             OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
@@ -970,30 +972,24 @@ static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
        if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                return -EINVAL;
 
-       if (remount)
-               return 0;       /* Just ignore it has been handled in
-                                * ocfs2_remount() */
-       return vfs_quota_enable(sb_dqopt(sb)->files[type], type,
-                                   format_id, DQUOT_LIMITS_ENABLED);
+       return dquot_enable(sb_dqopt(sb)->files[type], type,
+                           format_id, DQUOT_LIMITS_ENABLED);
 }
 
 /* Handle quota off quotactl */
-static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
+static int ocfs2_quota_off(struct super_block *sb, int type)
 {
-       if (remount)
-               return 0;       /* Ignore now and handle later in
-                                * ocfs2_remount() */
-       return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
+       return dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
 }
 
 static const struct quotactl_ops ocfs2_quotactl_ops = {
        .quota_on       = ocfs2_quota_on,
        .quota_off      = ocfs2_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk,
 };
 
 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
index 399487c..6e7a329 100644 (file)
@@ -329,7 +329,7 @@ const struct file_operations omfs_file_operations = {
        .aio_read = generic_file_aio_read,
        .aio_write = generic_file_aio_write,
        .mmap = generic_file_mmap,
-       .fsync = simple_fsync,
+       .fsync = generic_file_fsync,
        .splice_read = generic_file_splice_read,
 };
 
index d79872e..60da077 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1169,14 +1169,18 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case F_SETPIPE_SZ:
-               if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages)
-                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                /*
                 * The pipe needs to be at least 2 pages large to
                 * guarantee POSIX behaviour.
                 */
-               if (arg < 2)
-                       return -EINVAL;
+               if (arg < 2) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                ret = pipe_set_size(pipe, arg);
                break;
        case F_GETPIPE_SZ:
@@ -1187,6 +1191,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
        }
 
+out:
        mutex_unlock(&pipe->inode->i_mutex);
        return ret;
 }
index 3d3fd46..6e8fc62 100644 (file)
@@ -80,7 +80,7 @@ const struct file_operations qnx4_dir_operations =
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = qnx4_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 const struct inode_operations qnx4_dir_inode_operations =
index 1ad8bf0..12c233d 100644 (file)
@@ -228,10 +228,6 @@ static struct hlist_head *dquot_hash;
 
 struct dqstats dqstats;
 EXPORT_SYMBOL(dqstats);
-#ifdef CONFIG_SMP
-struct dqstats *dqstats_pcpu;
-EXPORT_SYMBOL(dqstats_pcpu);
-#endif
 
 static qsize_t inode_get_rsv_space(struct inode *inode);
 static void __dquot_initialize(struct inode *inode, int type);
@@ -584,7 +580,7 @@ out:
 }
 EXPORT_SYMBOL(dquot_scan_active);
 
-int vfs_quota_sync(struct super_block *sb, int type, int wait)
+int dquot_quota_sync(struct super_block *sb, int type, int wait)
 {
        struct list_head *dirty;
        struct dquot *dquot;
@@ -656,7 +652,7 @@ int vfs_quota_sync(struct super_block *sb, int type, int wait)
 
        return 0;
 }
-EXPORT_SYMBOL(vfs_quota_sync);
+EXPORT_SYMBOL(dquot_quota_sync);
 
 /* Free unused dquots from cache */
 static void prune_dqcache(int count)
@@ -676,27 +672,10 @@ static void prune_dqcache(int count)
        }
 }
 
-static int dqstats_read(unsigned int type)
-{
-       int count = 0;
-#ifdef CONFIG_SMP
-       int cpu;
-       for_each_possible_cpu(cpu)
-               count += per_cpu_ptr(dqstats_pcpu, cpu)->stat[type];
-       /* Statistics reading is racy, but absolute accuracy isn't required */
-       if (count < 0)
-               count = 0;
-#else
-       count = dqstats.stat[type];
-#endif
-       return count;
-}
-
 /*
  * This is called from kswapd when we think we need some
  * more memory
  */
-
 static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
 {
        if (nr) {
@@ -704,7 +683,9 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
                prune_dqcache(nr);
                spin_unlock(&dq_list_lock);
        }
-       return (dqstats_read(DQST_FREE_DQUOTS)/100) * sysctl_vfs_cache_pressure;
+       return ((unsigned)
+               percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS])
+               /100) * sysctl_vfs_cache_pressure;
 }
 
 static struct shrinker dqcache_shrinker = {
@@ -1815,7 +1796,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
        if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
                transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
        if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
-               transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_uid, GRPQUOTA);
+               transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
 
        ret = __dquot_transfer(inode, transfer_to);
        dqput_all(transfer_to);
@@ -1850,6 +1831,7 @@ const struct dquot_operations dquot_operations = {
        .alloc_dquot    = dquot_alloc,
        .destroy_dquot  = dquot_destroy,
 };
+EXPORT_SYMBOL(dquot_operations);
 
 /*
  * Generic helper for ->open on filesystems supporting disk quotas.
@@ -1868,7 +1850,7 @@ EXPORT_SYMBOL(dquot_file_open);
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags)
+int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 {
        int cnt, ret = 0;
        struct quota_info *dqopt = sb_dqopt(sb);
@@ -1998,14 +1980,15 @@ put_inodes:
                }
        return ret;
 }
-EXPORT_SYMBOL(vfs_quota_disable);
+EXPORT_SYMBOL(dquot_disable);
 
-int vfs_quota_off(struct super_block *sb, int type, int remount)
+int dquot_quota_off(struct super_block *sb, int type)
 {
-       return vfs_quota_disable(sb, type, remount ? DQUOT_SUSPENDED :
-                                (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED));
+       return dquot_disable(sb, type,
+                            DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 }
-EXPORT_SYMBOL(vfs_quota_off);
+EXPORT_SYMBOL(dquot_quota_off);
+
 /*
  *     Turn quotas on on a device
  */
@@ -2123,36 +2106,43 @@ out_fmt:
 }
 
 /* Reenable quotas on remount RW */
-static int vfs_quota_on_remount(struct super_block *sb, int type)
+int dquot_resume(struct super_block *sb, int type)
 {
        struct quota_info *dqopt = sb_dqopt(sb);
        struct inode *inode;
-       int ret;
+       int ret = 0, cnt;
        unsigned int flags;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (!sb_has_quota_suspended(sb, type)) {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (type != -1 && cnt != type)
+                       continue;
+
+               mutex_lock(&dqopt->dqonoff_mutex);
+               if (!sb_has_quota_suspended(sb, cnt)) {
+                       mutex_unlock(&dqopt->dqonoff_mutex);
+                       continue;
+               }
+               inode = dqopt->files[cnt];
+               dqopt->files[cnt] = NULL;
+               spin_lock(&dq_state_lock);
+               flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
+                                                       DQUOT_LIMITS_ENABLED,
+                                                       cnt);
+               dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt);
+               spin_unlock(&dq_state_lock);
                mutex_unlock(&dqopt->dqonoff_mutex);
-               return 0;
-       }
-       inode = dqopt->files[type];
-       dqopt->files[type] = NULL;
-       spin_lock(&dq_state_lock);
-       flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
-                                               DQUOT_LIMITS_ENABLED, type);
-       dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, type);
-       spin_unlock(&dq_state_lock);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
-       flags = dquot_generic_flag(flags, type);
-       ret = vfs_load_quota_inode(inode, type, dqopt->info[type].dqi_fmt_id,
-                                  flags);
-       iput(inode);
+               flags = dquot_generic_flag(flags, cnt);
+               ret = vfs_load_quota_inode(inode, cnt,
+                               dqopt->info[cnt].dqi_fmt_id, flags);
+               iput(inode);
+       }
 
        return ret;
 }
+EXPORT_SYMBOL(dquot_resume);
 
-int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
                      struct path *path)
 {
        int error = security_quota_on(path->dentry);
@@ -2167,40 +2157,36 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
                                             DQUOT_LIMITS_ENABLED);
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on_path);
+EXPORT_SYMBOL(dquot_quota_on_path);
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name,
-                int remount)
+int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name)
 {
        struct path path;
        int error;
 
-       if (remount)
-               return vfs_quota_on_remount(sb, type);
-
        error = kern_path(name, LOOKUP_FOLLOW, &path);
        if (!error) {
-               error = vfs_quota_on_path(sb, type, format_id, &path);
+               error = dquot_quota_on_path(sb, type, format_id, &path);
                path_put(&path);
        }
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on);
+EXPORT_SYMBOL(dquot_quota_on);
 
 /*
  * More powerful function for turning on quotas allowing setting
  * of individual quota flags
  */
-int vfs_quota_enable(struct inode *inode, int type, int format_id,
-               unsigned int flags)
+int dquot_enable(struct inode *inode, int type, int format_id,
+                unsigned int flags)
 {
        int ret = 0;
        struct super_block *sb = inode->i_sb;
        struct quota_info *dqopt = sb_dqopt(sb);
 
        /* Just unsuspend quotas? */
-       if (flags & DQUOT_SUSPENDED)
-               return vfs_quota_on_remount(sb, type);
+       BUG_ON(flags & DQUOT_SUSPENDED);
+
        if (!flags)
                return 0;
        /* Just updating flags needed? */
@@ -2232,13 +2218,13 @@ out_lock:
 load_quota:
        return vfs_load_quota_inode(inode, type, format_id, flags);
 }
-EXPORT_SYMBOL(vfs_quota_enable);
+EXPORT_SYMBOL(dquot_enable);
 
 /*
  * This function is used when filesystem needs to initialize quotas
  * during mount time.
  */
-int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
+int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
                int format_id, int type)
 {
        struct dentry *dentry;
@@ -2264,24 +2250,7 @@ out:
        dput(dentry);
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on_mount);
-
-/* Wrapper to turn on quotas when remounting rw */
-int vfs_dq_quota_on_remount(struct super_block *sb)
-{
-       int cnt;
-       int ret = 0, err;
-
-       if (!sb->s_qcop || !sb->s_qcop->quota_on)
-               return -ENOSYS;
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               err = sb->s_qcop->quota_on(sb, cnt, 0, NULL, 1);
-               if (err < 0 && !ret)
-                       ret = err;
-       }
-       return ret;
-}
-EXPORT_SYMBOL(vfs_dq_quota_on_remount);
+EXPORT_SYMBOL(dquot_quota_on_mount);
 
 static inline qsize_t qbtos(qsize_t blocks)
 {
@@ -2316,8 +2285,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
        spin_unlock(&dq_data_lock);
 }
 
-int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
-                 struct fs_disk_quota *di)
+int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+                   struct fs_disk_quota *di)
 {
        struct dquot *dquot;
 
@@ -2329,7 +2298,7 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
 
        return 0;
 }
-EXPORT_SYMBOL(vfs_get_dqblk);
+EXPORT_SYMBOL(dquot_get_dqblk);
 
 #define VFS_FS_DQ_MASK \
        (FS_DQ_BCOUNT | FS_DQ_BSOFT | FS_DQ_BHARD | \
@@ -2428,7 +2397,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
        return 0;
 }
 
-int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
                  struct fs_disk_quota *di)
 {
        struct dquot *dquot;
@@ -2444,10 +2413,10 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
 out:
        return rc;
 }
-EXPORT_SYMBOL(vfs_set_dqblk);
+EXPORT_SYMBOL(dquot_set_dqblk);
 
 /* Generic routine for getting common part of quota file information */
-int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
   
@@ -2466,10 +2435,10 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
-EXPORT_SYMBOL(vfs_get_dqinfo);
+EXPORT_SYMBOL(dquot_get_dqinfo);
 
 /* Generic routine for setting common part of quota file information */
-int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
        int err = 0;
@@ -2496,27 +2465,27 @@ out:
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return err;
 }
-EXPORT_SYMBOL(vfs_set_dqinfo);
+EXPORT_SYMBOL(dquot_set_dqinfo);
 
-const struct quotactl_ops vfs_quotactl_ops = {
-       .quota_on       = vfs_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+const struct quotactl_ops dquot_quotactl_ops = {
+       .quota_on       = dquot_quota_on,
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
-
+EXPORT_SYMBOL(dquot_quotactl_ops);
 
 static int do_proc_dqstats(struct ctl_table *table, int write,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-#ifdef CONFIG_SMP
-       /* Update global table */
        unsigned int type = (int *)table->data - dqstats.stat;
-       dqstats.stat[type] = dqstats_read(type);
-#endif
+
+       /* Update global table */
+       dqstats.stat[type] =
+                       percpu_counter_sum_positive(&dqstats.counter[type]);
        return proc_dointvec(table, write, buffer, lenp, ppos);
 }
 
@@ -2609,7 +2578,7 @@ static ctl_table sys_table[] = {
 
 static int __init dquot_init(void)
 {
-       int i;
+       int i, ret;
        unsigned long nr_hash, order;
 
        printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__);
@@ -2627,12 +2596,11 @@ static int __init dquot_init(void)
        if (!dquot_hash)
                panic("Cannot create dquot hash table");
 
-#ifdef CONFIG_SMP
-       dqstats_pcpu = alloc_percpu(struct dqstats);
-       if (!dqstats_pcpu)
-               panic("Cannot create dquot stats table");
-#endif
-       memset(&dqstats, 0, sizeof(struct dqstats));
+       for (i = 0; i < _DQST_DQSTAT_LAST; i++) {
+               ret = percpu_counter_init(&dqstats.counter[i], 0);
+               if (ret)
+                       panic("Cannot create dquot stat counters");
+       }
 
        /* Find power-of-two hlist_heads which can fit into allocation */
        nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head);
index ce3dfd0..b299961 100644 (file)
@@ -73,7 +73,7 @@ static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
        if (IS_ERR(pathname))
                return PTR_ERR(pathname);
        if (sb->s_qcop->quota_on)
-               ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
+               ret = sb->s_qcop->quota_on(sb, type, id, pathname);
        putname(pathname);
        return ret;
 }
@@ -260,7 +260,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
        case Q_QUOTAOFF:
                if (!sb->s_qcop->quota_off)
                        return -ENOSYS;
-               return sb->s_qcop->quota_off(sb, type, 0);
+               return sb->s_qcop->quota_off(sb, type);
        case Q_GETFMT:
                return quota_getfmt(sb, type, addr);
        case Q_GETINFO:
index 78f613c..4884ac5 100644 (file)
@@ -43,12 +43,13 @@ const struct file_operations ramfs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
        .llseek         = generic_file_llseek,
 };
 
 const struct inode_operations ramfs_file_inode_operations = {
+       .setattr        = simple_setattr,
        .getattr        = simple_getattr,
 };
index 5ea4ad8..d532c20 100644 (file)
@@ -42,7 +42,7 @@ const struct file_operations ramfs_file_operations = {
        .aio_read               = generic_file_aio_read,
        .write                  = do_sync_write,
        .aio_write              = generic_file_aio_write,
-       .fsync                  = simple_sync_file,
+       .fsync                  = noop_fsync,
        .splice_read            = generic_file_splice_read,
        .splice_write           = generic_file_splice_write,
        .llseek                 = generic_file_llseek,
@@ -146,7 +146,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
                        return ret;
        }
 
-       ret = vmtruncate(inode, newsize);
+       ret = simple_setsize(inode, newsize);
 
        return ret;
 }
@@ -169,7 +169,8 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
 
        /* pick out size-changing events */
        if (ia->ia_valid & ATTR_SIZE) {
-               loff_t size = i_size_read(inode);
+               loff_t size = inode->i_size;
+
                if (ia->ia_size != size) {
                        ret = ramfs_nommu_resize(inode, ia->ia_size, size);
                        if (ret < 0 || ia->ia_valid == ATTR_SIZE)
@@ -182,7 +183,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
                }
        }
 
-       ret = inode_setattr(inode, ia);
+       generic_setattr(inode, ia);
  out:
        ia->ia_valid = old_ia_valid;
        return ret;
index 4455fbe..198dabf 100644 (file)
@@ -14,8 +14,7 @@
 extern const struct reiserfs_key MIN_KEY;
 
 static int reiserfs_readdir(struct file *, void *, filldir_t);
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
-                             int datasync);
+static int reiserfs_dir_fsync(struct file *filp, int datasync);
 
 const struct file_operations reiserfs_dir_operations = {
        .llseek = generic_file_llseek,
@@ -28,10 +27,9 @@ const struct file_operations reiserfs_dir_operations = {
 #endif
 };
 
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
-                             int datasync)
+static int reiserfs_dir_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int err;
        reiserfs_write_lock(inode->i_sb);
        err = reiserfs_commit_for_inode(inode);
index 9977df9..b82cdd8 100644 (file)
@@ -134,10 +134,9 @@ static void reiserfs_vfs_truncate_file(struct inode *inode)
  * be removed...
  */
 
-static int reiserfs_sync_file(struct file *filp,
-                             struct dentry *dentry, int datasync)
+static int reiserfs_sync_file(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int err;
        int barrier_done;
 
index 59125fb..9822fa1 100644 (file)
@@ -158,6 +158,7 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        int i;
        int ms_active_set;
+       int quota_enabled[MAXQUOTAS];
 #endif
 
        /* compose key to look for "save" links */
@@ -179,8 +180,15 @@ static int finish_unfinished(struct super_block *s)
        }
        /* Turn on quotas so that they are updated correctly */
        for (i = 0; i < MAXQUOTAS; i++) {
+               quota_enabled[i] = 1;
                if (REISERFS_SB(s)->s_qf_names[i]) {
-                       int ret = reiserfs_quota_on_mount(s, i);
+                       int ret;
+
+                       if (sb_has_quota_active(s, i)) {
+                               quota_enabled[i] = 0;
+                               continue;
+                       }
+                       ret = reiserfs_quota_on_mount(s, i);
                        if (ret < 0)
                                reiserfs_warning(s, "reiserfs-2500",
                                                 "cannot turn on journaled "
@@ -304,8 +312,8 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
-               if (sb_dqopt(s)->files[i])
-                       vfs_quota_off(s, i, 0);
+               if (sb_dqopt(s)->files[i] && quota_enabled[i])
+                       dquot_quota_off(s, i);
        }
        if (ms_active_set)
                /* Restore the flag back */
@@ -466,6 +474,8 @@ static void reiserfs_put_super(struct super_block *s)
        struct reiserfs_transaction_handle th;
        th.t_trans_id = 0;
 
+       dquot_disable(s, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        reiserfs_write_lock(s);
 
        if (s->s_dirt)
@@ -620,7 +630,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
 static int reiserfs_release_dquot(struct dquot *);
 static int reiserfs_mark_dquot_dirty(struct dquot *);
 static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *, int);
+static int reiserfs_quota_on(struct super_block *, int, int, char *);
 
 static const struct dquot_operations reiserfs_quota_operations = {
        .write_dquot = reiserfs_write_dquot,
@@ -634,12 +644,12 @@ static const struct dquot_operations reiserfs_quota_operations = {
 
 static const struct quotactl_ops reiserfs_qctl_operations = {
        .quota_on = reiserfs_quota_on,
-       .quota_off = vfs_quota_off,
-       .quota_sync = vfs_quota_sync,
-       .get_info = vfs_get_dqinfo,
-       .set_info = vfs_set_dqinfo,
-       .get_dqblk = vfs_get_dqblk,
-       .set_dqblk = vfs_set_dqblk,
+       .quota_off = dquot_quota_off,
+       .quota_sync = dquot_quota_sync,
+       .get_info = dquot_get_dqinfo,
+       .set_info = dquot_set_dqinfo,
+       .get_dqblk = dquot_get_dqblk,
+       .set_dqblk = dquot_set_dqblk,
 };
 #endif
 
@@ -1242,6 +1252,11 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                if (s->s_flags & MS_RDONLY)
                        /* it is read-only already */
                        goto out_ok;
+
+               err = dquot_suspend(s, -1);
+               if (err < 0)
+                       goto out_err;
+
                /* try to remount file system with read-only permissions */
                if (sb_umount_state(rs) == REISERFS_VALID_FS
                    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
@@ -1295,6 +1310,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        s->s_dirt = 0;
 
        if (!(*mount_flags & MS_RDONLY)) {
+               dquot_resume(s, -1);
                finish_unfinished(s);
                reiserfs_xattr_init(s, *mount_flags);
        }
@@ -2022,15 +2038,15 @@ static int reiserfs_write_info(struct super_block *sb, int type)
  */
 static int reiserfs_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
-                                 REISERFS_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
+                                       REISERFS_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
-                            char *name, int remount)
+                            char *name)
 {
        int err;
        struct path path;
@@ -2039,9 +2055,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
 
        if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
                return -EINVAL;
-       /* No more checks needed? Path and format_id are bogus anyway... */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, 1);
+
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
@@ -2085,7 +2099,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
                if (err)
                        goto out;
        }
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
 out:
        path_put(&path);
        return err;
index 84ecf0e..8e187a0 100644 (file)
@@ -28,8 +28,9 @@
 #include "proto.h"
 
 static int
-smb_fsync(struct file *file, struct dentry * dentry, int datasync)
+smb_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct smb_sb_info *server = server_from_dentry(dentry);
        int result;
 
index dfa1d67..9551cb6 100644 (file)
@@ -714,7 +714,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
                error = server->ops->truncate(inode, attr->ia_size);
                if (error)
                        goto out;
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                if (error)
                        goto out;
                refresh = 1;
index 69688b1..5c35bc7 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
-#include <linux/quotaops.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/writeback.h>           /* for the emergency remount stuff */
@@ -94,8 +93,6 @@ static struct super_block *alloc_super(struct file_system_type *type)
                init_rwsem(&s->s_dquot.dqptr_sem);
                init_waitqueue_head(&s->s_wait_unfrozen);
                s->s_maxbytes = MAX_NON_LFS;
-               s->dq_op = sb_dquot_ops;
-               s->s_qcop = sb_quotactl_ops;
                s->s_op = &default_op;
                s->s_time_gran = 1000000000;
        }
@@ -160,7 +157,6 @@ void deactivate_locked_super(struct super_block *s)
 {
        struct file_system_type *fs = s->s_type;
        if (atomic_dec_and_test(&s->s_active)) {
-               vfs_dq_off(s, 0);
                fs->kill_sb(s);
                put_filesystem(fs);
                put_super(s);
@@ -524,7 +520,7 @@ rescan:
 int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 {
        int retval;
-       int remount_rw, remount_ro;
+       int remount_ro;
 
        if (sb->s_frozen != SB_UNFROZEN)
                return -EBUSY;
@@ -540,7 +536,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
        sync_filesystem(sb);
 
        remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
-       remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
 
        /* If we are remounting RDONLY and current sb is read/write,
           make sure there are no rw files opened */
@@ -549,9 +544,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        mark_files_ro(sb);
                else if (!fs_may_remount_ro(sb))
                        return -EBUSY;
-               retval = vfs_dq_off(sb, 1);
-               if (retval < 0 && retval != -ENOSYS)
-                       return -EBUSY;
        }
 
        if (sb->s_op->remount_fs) {
@@ -560,8 +552,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        return retval;
        }
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-       if (remount_rw)
-               vfs_dq_quota_on_remount(sb);
+
        /*
         * Some filesystems modify their metadata via some other path than the
         * bdev buffer cache (eg. use a private mapping, or directories in
@@ -946,8 +937,8 @@ out:
 EXPORT_SYMBOL_GPL(vfs_kern_mount);
 
 /**
- * freeze_super -- lock the filesystem and force it into a consistent state
- * @super: the super to lock
+ * freeze_super - lock the filesystem and force it into a consistent state
+ * @sb: the super to lock
  *
  * Syncs the super to make sure the filesystem is consistent and calls the fs's
  * freeze_fs.  Subsequent calls to this without first thawing the fs will return
index e8cbd41..c9f83f4 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -130,12 +130,10 @@ void emergency_sync(void)
 
 /*
  * Generic function to fsync a file.
- *
- * filp may be NULL if called via the msync of a vma.
  */
-int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int file_fsync(struct file *filp, int datasync)
 {
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        struct super_block * sb;
        int ret, err;
 
@@ -183,7 +181,7 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
         * livelocks in fsync_buffers_list().
         */
        mutex_lock(&mapping->host->i_mutex);
-       err = file->f_op->fsync(file, file->f_path.dentry, datasync);
+       err = file->f_op->fsync(file, datasync);
        if (!ret)
                ret = err;
        mutex_unlock(&mapping->host->i_mutex);
index bbd77e9..bde1a4c 100644 (file)
@@ -117,13 +117,11 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
        if (error)
                goto out;
 
-       iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
-
-       error = inode_setattr(inode, iattr);
-       if (error)
-               goto out;
+       /* this ignores size changes */
+       generic_setattr(inode, iattr);
 
        error = sysfs_sd_setattr(sd, iattr);
+
 out:
        mutex_unlock(&sysfs_mutex);
        return error;
index 1dabed2..79941e4 100644 (file)
@@ -24,7 +24,7 @@ const struct file_operations sysv_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = sysv_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static inline void dir_put_page(struct page *page)
index 96340c0..750cc22 100644 (file)
@@ -26,7 +26,7 @@ const struct file_operations sysv_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
 
index 4573734..d4a5380 100644 (file)
@@ -43,6 +43,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
         * then attach current time stamp.
         * But if the filesystem was marked clean, keep it clean.
         */
+       sb->s_dirt = 0;
        old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
        if (sbi->s_type == FSTYPE_SYSV4) {
                if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
index 5692cf7..12f445c 100644 (file)
@@ -967,12 +967,15 @@ static int do_writepage(struct page *page, int len)
  * the page locked, and it locks @ui_mutex. However, write-back does take inode
  * @i_mutex, which means other VFS operations may be run on this inode at the
  * same time. And the problematic one is truncation to smaller size, from where
- * we have to call 'vmtruncate()', which first changes @inode->i_size, then
+ * we have to call 'simple_setsize()', which first changes @inode->i_size, then
  * drops the truncated pages. And while dropping the pages, it takes the page
- * lock. This means that 'do_truncation()' cannot call 'vmtruncate()' with
+ * lock. This means that 'do_truncation()' cannot call 'simple_setsize()' with
  * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
  * means that @inode->i_size is changed while @ui_mutex is unlocked.
  *
+ * XXX: with the new truncate the above is not true anymore, the simple_setsize
+ * calls can be replaced with the individual components.
+ *
  * But in 'ubifs_writepage()' we have to guarantee that we do not write beyond
  * inode size. How do we do this if @inode->i_size may became smaller while we
  * are in the middle of 'ubifs_writepage()'? The UBIFS solution is the
@@ -1125,7 +1128,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
                budgeted = 0;
        }
 
-       err = vmtruncate(inode, new_size);
+       err = simple_setsize(inode, new_size);
        if (err)
                goto out_budg;
 
@@ -1214,7 +1217,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
 
        if (attr->ia_valid & ATTR_SIZE) {
                dbg_gen("size %lld -> %lld", inode->i_size, new_size);
-               err = vmtruncate(inode, new_size);
+               err = simple_setsize(inode, new_size);
                if (err)
                        goto out;
        }
@@ -1223,7 +1226,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
        if (attr->ia_valid & ATTR_SIZE) {
                /* Truncation changes inode [mc]time */
                inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
-               /* 'vmtruncate()' changed @i_size, update @ui_size */
+               /* 'simple_setsize()' changed @i_size, update @ui_size */
                ui->ui_size = inode->i_size;
        }
 
@@ -1304,9 +1307,9 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
        return NULL;
 }
 
-int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ubifs_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        int err;
 
index bd2542d..2eef553 100644 (file)
@@ -379,7 +379,7 @@ struct ubifs_gced_idx_leb {
  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
  * make sure @inode->i_size is always changed under @ui_mutex, because it
- * cannot call 'vmtruncate()' with @ui_mutex locked, because it would deadlock
+ * cannot call 'simple_setsize()' with @ui_mutex locked, because it would deadlock
  * with 'ubifs_writepage()' (see file.c). All the other inode fields are
  * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
  * could consider to rework locking and base it on "shadow" fields.
@@ -1678,7 +1678,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
 int ubifs_calc_dark(const struct ubifs_info *c, int spc);
 
 /* file.c */
-int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int ubifs_fsync(struct file *file, int datasync);
 int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
 
 /* dir.c */
index 9a9378b..b608efa 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "udfdecl.h"
 
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/bitops.h>
 
@@ -159,8 +158,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
                                udf_debug("byte=%2x\n",
                                        ((char *)bh->b_data)[(bit + i) >> 3]);
                        } else {
-                               if (inode)
-                                       dquot_free_block(inode, 1);
                                udf_add_free_space(sb, sbi->s_partition, 1);
                        }
                }
@@ -210,15 +207,8 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
                bit = block % (sb->s_blocksize << 3);
 
                while (bit < (sb->s_blocksize << 3) && block_count > 0) {
-                       if (!udf_test_bit(bit, bh->b_data))
+                       if (!udf_clear_bit(bit, bh->b_data))
                                goto out;
-                       else if (dquot_prealloc_block(inode, 1))
-                               goto out;
-                       else if (!udf_clear_bit(bit, bh->b_data)) {
-                               udf_debug("bit already cleared for block %d\n", bit);
-                               dquot_free_block(inode, 1);
-                               goto out;
-                       }
                        block_count--;
                        alloc_count++;
                        bit++;
@@ -338,20 +328,6 @@ search_back:
        }
 
 got_block:
-
-       /*
-        * Check quota for allocation of this block.
-        */
-       if (inode) {
-               int ret = dquot_alloc_block(inode, 1);
-
-               if (ret) {
-                       mutex_unlock(&sbi->s_alloc_mutex);
-                       *err = ret;
-                       return 0;
-               }
-       }
-
        newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
                (sizeof(struct spaceBitmapDesc) << 3);
 
@@ -401,10 +377,6 @@ static void udf_table_free_blocks(struct super_block *sb,
        }
 
        iinfo = UDF_I(table);
-       /* We do this up front - There are some error conditions that
-          could occure, but.. oh well */
-       if (inode)
-               dquot_free_block(inode, count);
        udf_add_free_space(sb, sbi->s_partition, count);
 
        start = bloc->logicalBlockNum + offset;
@@ -649,10 +621,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
                epos.offset -= adsize;
 
                alloc_count = (elen >> sb->s_blocksize_bits);
-               if (inode && dquot_prealloc_block(inode,
-                       alloc_count > block_count ? block_count : alloc_count))
-                       alloc_count = 0;
-               else if (alloc_count > block_count) {
+               if (alloc_count > block_count) {
                        alloc_count = block_count;
                        eloc.logicalBlockNum += alloc_count;
                        elen -= (alloc_count << sb->s_blocksize_bits);
@@ -752,14 +721,6 @@ static int udf_table_new_block(struct super_block *sb,
        newblock = goal_eloc.logicalBlockNum;
        goal_eloc.logicalBlockNum++;
        goal_elen -= sb->s_blocksize;
-       if (inode) {
-               *err = dquot_alloc_block(inode, 1);
-               if (*err) {
-                       brelse(goal_epos.bh);
-                       mutex_unlock(&sbi->s_alloc_mutex);
-                       return 0;
-               }
-       }
 
        if (goal_elen)
                udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
index 1660c81..51552bf 100644 (file)
@@ -211,5 +211,5 @@ const struct file_operations udf_dir_operations = {
        .read                   = generic_read_dir,
        .readdir                = udf_readdir,
        .unlocked_ioctl         = udf_ioctl,
-       .fsync                  = simple_fsync,
+       .fsync                  = generic_file_fsync,
 };
index baae3a7..94e06d6 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/pagemap.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/aio.h>
 #include <linux/smp_lock.h>
@@ -219,39 +218,16 @@ const struct file_operations udf_file_operations = {
        .read                   = do_sync_read,
        .aio_read               = generic_file_aio_read,
        .unlocked_ioctl         = udf_ioctl,
-       .open                   = dquot_file_open,
+       .open                   = generic_file_open,
        .mmap                   = generic_file_mmap,
        .write                  = do_sync_write,
        .aio_write              = udf_file_aio_write,
        .release                = udf_release_file,
-       .fsync                  = simple_fsync,
+       .fsync                  = generic_file_fsync,
        .splice_read            = generic_file_splice_read,
        .llseek                 = generic_file_llseek,
 };
 
-int udf_setattr(struct dentry *dentry, struct iattr *iattr)
-{
-       struct inode *inode = dentry->d_inode;
-       int error;
-
-       error = inode_change_ok(inode, iattr);
-       if (error)
-               return error;
-
-       if (is_quota_modification(inode, iattr))
-               dquot_initialize(inode);
-
-       if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-            (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
-               error = dquot_transfer(inode, iattr);
-               if (error)
-                       return error;
-       }
-
-       return inode_setattr(inode, iattr);
-}
-
 const struct inode_operations udf_file_inode_operations = {
        .truncate               = udf_truncate,
-       .setattr                = udf_setattr,
 };
index 2b5586c..18cd711 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "udfdecl.h"
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
@@ -32,13 +31,6 @@ void udf_free_inode(struct inode *inode)
        struct super_block *sb = inode->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
 
-       /*
-        * Note: we must free any quota before locking the superblock,
-        * as writing the quota to disk may need the lock as well.
-        */
-       dquot_free_inode(inode);
-       dquot_drop(inode);
-
        clear_inode(inode);
 
        mutex_lock(&sbi->s_alloc_mutex);
@@ -61,7 +53,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        struct super_block *sb = dir->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct inode *inode;
-       int block, ret;
+       int block;
        uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
        struct udf_inode_info *iinfo;
        struct udf_inode_info *dinfo = UDF_I(dir);
@@ -146,17 +138,6 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
 
-       dquot_initialize(inode);
-       ret = dquot_alloc_inode(inode);
-       if (ret) {
-               dquot_drop(inode);
-               inode->i_flags |= S_NOQUOTA;
-               inode->i_nlink = 0;
-               iput(inode);
-               *err = ret;
-               return NULL;
-       }
-
        *err = 0;
        return inode;
 }
index 8a3fbd1..124852b 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/crc-itu-t.h>
 
@@ -71,9 +70,6 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 void udf_delete_inode(struct inode *inode)
 {
-       if (!is_bad_inode(inode))
-               dquot_initialize(inode);
-
        truncate_inode_pages(&inode->i_data, 0);
 
        if (is_bad_inode(inode))
@@ -113,7 +109,6 @@ void udf_clear_inode(struct inode *inode)
                        (unsigned long long)iinfo->i_lenExtents);
        }
 
-       dquot_drop(inode);
        kfree(iinfo->i_ext.i_data);
        iinfo->i_ext.i_data = NULL;
 }
index 585f733..bf5fc67 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/quotaops.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
@@ -563,8 +562,6 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
        int err;
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode = udf_new_inode(dir, mode, &err);
        if (!inode) {
@@ -617,8 +614,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
        if (!old_valid_dev(rdev))
                return -EINVAL;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        err = -EIO;
        inode = udf_new_inode(dir, mode, &err);
@@ -664,8 +659,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct udf_inode_info *dinfo = UDF_I(dir);
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        err = -EMLINK;
        if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
@@ -800,8 +793,6 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
        struct fileIdentDesc *fi, cfi;
        struct kernel_lb_addr tloc;
 
-       dquot_initialize(dir);
-
        retval = -ENOENT;
        lock_kernel();
        fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
@@ -848,8 +839,6 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
        struct fileIdentDesc cfi;
        struct kernel_lb_addr tloc;
 
-       dquot_initialize(dir);
-
        retval = -ENOENT;
        lock_kernel();
        fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
@@ -904,8 +893,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        struct buffer_head *bh;
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);
        if (!inode)
@@ -1075,8 +1062,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        int err;
        struct buffer_head *bh;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
                unlock_kernel();
@@ -1139,9 +1124,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct kernel_lb_addr tloc;
        struct udf_inode_info *old_iinfo = UDF_I(old_inode);
 
-       dquot_initialize(old_dir);
-       dquot_initialize(new_dir);
-
        lock_kernel();
        ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
        if (ofi) {
@@ -1387,7 +1369,6 @@ const struct export_operations udf_export_ops = {
 const struct inode_operations udf_dir_inode_operations = {
        .lookup                         = udf_lookup,
        .create                         = udf_create,
-       .setattr                        = udf_setattr,
        .link                           = udf_link,
        .unlink                         = udf_unlink,
        .symlink                        = udf_symlink,
@@ -1400,5 +1381,4 @@ const struct inode_operations udf_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
-       .setattr        = udf_setattr,
 };
index 1e4543c..612d1e2 100644 (file)
@@ -557,6 +557,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 {
        struct udf_options uopt;
        struct udf_sb_info *sbi = UDF_SB(sb);
+       int error = 0;
 
        uopt.flags = sbi->s_flags;
        uopt.uid   = sbi->s_uid;
@@ -582,17 +583,17 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
                        *flags |= MS_RDONLY;
        }
 
-       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
-               unlock_kernel();
-               return 0;
-       }
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+               goto out_unlock;
+
        if (*flags & MS_RDONLY)
                udf_close_lvid(sb);
        else
                udf_open_lvid(sb);
 
+out_unlock:
        unlock_kernel();
-       return 0;
+       return error;
 }
 
 /* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
@@ -1939,7 +1940,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        /* Fill in the rest of the superblock */
        sb->s_op = &udf_sb_ops;
        sb->s_export_op = &udf_export_ops;
-       sb->dq_op = NULL;
+
        sb->s_dirt = 0;
        sb->s_magic = UDF_SUPER_MAGIC;
        sb->s_time_gran = 1000;
index 9079ff7..2bac035 100644 (file)
@@ -131,7 +131,6 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
 
 /* file.c */
 extern long udf_ioctl(struct file *, unsigned int, unsigned long);
-extern int udf_setattr(struct dentry *dentry, struct iattr *iattr);
 /* inode.c */
 extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
 extern int udf_sync_inode(struct inode *);
index 5cfa4d8..048484f 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/stat.h>
 #include <linux/time.h>
 #include <linux/string.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/capability.h>
 #include <linux/bitops.h>
@@ -85,9 +84,6 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
                                   "bit already cleared for fragment %u", i);
        }
        
-       dquot_free_block(inode, count);
-
-       
        fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
        uspi->cs_total.cs_nffree += count;
        fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -195,7 +191,6 @@ do_more:
                ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
                if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                        ufs_clusteracct (sb, ucpi, blkno, 1);
-               dquot_free_block(inode, uspi->s_fpb);
 
                fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
                uspi->cs_total.cs_nbfree++;
@@ -511,7 +506,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned cgno, fragno, fragoff, count, fragsize, i;
-       int ret;
        
        UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
             (unsigned long long)fragment, oldcount, newcount);
@@ -557,11 +551,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
                fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
        for (i = oldcount; i < newcount; i++)
                ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
-       ret = dquot_alloc_block(inode, count);
-       if (ret) {
-               *err = ret;
-               return 0;
-       }
 
        fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
        fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -598,7 +587,6 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
        struct ufs_cylinder_group * ucg;
        unsigned oldcg, i, j, k, allocsize;
        u64 result;
-       int ret;
        
        UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
             inode->i_ino, cgno, (unsigned long long)goal, count);
@@ -667,7 +655,6 @@ cg_found:
                for (i = count; i < uspi->s_fpb; i++)
                        ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
                i = uspi->s_fpb - count;
-               dquot_free_block(inode, i);
 
                fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
                uspi->cs_total.cs_nffree += i;
@@ -679,11 +666,6 @@ cg_found:
        result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
        if (result == INVBLOCK)
                return 0;
-       ret = dquot_alloc_block(inode, count);
-       if (ret) {
-               *err = ret;
-               return 0;
-       }
        for (i = 0; i < count; i++)
                ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
        
@@ -718,7 +700,6 @@ static u64 ufs_alloccg_block(struct inode *inode,
        struct ufs_super_block_first * usb1;
        struct ufs_cylinder_group * ucg;
        u64 result, blkno;
-       int ret;
 
        UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
 
@@ -752,11 +733,6 @@ gotit:
        ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
        if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                ufs_clusteracct (sb, ucpi, blkno, -1);
-       ret = dquot_alloc_block(inode, uspi->s_fpb);
-       if (ret) {
-               *err = ret;
-               return INVBLOCK;
-       }
 
        fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
        uspi->cs_total.cs_nbfree--;
index 317a0d4..ec78475 100644 (file)
@@ -666,6 +666,6 @@ not_empty:
 const struct file_operations ufs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = ufs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .llseek         = generic_file_llseek,
 };
index a8962ce..33afa20 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -41,7 +40,7 @@ const struct file_operations ufs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .open           = dquot_file_open,
-       .fsync          = simple_fsync,
+       .open           = generic_file_open,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
index 3a959d5..594480e 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/time.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
@@ -95,9 +94,6 @@ void ufs_free_inode (struct inode * inode)
 
        is_directory = S_ISDIR(inode->i_mode);
 
-       dquot_free_inode(inode);
-       dquot_drop(inode);
-
        clear_inode (inode);
 
        if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
@@ -347,21 +343,12 @@ cg_found:
 
        unlock_super (sb);
 
-       dquot_initialize(inode);
-       err = dquot_alloc_inode(inode);
-       if (err) {
-               dquot_drop(inode);
-               goto fail_without_unlock;
-       }
-
        UFSD("allocating inode %lu\n", inode->i_ino);
        UFSD("EXIT\n");
        return inode;
 
 fail_remove_inode:
        unlock_super(sb);
-fail_without_unlock:
-       inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
        iput(inode);
        UFSD("EXIT (FAILED): err %d\n", err);
index cffa756..73fe773 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -910,9 +909,6 @@ void ufs_delete_inode (struct inode * inode)
 {
        loff_t old_i_size;
 
-       if (!is_bad_inode(inode))
-               dquot_initialize(inode);
-
        truncate_inode_pages(&inode->i_data, 0);
        if (is_bad_inode(inode))
                goto no_delete;
index eabc02e..b056f02 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/smp_lock.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -86,8 +85,6 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
 
        UFSD("BEGIN\n");
 
-       dquot_initialize(dir);
-
        inode = ufs_new_inode(dir, mode);
        err = PTR_ERR(inode);
 
@@ -112,8 +109,6 @@ static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t
        if (!old_valid_dev(rdev))
                return -EINVAL;
 
-       dquot_initialize(dir);
-
        inode = ufs_new_inode(dir, mode);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
@@ -138,8 +133,6 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
        if (l > sb->s_blocksize)
                goto out_notlocked;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
        err = PTR_ERR(inode);
@@ -185,8 +178,6 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
                return -EMLINK;
        }
 
-       dquot_initialize(dir);
-
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
        atomic_inc(&inode->i_count);
@@ -204,8 +195,6 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
        if (dir->i_nlink >= UFS_LINK_MAX)
                goto out;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode_inc_link_count(dir);
 
@@ -250,8 +239,6 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry)
        struct page *page;
        int err = -ENOENT;
 
-       dquot_initialize(dir);
-
        de = ufs_find_entry(dir, &dentry->d_name, &page);
        if (!de)
                goto out;
@@ -296,9 +283,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct ufs_dir_entry *old_de;
        int err = -ENOENT;
 
-       dquot_initialize(old_dir);
-       dquot_initialize(new_dir);
-
        old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
        if (!old_de)
                goto out;
index ad9bc1e..3ec5a9e 100644 (file)
@@ -77,7 +77,6 @@
 
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/stat.h>
@@ -1047,7 +1046,7 @@ magic_found:
         */
        sb->s_op = &ufs_super_ops;
        sb->s_export_op = &ufs_export_ops;
-       sb->dq_op = NULL; /***/
+
        sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic);
 
        uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno);
@@ -1437,126 +1436,19 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(ufs_inode_cachep);
 }
 
-static void ufs_clear_inode(struct inode *inode)
-{
-       dquot_drop(inode);
-}
-
-#ifdef CONFIG_QUOTA
-static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t);
-static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t);
-#endif
-
 static const struct super_operations ufs_super_ops = {
        .alloc_inode    = ufs_alloc_inode,
        .destroy_inode  = ufs_destroy_inode,
        .write_inode    = ufs_write_inode,
        .delete_inode   = ufs_delete_inode,
-       .clear_inode    = ufs_clear_inode,
        .put_super      = ufs_put_super,
        .write_super    = ufs_write_super,
        .sync_fs        = ufs_sync_fs,
        .statfs         = ufs_statfs,
        .remount_fs     = ufs_remount,
        .show_options   = ufs_show_options,
-#ifdef CONFIG_QUOTA
-       .quota_read     = ufs_quota_read,
-       .quota_write    = ufs_quota_write,
-#endif
 };
 
-#ifdef CONFIG_QUOTA
-
-/* Read data from quotafile - avoid pagecache and such because we cannot afford
- * acquiring the locks... As quota files are never truncated and quota code
- * itself serializes the operations (and noone else should touch the files)
- * we don't have to be afraid of races */
-static ssize_t ufs_quota_read(struct super_block *sb, int type, char *data,
-                              size_t len, loff_t off)
-{
-       struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> sb->s_blocksize_bits;
-       int err = 0;
-       int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
-       size_t toread;
-       struct buffer_head *bh;
-       loff_t i_size = i_size_read(inode);
-
-       if (off > i_size)
-               return 0;
-       if (off+len > i_size)
-               len = i_size-off;
-       toread = len;
-       while (toread > 0) {
-               tocopy = sb->s_blocksize - offset < toread ?
-                               sb->s_blocksize - offset : toread;
-
-               bh = ufs_bread(inode, blk, 0, &err);
-               if (err)
-                       return err;
-               if (!bh)        /* A hole? */
-                       memset(data, 0, tocopy);
-               else {
-                       memcpy(data, bh->b_data+offset, tocopy);
-                       brelse(bh);
-               }
-               offset = 0;
-               toread -= tocopy;
-               data += tocopy;
-               blk++;
-       }
-       return len;
-}
-
-/* Write to quotafile */
-static ssize_t ufs_quota_write(struct super_block *sb, int type,
-                               const char *data, size_t len, loff_t off)
-{
-       struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> sb->s_blocksize_bits;
-       int err = 0;
-       int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
-       size_t towrite = len;
-       struct buffer_head *bh;
-
-       mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
-       while (towrite > 0) {
-               tocopy = sb->s_blocksize - offset < towrite ?
-                               sb->s_blocksize - offset : towrite;
-
-               bh = ufs_bread(inode, blk, 1, &err);
-               if (!bh)
-                       goto out;
-               lock_buffer(bh);
-               memcpy(bh->b_data+offset, data, tocopy);
-               flush_dcache_page(bh->b_page);
-               set_buffer_uptodate(bh);
-               mark_buffer_dirty(bh);
-               unlock_buffer(bh);
-               brelse(bh);
-               offset = 0;
-               towrite -= tocopy;
-               data += tocopy;
-               blk++;
-       }
-out:
-       if (len == towrite) {
-               mutex_unlock(&inode->i_mutex);
-               return err;
-       }
-       if (inode->i_size < off+len-towrite)
-               i_size_write(inode, off+len-towrite);
-       inode->i_version++;
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(inode);
-       mutex_unlock(&inode->i_mutex);
-       return len - towrite;
-}
-
-#endif
-
 static int ufs_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
index f294c44..589e01a 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -501,12 +500,10 @@ out:
        return err;
 }
 
-
 /*
- * We don't define our `inode->i_op->truncate', and call it here,
- * because of:
- * - there is no way to know old size
- * - there is no way inform user about error, if it happens in `truncate'
+ * TODO:
+ *     - truncate case should use proper ordering instead of using
+ *       simple_setsize
  */
 int ufs_setattr(struct dentry *dentry, struct iattr *attr)
 {
@@ -518,19 +515,10 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
        if (error)
                return error;
 
-       if (is_quota_modification(inode, attr))
-               dquot_initialize(inode);
-
-       if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               error = dquot_transfer(inode, attr);
-               if (error)
-                       return error;
-       }
        if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
                loff_t old_i_size = inode->i_size;
 
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                if (error)
                        return error;
                error = ufs_truncate(inode, old_i_size);
index d8fb1b5..257a56b 100644 (file)
@@ -100,10 +100,10 @@ xfs_iozero(
 STATIC int
 xfs_file_fsync(
        struct file             *file,
-       struct dentry           *dentry,
        int                     datasync)
 {
-       struct xfs_inode        *ip = XFS_I(dentry->d_inode);
+       struct inode            *inode = file->f_mapping->host;
+       struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
@@ -140,8 +140,8 @@ xfs_file_fsync(
         * might gets cleared when the inode gets written out via the AIL
         * or xfs_iflush_cluster.
         */
-       if (((dentry->d_inode->i_state & I_DIRTY_DATASYNC) ||
-           ((dentry->d_inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
+       if (((inode->i_state & I_DIRTY_DATASYNC) ||
+           ((inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
            ip->i_update_core) {
                /*
                 * Kick off a transaction to log the inode core to get the
@@ -868,7 +868,7 @@ write_retry:
                        mutex_lock(&inode->i_mutex);
                xfs_ilock(ip, iolock);
 
-               error2 = -xfs_file_fsync(file, file->f_path.dentry,
+               error2 = -xfs_file_fsync(file,
                                         (file->f_flags & __O_SYNC) ? 0 : 1);
                if (!error)
                        error = error2;
index 7bf83dd..baacd98 100644 (file)
@@ -373,7 +373,7 @@ struct acpi_pci_root {
        struct acpi_pci_id id;
        struct pci_bus *bus;
        u16 segment;
-       u8 bus_nr;
+       struct resource secondary;      /* downstream bus range */
 
        u32 osc_support_set;    /* _OSC state of support bits */
        u32 osc_control_set;    /* _OSC state of control bits */
index 4f7b448..23d78b4 100644 (file)
@@ -104,8 +104,7 @@ int acpi_pci_bind_root(struct acpi_device *device);
 
 /* Arch-defined function to add a bus to the system */
 
-struct pci_bus *pci_acpi_scan_root(struct acpi_device *device, int domain,
-                                  int bus);
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root);
 void pci_acpi_crs_quirks(void);
 
 /* --------------------------------------------------------------------------
diff --git a/include/acpi/acpi_hest.h b/include/acpi/acpi_hest.h
deleted file mode 100644 (file)
index 63194d0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __ACPI_HEST_H
-#define __ACPI_HEST_H
-
-#include <linux/pci.h>
-
-#ifdef CONFIG_ACPI
-extern int acpi_hest_firmware_first_pci(struct pci_dev *pci);
-#else
-static inline int acpi_hest_firmware_first_pci(struct pci_dev *pci) { return 0; }
-#endif
-
-#endif
diff --git a/include/acpi/apei.h b/include/acpi/apei.h
new file mode 100644 (file)
index 0000000..b336502
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * apei.h - ACPI Platform Error Interface
+ */
+
+#ifndef ACPI_APEI_H
+#define ACPI_APEI_H
+
+#include <linux/acpi.h>
+#include <linux/cper.h>
+#include <asm/ioctls.h>
+
+#define APEI_ERST_INVALID_RECORD_ID    0xffffffffffffffffULL
+
+#define APEI_ERST_CLEAR_RECORD         _IOW('E', 1, u64)
+#define APEI_ERST_GET_RECORD_COUNT     _IOR('E', 2, u32)
+
+#ifdef __KERNEL__
+
+extern int hest_disable;
+extern int erst_disable;
+
+typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
+int apei_hest_parse(apei_hest_func_t func, void *data);
+
+int erst_write(const struct cper_record_header *record);
+ssize_t erst_get_record_count(void);
+int erst_get_next_record_id(u64 *record_id);
+ssize_t erst_read(u64 record_id, struct cper_record_header *record,
+                 size_t buflen);
+ssize_t erst_read_next(struct cper_record_header *record, size_t buflen);
+int erst_clear(u64 record_id);
+
+#endif
+#endif
diff --git a/include/acpi/atomicio.h b/include/acpi/atomicio.h
new file mode 100644 (file)
index 0000000..8b9fb4b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ACPI_ATOMIC_IO_H
+#define ACPI_ATOMIC_IO_H
+
+int acpi_pre_map_gar(struct acpi_generic_address *reg);
+int acpi_post_unmap_gar(struct acpi_generic_address *reg);
+
+int acpi_atomic_read(u64 *val, struct acpi_generic_address *reg);
+int acpi_atomic_write(u64 val, struct acpi_generic_address *reg);
+
+#endif
diff --git a/include/acpi/hed.h b/include/acpi/hed.h
new file mode 100644 (file)
index 0000000..46e1249
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * hed.h - ACPI Hardware Error Device
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef ACPI_HED_H
+#define ACPI_HED_H
+
+#include <linux/notifier.h>
+
+int register_acpi_hed_notifier(struct notifier_block *nb);
+void unregister_acpi_hed_notifier(struct notifier_block *nb);
+
+#endif
index 86825dd..da565a4 100644 (file)
@@ -52,17 +52,6 @@ struct acpi_power_register {
        u64 address;
 } __attribute__ ((packed));
 
-struct acpi_processor_cx_policy {
-       u32 count;
-       struct acpi_processor_cx *state;
-       struct {
-               u32 time;
-               u32 ticks;
-               u32 count;
-               u32 bm;
-       } threshold;
-};
-
 struct acpi_processor_cx {
        u8 valid;
        u8 type;
@@ -74,8 +63,6 @@ struct acpi_processor_cx {
        u32 power;
        u32 usage;
        u64 time;
-       struct acpi_processor_cx_policy promotion;
-       struct acpi_processor_cx_policy demotion;
        char desc[ACPI_CX_DESC_LEN];
 };
 
index cf7be3d..551793c 100644 (file)
@@ -1,12 +1,28 @@
 #ifndef __ACPI_VIDEO_H
 #define __ACPI_VIDEO_H
 
+#define ACPI_VIDEO_DISPLAY_CRT  1
+#define ACPI_VIDEO_DISPLAY_TV   2
+#define ACPI_VIDEO_DISPLAY_DVI  3
+#define ACPI_VIDEO_DISPLAY_LCD  4
+
+#define ACPI_VIDEO_DISPLAY_LEGACY_MONITOR 0x0100
+#define ACPI_VIDEO_DISPLAY_LEGACY_PANEL   0x0110
+#define ACPI_VIDEO_DISPLAY_LEGACY_TV      0x0200
+
 #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
 extern int acpi_video_register(void);
 extern void acpi_video_unregister(void);
+extern int acpi_video_get_edid(struct acpi_device *device, int type,
+                              int device_id, void **edid);
 #else
 static inline int acpi_video_register(void) { return 0; }
 static inline void acpi_video_unregister(void) { return; }
+static inline int acpi_video_get_edid(struct acpi_device *device, int type,
+                                     int device_id, void **edid)
+{
+       return -ENODEV;
+}
 #endif
 
 #endif
index 2c60f1f..224a38c 100644 (file)
@@ -254,7 +254,6 @@ int acpi_resources_are_enforced(void);
 void __init acpi_no_s4_hw_signature(void);
 void __init acpi_old_suspend_ordering(void);
 void __init acpi_s4_no_nvs(void);
-void __init acpi_set_sci_en_on_resume(void);
 #endif /* CONFIG_PM_SLEEP */
 
 struct acpi_osc_context {
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
new file mode 100644 (file)
index 0000000..cbee7de
--- /dev/null
@@ -0,0 +1,45 @@
+/* linux/include/linux/amba/pl330.h
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef        __AMBA_PL330_H_
+#define        __AMBA_PL330_H_
+
+#include <asm/hardware/pl330.h>
+
+struct dma_pl330_peri {
+       /*
+        * Peri_Req i/f of the DMAC that is
+        * peripheral could be reached from.
+        */
+       u8 peri_id; /* {0, 31} */
+       enum pl330_reqtype rqtype;
+
+       /* For M->D and D->M Channels */
+       int burst_sz; /* in power of 2 */
+       dma_addr_t fifo_addr;
+};
+
+struct dma_pl330_platdata {
+       /*
+        * Number of valid peripherals connected to DMAC.
+        * This may be different from the value read from
+        * CR0, as the PL330 implementation might have 'holes'
+        * in the peri list or the peri could also be reached
+        * from another DMAC which the platform prefers.
+        */
+       u8 nr_valid_peri;
+       /* Array of valid peripherals */
+       struct dma_pl330_peri *peri;
+       /* Bytes to allocate for MC buffer */
+       unsigned mcbuf_sz;
+};
+
+#endif /* __AMBA_PL330_H_ */
index 6fb2720..daf8c48 100644 (file)
@@ -141,7 +141,6 @@ extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
 extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits);
-extern int bitmap_ord_to_pos(const unsigned long *bitmap, int n, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)                                   \
 (                                                                      \
index 16ed028..1b9ba19 100644 (file)
@@ -203,6 +203,9 @@ int block_write_full_page_endio(struct page *page, get_block_t *get_block,
 int block_read_full_page(struct page*, get_block_t*);
 int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
                                unsigned long from);
+int block_write_begin_newtrunc(struct file *, struct address_space *,
+                               loff_t, unsigned, unsigned,
+                               struct page **, void **, get_block_t*);
 int block_write_begin(struct file *, struct address_space *,
                                loff_t, unsigned, unsigned,
                                struct page **, void **, get_block_t*);
@@ -214,6 +217,9 @@ int generic_write_end(struct file *, struct address_space *,
                                struct page *, void *);
 void page_zero_new_buffers(struct page *page, unsigned from, unsigned to);
 int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
+int cont_write_begin_newtrunc(struct file *, struct address_space *, loff_t,
+                       unsigned, unsigned, struct page **, void **,
+                       get_block_t *, loff_t *);
 int cont_write_begin(struct file *, struct address_space *, loff_t,
                        unsigned, unsigned, struct page **, void **,
                        get_block_t *, loff_t *);
@@ -224,7 +230,10 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
 void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
-int file_fsync(struct file *, struct dentry *, int);
+int file_fsync(struct file *, int);
+int nobh_write_begin_newtrunc(struct file *, struct address_space *,
+                               loff_t, unsigned, unsigned,
+                               struct page **, void **, get_block_t*);
 int nobh_write_begin(struct file *, struct address_space *,
                                loff_t, unsigned, unsigned,
                                struct page **, void **, get_block_t*);
index 4a6b604..51e3145 100644 (file)
@@ -83,6 +83,8 @@ extern unsigned long wait_for_completion_timeout(struct completion *x,
                                                   unsigned long timeout);
 extern unsigned long wait_for_completion_interruptible_timeout(
                        struct completion *x, unsigned long timeout);
+extern unsigned long wait_for_completion_killable_timeout(
+                       struct completion *x, unsigned long timeout);
 extern bool try_wait_for_completion(struct completion *x);
 extern bool completion_done(struct completion *x);
 
diff --git a/include/linux/cper.h b/include/linux/cper.h
new file mode 100644 (file)
index 0000000..4b38f90
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * UEFI Common Platform Error Record
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef LINUX_CPER_H
+#define LINUX_CPER_H
+
+#include <linux/uuid.h>
+
+/* CPER record signature and the size */
+#define CPER_SIG_RECORD                                "CPER"
+#define CPER_SIG_SIZE                          4
+/* Used in signature_end field in struct cper_record_header */
+#define CPER_SIG_END                           0xffffffff
+
+/*
+ * CPER record header revision, used in revision field in struct
+ * cper_record_header
+ */
+#define CPER_RECORD_REV                                0x0100
+
+/*
+ * Severity difinition for error_severity in struct cper_record_header
+ * and section_severity in struct cper_section_descriptor
+ */
+#define CPER_SER_RECOVERABLE                   0x0
+#define CPER_SER_FATAL                         0x1
+#define CPER_SER_CORRECTED                     0x2
+#define CPER_SER_INFORMATIONAL                 0x3
+
+/*
+ * Validation bits difinition for validation_bits in struct
+ * cper_record_header. If set, corresponding fields in struct
+ * cper_record_header contain valid information.
+ *
+ * corresponds platform_id
+ */
+#define CPER_VALID_PLATFORM_ID                 0x0001
+/* corresponds timestamp */
+#define CPER_VALID_TIMESTAMP                   0x0002
+/* corresponds partition_id */
+#define CPER_VALID_PARTITION_ID                        0x0004
+
+/*
+ * Notification type used to generate error record, used in
+ * notification_type in struct cper_record_header
+ *
+ * Corrected Machine Check
+ */
+#define CPER_NOTIFY_CMC                                                        \
+       UUID_LE(0x2DCE8BB1, 0xBDD7, 0x450e, 0xB9, 0xAD, 0x9C, 0xF4,     \
+               0xEB, 0xD4, 0xF8, 0x90)
+/* Corrected Platform Error */
+#define CPER_NOTIFY_CPE                                                        \
+       UUID_LE(0x4E292F96, 0xD843, 0x4a55, 0xA8, 0xC2, 0xD4, 0x81,     \
+               0xF2, 0x7E, 0xBE, 0xEE)
+/* Machine Check Exception */
+#define CPER_NOTIFY_MCE                                                        \
+       UUID_LE(0xE8F56FFE, 0x919C, 0x4cc5, 0xBA, 0x88, 0x65, 0xAB,     \
+               0xE1, 0x49, 0x13, 0xBB)
+/* PCI Express Error */
+#define CPER_NOTIFY_PCIE                                               \
+       UUID_LE(0xCF93C01F, 0x1A16, 0x4dfc, 0xB8, 0xBC, 0x9C, 0x4D,     \
+               0xAF, 0x67, 0xC1, 0x04)
+/* INIT Record (for IPF) */
+#define CPER_NOTIFY_INIT                                               \
+       UUID_LE(0xCC5263E8, 0x9308, 0x454a, 0x89, 0xD0, 0x34, 0x0B,     \
+               0xD3, 0x9B, 0xC9, 0x8E)
+/* Non-Maskable Interrupt */
+#define CPER_NOTIFY_NMI                                                        \
+       UUID_LE(0x5BAD89FF, 0xB7E6, 0x42c9, 0x81, 0x4A, 0xCF, 0x24,     \
+               0x85, 0xD6, 0xE9, 0x8A)
+/* BOOT Error Record */
+#define CPER_NOTIFY_BOOT                                               \
+       UUID_LE(0x3D61A466, 0xAB40, 0x409a, 0xA6, 0x98, 0xF3, 0x62,     \
+               0xD4, 0x64, 0xB3, 0x8F)
+/* DMA Remapping Error */
+#define CPER_NOTIFY_DMAR                                               \
+       UUID_LE(0x667DD791, 0xC6B3, 0x4c27, 0x8A, 0x6B, 0x0F, 0x8E,     \
+               0x72, 0x2D, 0xEB, 0x41)
+
+/*
+ * Flags bits definitions for flags in struct cper_record_header
+ * If set, the error has been recovered
+ */
+#define CPER_HW_ERROR_FLAGS_RECOVERED          0x1
+/* If set, the error is for previous boot */
+#define CPER_HW_ERROR_FLAGS_PREVERR            0x2
+/* If set, the error is injected for testing */
+#define CPER_HW_ERROR_FLAGS_SIMULATED          0x4
+
+/*
+ * CPER section header revision, used in revision field in struct
+ * cper_section_descriptor
+ */
+#define CPER_SEC_REV                           0x0100
+
+/*
+ * Validation bits difinition for validation_bits in struct
+ * cper_section_descriptor. If set, corresponding fields in struct
+ * cper_section_descriptor contain valid information.
+ *
+ * corresponds fru_id
+ */
+#define CPER_SEC_VALID_FRU_ID                  0x1
+/* corresponds fru_text */
+#define CPER_SEC_VALID_FRU_TEXT                        0x2
+
+/*
+ * Flags bits definitions for flags in struct cper_section_descriptor
+ *
+ * If set, the section is associated with the error condition
+ * directly, and should be focused on
+ */
+#define CPER_SEC_PRIMARY                       0x0001
+/*
+ * If set, the error was not contained within the processor or memory
+ * hierarchy and the error may have propagated to persistent storage
+ * or network
+ */
+#define CPER_SEC_CONTAINMENT_WARNING           0x0002
+/* If set, the component must be re-initialized or re-enabled prior to use */
+#define CPER_SEC_RESET                         0x0004
+/* If set, Linux may choose to discontinue use of the resource */
+#define CPER_SEC_ERROR_THRESHOLD_EXCEEDED      0x0008
+/*
+ * If set, resource could not be queried for error information due to
+ * conflicts with other system software or resources. Some fields of
+ * the section will be invalid
+ */
+#define CPER_SEC_RESOURCE_NOT_ACCESSIBLE       0x0010
+/*
+ * If set, action has been taken to ensure error containment (such as
+ * poisoning data), but the error has not been fully corrected and the
+ * data has not been consumed. Linux may choose to take further
+ * corrective action before the data is consumed
+ */
+#define CPER_SEC_LATENT_ERROR                  0x0020
+
+/*
+ * Section type definitions, used in section_type field in struct
+ * cper_section_descriptor
+ *
+ * Processor Generic
+ */
+#define CPER_SEC_PROC_GENERIC                                          \
+       UUID_LE(0x9876CCAD, 0x47B4, 0x4bdb, 0xB6, 0x5E, 0x16, 0xF1,     \
+               0x93, 0xC4, 0xF3, 0xDB)
+/* Processor Specific: X86/X86_64 */
+#define CPER_SEC_PROC_IA                                               \
+       UUID_LE(0xDC3EA0B0, 0xA144, 0x4797, 0xB9, 0x5B, 0x53, 0xFA,     \
+               0x24, 0x2B, 0x6E, 0x1D)
+/* Processor Specific: IA64 */
+#define CPER_SEC_PROC_IPF                                              \
+       UUID_LE(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00,     \
+               0x80, 0xC7, 0x3C, 0x88, 0x81)
+/* Platform Memory */
+#define CPER_SEC_PLATFORM_MEM                                          \
+       UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83,     \
+               0xED, 0x7C, 0x83, 0xB1)
+#define CPER_SEC_PCIE                                                  \
+       UUID_LE(0xD995E954, 0xBBC1, 0x430F, 0xAD, 0x91, 0xB4, 0x4D,     \
+               0xCB, 0x3C, 0x6F, 0x35)
+/* Firmware Error Record Reference */
+#define CPER_SEC_FW_ERR_REC_REF                                                \
+       UUID_LE(0x81212A96, 0x09ED, 0x4996, 0x94, 0x71, 0x8D, 0x72,     \
+               0x9C, 0x8E, 0x69, 0xED)
+/* PCI/PCI-X Bus */
+#define CPER_SEC_PCI_X_BUS                                             \
+       UUID_LE(0xC5753963, 0x3B84, 0x4095, 0xBF, 0x78, 0xED, 0xDA,     \
+               0xD3, 0xF9, 0xC9, 0xDD)
+/* PCI Component/Device */
+#define CPER_SEC_PCI_DEV                                               \
+       UUID_LE(0xEB5E4685, 0xCA66, 0x4769, 0xB6, 0xA2, 0x26, 0x06,     \
+               0x8B, 0x00, 0x13, 0x26)
+#define CPER_SEC_DMAR_GENERIC                                          \
+       UUID_LE(0x5B51FEF7, 0xC79D, 0x4434, 0x8F, 0x1B, 0xAA, 0x62,     \
+               0xDE, 0x3E, 0x2C, 0x64)
+/* Intel VT for Directed I/O specific DMAr */
+#define CPER_SEC_DMAR_VT                                               \
+       UUID_LE(0x71761D37, 0x32B2, 0x45cd, 0xA7, 0xD0, 0xB0, 0xFE,     \
+               0xDD, 0x93, 0xE8, 0xCF)
+/* IOMMU specific DMAr */
+#define CPER_SEC_DMAR_IOMMU                                            \
+       UUID_LE(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F,     \
+               0xDF, 0xAA, 0x84, 0xEC)
+
+/*
+ * All tables and structs must be byte-packed to match CPER
+ * specification, since the tables are provided by the system BIOS
+ */
+#pragma pack(1)
+
+struct cper_record_header {
+       char    signature[CPER_SIG_SIZE];       /* must be CPER_SIG_RECORD */
+       __u16   revision;                       /* must be CPER_RECORD_REV */
+       __u32   signature_end;                  /* must be CPER_SIG_END */
+       __u16   section_count;
+       __u32   error_severity;
+       __u32   validation_bits;
+       __u32   record_length;
+       __u64   timestamp;
+       uuid_le platform_id;
+       uuid_le partition_id;
+       uuid_le creator_id;
+       uuid_le notification_type;
+       __u64   record_id;
+       __u32   flags;
+       __u64   persistence_information;
+       __u8    reserved[12];                   /* must be zero */
+};
+
+struct cper_section_descriptor {
+       __u32   section_offset;         /* Offset in bytes of the
+                                        *  section body from the base
+                                        *  of the record header */
+       __u32   section_length;
+       __u16   revision;               /* must be CPER_RECORD_REV */
+       __u8    validation_bits;
+       __u8    reserved;               /* must be zero */
+       __u32   flags;
+       uuid_le section_type;
+       uuid_le fru_id;
+       __u32   section_severity;
+       __u8    fru_text[20];
+};
+
+/* Generic Processor Error Section */
+struct cper_sec_proc_generic {
+       __u64   validation_bits;
+       __u8    proc_type;
+       __u8    proc_isa;
+       __u8    proc_error_type;
+       __u8    operation;
+       __u8    flags;
+       __u8    level;
+       __u16   reserved;
+       __u64   cpu_version;
+       char    cpu_brand[128];
+       __u64   proc_id;
+       __u64   target_addr;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   ip;
+};
+
+/* IA32/X64 Processor Error Section */
+struct cper_sec_proc_ia {
+       __u64   validation_bits;
+       __u8    lapic_id;
+       __u8    cpuid[48];
+};
+
+/* IA32/X64 Processor Error Infomation Structure */
+struct cper_ia_err_info {
+       uuid_le err_type;
+       __u64   validation_bits;
+       __u64   check_info;
+       __u64   target_id;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   ip;
+};
+
+/* IA32/X64 Processor Context Information Structure */
+struct cper_ia_proc_ctx {
+       __u16   reg_ctx_type;
+       __u16   reg_arr_size;
+       __u32   msr_addr;
+       __u64   mm_reg_addr;
+};
+
+/* Memory Error Section */
+struct cper_sec_mem_err {
+       __u64   validation_bits;
+       __u64   error_status;
+       __u64   physical_addr;
+       __u64   physical_addr_mask;
+       __u16   node;
+       __u16   card;
+       __u16   module;
+       __u16   bank;
+       __u16   device;
+       __u16   row;
+       __u16   column;
+       __u16   bit_pos;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   target_id;
+       __u8    error_type;
+};
+
+/* Reset to default packing */
+#pragma pack()
+
+u64 cper_next_record_id(void);
+
+#endif
index dcf77fa..55215cc 100644 (file)
@@ -125,6 +125,7 @@ struct cpuidle_driver {
 #ifdef CONFIG_CPU_IDLE
 
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
+struct cpuidle_driver *cpuidle_get_driver(void);
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
@@ -137,16 +138,17 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
 #else
 
 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
-{return 0;}
+{return -ENODEV; }
+static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
 static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
 static inline int cpuidle_register_device(struct cpuidle_device *dev)
-{return 0;}
+{return -ENODEV; }
 static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
 
 static inline void cpuidle_pause_and_lock(void) { }
 static inline void cpuidle_resume_and_unlock(void) { }
 static inline int cpuidle_enable_device(struct cpuidle_device *dev)
-{return 0;}
+{return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
 
 #endif
index fc1b930..e7d9b20 100644 (file)
@@ -63,6 +63,8 @@ struct dentry *debugfs_create_x16(const char *name, mode_t mode,
                                  struct dentry *parent, u16 *value);
 struct dentry *debugfs_create_x32(const char *name, mode_t mode,
                                  struct dentry *parent, u32 *value);
+struct dentry *debugfs_create_x64(const char *name, mode_t mode,
+                                 struct dentry *parent, u64 *value);
 struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
                                     struct dentry *parent, size_t *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
index 5f494b4..7fc62d4 100644 (file)
@@ -868,7 +868,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext3_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext3_sync_file (struct file *, struct dentry *, int);
+extern int ext3_sync_file(struct file *, int);
 
 /* hash.c */
 extern int ext3fs_dirhash(const char *name, int len, struct
index f3793eb..907ace3 100644 (file)
@@ -4,8 +4,6 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
-struct dentry;
-
 /* Definitions of frame buffers                                                */
 
 #define FB_MAX                 32      /* sufficient for now */
@@ -1017,8 +1015,7 @@ extern void fb_deferred_io_open(struct fb_info *info,
                                struct inode *inode,
                                struct file *file);
 extern void fb_deferred_io_cleanup(struct fb_info *info);
-extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
-                               int datasync);
+extern int fb_deferred_io_fsync(struct file *file, int datasync);
 
 static inline bool fb_be_math(struct fb_info *info)
 {
index 5555508..b1e1297 100644 (file)
@@ -11,7 +11,6 @@
 
 struct file;
 
-extern void __fput(struct file *);
 extern void fput(struct file *);
 extern void drop_file_write_access(struct file *file);
 
index 85e823a..3428393 100644 (file)
@@ -954,6 +954,7 @@ extern spinlock_t files_lock;
 #define file_list_unlock() spin_unlock(&files_lock);
 
 #define get_file(x)    atomic_long_inc(&(x)->f_count)
+#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
 #define file_count(x)  atomic_long_read(&(x)->f_count)
 
 #ifdef CONFIG_DEBUG_WRITECOUNT
@@ -1497,7 +1498,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
@@ -2212,7 +2213,7 @@ extern int generic_segment_checks(const struct iovec *iov,
 /* fs/block_dev.c */
 extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
-extern int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync);
+extern int blkdev_fsync(struct file *filp, int datasync);
 
 /* fs/splice.c */
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
@@ -2256,6 +2257,10 @@ typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
                            loff_t file_offset);
 void dio_end_io(struct bio *bio, int error);
 
+ssize_t __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset,
+       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       dio_submit_t submit_io, int lock_type);
 ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        struct block_device *bdev, const struct iovec *iov, loff_t offset,
        unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
@@ -2269,6 +2274,24 @@ enum {
        DIO_SKIP_HOLES  = 0x02,
 };
 
+static inline ssize_t blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb,
+       struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+       loff_t offset, unsigned long nr_segs, get_block_t get_block,
+       dio_iodone_t end_io)
+{
+       return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
+                                   nr_segs, get_block, end_io, NULL,
+                                   DIO_LOCKING | DIO_SKIP_HOLES);
+}
+
+static inline ssize_t blockdev_direct_IO_no_locking_newtrunc(int rw, struct kiocb *iocb,
+       struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+       loff_t offset, unsigned long nr_segs, get_block_t get_block,
+       dio_iodone_t end_io)
+{
+       return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
+                               nr_segs, get_block, end_io, NULL, 0);
+}
 static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
        struct inode *inode, struct block_device *bdev, const struct iovec *iov,
        loff_t offset, unsigned long nr_segs, get_block_t get_block,
@@ -2341,13 +2364,15 @@ extern int dcache_dir_open(struct inode *, struct file *);
 extern int dcache_dir_close(struct inode *, struct file *);
 extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 extern int dcache_readdir(struct file *, void *, filldir_t);
+extern int simple_setattr(struct dentry *, struct iattr *);
 extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int simple_statfs(struct dentry *, struct kstatfs *);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
 extern int simple_rmdir(struct inode *, struct dentry *);
 extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
-extern int simple_sync_file(struct file *, struct dentry *, int);
+extern int simple_setsize(struct inode *, loff_t);
+extern int noop_fsync(struct file *, int);
 extern int simple_empty(struct dentry *);
 extern int simple_readpage(struct file *file, struct page *page);
 extern int simple_write_begin(struct file *file, struct address_space *mapping,
@@ -2372,7 +2397,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                const void __user *from, size_t count);
 
-extern int simple_fsync(struct file *, struct dentry *, int);
+extern int generic_file_fsync(struct file *, int);
 
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
@@ -2383,7 +2408,8 @@ extern int buffer_migrate_page(struct address_space *,
 
 extern int inode_change_ok(const struct inode *, struct iattr *);
 extern int inode_newsize_ok(const struct inode *, loff_t offset);
-extern int __must_check inode_setattr(struct inode *, struct iattr *);
+extern int __must_check inode_setattr(struct inode *, const struct iattr *);
+extern void generic_setattr(struct inode *inode, const struct iattr *attr);
 
 extern void file_update_time(struct file *file);
 
index ee84e7e..3bad270 100644 (file)
@@ -386,6 +386,7 @@ enum {
        ATA_HORKAGE_1_5_GBPS    = (1 << 13),    /* force 1.5 Gbps */
        ATA_HORKAGE_NOSETXFER   = (1 << 14),    /* skip SETXFER, SATA only */
        ATA_HORKAGE_BROKEN_FPDMA_AA     = (1 << 15),    /* skip AA */
+       ATA_HORKAGE_DUMP_ID     = (1 << 16),    /* dump IDENTIFY data */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
@@ -513,7 +514,9 @@ struct ata_ioports {
        void __iomem            *command_addr;
        void __iomem            *altstatus_addr;
        void __iomem            *ctl_addr;
+#ifdef CONFIG_ATA_BMDMA
        void __iomem            *bmdma_addr;
+#endif /* CONFIG_ATA_BMDMA */
        void __iomem            *scr_addr;
 };
 #endif /* CONFIG_ATA_SFF */
@@ -721,8 +724,10 @@ struct ata_port {
        u8                      ctl;    /* cache of ATA control register */
        u8                      last_ctl;       /* Cache last written value */
        struct delayed_work     sff_pio_task;
+#ifdef CONFIG_ATA_BMDMA
        struct ata_bmdma_prd    *bmdma_prd;     /* BMDMA SG list */
        dma_addr_t              bmdma_prd_dma;  /* and its DMA mapping */
+#endif /* CONFIG_ATA_BMDMA */
 #endif /* CONFIG_ATA_SFF */
 
        unsigned int            pio_mask;
@@ -856,10 +861,12 @@ struct ata_port_operations {
        void (*sff_irq_clear)(struct ata_port *);
        void (*sff_drain_fifo)(struct ata_queued_cmd *qc);
 
+#ifdef CONFIG_ATA_BMDMA
        void (*bmdma_setup)(struct ata_queued_cmd *qc);
        void (*bmdma_start)(struct ata_queued_cmd *qc);
        void (*bmdma_stop)(struct ata_queued_cmd *qc);
        u8   (*bmdma_status)(struct ata_port *ap);
+#endif /* CONFIG_ATA_BMDMA */
 #endif /* CONFIG_ATA_SFF */
 
        ssize_t (*em_show)(struct ata_port *ap, char *buf);
@@ -1555,7 +1562,6 @@ extern void sata_pmp_error_handler(struct ata_port *ap);
 #ifdef CONFIG_ATA_SFF
 
 extern const struct ata_port_operations ata_sff_port_ops;
-extern const struct ata_port_operations ata_bmdma_port_ops;
 extern const struct ata_port_operations ata_bmdma32_port_ops;
 
 /* PIO only, sg_tablesize and dma_boundary limits can be removed */
@@ -1564,11 +1570,6 @@ extern const struct ata_port_operations ata_bmdma32_port_ops;
        .sg_tablesize           = LIBATA_MAX_PRD,               \
        .dma_boundary           = ATA_DMA_BOUNDARY
 
-#define ATA_BMDMA_SHT(drv_name)                                        \
-       ATA_BASE_SHT(drv_name),                                 \
-       .sg_tablesize           = LIBATA_MAX_PRD,               \
-       .dma_boundary           = ATA_DMA_BOUNDARY
-
 extern void ata_sff_dev_select(struct ata_port *ap, unsigned int device);
 extern u8 ata_sff_check_status(struct ata_port *ap);
 extern void ata_sff_pause(struct ata_port *ap);
@@ -1593,7 +1594,7 @@ extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
 extern void ata_sff_queue_pio_task(struct ata_port *ap, unsigned long delay);
 extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc);
 extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc);
-extern unsigned int ata_sff_host_intr(struct ata_port *ap,
+extern unsigned int ata_sff_port_intr(struct ata_port *ap,
                                      struct ata_queued_cmd *qc);
 extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance);
 extern void ata_sff_lost_interrupt(struct ata_port *ap);
@@ -1625,11 +1626,24 @@ extern int ata_pci_sff_init_one(struct pci_dev *pdev,
                struct scsi_host_template *sht, void *host_priv, int hflags);
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_ATA_BMDMA
+
+extern const struct ata_port_operations ata_bmdma_port_ops;
+
+#define ATA_BMDMA_SHT(drv_name)                                        \
+       ATA_BASE_SHT(drv_name),                                 \
+       .sg_tablesize           = LIBATA_MAX_PRD,               \
+       .dma_boundary           = ATA_DMA_BOUNDARY
+
 extern void ata_bmdma_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc);
 extern void ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc);
+extern unsigned int ata_bmdma_port_intr(struct ata_port *ap,
+                                     struct ata_queued_cmd *qc);
+extern irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance);
 extern void ata_bmdma_error_handler(struct ata_port *ap);
 extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
+extern void ata_bmdma_irq_clear(struct ata_port *ap);
 extern void ata_bmdma_setup(struct ata_queued_cmd *qc);
 extern void ata_bmdma_start(struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
@@ -1640,7 +1654,15 @@ extern int ata_bmdma_port_start32(struct ata_port *ap);
 #ifdef CONFIG_PCI
 extern int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev);
 extern void ata_pci_bmdma_init(struct ata_host *host);
+extern int ata_pci_bmdma_prepare_host(struct pci_dev *pdev,
+                                     const struct ata_port_info * const * ppi,
+                                     struct ata_host **r_host);
+extern int ata_pci_bmdma_init_one(struct pci_dev *pdev,
+                                 const struct ata_port_info * const * ppi,
+                                 struct scsi_host_template *sht,
+                                 void *host_priv, int hflags);
 #endif /* CONFIG_PCI */
+#endif /* CONFIG_ATA_BMDMA */
 
 /**
  *     ata_sff_busy_wait - Wait for a port status register
index 8a8f1d0..dba35e4 100644 (file)
@@ -66,8 +66,6 @@
  * int num_online_nodes()              Number of online Nodes
  * int num_possible_nodes()            Number of all possible Nodes
  *
- * int node_random(mask)               Random node with set bit in mask
- *
  * int node_online(node)               Is some node online?
  * int node_possible(node)             Is some node possible?
  *
@@ -432,10 +430,6 @@ static inline void node_set_offline(int nid)
        node_clear_state(nid, N_ONLINE);
        nr_online_nodes = num_node_state(N_ONLINE);
 }
-
-#define node_random(mask) __node_random(&(mask))
-extern int __node_random(const nodemask_t *maskp);
-
 #else
 
 static inline int node_state(int node, enum node_states state)
@@ -466,8 +460,6 @@ static inline int num_node_state(enum node_states state)
 
 #define node_set_online(node)     node_set_state((node), N_ONLINE)
 #define node_set_offline(node)    node_clear_state((node), N_ONLINE)
-
-static inline int node_random(const nodemask_t mask) { return 0; }
 #endif
 
 #define node_online_map        node_states[N_ONLINE]
index a327322..6a471ab 100644 (file)
@@ -311,7 +311,8 @@ struct pci_dev {
        unsigned int    is_virtfn:1;
        unsigned int    reset_fn:1;
        unsigned int    is_hotplug_bridge:1;
-       unsigned int    aer_firmware_first:1;
+       unsigned int    __aer_firmware_first_valid:1;
+       unsigned int    __aer_firmware_first:1;
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
index 7126a15..94c1f03 100644 (file)
@@ -174,8 +174,7 @@ enum {
 #include <linux/rwsem.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/percpu.h>
-#include <linux/smp.h>
+#include <linux/percpu_counter.h>
 
 #include <linux/dqblk_xfs.h>
 #include <linux/dqblk_v1.h>
@@ -254,6 +253,7 @@ enum {
 
 struct dqstats {
        int stat[_DQST_DQSTAT_LAST];
+       struct percpu_counter counter[_DQST_DQSTAT_LAST];
 };
 
 extern struct dqstats *dqstats_pcpu;
@@ -261,20 +261,12 @@ extern struct dqstats dqstats;
 
 static inline void dqstats_inc(unsigned int type)
 {
-#ifdef CONFIG_SMP
-       per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]++;
-#else
-       dqstats.stat[type]++;
-#endif
+       percpu_counter_inc(&dqstats.counter[type]);
 }
 
 static inline void dqstats_dec(unsigned int type)
 {
-#ifdef CONFIG_SMP
-       per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]--;
-#else
-       dqstats.stat[type]--;
-#endif
+       percpu_counter_dec(&dqstats.counter[type]);
 }
 
 #define DQ_MOD_B       0       /* dquot modified since read */
@@ -332,8 +324,8 @@ struct dquot_operations {
 
 /* Operations handling requests from userspace */
 struct quotactl_ops {
-       int (*quota_on)(struct super_block *, int, int, char *, int);
-       int (*quota_off)(struct super_block *, int, int);
+       int (*quota_on)(struct super_block *, int, int, char *);
+       int (*quota_off)(struct super_block *, int);
        int (*quota_sync)(struct super_block *, int, int);
        int (*get_info)(struct super_block *, int, struct if_dqinfo *);
        int (*set_info)(struct super_block *, int, struct if_dqinfo *);
index e38ae53..aa36793 100644 (file)
@@ -53,6 +53,14 @@ int dquot_alloc_inode(const struct inode *inode);
 int dquot_claim_space_nodirty(struct inode *inode, qsize_t number);
 void dquot_free_inode(const struct inode *inode);
 
+int dquot_disable(struct super_block *sb, int type, unsigned int flags);
+/* Suspend quotas on remount RO */
+static inline int dquot_suspend(struct super_block *sb, int type)
+{
+       return dquot_disable(sb, type, DQUOT_SUSPENDED);
+}
+int dquot_resume(struct super_block *sb, int type);
+
 int dquot_commit(struct dquot *dquot);
 int dquot_acquire(struct dquot *dquot);
 int dquot_release(struct dquot *dquot);
@@ -61,27 +69,25 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
 
 int dquot_file_open(struct inode *inode, struct file *file);
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id,
-       char *path, int remount);
-int vfs_quota_enable(struct inode *inode, int type, int format_id,
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
+       char *path);
+int dquot_enable(struct inode *inode, int type, int format_id,
        unsigned int flags);
-int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
        struct path *path);
-int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
+int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        int format_id, int type);
-int vfs_quota_off(struct super_block *sb, int type, int remount);
-int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags);
-int vfs_quota_sync(struct super_block *sb, int type, int wait);
-int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_quota_off(struct super_block *sb, int type);
+int dquot_quota_sync(struct super_block *sb, int type, int wait);
+int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
                struct fs_disk_quota *di);
-int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
                struct fs_disk_quota *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
 int dquot_transfer(struct inode *inode, struct iattr *iattr);
-int vfs_dq_quota_on_remount(struct super_block *sb);
 
 static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
 {
@@ -148,20 +154,7 @@ static inline unsigned sb_any_quota_active(struct super_block *sb)
  * Operations supported for diskquotas.
  */
 extern const struct dquot_operations dquot_operations;
-extern const struct quotactl_ops vfs_quotactl_ops;
-
-#define sb_dquot_ops (&dquot_operations)
-#define sb_quotactl_ops (&vfs_quotactl_ops)
-
-/* Cannot be called inside a transaction */
-static inline int vfs_dq_off(struct super_block *sb, int remount)
-{
-       int ret = -ENOSYS;
-
-       if (sb->s_qcop && sb->s_qcop->quota_off)
-               ret = sb->s_qcop->quota_off(sb, -1, remount);
-       return ret;
-}
+extern const struct quotactl_ops dquot_quotactl_ops;
 
 #else
 
@@ -206,12 +199,6 @@ static inline int sb_any_quota_active(struct super_block *sb)
        return 0;
 }
 
-/*
- * NO-OP when quota not configured.
- */
-#define sb_dquot_ops                           (NULL)
-#define sb_quotactl_ops                                (NULL)
-
 static inline void dquot_initialize(struct inode *inode)
 {
 }
@@ -229,16 +216,6 @@ static inline void dquot_free_inode(const struct inode *inode)
 {
 }
 
-static inline int vfs_dq_off(struct super_block *sb, int remount)
-{
-       return 0;
-}
-
-static inline int vfs_dq_quota_on_remount(struct super_block *sb)
-{
-       return 0;
-}
-
 static inline int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
        return 0;
@@ -265,6 +242,22 @@ static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
        return 0;
 }
 
+static inline int dquot_disable(struct super_block *sb, int type,
+               unsigned int flags)
+{
+       return 0;
+}
+
+static inline int dquot_suspend(struct super_block *sb, int type)
+{
+       return 0;
+}
+
+static inline int dquot_resume(struct super_block *sb, int type)
+{
+       return 0;
+}
+
 #define dquot_file_open                generic_file_open
 
 #endif /* CONFIG_QUOTA */
index 19b5f22..bd6eb0e 100644 (file)
@@ -88,11 +88,15 @@ union rio_pw_msg;
  * @swpinfo: Switch port info
  * @src_ops: Source operation capabilities
  * @dst_ops: Destination operation capabilities
+ * @comp_tag: RIO component tag
+ * @phys_efptr: RIO device extended features pointer
+ * @em_efptr: RIO Error Management features pointer
  * @dma_mask: Mask of bits of RIO address this device implements
  * @rswitch: Pointer to &struct rio_switch if valid for this device
  * @driver: Driver claiming this device
  * @dev: Device model device
  * @riores: RIO resources this device owns
+ * @pwcback: port-write callback function for this device
  * @destid: Network destination ID
  */
 struct rio_dev {
@@ -222,6 +226,8 @@ struct rio_net {
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
  * @clr_table: Callback for switch-specific clear route table function
+ * @set_domain: Callback for switch-specific domain setting function
+ * @get_domain: Callback for switch-specific domain get function
  * @em_init: Callback for switch-specific error management initialization function
  * @em_handle: Callback for switch-specific error management handler function
  */
index 2389f93..92f1d99 100644 (file)
@@ -105,6 +105,22 @@ struct uac_as_header_descriptor_v2 {
        __u8 iChannelNames;
 } __attribute__((packed));
 
+/* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
+
+struct uac2_iso_endpoint_descriptor {
+       __u8  bLength;                  /* in bytes: 8 */
+       __u8  bDescriptorType;          /* USB_DT_CS_ENDPOINT */
+       __u8  bDescriptorSubtype;       /* EP_GENERAL */
+       __u8  bmAttributes;
+       __u8  bmControls;
+       __u8  bLockDelayUnits;
+       __le16 wLockDelay;
+} __attribute__((packed));
+
+#define UAC2_CONTROL_PITCH             (3 << 0)
+#define UAC2_CONTROL_DATA_OVERRUN      (3 << 2)
+#define UAC2_CONTROL_DATA_UNDERRUN     (3 << 4)
+
 /* 6.1 Interrupt Data Message */
 
 #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0)
diff --git a/include/linux/uuid.h b/include/linux/uuid.h
new file mode 100644 (file)
index 0000000..5b7efbf
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * UUID/GUID definition
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_UUID_H_
+#define _LINUX_UUID_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+typedef struct {
+       __u8 b[16];
+} uuid_le;
+
+typedef struct {
+       __u8 b[16];
+} uuid_be;
+
+#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
+((uuid_le)                                                             \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+   (b) & 0xff, ((b) >> 8) & 0xff,                                      \
+   (c) & 0xff, ((c) >> 8) & 0xff,                                      \
+   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define UUID_BE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
+((uuid_be)                                                             \
+{{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
+   ((b) >> 8) & 0xff, (b) & 0xff,                                      \
+   ((c) >> 8) & 0xff, (c) & 0xff,                                      \
+   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define NULL_UUID_LE                                                   \
+       UUID_LE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,     \
+               0x00, 0x00, 0x00, 0x00)
+
+#define NULL_UUID_BE                                                   \
+       UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,     \
+               0x00, 0x00, 0x00, 0x00)
+
+static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
+{
+       return memcmp(&u1, &u2, sizeof(uuid_le));
+}
+
+static inline int uuid_be_cmp(const uuid_be u1, const uuid_be u2)
+{
+       return memcmp(&u1, &u2, sizeof(uuid_be));
+}
+
+extern void uuid_le_gen(uuid_le *u);
+extern void uuid_be_gen(uuid_be *u);
+
+#endif
index 6cf4486..726cc35 100644 (file)
@@ -39,7 +39,7 @@ extern int net_cls_subsys_id;
 static inline u32 task_cls_classid(struct task_struct *p)
 {
        int id;
-       u32 classid;
+       u32 classid = 0;
 
        if (in_interrupt())
                return 0;
index 6173c61..4b86011 100644 (file)
@@ -876,7 +876,7 @@ struct sctp_transport {
 
        /* Reference counting. */
        atomic_t refcnt;
-       int      dead:1,
+       __u32    dead:1,
                /* RTO-Pending : A flag used to track if one of the DATA
                 *              chunks sent to this address is currently being
                 *              used to compute a RTT. If this flag is 0,
index d2a71b0..ca241ea 100644 (file)
@@ -1026,15 +1026,23 @@ extern void release_sock(struct sock *sk);
                                SINGLE_DEPTH_NESTING)
 #define bh_unlock_sock(__sk)   spin_unlock(&((__sk)->sk_lock.slock))
 
-static inline void lock_sock_bh(struct sock *sk)
+extern bool lock_sock_fast(struct sock *sk);
+/**
+ * unlock_sock_fast - complement of lock_sock_fast
+ * @sk: socket
+ * @slow: slow mode
+ *
+ * fast unlock socket for user context.
+ * If slow mode is on, we call regular release_sock()
+ */
+static inline void unlock_sock_fast(struct sock *sk, bool slow)
 {
-       spin_lock_bh(&sk->sk_lock.slock);
+       if (slow)
+               release_sock(sk);
+       else
+               spin_unlock_bh(&sk->sk_lock.slock);
 }
 
-static inline void unlock_sock_bh(struct sock *sk)
-{
-       spin_unlock_bh(&sk->sk_lock.slock);
-}
 
 extern struct sock             *sk_alloc(struct net *net, int family,
                                          gfp_t priority,
index 5d60ad4..f5b1ba9 100644 (file)
@@ -606,9 +606,9 @@ TRACE_EVENT(ext4_free_blocks,
 );
 
 TRACE_EVENT(ext4_sync_file,
-       TP_PROTO(struct file *file, struct dentry *dentry, int datasync),
+       TP_PROTO(struct file *file, int datasync),
 
-       TP_ARGS(file, dentry, datasync),
+       TP_ARGS(file, datasync),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
@@ -618,6 +618,8 @@ TRACE_EVENT(ext4_sync_file,
        ),
 
        TP_fast_assign(
+               struct dentry *dentry = file->f_path.dentry;
+
                __entry->dev            = dentry->d_inode->i_sb->s_dev;
                __entry->ino            = dentry->d_inode->i_ino;
                __entry->datasync       = datasync;
index 1a314c8..52ed77e 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -273,16 +273,13 @@ static int shm_release(struct inode *ino, struct file *file)
        return 0;
 }
 
-static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int shm_fsync(struct file *file, int datasync)
 {
-       int (*fsync) (struct file *, struct dentry *, int datasync);
        struct shm_file_data *sfd = shm_file_data(file);
-       int ret = -EINVAL;
 
-       fsync = sfd->file->f_op->fsync;
-       if (fsync)
-               ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
-       return ret;
+       if (!sfd->file->f_op->fsync)
+               return -EINVAL;
+       return sfd->file->f_op->fsync(sfd->file, datasync);
 }
 
 static unsigned long shm_get_unmapped_area(struct file *file,
index 3097382..8b92539 100644 (file)
@@ -394,7 +394,7 @@ static cpumask_var_t frozen_cpus;
 
 int disable_nonboot_cpus(void)
 {
-       int cpu, first_cpu, error;
+       int cpu, first_cpu, error = 0;
 
        cpu_maps_update_begin();
        first_cpu = cpumask_first(cpu_online_mask);
index bf9fef6..b6cce14 100644 (file)
@@ -1086,10 +1086,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
        mpol_fix_fork_child_flag(p);
 #endif
-#ifdef CONFIG_CPUSETS
-       p->cpuset_mem_spread_rotor = node_random(p->mems_allowed);
-       p->cpuset_slab_spread_rotor = node_random(p->mems_allowed);
-#endif
 #ifdef CONFIG_TRACE_IRQFLAGS
        p->irq_events = 0;
 #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
index b9b134b..5c69e99 100644 (file)
@@ -89,7 +89,7 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
 
        do {
                seq = read_seqbegin(&xtime_lock);
-               xts = current_kernel_time();
+               xts = __current_kernel_time();
                tom = wall_to_monotonic;
        } while (read_seqretry(&xtime_lock, seq));
 
index e099650..bd7ce8c 100644 (file)
@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
        struct file *group_file = NULL;
+       int event_fd;
        int fput_needed = 0;
-       int fput_needed2 = 0;
        int err;
 
        /* for future expandability... */
@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
                        return -EINVAL;
        }
 
+       event_fd = get_unused_fd_flags(O_RDWR);
+       if (event_fd < 0)
+               return event_fd;
+
        /*
         * Get the target context (task or percpu):
         */
        ctx = find_get_context(pid, cpu);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_fd;
+       }
 
        /*
         * Look up the group leader (we will attach this event to it):
@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
        if (IS_ERR(event))
                goto err_put_context;
 
-       err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
-       if (err < 0)
-               goto err_free_put_context;
-
-       event_file = fget_light(err, &fput_needed2);
-       if (!event_file)
+       event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
+       if (IS_ERR(event_file)) {
+               err = PTR_ERR(event_file);
                goto err_free_put_context;
+       }
 
        if (flags & PERF_FLAG_FD_OUTPUT) {
                err = perf_event_set_output(event, group_fd);
@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
        list_add_tail(&event->owner_entry, &current->perf_event_list);
        mutex_unlock(&current->perf_event_mutex);
 
-err_fput_free_put_context:
-       fput_light(event_file, fput_needed2);
+       fput_light(group_file, fput_needed);
+       fd_install(event_fd, event_file);
+       return event_fd;
 
+err_fput_free_put_context:
+       fput(event_file);
 err_free_put_context:
-       if (err < 0)
-               free_event(event);
-
+       free_event(event);
 err_put_context:
-       if (err < 0)
-               put_ctx(ctx);
-
        fput_light(group_file, fput_needed);
-
+       put_ctx(ctx);
+err_fd:
+       put_unused_fd(event_fd);
        return err;
 }
 
index 00d1fda..ad72342 100644 (file)
@@ -559,14 +559,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        new_timer->it_id = (timer_t) new_timer_id;
        new_timer->it_clock = which_clock;
        new_timer->it_overrun = -1;
-       error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
-       if (error)
-               goto out;
 
-       /*
-        * return the timer_id now.  The next step is hard to
-        * back out if there is an error.
-        */
        if (copy_to_user(created_timer_id,
                         &new_timer_id, sizeof (new_timer_id))) {
                error = -EFAULT;
@@ -597,6 +590,10 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        new_timer->sigq->info.si_tid   = new_timer->it_id;
        new_timer->sigq->info.si_code  = SI_TIMER;
 
+       error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
+       if (error)
+               goto out;
+
        spin_lock_irq(&current->sighand->siglock);
        new_timer->it_signal = current->signal;
        list_add(&new_timer->list, &current->signal->posix_timers);
index 15b93f6..d484081 100644 (file)
@@ -4053,6 +4053,23 @@ int __sched wait_for_completion_killable(struct completion *x)
 }
 EXPORT_SYMBOL(wait_for_completion_killable);
 
+/**
+ * wait_for_completion_killable_timeout: - waits for completion of a task (w/(to,killable))
+ * @x:  holds the state of this particular completion
+ * @timeout:  timeout value in jiffies
+ *
+ * This waits for either a completion of a specific task to be
+ * signaled or for a specified timeout to expire. It can be
+ * interrupted by a kill signal. The timeout is in jiffies.
+ */
+unsigned long __sched
+wait_for_completion_killable_timeout(struct completion *x,
+                                    unsigned long timeout)
+{
+       return wait_for_common(x, timeout, TASK_KILLABLE);
+}
+EXPORT_SYMBOL(wait_for_completion_killable_timeout);
+
 /**
  *     try_wait_for_completion - try to decrement a completion without blocking
  *     @x:     completion structure
index e3b8c69..2454172 100644 (file)
@@ -752,11 +752,15 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
 
        expires_limit = expires;
 
-       if (timer->slack > -1)
+       if (timer->slack >= 0) {
                expires_limit = expires + timer->slack;
-       else if (time_after(expires, jiffies)) /* auto slack: use 0.4% */
-               expires_limit = expires + (expires - jiffies)/256;
+       } else {
+               unsigned long now = jiffies;
 
+               /* No slack, if already expired else auto slack 0.4% */
+               if (time_after(expires, now))
+                       expires_limit = expires + (expires - now)/256;
+       }
        mask = expires ^ expires_limit;
        if (mask == 0)
                return expires;
index c8567a5..3f1062c 100644 (file)
@@ -21,7 +21,7 @@ lib-y += kobject.o kref.o klist.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
-        string_helpers.o gcd.o lcm.o list_sort.o
+        string_helpers.o gcd.o lcm.o list_sort.o uuid.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
index 65e482c..9087d71 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <asm/atomic.h>
 
 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
index d7137e7..ffb78c9 100644 (file)
@@ -672,7 +672,7 @@ static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits)
  *
  * The bit positions 0 through @bits are valid positions in @buf.
  */
-int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
+static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
 {
        int pos = 0;
 
diff --git a/lib/uuid.c b/lib/uuid.c
new file mode 100644 (file)
index 0000000..8fadd7c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Unified UUID/GUID definition
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uuid.h>
+#include <linux/random.h>
+
+static void __uuid_gen_common(__u8 b[16])
+{
+       int i;
+       u32 r;
+
+       for (i = 0; i < 4; i++) {
+               r = random32();
+               memcpy(b + i * 4, &r, 4);
+       }
+       /* reversion 0b10 */
+       b[8] = (b[8] & 0x3F) | 0x80;
+}
+
+void uuid_le_gen(uuid_le *lu)
+{
+       __uuid_gen_common(lu->b);
+       /* version 4 : random generation */
+       lu->b[7] = (lu->b[7] & 0x0F) | 0x40;
+}
+EXPORT_SYMBOL_GPL(uuid_le_gen);
+
+void uuid_be_gen(uuid_be *bu)
+{
+       __uuid_gen_common(bu->b);
+       /* version 4 : random generation */
+       bu->b[6] = (bu->b[6] & 0x0F) | 0x40;
+}
+EXPORT_SYMBOL_GPL(uuid_be_gen);
index 855eaf5..7e5030a 100644 (file)
@@ -727,10 +727,11 @@ done2:
        if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) {
                /*
                 * Call truncate_inode_pages again: racing shmem_unuse_inode
-                * may have swizzled a page in from swap since vmtruncate or
-                * generic_delete_inode did it, before we lowered next_index.
-                * Also, though shmem_getpage checks i_size before adding to
-                * cache, no recheck after: so fix the narrow window there too.
+                * may have swizzled a page in from swap since
+                * truncate_pagecache or generic_delete_inode did it, before we
+                * lowered next_index.  Also, though shmem_getpage checks
+                * i_size before adding to cache, no recheck after: so fix the
+                * narrow window there too.
                 *
                 * Recalling truncate_inode_pages_range and unmap_mapping_range
                 * every time for punch_hole (which never got a chance to clear
@@ -760,19 +761,16 @@ done2:
        }
 }
 
-static void shmem_truncate(struct inode *inode)
-{
-       shmem_truncate_range(inode, inode->i_size, (loff_t)-1);
-}
-
 static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
-       struct page *page = NULL;
        int error;
 
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
-               if (attr->ia_size < inode->i_size) {
+               loff_t newsize = attr->ia_size;
+               struct page *page = NULL;
+
+               if (newsize < inode->i_size) {
                        /*
                         * If truncating down to a partial page, then
                         * if that page is already allocated, hold it
@@ -780,9 +778,9 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                         * truncate_partial_page cannnot miss it were
                         * it assigned to swap.
                         */
-                       if (attr->ia_size & (PAGE_CACHE_SIZE-1)) {
+                       if (newsize & (PAGE_CACHE_SIZE-1)) {
                                (void) shmem_getpage(inode,
-                                       attr->ia_size>>PAGE_CACHE_SHIFT,
+                                       newsize >> PAGE_CACHE_SHIFT,
                                                &page, SGP_READ, NULL);
                                if (page)
                                        unlock_page(page);
@@ -794,24 +792,29 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                         * if it's being fully truncated to zero-length: the
                         * nrpages check is efficient enough in that case.
                         */
-                       if (attr->ia_size) {
+                       if (newsize) {
                                struct shmem_inode_info *info = SHMEM_I(inode);
                                spin_lock(&info->lock);
                                info->flags &= ~SHMEM_PAGEIN;
                                spin_unlock(&info->lock);
                        }
                }
+
+               error = simple_setsize(inode, newsize);
+               if (page)
+                       page_cache_release(page);
+               if (error)
+                       return error;
+               shmem_truncate_range(inode, newsize, (loff_t)-1);
        }
 
        error = inode_change_ok(inode, attr);
        if (!error)
-               error = inode_setattr(inode, attr);
+               generic_setattr(inode, attr);
 #ifdef CONFIG_TMPFS_POSIX_ACL
        if (!error && (attr->ia_valid & ATTR_MODE))
                error = generic_acl_chmod(inode);
 #endif
-       if (page)
-               page_cache_release(page);
        return error;
 }
 
@@ -819,11 +822,11 @@ static void shmem_delete_inode(struct inode *inode)
 {
        struct shmem_inode_info *info = SHMEM_I(inode);
 
-       if (inode->i_op->truncate == shmem_truncate) {
+       if (inode->i_mapping->a_ops == &shmem_aops) {
                truncate_inode_pages(inode->i_mapping, 0);
                shmem_unacct_size(info->flags, inode->i_size);
                inode->i_size = 0;
-               shmem_truncate(inode);
+               shmem_truncate_range(inode, 0, (loff_t)-1);
                if (!list_empty(&info->swaplist)) {
                        mutex_lock(&shmem_swaplist_mutex);
                        list_del_init(&info->swaplist);
@@ -2022,7 +2025,6 @@ static const struct inode_operations shmem_symlink_inline_operations = {
 };
 
 static const struct inode_operations shmem_symlink_inode_operations = {
-       .truncate       = shmem_truncate,
        .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link,
        .put_link       = shmem_put_link,
@@ -2433,14 +2435,13 @@ static const struct file_operations shmem_file_operations = {
        .write          = do_sync_write,
        .aio_read       = shmem_file_aio_read,
        .aio_write      = generic_file_aio_write,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 #endif
 };
 
 static const struct inode_operations shmem_inode_operations = {
-       .truncate       = shmem_truncate,
        .setattr        = shmem_notify_change,
        .truncate_range = shmem_truncate_range,
 #ifdef CONFIG_TMPFS_POSIX_ACL
index f42675a..937571b 100644 (file)
@@ -548,18 +548,18 @@ EXPORT_SYMBOL(truncate_pagecache);
  * NOTE! We have to be ready to update the memory sharing
  * between the file and the memory map for a potential last
  * incomplete page.  Ugly, but necessary.
+ *
+ * This function is deprecated and simple_setsize or truncate_pagecache
+ * should be used instead.
  */
 int vmtruncate(struct inode *inode, loff_t offset)
 {
-       loff_t oldsize;
        int error;
 
-       error = inode_newsize_ok(inode, offset);
+       error = simple_setsize(inode, offset);
        if (error)
                return error;
-       oldsize = inode->i_size;
-       i_size_write(inode, offset);
-       truncate_pagecache(inode, oldsize, offset);
+
        if (inode->i_op->truncate)
                inode->i_op->truncate(inode);
 
index e009753..f5b6f43 100644 (file)
@@ -229,15 +229,17 @@ EXPORT_SYMBOL(skb_free_datagram);
 
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
 {
+       bool slow;
+
        if (likely(atomic_read(&skb->users) == 1))
                smp_rmb();
        else if (likely(!atomic_dec_and_test(&skb->users)))
                return;
 
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        skb_orphan(skb);
        sk_mem_reclaim_partial(sk);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        /* skb is now orphaned, can be freed outside of locked section */
        __kfree_skb(skb);
index bff3790..6ba1c0e 100644 (file)
@@ -934,6 +934,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                                kfree_skb(buff);
                                NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
+                       skb_dst_force(skb);
                        __skb_queue_tail(&neigh->arp_queue, skb);
                }
                rc = 1;
index 7ab86f3..1a2af24 100644 (file)
@@ -650,11 +650,12 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev)
        if (dev->dev.parent && dev_is_pci(dev->dev.parent)) {
 
                int num_vfs = dev_num_vf(dev->dev.parent);
-               size_t size = nlmsg_total_size(sizeof(struct nlattr));
-               size += nlmsg_total_size(num_vfs * sizeof(struct nlattr));
-               size += num_vfs * (sizeof(struct ifla_vf_mac) +
-                                 sizeof(struct ifla_vf_vlan) +
-                                 sizeof(struct ifla_vf_tx_rate));
+               size_t size = nla_total_size(sizeof(struct nlattr));
+               size += nla_total_size(num_vfs * sizeof(struct nlattr));
+               size += num_vfs *
+                       (nla_total_size(sizeof(struct ifla_vf_mac)) +
+                        nla_total_size(sizeof(struct ifla_vf_vlan)) +
+                        nla_total_size(sizeof(struct ifla_vf_tx_rate)));
                return size;
        } else
                return 0;
@@ -722,14 +723,13 @@ static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
 
        for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) {
                vf_port = nla_nest_start(skb, IFLA_VF_PORT);
-               if (!vf_port) {
-                       nla_nest_cancel(skb, vf_ports);
-                       return -EMSGSIZE;
-               }
+               if (!vf_port)
+                       goto nla_put_failure;
                NLA_PUT_U32(skb, IFLA_PORT_VF, vf);
                err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb);
+               if (err == -EMSGSIZE)
+                       goto nla_put_failure;
                if (err) {
-nla_put_failure:
                        nla_nest_cancel(skb, vf_port);
                        continue;
                }
@@ -739,6 +739,10 @@ nla_put_failure:
        nla_nest_end(skb, vf_ports);
 
        return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, vf_ports);
+       return -EMSGSIZE;
 }
 
 static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
@@ -753,7 +757,7 @@ static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
        err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb);
        if (err) {
                nla_nest_cancel(skb, port_self);
-               return err;
+               return (err == -EMSGSIZE) ? err : 0;
        }
 
        nla_nest_end(skb, port_self);
index 37fe9b6..2cf7f9f 100644 (file)
@@ -2007,6 +2007,39 @@ void release_sock(struct sock *sk)
 }
 EXPORT_SYMBOL(release_sock);
 
+/**
+ * lock_sock_fast - fast version of lock_sock
+ * @sk: socket
+ *
+ * This version should be used for very small section, where process wont block
+ * return false if fast path is taken
+ *   sk_lock.slock locked, owned = 0, BH disabled
+ * return true if slow path is taken
+ *   sk_lock.slock unlocked, owned = 1, BH enabled
+ */
+bool lock_sock_fast(struct sock *sk)
+{
+       might_sleep();
+       spin_lock_bh(&sk->sk_lock.slock);
+
+       if (!sk->sk_lock.owned)
+               /*
+                * Note : We must disable BH
+                */
+               return false;
+
+       __lock_sock(sk);
+       sk->sk_lock.owned = 1;
+       spin_unlock(&sk->sk_lock.slock);
+       /*
+        * The sk_lock has mutex_lock() semantics here:
+        */
+       mutex_acquire(&sk->sk_lock.dep_map, 0, 0, _RET_IP_);
+       local_bh_enable();
+       return true;
+}
+EXPORT_SYMBOL(lock_sock_fast);
+
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
        struct timeval tv;
index 4588910..856123f 100644 (file)
@@ -1911,7 +1911,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
        struct rtattr *mp_head;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->mfc_parent > MAXVIFS)
+       if (c->mfc_parent >= MAXVIFS)
                return -ENOENT;
 
        if (VIF_EXISTS(mrt, c->mfc_parent))
index baeec29..5858574 100644 (file)
@@ -1063,10 +1063,11 @@ static unsigned int first_packet_length(struct sock *sk)
        spin_unlock_bh(&rcvq->lock);
 
        if (!skb_queue_empty(&list_kill)) {
-               lock_sock_bh(sk);
+               bool slow = lock_sock_fast(sk);
+
                __skb_queue_purge(&list_kill);
                sk_mem_reclaim_partial(sk);
-               unlock_sock_bh(sk);
+               unlock_sock_fast(sk, slow);
        }
        return res;
 }
@@ -1123,6 +1124,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        int peeked;
        int err;
        int is_udplite = IS_UDPLITE(sk);
+       bool slow;
 
        /*
         *      Check any passed addresses
@@ -1197,10 +1199,10 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags))
                UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        if (noblock)
                return -EAGAIN;
@@ -1625,9 +1627,9 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
-       lock_sock_bh(sk);
+       bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 }
 
 /*
index cd963f6..89425af 100644 (file)
@@ -507,7 +507,7 @@ int ip6_forward(struct sk_buff *skb)
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
 
-       if (skb->len > mtu) {
+       if (skb->len > mtu && !skb_is_gso(skb)) {
                /* Again, force OUTPUT device used as source address */
                skb->dev = dst->dev;
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
index bd9e7d3..073071f 100644 (file)
@@ -2017,7 +2017,7 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
        struct rtattr *mp_head;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->mf6c_parent > MAXMIFS)
+       if (c->mf6c_parent >= MAXMIFS)
                return -ENOENT;
 
        if (MIF_EXISTS(mrt, c->mf6c_parent))
index 3d7a2c0..87be586 100644 (file)
@@ -328,6 +328,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        int err;
        int is_udplite = IS_UDPLITE(sk);
        int is_udp4;
+       bool slow;
 
        if (addr_len)
                *addr_len=sizeof(struct sockaddr_in6);
@@ -424,7 +425,7 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags)) {
                if (is_udp4)
                        UDP_INC_STATS_USER(sock_net(sk),
@@ -433,7 +434,7 @@ csum_copy_err:
                        UDP6_INC_STATS_USER(sock_net(sk),
                                        UDP_MIB_INERRORS, is_udplite);
        }
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
index c8b4599..9637e45 100644 (file)
@@ -1619,7 +1619,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
 save_message:
        save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA);
        if (!save_msg)
-               return;
+               goto out_unlock;
        save_msg->path = path;
        save_msg->msg = *msg;
 
index d7920d9..859d9fd 100644 (file)
@@ -76,7 +76,7 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
        if (ip_route_output_key(net, &rt, &fl) != 0)
                return false;
 
-       dst_release(skb_dst(skb));
+       skb_dst_drop(skb);
        skb_dst_set(skb, &rt->u.dst);
        skb->dev      = rt->u.dst.dev;
        skb->protocol = htons(ETH_P_IP);
@@ -157,7 +157,7 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
        if (dst == NULL)
                return false;
 
-       dst_release(skb_dst(skb));
+       skb_dst_drop(skb);
        skb_dst_set(skb, dst);
        skb->dev      = dst->dev;
        skb->protocol = htons(ETH_P_IPV6);
index 3e763d6..446cf97 100644 (file)
@@ -516,6 +516,7 @@ get the interrupt driven case to work efficiently */
                        break;
        if (i == 0x5000) {
                printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
+               spin_unlock(&au1000->ac97_lock);
                return 0;
        }
 
index 1f47741..13c2144 100644 (file)
@@ -1277,7 +1277,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
                 * (almost) like on the TT.
                 */
                write_sq_ignore_int = 0;
-               return IRQ_HANDLED;
+               goto out;
        }
 
        if (!write_sq.active) {
@@ -1285,7 +1285,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
                 * the sq variables, so better don't do anything here.
                 */
                WAKE_UP(write_sq.sync_queue);
-               return IRQ_HANDLED;
+               goto out;
        }
 
        /* Probably ;) one frame is finished. Well, in fact it may be that a
@@ -1322,6 +1322,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
        /* We are not playing after AtaPlay(), so there
           is nothing to play any more. Wake up a process
           waiting for audio output to drain. */
+out:
        spin_unlock(&dmasound.lock);
        return IRQ_HANDLED;
 }
index 99400de..0173bbe 100644 (file)
@@ -50,7 +50,7 @@ i.e 3.05.02 is a development version
 #define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
 
 /* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 18)
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25)
 
 /* Library version as documented in hpi-api-versions.txt */
 #define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
@@ -1632,6 +1632,12 @@ u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
        u32 h_control, u32 *pquality);
 
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, u32 *pblend);
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, const u32 blend);
+
 /****************************/
 /* PADs control             */
 /****************************/
index 839ecb2..12dab5e 100644 (file)
@@ -691,9 +691,6 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        case 0x6200:
                boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
                break;
-       case 0x8800:
-               boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x8800);
-               break;
        default:
                return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;
        }
@@ -1775,7 +1772,6 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
        u16 error = 0;
        u16 dsp_index = 0;
        u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp;
-       hpios_dsplock_lock(pao);
 
        if (num_dsp < 2)
                dsp_index = 0;
@@ -1796,6 +1792,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
                        }
                }
        }
+
+       hpios_dsplock_lock(pao);
        error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
 
        /* maybe an error response */
index 5e88c1f..e89991e 100644 (file)
@@ -965,24 +965,17 @@ static void outstream_write(struct hpi_adapter_obj *pao,
        hpi_init_response(phr, phm->object, phm->function, 0);
        status = &interface->outstream_host_buffer_status[phm->obj_index];
 
-       if (phw->flag_outstream_just_reset[phm->obj_index]) {
-               /* Format can only change after reset. Must tell DSP. */
-               u16 function = phm->function;
-               phw->flag_outstream_just_reset[phm->obj_index] = 0;
-               phm->function = HPI_OSTREAM_SET_FORMAT;
-               hw_message(pao, phm, phr);      /* send the format to the DSP */
-               phm->function = function;
-               if (phr->error)
-                       return;
-       }
-#if 1
        if (phw->flag_outstream_just_reset[phm->obj_index]) {
                /* First OutStremWrite() call following reset will write data to the
-                  adapter's buffers, reducing delay before stream can start
+                  adapter's buffers, reducing delay before stream can start. The DSP
+                  takes care of setting the stream data format using format information
+                  embedded in phm.
                 */
                int partial_write = 0;
                unsigned int original_size = 0;
 
+               phw->flag_outstream_just_reset[phm->obj_index] = 0;
+
                /* Send the first buffer to the DSP the old way. */
                /* Limit size of first transfer - */
                /* expect that this will not usually be triggered. */
@@ -1012,7 +1005,6 @@ static void outstream_write(struct hpi_adapter_obj *pao,
                        original_size - HPI6205_SIZEOF_DATA;
                phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
        }
-#endif
 
        space_available = outstream_get_space_available(status);
        if (space_available < (long)phm->u.d.u.data.data_size) {
@@ -1369,6 +1361,9 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        case HPI_ADAPTER_FAMILY_ASI(0x6500):
                firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
                break;
+       case HPI_ADAPTER_FAMILY_ASI(0x8800):
+               firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
+               break;
        }
        boot_code_id[1] = firmware_id;
 
index f1cd6f1..fdd0ce0 100644 (file)
@@ -232,6 +232,8 @@ enum HPI_BUSES {
 #define HPI_TUNER_HDRADIO_SDK_VERSION   HPI_CTL_ATTR(TUNER, 13)
 /** HD Radio DSP firmware version. */
 #define HPI_TUNER_HDRADIO_DSP_VERSION   HPI_CTL_ATTR(TUNER, 14)
+/** HD Radio signal blend (force analog, or automatic). */
+#define HPI_TUNER_HDRADIO_BLEND         HPI_CTL_ATTR(TUNER, 15)
 
 /** \} */
 
@@ -478,8 +480,10 @@ Threshold is a -ve number in units of dB/100,
 
 /** First 2 hex digits define the adapter family */
 #define HPI_ADAPTER_FAMILY_MASK         0xff00
+#define HPI_MODULE_FAMILY_MASK          0xfff0
 
 #define HPI_ADAPTER_FAMILY_ASI(f)   (f & HPI_ADAPTER_FAMILY_MASK)
+#define HPI_MODULE_FAMILY_ASI(f)   (f & HPI_MODULE_FAMILY_MASK)
 #define HPI_ADAPTER_ASI(f)   (f)
 
 /******************************************* message types */
@@ -970,6 +974,7 @@ struct hpi_control_union_msg {
                                u32 mode;
                                u32 value;
                        } mode;
+                       u32 blend;
                } tuner;
        } u;
 };
index 565102c..fcd6453 100644 (file)
@@ -347,20 +347,15 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
                        found = 0;
                break;
        case HPI_CONTROL_TUNER:
-               {
-                       struct hpi_control_cache_single *pCT =
-                               (struct hpi_control_cache_single *)pI;
-                       if (phm->u.c.attribute == HPI_TUNER_FREQ)
-                               phr->u.c.param1 = pCT->u.t.freq_ink_hz;
-                       else if (phm->u.c.attribute == HPI_TUNER_BAND)
-                               phr->u.c.param1 = pCT->u.t.band;
-                       else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
-                               && (phm->u.c.param1 ==
-                                       HPI_TUNER_LEVEL_AVERAGE))
-                               phr->u.c.param1 = pCT->u.t.level;
-                       else
-                               found = 0;
-               }
+               if (phm->u.c.attribute == HPI_TUNER_FREQ)
+                       phr->u.c.param1 = pC->u.t.freq_ink_hz;
+               else if (phm->u.c.attribute == HPI_TUNER_BAND)
+                       phr->u.c.param1 = pC->u.t.band;
+               else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
+                       && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
+                       phr->u.c.param1 = pC->u.t.level;
+               else
+                       found = 0;
                break;
        case HPI_CONTROL_AESEBU_RECEIVER:
                if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
@@ -503,6 +498,9 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
        struct hpi_control_cache_single *pC;
        struct hpi_control_cache_info *pI;
 
+       if (phr->error)
+               return;
+
        if (!find_control(phm, p_cache, &pI, &control_index))
                return;
 
@@ -520,8 +518,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                break;
        case HPI_CONTROL_MULTIPLEXER:
                /* mux does not return its setting on Set command. */
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
                        pC->u.x.source_node_type = (u16)phm->u.c.param1;
                        pC->u.x.source_node_index = (u16)phm->u.c.param2;
@@ -529,8 +525,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                break;
        case HPI_CONTROL_CHANNEL_MODE:
                /* mode does not return its setting on Set command. */
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
                        pC->u.m.mode = (u16)phm->u.c.param1;
                break;
@@ -545,20 +539,14 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                        pC->u.phantom_power.state = (u16)phm->u.c.param1;
                break;
        case HPI_CONTROL_AESEBU_TRANSMITTER:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
                        pC->u.aes3tx.format = phm->u.c.param1;
                break;
        case HPI_CONTROL_AESEBU_RECEIVER:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
                        pC->u.aes3rx.source = phm->u.c.param1;
                break;
        case HPI_CONTROL_SAMPLECLOCK:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
                        pC->u.clk.source = (u16)phm->u.c.param1;
                else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
@@ -590,7 +578,7 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
 
 void hpi_free_control_cache(struct hpi_control_cache *p_cache)
 {
-       if ((p_cache->init) && (p_cache->p_info)) {
+       if (p_cache->init) {
                kfree(p_cache->p_info);
                p_cache->p_info = NULL;
                p_cache->init = 0;
index eda26b3..298eef3 100644 (file)
@@ -2946,6 +2946,20 @@ u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
                HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
 }
 
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, u32 *pblend)
+{
+       return hpi_control_param_get(ph_subsys, h_control,
+               HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL);
+}
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, const u32 blend)
+{
+       return hpi_control_param_set(ph_subsys, h_control,
+               HPI_TUNER_HDRADIO_BLEND, blend, 0);
+}
+
 u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
        char *p_data)
 {
@@ -3266,8 +3280,7 @@ u16 hpi_entity_find_next(struct hpi_entity *container_entity,
 
 void hpi_entity_free(struct hpi_entity *entity)
 {
-       if (entity != NULL)
-               kfree(entity);
+       kfree(entity);
 }
 
 static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src,
index de615cf..742ee12 100644 (file)
@@ -89,26 +89,3 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
 void hpios_locked_mem_free_all(void)
 {
 }
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
-       unsigned int length)
-{
-       HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n",
-               idx, pci_dev->resource[idx].name,
-               (unsigned long long)pci_resource_start(pci_dev, idx),
-               (unsigned long long)pci_resource_end(pci_dev, idx),
-               (unsigned long long)pci_resource_flags(pci_dev, idx), length);
-
-       if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) {
-               HPI_DEBUG_LOG(ERROR, "not an io memory resource\n");
-               return NULL;
-       }
-
-       if (length > pci_resource_len(pci_dev, idx)) {
-               HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n",
-                       length);
-               return NULL;
-       }
-
-       return ioremap(pci_resource_start(pci_dev, idx), length);
-}
index a62c3f1..370f39b 100644 (file)
@@ -166,13 +166,4 @@ struct hpi_adapter {
        void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
 };
 
-static inline void hpios_unmap_io(void __iomem *addr,
-       unsigned long size)
-{
-       iounmap(addr);
-}
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
-       unsigned int length);
-
 #endif
index 77e22c2..dc79564 100644 (file)
@@ -2288,8 +2288,10 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
index e863649..2bf2cb5 100644 (file)
@@ -2975,6 +2975,8 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
        {}
index 8ae2020..0221ca7 100644 (file)
@@ -426,8 +426,8 @@ static const struct soc_enum wm8350_enum[] = {
        SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr),
 };
 
-static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525);
-static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600);
+static DECLARE_TLV_DB_SCALE(pre_amp_tlv, -1200, 3525, 0);
+static DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 600, 0);
 static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
 static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
 static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
index 7f5d080..8f29406 100644 (file)
@@ -107,21 +107,21 @@ static void wm8400_codec_reset(struct snd_soc_codec *codec)
        wm8400_reset_codec_reg_cache(wm8400->wm8400);
 }
 
-static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0);
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -2100, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 
 static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
         struct snd_ctl_elem_value *ucontrol)
@@ -440,7 +440,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 /* INMIX dB values */
 static const unsigned int in_mix_tlv[] = {
        TLV_DB_RANGE_HEAD(1),
-       0,7, TLV_DB_LINEAR_ITEM(-1200, 600),
+       0,7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
 };
 
 /* Left In PGA Connections */
index 7b536d9..c018772 100644 (file)
@@ -111,21 +111,21 @@ static const u16 wm8990_reg[] = {
 
 #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
 
-static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100);
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
@@ -451,7 +451,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 /* INMIX dB values */
 static const unsigned int in_mix_tlv[] = {
        TLV_DB_RANGE_HEAD(1),
-       0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
+       0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
 };
 
 /* Left In PGA Connections */
index 2b31ac6..05f19c9 100644 (file)
@@ -73,7 +73,8 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err)
 {
        struct snd_pcm_substream *substream = data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+       struct imx_pcm_dma_params *dma_params = 
+               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
@@ -102,7 +103,7 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
 
-       dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
 
        iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
        if (iprtd->dma < 0) {
@@ -212,7 +213,7 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int err;
 
-       dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
 
        iprtd->substream = substream;
        iprtd->buf = (unsigned int *)substream->dma_buffer.area;
index d86ee1b..eeed5ed 100644 (file)
@@ -588,6 +588,8 @@ static int siu_dai_prepare(struct snd_pcm_substream *substream,
                ret = siu_dai_spbstart(port_info);
                if (ret < 0)
                        goto fail;
+       } else {
+               ret = 0;
        }
 
        port_info->play_cap |= self;
index 36ed703..91c804c 100644 (file)
@@ -42,21 +42,12 @@ static int control_info(struct snd_kcontrol *kcontrol,
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
-               if (pos == 0) {
-                       /* current input mode of A8DJ */
-                       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-                       uinfo->value.integer.min = 0;
-                       uinfo->value.integer.max = 2;
-                       return 0;
-               }
-               break;
-
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
                if (pos == 0) {
-                       /* current input mode of A4DJ */
+                       /* current input mode of A8DJ and A4DJ */
                        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
                        uinfo->value.integer.min = 0;
-                       uinfo->value.integer.max = 1;
+                       uinfo->value.integer.max = 2;
                        return 0;
                }
                break;
@@ -86,14 +77,6 @@ static int control_get(struct snd_kcontrol *kcontrol,
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
 
-       if (dev->chip.usb_id ==
-               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
-               /* A4DJ has only one control */
-               /* do not expose hardware input mode 0 */
-               ucontrol->value.integer.value[0] = dev->control_state[0] - 1;
-               return 0;
-       }
-
        if (pos & CNT_INTVAL)
                ucontrol->value.integer.value[0]
                        = dev->control_state[pos & ~CNT_INTVAL];
@@ -112,20 +95,9 @@ static int control_put(struct snd_kcontrol *kcontrol,
        int pos = kcontrol->private_value;
        unsigned char cmd = EP1_CMD_WRITE_IO;
 
-       switch (dev->chip.usb_id) {
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
-               /* A4DJ has only one control */
-               /* do not expose hardware input mode 0 */
-               dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
-                               dev->control_state, sizeof(dev->control_state));
-               return 1;
-       }
-
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
                cmd = EP1_CMD_DIMM_LEDS;
-               break;
-       }
 
        if (pos & CNT_INTVAL) {
                dev->control_state[pos & ~CNT_INTVAL]
index 8052718..cdfb856 100644 (file)
@@ -36,7 +36,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.20");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -320,12 +320,6 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                }
 
                break;
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
-               /* Audio 4 DJ - default input mode to phono */
-               dev->control_state[0] = 2;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
-                       dev->control_state, 1);
-               break;
        }
 
        if (dev->spec.num_analog_audio_out +
index ef07a6d..28ee1ce 100644 (file)
@@ -149,6 +149,47 @@ int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct au
        return 0;
 }
 
+static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
+                                        struct usb_host_interface *alts,
+                                        int protocol, int iface_no)
+{
+       /* parsed with a v1 header here. that's ok as we only look at the
+        * header first which is the same for both versions */
+       struct uac_iso_endpoint_descriptor *csep;
+       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+       int attributes = 0;
+
+       csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+       /* Creamware Noah has this descriptor after the 2nd endpoint */
+       if (!csep && altsd->bNumEndpoints >= 2)
+               csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+       if (!csep || csep->bLength < 7 ||
+           csep->bDescriptorSubtype != UAC_EP_GENERAL) {
+               snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+                          " class specific endpoint descriptor\n",
+                          chip->dev->devnum, iface_no,
+                          altsd->bAlternateSetting);
+               return 0;
+       }
+
+       if (protocol == UAC_VERSION_1) {
+               attributes = csep->bmAttributes;
+       } else {
+               struct uac2_iso_endpoint_descriptor *csep2 =
+                       (struct uac2_iso_endpoint_descriptor *) csep;
+
+               attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
+
+               /* emulate the endpoint attributes of a v1 device */
+               if (csep2->bmControls & UAC2_CONTROL_PITCH)
+                       attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
+       }
+
+       return attributes;
+}
+
 int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
        struct usb_device *dev;
@@ -158,8 +199,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        int i, altno, err, stream;
        int format = 0, num_channels = 0;
        struct audioformat *fp = NULL;
-       unsigned char *fmt, *csep;
        int num, protocol;
+       struct uac_format_type_i_continuous_descriptor *fmt;
 
        dev = chip->dev;
 
@@ -256,8 +297,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                                   dev->devnum, iface_no, altno);
                        continue;
                }
-               if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) ||
-                   ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) {
+               if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
+                   ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
                        snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
@@ -268,7 +309,9 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                 * with the previous one, except for a larger packet size, but
                 * is actually a mislabeled two-channel setting; ignore it.
                 */
-               if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+               if (fmt->bNrChannels == 1 &&
+                   fmt->bSubframeSize == 2 &&
+                   altno == 2 && num == 3 &&
                    fp && fp->altsetting == 1 && fp->channels == 1 &&
                    fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
                    protocol == UAC_VERSION_1 &&
@@ -276,17 +319,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                                                        fp->maxpacksize * 2)
                        continue;
 
-               csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
-               /* Creamware Noah has this descriptor after the 2nd endpoint */
-               if (!csep && altsd->bNumEndpoints >= 2)
-                       csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
-               if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) {
-                       snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
-                                  " class specific endpoint descriptor\n",
-                                  dev->devnum, iface_no, altno);
-                       csep = NULL;
-               }
-
                fp = kzalloc(sizeof(*fp), GFP_KERNEL);
                if (! fp) {
                        snd_printk(KERN_ERR "cannot malloc\n");
@@ -305,7 +337,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
                                        * (fp->maxpacksize & 0x7ff);
-               fp->attributes = csep ? csep[3] : 0;
+               fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
 
                /* some quirks for attributes here */
 
index b87cf87..fe29d61 100644 (file)
@@ -278,12 +278,11 @@ err:
  * parse the format type I and III descriptors
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
-                               struct audioformat *fp,
-                               int format, void *_fmt,
+                               struct audioformat *fp, int format,
+                               struct uac_format_type_i_continuous_descriptor *fmt,
                                struct usb_host_interface *iface)
 {
        struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
        int protocol = altsd->bInterfaceProtocol;
        int pcm_format, ret;
 
@@ -320,7 +319,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
        switch (protocol) {
        case UAC_VERSION_1:
                fp->channels = fmt->bNrChannels;
-               ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7);
+               ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
                break;
        case UAC_VERSION_2:
                /* fp->channels is already set in this case */
@@ -392,12 +391,12 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 }
 
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                      int format, unsigned char *fmt, int stream,
-                      struct usb_host_interface *iface)
+                              int format, struct uac_format_type_i_continuous_descriptor *fmt,
+                              int stream, struct usb_host_interface *iface)
 {
        int err;
 
-       switch (fmt[3]) {
+       switch (fmt->bFormatType) {
        case UAC_FORMAT_TYPE_I:
        case UAC_FORMAT_TYPE_III:
                err = parse_audio_format_i(chip, fp, format, fmt, iface);
@@ -407,10 +406,11 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
                break;
        default:
                snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]);
-               return -1;
+                          chip->dev->devnum, fp->iface, fp->altsetting,
+                          fmt->bFormatType);
+               return -ENOTSUPP;
        }
-       fp->fmt_type = fmt[3];
+       fp->fmt_type = fmt->bFormatType;
        if (err < 0)
                return err;
 #if 1
@@ -421,10 +421,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
        if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
            chip->usb_id == USB_ID(0x041e, 0x3020) ||
            chip->usb_id == USB_ID(0x041e, 0x3061)) {
-               if (fmt[3] == UAC_FORMAT_TYPE_I &&
+               if (fmt->bFormatType == UAC_FORMAT_TYPE_I &&
                    fp->rates != SNDRV_PCM_RATE_48000 &&
                    fp->rates != SNDRV_PCM_RATE_96000)
-                       return -1;
+                       return -ENOTSUPP;
        }
 #endif
        return 0;
index 8298c4e..387924f 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef __USBAUDIO_FORMAT_H
 #define __USBAUDIO_FORMAT_H
 
-int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                              int format, unsigned char *fmt, int stream,
-                              struct usb_host_interface *iface);
+int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
+                              struct audioformat *fp, int format,
+                              struct uac_format_type_i_continuous_descriptor *fmt,
+                              int stream, struct usb_host_interface *iface);
 
 #endif /*  __USBAUDIO_FORMAT_H */
index 97dd176..03ce971 100644 (file)
@@ -1126,7 +1126,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        } else {
                struct uac2_feature_unit_descriptor *ftr = _ftr;
                csize = 4;
-               channels = (hdr->bLength - 6) / 4;
+               channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
        }
 
index 2bf0d77..056587d 100644 (file)
@@ -120,10 +120,6 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
 
        ep = get_endpoint(alts, 0)->bEndpointAddress;
 
-       /* if endpoint doesn't have pitch control, bail out */
-       if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
-               return 0;
-
        data[0] = 1;
        if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
                                   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
@@ -137,8 +133,32 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
        return 0;
 }
 
+static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
+                        struct usb_host_interface *alts,
+                        struct audioformat *fmt)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned char data[1];
+       unsigned int ep;
+       int err;
+
+       ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+       data[0] = 1;
+       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+                                  UAC2_EP_CS_PITCH << 8, 0,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
+                          dev->devnum, iface, fmt->altsetting);
+               return err;
+       }
+
+       return 0;
+}
+
 /*
- * initialize the picth control and sample rate
+ * initialize the pitch control and sample rate
  */
 int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
                       struct usb_host_interface *alts,
@@ -146,13 +166,16 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
 {
        struct usb_interface_descriptor *altsd = get_iface_desc(alts);
 
+       /* if endpoint doesn't have pitch control, bail out */
+       if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
+               return 0;
+
        switch (altsd->bInterfaceProtocol) {
        case UAC_VERSION_1:
                return init_pitch_v1(chip, iface, alts, fmt);
 
        case UAC_VERSION_2:
-               /* not implemented yet */
-               return 0;
+               return init_pitch_v2(chip, iface, alts, fmt);
        }
 
        return -EINVAL;