]> Git Repo - linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <[email protected]>
Fri, 22 Aug 2014 21:33:18 +0000 (14:33 -0700)
committerLinus Torvalds <[email protected]>
Fri, 22 Aug 2014 21:33:18 +0000 (14:33 -0700)
Pull networking fixes from David Miller:
 "Here are some bug fixes that have piled up during ksummit/linuxcon.

   1) Fix endian problems in ibmveth, from Anton Blanchard.

   2) IPV6 routing code does GFP_KERNEL allocation in atomic, fix from
      Benjamin Block.

   3) SCTP association fixes from Daniel Borkmann.

   4) When multiple VLAN headers are present we have to make sure the
      second and subsequent ones are pullable in the SKB otherwise we
      blindly dereference garbage.  From Jiri Benc.

   5) The argument adjustment of the signature of hlist_add_after*()
      introduced a regression in the batman-adv code, fix from Sven
      Eckelmann.

   6) Fix TX hang handling to avoid a panic in i40e, from Anjali Singhai
      Jain.

   7) PTP flag test is inverted in i40e driver, from Jesse Brandeburg.

   8) ATM LEC driver needs to hold RTNL mutex over MTU changes, from
      Chas Williams.

   9) Truncate packets larger then the TPACKET_V3 format configured
      buffers, otherwise we overwrite past the end of said buffers.
      From Eric Dumazet.

  10) Fix endianness bugs in qlcnic firmware handling, from Rajesh
      Borundia and Shahed Shaikh.

  11) CXGB4 sometimes doesn't get all of the TX completion events it
      should resulting in SKBs getting stuck in the TX queue, from
      Hariprasad Shenai.

  12) When the FEC chip's PTP clock is disabled, you can't access the
      register.  Add necessary checks to avoid the resulting hang, from
      Fugang Duan"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (37 commits)
  drivers: isdn: eicon: xdi_msg.h: Fix typo in #ifndef
  net: sctp: fix suboptimal edge-case on non-active active/retrans path selection
  net: sctp: spare unnecessary comparison in sctp_trans_elect_best
  net: ethernet: broadcom: bnx2x: Remove redundant #ifdef
  ibmveth: Fix endian issues with rx_no_buffer statistic
  net: xgene: fix possible NULL dereference in xgene_enet_free_desc_rings()
  openvswitch: fix panic with multiple vlan headers
  net: ipv6: fib: don't sleep inside atomic lock
  net: fec: ptp: avoid register access when ipg clock is disabled
  cxgb4: Free completed tx skbs promptly
  cxgb4: Fix race condition in cleanup
  sctp: not send SCTP_PEER_ADDR_CHANGE notifications with failed probe
  bnx2x: Revert UNDI flushing mechanism
  qlcnic: Fix endianess issue in firmware load from file operation
  qlcnic: Fix endianess issue in FW dump template header
  qlcnic: Fix flash access interface to application
  MAINTAINERS: Add section for MRF24J40 IEEE 802.15.4 radio driver
  macvlan: Allow setting multicast filter on all macvlan types
  packet: handle too big packets for PACKET_V3
  MAINTAINERS: add entry for ec_bhf driver
  ...

190 files changed:
Documentation/DocBook/drm.tmpl
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/ti-pci.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/laptops/00-INDEX
Documentation/laptops/toshiba_haps.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm64/Makefile
arch/arm64/configs/defconfig
arch/arm64/include/asm/sparsemem.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/head.S
arch/arm64/kernel/ptrace.c
arch/arm64/mm/init.c
arch/frv/include/asm/processor.h
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/entry.S
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/syscall_table.S
arch/powerpc/kvm/book3s_hv_builtin.c
arch/x86/include/asm/kvm_host.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kvm/emulate.c
drivers/ata/ahci_tegra.c
drivers/ata/ahci_xgene.c
drivers/ata/libata-core.c
drivers/ata/pata_samsung_cf.c
drivers/ata/pata_scc.c
drivers/char/hw_random/virtio-rng.c
drivers/edac/Kconfig
drivers/edac/edac_mc_sysfs.c
drivers/edac/sb_edac.c
drivers/gpu/drm/nouveau/core/core/client.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/include/core/client.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nvif/class.h
drivers/gpu/drm/nouveau/nvif/notify.c
drivers/gpu/drm/nouveau/nvif/object.c
drivers/hid/hid-cherry.c
drivers/hid/hid-huion.c
drivers/hid/hid-kye.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-monterey.c
drivers/hid/hid-petalynx.c
drivers/hid/hid-rmi.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sunplus.c
drivers/hid/wacom_sys.c
drivers/i2c/Kconfig
drivers/i2c/Makefile
drivers/i2c/busses/i2c-i801.c
drivers/i2c/i2c-acpi.c
drivers/idle/intel_idle.c
drivers/input/input-mt.c
drivers/input/joystick/analog.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/cap1106.c
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/iommu/amd_iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/iommu.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/selftest.c
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-dra7xx.c [new file with mode: 0644]
drivers/pci/host/pci-tegra.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-designware.h
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/alienware-wmi.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_haps.c [new file with mode: 0644]
drivers/platform/x86/wmi.c
drivers/scsi/libiscsi.c
drivers/scsi/pm8001/pm8001_ctl.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/u14-34f.c
fs/aio.c
fs/btrfs/backref.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/ulist.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c
fs/cifs/smb2maperror.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smbfsctl.h
fs/ext3/super.c
fs/isofs/inode.c
fs/isofs/isofs.h
fs/isofs/rock.c
fs/locks.c
fs/udf/namei.c
include/linux/edac.h
include/linux/i2c.h
include/linux/input/mt.h
include/scsi/iscsi_if.h
include/uapi/asm-generic/unistd.h
kernel/module.c
sound/oss/uart401.c
sound/oss/waveartist.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/arizona.c
sound/soc/codecs/pcm512x.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_esai.c
sound/soc/intel/sst-acpi.c
sound/soc/intel/sst-baytrail-ipc.c
sound/soc/intel/sst-baytrail-ipc.h
sound/soc/intel/sst-baytrail-pcm.c
sound/soc/pxa/pxa-ssp.c
sound/soc/soc-dapm.c
sound/usb/quirks-table.h
tools/power/x86/turbostat/turbostat.c
virt/kvm/assigned-dev.c
virt/kvm/iommu.c

index 1d3756d3176ce58656999f8103a98e6256f9b2a5..bacefc5b222ec0dff365e83c63191859d5803a22 100644 (file)
@@ -315,7 +315,7 @@ char *date;</synopsis>
         <function>drm_dev_unregister()</function> followed by a call to
         <function>drm_dev_unref()</function>.
       </para>
-!Edrivers/gpu/drm/drm_stub.c
+!Edrivers/gpu/drm/drm_drv.c
     </sect2>
     <sect2>
       <title>Driver Load</title>
index 1486497a24c1d41c9d64208b4178a8cb2e2c28d1..ce6a1a0720285bd9be4549d478ea49b4b985ee31 100644 (file)
@@ -4,11 +4,13 @@ Specifying interrupt information for devices
 1) Interrupt client nodes
 -------------------------
 
-Nodes that describe devices which generate interrupts must contain an either an
-"interrupts" property or an "interrupts-extended" property. These properties
-contain a list of interrupt specifiers, one per output interrupt. The format of
-the interrupt specifier is determined by the interrupt controller to which the
-interrupts are routed; see section 2 below for details.
+Nodes that describe devices which generate interrupts must contain an
+"interrupts" property, an "interrupts-extended" property, or both. If both are
+present, the latter should take precedence; the former may be provided simply
+for compatibility with software that does not recognize the latter. These
+properties contain a list of interrupt specifiers, one per output interrupt. The
+format of the interrupt specifier is determined by the interrupt controller to
+which the interrupts are routed; see section 2 below for details.
 
   Example:
        interrupt-parent = <&intc1>;
index d0d15ee42834089abfd2ffad2bad205b28e33d18..ed0d9b9fff2be5f5be5902554d0da70ed81591df 100644 (file)
@@ -2,6 +2,10 @@
 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the core.
+- reg: Should contain the configuration address space.
+- reg-names: Must be "config" for the PCIe configuration space.
+    (The old way of getting the configuration address space from "ranges"
+    is deprecated and should be avoided.)
 - #address-cells: set to <3>
 - #size-cells: set to <2>
 - device_type: set to "pci"
diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt
new file mode 100644 (file)
index 0000000..3d21791
--- /dev/null
@@ -0,0 +1,59 @@
+TI PCI Controllers
+
+PCIe Designware Controller
+ - compatible: Should be "ti,dra7-pcie""
+ - reg : Two register ranges as listed in the reg-names property
+ - reg-names : The first entry must be "ti-conf" for the TI specific registers
+              The second entry must be "rc-dbics" for the designware pcie
+              registers
+              The third entry must be "config" for the PCIe configuration space
+ - phys : list of PHY specifiers (used by generic PHY framework)
+ - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
+              number of PHYs as specified in *phys* property.
+ - ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>",
+              where <X> is the instance number of the pcie from the HW spec.
+ - interrupts : Two interrupt entries must be specified. The first one is for
+               main interrupt line and the second for MSI interrupt line.
+ - #address-cells,
+   #size-cells,
+   #interrupt-cells,
+   device_type,
+   ranges,
+   num-lanes,
+   interrupt-map-mask,
+   interrupt-map : as specified in ../designware-pcie.txt
+
+Example:
+axi {
+       compatible = "simple-bus";
+       #size-cells = <1>;
+       #address-cells = <1>;
+       ranges = <0x51000000 0x51000000 0x3000
+                 0x0        0x20000000 0x10000000>;
+       pcie@51000000 {
+               compatible = "ti,dra7-pcie";
+               reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>;
+               reg-names = "rc_dbics", "ti_conf", "config";
+               interrupts = <0 232 0x4>, <0 233 0x4>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               ranges = <0x81000000 0 0          0x03000 0 0x00010000
+                         0x82000000 0 0x20013000 0x13000 0 0xffed000>;
+               #interrupt-cells = <1>;
+               num-lanes = <1>;
+               ti,hwmods = "pcie1";
+               phys = <&pcie1_phy>;
+               phy-names = "pcie-phy0";
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc 1>,
+                               <0 0 0 2 &pcie_intc 2>,
+                               <0 0 0 3 &pcie_intc 3>,
+                               <0 0 0 4 &pcie_intc 4>;
+               pcie_intc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
+};
index b18dd17790299de1b01053117a065af1ed7f251f..f1997e9da61f1cb2fbb122b610c648c537520185 100644 (file)
@@ -349,7 +349,11 @@ prototypes:
 locking rules:
                        inode->i_lock   may block
 fl_copy_lock:          yes             no
-fl_release_private:    maybe           no
+fl_release_private:    maybe           maybe[1]
+
+[1]:   ->fl_release_private for flock or POSIX locks is currently allowed
+to block. Leases however can still be freed while the i_lock is held and
+so fl_release_private called on a lease should not block.
 
 ----------------------- lock_manager_operations ---------------------------
 prototypes:
index d399ae1fc724aaaf4bd52a20f4a08387970eddc7..a3b4f209e562ff7ba2ce2da2a5cc1dae09f6fa3d 100644 (file)
@@ -18,3 +18,5 @@ sonypi.txt
        - info on Linux Sony Programmable I/O Device support.
 thinkpad-acpi.txt
        - information on the (IBM and Lenovo) ThinkPad ACPI Extras driver.
+toshiba_haps.txt
+       - information on the Toshiba HDD Active Protection Sensor driver.
diff --git a/Documentation/laptops/toshiba_haps.txt b/Documentation/laptops/toshiba_haps.txt
new file mode 100644 (file)
index 0000000..11dbcfd
--- /dev/null
@@ -0,0 +1,76 @@
+Kernel driver toshiba_haps
+Toshiba HDD Active Protection Sensor
+====================================
+
+Author: Azael Avalos <[email protected]>
+
+
+0. Contents
+-----------
+
+1. Description
+2. Interface
+3. Accelerometer axes
+4. Supported devices
+5. Usage
+
+
+1. Description
+--------------
+
+This driver provides support for the accelerometer found in various Toshiba
+laptops, being called "Toshiba HDD Protection - Shock Sensor" officialy,
+and detects laptops automatically with this device.
+On Windows, Toshiba provided software monitors this device and provides
+automatic HDD protection (head unload) on sudden moves or harsh vibrations,
+however, this driver only provides a notification via a sysfs file to let
+userspace tools or daemons act accordingly, as well as providing a sysfs
+file to set the desired protection level or sensor sensibility.
+
+
+2. Interface
+------------
+
+This device comes with 3 methods:
+_STA -  Checks existence of the device, returning Zero if the device does not
+       exists or is not supported.
+PTLV -  Sets the desired protection level.
+RSSS -  Shuts down the HDD protection interface for a few seconds,
+       then restores normal operation.
+
+Note:
+The presence of Solid State Drives (SSD) can make this driver to fail loading,
+given the fact that such drives have no movable parts, and thus, not requiring
+any "protection" as well as failing during the evaluation of the _STA method
+found under this device.
+
+
+3. Accelerometer axes
+---------------------
+
+This device does not report any axes, however, to query the sensor position
+a couple HCI (Hardware Configuration Interface) calls (0x6D and 0xA6) are
+provided to query such information, handled by the kernel module toshiba_acpi
+since kernel version 3.15.
+
+
+4. Supported devices
+--------------------
+
+This driver binds itself to the ACPI device TOS620A, and any Toshiba laptop
+with this device is supported, given the fact that they have the presence of
+conventional HDD and not only SSD, or a combination of both HDD and SSD.
+
+
+5. Usage
+--------
+
+The sysfs files under /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS620A:00/ are:
+protection_level - The protection_level is readable and writeable, and
+                  provides a way to let userspace query the current protection
+                  level, as well as set the desired protection level, the
+                  available protection levels are:
+                  0 - Disabled | 1 - Low | 2 - Medium | 3 - High
+reset_protection - The reset_protection entry is writeable only, being "1"
+                  the only parameter it accepts, it is used to trigger
+                  a reset of the protection interface.
index 92b5234aad7592f81c22687dbdad97e8eed77a73..f01f54f277504ac373fdfd5d9a788509c1ae0ae1 100644 (file)
@@ -3849,10 +3849,13 @@ F:      drivers/tty/serial/ucc_uart.c
 
 FREESCALE SOC SOUND DRIVERS
 M:     Timur Tabi <[email protected]>
+M:     Nicolin Chen <[email protected]>
+M:     Xiubo Li <[email protected]>
 L:     [email protected] (moderated for non-subscribers)
 L:     [email protected]
 S:     Maintained
 F:     sound/soc/fsl/fsl*
+F:     sound/soc/fsl/imx*
 F:     sound/soc/fsl/mpc8610_hpcd.c
 
 FREEVXFS FILESYSTEM
@@ -4452,6 +4455,13 @@ F:       include/linux/i2c-*.h
 F:     include/uapi/linux/i2c.h
 F:     include/uapi/linux/i2c-*.h
 
+I2C ACPI SUPPORT
+M:     Mika Westerberg <[email protected]>
+L:     [email protected]
+L:     [email protected]
+S:     Maintained
+F:     drivers/i2c/i2c-acpi.c
+
 I2C-TAOS-EVM DRIVER
 M:     Jean Delvare <[email protected]>
 L:     [email protected]
@@ -6870,6 +6880,14 @@ S:       Supported
 F:     Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
 F:     drivers/pci/host/pci-tegra.c
 
+PCI DRIVER FOR TI DRA7XX
+M:     Kishon Vijay Abraham I <[email protected]>
+L:     [email protected]
+L:     [email protected]
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/ti-pci.txt
+F:     drivers/pci/host/pci-dra7xx.c
+
 PCI DRIVER FOR RENESAS R-CAR
 M:     Simon Horman <[email protected]>
 L:     [email protected]
@@ -7071,6 +7089,7 @@ F:        drivers/scsi/pmcraid.*
 PMC SIERRA PM8001 DRIVER
 M:     [email protected]
 M:     [email protected]
+L:     [email protected]
 L:     [email protected]
 S:     Supported
 F:     drivers/scsi/pm8001/
@@ -10028,7 +10047,7 @@ F:      arch/x86/
 X86 PLATFORM DRIVERS
 M:     Matthew Garrett <[email protected]>
 L:     [email protected]
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
+T:     git git://cavan.codon.org.uk/platform-drivers-x86.git
 S:     Maintained
 F:     drivers/platform/x86/
 
index 6aace6750567ba113388cdf43312d3a46d011c1b..e43244263306e0b9321b003a2aede021dcb7cc88 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
-PATCHLEVEL = 16
+PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
index 57833546bf003b5f8ffe5e70fb65c10c8dd1ef55..2df5e5daeebeaca04dc9c9948556b75eb21ffe78 100644 (file)
@@ -39,7 +39,7 @@ head-y                := arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
 ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
-TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
 else
 TEXT_OFFSET := 0x00080000
 endif
index 1e52b741d80644f0f293d247d412781dc18895e9..d92ef3c541617ec5bbe5a45f8da91bd9e27d1461 100644 (file)
@@ -64,6 +64,8 @@ CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=y
+CONFIG_AHCI_XGENE=y
+CONFIG_PHY_XGENE=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_PATA_OF_PLATFORM=y
 CONFIG_NETDEVICES=y
@@ -71,6 +73,7 @@ CONFIG_TUN=y
 CONFIG_VIRTIO_NET=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
+CONFIG_NET_XGENE=y
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_SERIO_SERPORT is not set
index 1be62bcb9d474e42e6b457eaecc4272bfc37d2b1..74a9d301819fbfa1128bcce879b95ae9c24a2e76 100644 (file)
@@ -17,7 +17,7 @@
 #define __ASM_SPARSEMEM_H
 
 #ifdef CONFIG_SPARSEMEM
-#define MAX_PHYSMEM_BITS       40
+#define MAX_PHYSMEM_BITS       48
 #define SECTION_SIZE_BITS      30
 #endif
 
index 4bc95d27e0636f785383ce222fdcc7adc3073d6a..6d2bf419431d86aece4a3aa0650091f120d3efcd 100644 (file)
@@ -41,7 +41,7 @@
 #define __ARM_NR_compat_cacheflush     (__ARM_NR_COMPAT_BASE+2)
 #define __ARM_NR_compat_set_tls                (__ARM_NR_COMPAT_BASE+5)
 
-#define __NR_compat_syscalls           383
+#define __NR_compat_syscalls           386
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
index e242600c4046c87e1cd554bdb55d02a16fc5f0f4..da1f06b535e38a97bbd981ade5c414d1131ef4e8 100644 (file)
@@ -787,3 +787,8 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
 __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 #define __NR_renameat2 382
 __SYSCALL(__NR_renameat2, sys_renameat2)
+                       /* 383 for seccomp */
+#define __NR_getrandom 384
+__SYSCALL(__NR_getrandom, sys_getrandom)
+#define __NR_memfd_create 385
+__SYSCALL(__NR_memfd_create, sys_memfd_create)
index f798f66634afaa1853f6845c75ab6fa9ac09958e..1771696230269673a64606714011b923995353e0 100644 (file)
@@ -49,7 +49,7 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
 
        if (l1ip != ICACHE_POLICY_PIPT)
                set_bit(ICACHEF_ALIASING, &__icache_flags);
-       if (l1ip == ICACHE_POLICY_AIVIVT);
+       if (l1ip == ICACHE_POLICY_AIVIVT)
                set_bit(ICACHEF_AIVIVT, &__icache_flags);
 
        pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
index e72f3100958f204ce5b72ba2ce788e2e6cdc3d95..24f0c6fb61d8cc63eab63de9d62b47cc31f37080 100644 (file)
@@ -188,6 +188,8 @@ static __init void reserve_regions(void)
                if (uefi_debug)
                        pr_cont("\n");
        }
+
+       set_bit(EFI_MEMMAP, &efi.flags);
 }
 
 
index 144f10567f82eaa3a6c9a428e3461e08ed911253..bed028364a93235006b467c20daeb8725b9a4615 100644 (file)
 
 #define KERNEL_RAM_VADDR       (PAGE_OFFSET + TEXT_OFFSET)
 
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4KB aligned
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif
 
index 0310811bd77d891fe248d0ddb6042af46d3f63ab..70526cfda056e7216ef7f773b059d31b6ca4f88a 100644 (file)
@@ -1115,19 +1115,15 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, regs->syscallno);
 
-#ifdef CONFIG_AUDITSYSCALL
        audit_syscall_entry(syscall_get_arch(), regs->syscallno,
                regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
-#endif
 
        return regs->syscallno;
 }
 
 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
 {
-#ifdef CONFIG_AUDITSYSCALL
        audit_syscall_exit(regs);
-#endif
 
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_exit(regs, regs_return_value(regs));
index 5b4526ee3a01a6b9c65f15a4985b70cccaf3edea..5472c24018766ea5348d2d0cb56f9a932f46356a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/of_fdt.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
+#include <linux/efi.h>
 
 #include <asm/fixmap.h>
 #include <asm/sections.h>
@@ -148,7 +149,8 @@ void __init arm64_memblock_init(void)
                memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
 #endif
 
-       early_init_fdt_scan_reserved_mem();
+       if (!efi_enabled(EFI_MEMMAP))
+               early_init_fdt_scan_reserved_mem();
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA))
index a34f309e580199b5f573db3f975a199cd74d5372..6554e78893f26bc88e96e103811e1f0881a3a5ca 100644 (file)
@@ -129,7 +129,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define        KSTK_EIP(tsk)   ((tsk)->thread.frame0->pc)
 #define        KSTK_ESP(tsk)   ((tsk)->thread.frame0->sp)
 
-#define cpu_relax()    barrier()
+#define cpu_relax() barrier()
+#define cpu_relax_lowlatency() cpu_relax()
 
 /* data cache prefetch */
 #define ARCH_HAS_PREFETCH
index 4254f5d3218c7ed4dc72c9ec2e966b331f3af3c0..10a14ead70b9d9fd627b416c8567008d1aebc606 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    316 /* length of syscall table */
+#define NR_syscalls                    317 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 99801c3be914afda7f30ccd7fe89306186ad1602..6a65bb7d06571050157bda55a30f9fe366387cbf 100644 (file)
 #define __NR_sched_getattr             1337
 #define __NR_renameat2                 1338
 #define __NR_getrandom                 1339
+#define __NR_memfd_create              1339
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index 4c13837a9269faecf350be25c9bfd10053d86936..01edf242eb296443293fc8b1ee178d72d0a89f55 100644 (file)
@@ -1777,6 +1777,7 @@ sys_call_table:
        data8 sys_sched_getattr
        data8 sys_renameat2
        data8 sys_getrandom
+       data8 sys_memfd_create                  // 1340
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 4e1ddc930a685ef0d6c137d0dc9d165f111acbba..1c2380bf8fe60850274dce0bdbc9e9bb16cc531f 100644 (file)
 #define __NR_sched_setattr     381
 #define __NR_sched_getattr     382
 #define __NR_renameat2         383
+#define __NR_seccomp           384
+#define __NR_getrandom         385
+#define __NR_memfd_create      386
 
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index 1a23d5d5480c7da12bae37f8a77e0015459c4704..de59ee1d7010a788cf916b4ade098375af6214d6 100644 (file)
@@ -384,3 +384,6 @@ ENTRY(sys_call_table)
        .long sys_sched_setattr
        .long sys_sched_getattr
        .long sys_renameat2
+       .long sys_seccomp
+       .long sys_getrandom             /* 385 */
+       .long sys_memfd_create
index 329d7fdd0a6ab7be8b9e203ac53b1870c1d37b0c..b9615ba5b083a6ddeea76b878925396561b5fb42 100644 (file)
@@ -101,7 +101,7 @@ struct kvm_rma_info *kvm_alloc_rma()
        ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL);
        if (!ri)
                return NULL;
-       page = cma_alloc(kvm_cma, kvm_rma_pages, get_order(kvm_rma_pages));
+       page = cma_alloc(kvm_cma, kvm_rma_pages, order_base_2(kvm_rma_pages));
        if (!page)
                goto err_out;
        atomic_set(&ri->use_count, 1);
@@ -135,12 +135,12 @@ struct page *kvm_alloc_hpt(unsigned long nr_pages)
 {
        unsigned long align_pages = HPT_ALIGN_PAGES;
 
-       VM_BUG_ON(get_order(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+       VM_BUG_ON(order_base_2(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
 
        /* Old CPUs require HPT aligned on a multiple of its size */
        if (!cpu_has_feature(CPU_FTR_ARCH_206))
                align_pages = nr_pages;
-       return cma_alloc(kvm_cma, nr_pages, get_order(align_pages));
+       return cma_alloc(kvm_cma, nr_pages, order_base_2(align_pages));
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
 
index 572460175ba509d9317e408e96975cf10780eef7..7c492ed9087b24510a150dad80ededaaa9873b85 100644 (file)
@@ -95,7 +95,7 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 80
 #define KVM_NR_FIXED_MTRR_REGION 88
-#define KVM_NR_VAR_MTRR 10
+#define KVM_NR_VAR_MTRR 8
 
 #define ASYNC_PF_PER_VCPU 64
 
index eac9e92fe181e5c5b95ae164ddaeae119024997a..e21331ce368fc60a4ae7fd727448a4ca30d7bdf2 100644 (file)
 
 #define MSR_CORE_C1_RES                        0x00000660
 
+#define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668
+#define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669
+
 #define MSR_AMD64_MC0_MASK             0xc0010044
 
 #define MSR_IA32_MCx_CTL(x)            (MSR_IA32_MC0_CTL + 4*(x))
index 56657b0bb3bb14f14b76fdcd99a746598ce5e8b4..03954f7900f522a496d8249174ec63cc760aa140 100644 (file)
@@ -1491,9 +1491,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                        goto exception;
                break;
        case VCPU_SREG_CS:
-               if (in_task_switch && rpl != dpl)
-                       goto exception;
-
                if (!(seg_desc.type & 8))
                        goto exception;
 
@@ -4394,8 +4391,11 @@ done_prefixes:
 
        ctxt->execute = opcode.u.execute;
 
+       if (unlikely(ctxt->ud) && likely(!(ctxt->d & EmulateOnUD)))
+               return EMULATION_FAILED;
+
        if (unlikely(ctxt->d &
-                    (NotImpl|EmulateOnUD|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
+                    (NotImpl|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
                /*
                 * These are copied unconditionally here, and checked unconditionally
                 * in x86_emulate_insn.
@@ -4406,9 +4406,6 @@ done_prefixes:
                if (ctxt->d & NotImpl)
                        return EMULATION_FAILED;
 
-               if (!(ctxt->d & EmulateOnUD) && ctxt->ud)
-                       return EMULATION_FAILED;
-
                if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
                        ctxt->op_bytes = 8;
 
index fc3df47fca3547b46d71073e3e5b429c0b3d29e4..f1fef74e503cd94716dfe090ab397d83118065f5 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include <linux/tegra-powergate.h>
 #include <linux/regulator/consumer.h>
+#include <soc/tegra/pmc.h>
 #include "ahci.h"
 
 #define SATA_CONFIGURATION_0                           0x180
index bc281115490ba5064e5495e0a48883b1d14f744f..c6962300b93c7c6292ed91d62611db6678af1f49 100644 (file)
@@ -344,7 +344,7 @@ static struct ata_port_operations xgene_ahci_ops = {
 };
 
 static const struct ata_port_info xgene_ahci_port_info = {
-       .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .flags = AHCI_FLAG_COMMON,
        .pio_mask = ATA_PIO4,
        .udma_mask = ATA_UDMA6,
        .port_ops = &xgene_ahci_ops,
@@ -480,7 +480,7 @@ static int xgene_ahci_probe(struct platform_device *pdev)
        /* Configure the host controller */
        xgene_ahci_hw_init(hpriv);
 
-       hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ;
+       hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
 
        rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info);
        if (rc)
index dbdc5d32343f53f7ed96a94cf2d6d69258a54237..f3e7b9f894cd131daea921fbd0e149fcaccadaeb 100644 (file)
@@ -4228,7 +4228,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
        { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
        { "Micron_M550*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M550SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT*M550SSD*",        NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
index 2578fc16960ad1d1671ab554cbbc40d6f5810e60..1a24a5dc39400705e709853908070ff9a4e3f45b 100644 (file)
@@ -360,7 +360,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link,
 /*
  * pata_s3c_bus_softreset - PATA device software reset
  */
-static unsigned int pata_s3c_bus_softreset(struct ata_port *ap,
+static int pata_s3c_bus_softreset(struct ata_port *ap,
                unsigned long deadline)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
index 4e006d74bef8c0599e11ddda98c8f37a90c839bb..7f4cb76ed9fac1c6ff51a5f91ad4df0468ac5096 100644 (file)
@@ -585,7 +585,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
  *     Note: Original code is ata_bus_softreset().
  */
 
-static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
+static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
                                       unsigned long deadline)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -599,9 +599,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
        udelay(20);
        out_be32(ioaddr->ctl_addr, ap->ctl);
 
-       scc_wait_after_reset(&ap->link, devmask, deadline);
-
-       return 0;
+       return scc_wait_after_reset(&ap->link, devmask, deadline);
 }
 
 /**
@@ -618,7 +616,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
 {
        struct ata_port *ap = link->ap;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
-       unsigned int devmask = 0, err_mask;
+       unsigned int devmask = 0;
+       int rc;
        u8 err;
 
        DPRINTK("ENTER\n");
@@ -634,9 +633,9 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
 
        /* issue bus reset */
        DPRINTK("about to softreset, devmask=%x\n", devmask);
-       err_mask = scc_bus_softreset(ap, devmask, deadline);
-       if (err_mask) {
-               ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask);
+       rc = scc_bus_softreset(ap, devmask, deadline);
+       if (rc) {
+               ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc);
                return -EIO;
        }
 
index 0027137daa561500ea8089423b3c22eb34f1bb84..2e3139eda93b687568aeda1698c5022eb9144c64 100644 (file)
@@ -116,6 +116,7 @@ static int probe_common(struct virtio_device *vdev)
                .cleanup = virtio_cleanup,
                .priv = (unsigned long)vi,
                .name = vi->name,
+               .quality = 1000,
        };
        vdev->priv = vi;
 
index f8665f9c3e0332f1a0d3eda12bd9d5edf97e9c65..fd89ca982748ed9cac8ff11e0b0c4bce59110c2c 100644 (file)
@@ -253,12 +253,12 @@ config EDAC_I7300
          Clarksboro MCH (Intel 7300 chipset).
 
 config EDAC_SBRIDGE
-       tristate "Intel Sandy-Bridge Integrated MC"
+       tristate "Intel Sandy-Bridge/Ivy-Bridge/Haswell Integrated MC"
        depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
        depends on PCI_MMCONFIG
        help
          Support for error detection and correction the Intel
-         Sandy Bridge Integrated Memory Controller.
+         Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers.
 
 config EDAC_MPC85XX
        tristate "Freescale MPC83xx / MPC85xx"
index 01fae8289cf05fe5f9f95bd3da13628f471aa260..a6cd36100663278dccae072e724bcc0c71c51794 100644 (file)
@@ -108,7 +108,9 @@ static const char * const mem_types[] = {
        [MEM_RDDR2] = "Registered-DDR2",
        [MEM_XDR] = "XDR",
        [MEM_DDR3] = "Unbuffered-DDR3",
-       [MEM_RDDR3] = "Registered-DDR3"
+       [MEM_RDDR3] = "Registered-DDR3",
+       [MEM_DDR4] = "Unbuffered-DDR4",
+       [MEM_RDDR4] = "Registered-DDR4"
 };
 
 static const char * const dev_types[] = {
index deea0dc9999bf1bb54d58fd2d43d4c98036d690e..0034c48444280e7c40d21fd0f94d8faf4a9b7df2 100644 (file)
@@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = {
 #define DRAM_ATTR(reg)         GET_BITFIELD(reg, 2,  3)
 #define INTERLEAVE_MODE(reg)   GET_BITFIELD(reg, 1,  1)
 #define DRAM_RULE_ENABLE(reg)  GET_BITFIELD(reg, 0,  0)
+#define A7MODE(reg)            GET_BITFIELD(reg, 26, 26)
 
 static char *get_dram_attr(u32 reg)
 {
@@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 
 #define TOLM           0x80
 #define        TOHM            0x84
+#define HASWELL_TOHM_0 0xd4
+#define HASWELL_TOHM_1 0xd8
 
 #define GET_TOLM(reg)          ((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)
 #define GET_TOHM(reg)          ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
@@ -176,8 +179,6 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 
 #define SAD_CONTROL    0xf4
 
-#define NODE_ID(reg)           GET_BITFIELD(reg, 0, 2)
-
 /* Device 14 function 0 */
 
 static const u32 tad_dram_rule[] = {
@@ -235,7 +236,6 @@ static const u32 rir_way_limit[] = {
 
 #define IS_RIR_VALID(reg)      GET_BITFIELD(reg, 31, 31)
 #define RIR_WAY(reg)           GET_BITFIELD(reg, 28, 29)
-#define RIR_LIMIT(reg)         ((GET_BITFIELD(reg,  1, 10) << 29)| 0x1fffffff)
 
 #define MAX_RIR_WAY    8
 
@@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = {
 
 #define IB_RANK_CFG_A          0x0320
 
-#define IS_RDIMM_ENABLED(reg)          GET_BITFIELD(reg, 11, 11)
-
 /*
  * sbridge structs
  */
@@ -291,6 +289,7 @@ static const u32 correrrthrsld[] = {
 enum type {
        SANDY_BRIDGE,
        IVY_BRIDGE,
+       HASWELL,
 };
 
 struct sbridge_pvt;
@@ -300,11 +299,15 @@ struct sbridge_info {
        u32             rankcfgr;
        u64             (*get_tolm)(struct sbridge_pvt *pvt);
        u64             (*get_tohm)(struct sbridge_pvt *pvt);
+       u64             (*rir_limit)(u32 reg);
        const u32       *dram_rule;
        const u32       *interleave_list;
        const struct interleave_pkg *interleave_pkg;
        u8              max_sad;
        u8              max_interleave;
+       u8              (*get_node_id)(struct sbridge_pvt *pvt);
+       enum mem_type   (*get_memory_type)(struct sbridge_pvt *pvt);
+       struct pci_dev  *pci_vtd;
 };
 
 struct sbridge_channel {
@@ -313,9 +316,7 @@ struct sbridge_channel {
 };
 
 struct pci_id_descr {
-       int                     dev;
-       int                     func;
-       int                     dev_id;
+       int                     dev_id;
        int                     optional;
 };
 
@@ -338,6 +339,7 @@ struct sbridge_pvt {
        struct pci_dev          *pci_sad0, *pci_sad1;
        struct pci_dev          *pci_ha0, *pci_ha1;
        struct pci_dev          *pci_br0, *pci_br1;
+       struct pci_dev          *pci_ha1_ta;
        struct pci_dev          *pci_tad[NUM_CHANNELS];
 
        struct sbridge_dev      *sbridge_dev;
@@ -362,31 +364,29 @@ struct sbridge_pvt {
        u64                     tolm, tohm;
 };
 
-#define PCI_DESCR(device, function, device_id, opt)    \
-       .dev = (device),                                \
-       .func = (function),                             \
-       .dev_id = (device_id),                          \
+#define PCI_DESCR(device_id, opt)      \
+       .dev_id = (device_id),          \
        .optional = opt
 
 static const struct pci_id_descr pci_dev_descr_sbridge[] = {
                /* Processor Home Agent */
-       { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)     },
 
                /* Memory controller */
-       { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)       },
-       { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)      },
-       { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)     },
-       { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)     },
-       { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)     },
-       { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)     },
-       { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)   },
 
                /* System Address Decoder */
-       { PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)         },
-       { PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)         },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)        },
 
                /* Broadcast Registers */
-       { PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)           },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)          },
 };
 
 #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
@@ -423,34 +423,34 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
 
 static const struct pci_id_descr pci_dev_descr_ibridge[] = {
                /* Processor Home Agent */
-       { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)             },
 
                /* Memory controller */
-       { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)   },
-       { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)  },
-       { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) },
-       { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) },
-       { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) },
-       { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)         },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)        },
 
                /* System Address Decoder */
-       { PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)                 },
 
                /* Broadcast Registers */
-       { PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)          },
-       { PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)                 },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)                 },
 
                /* Optional, mode 2HA */
-       { PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)             },
 #if 0
-       { PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)   },
-       { PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)  },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)  },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) },
 #endif
-       { PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) },
-       { PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)        },
 
-       { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
-       { PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1)      },
 };
 
 static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
@@ -458,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
        {0,}                    /* 0 terminated list. */
 };
 
+/* Haswell support */
+/* EN processor:
+ *     - 1 IMC
+ *     - 3 DDR3 channels, 2 DPC per channel
+ * EP processor:
+ *     - 1 or 2 IMC
+ *     - 4 DDR4 channels, 3 DPC per channel
+ * EP 4S processor:
+ *     - 2 IMC
+ *     - 4 DDR4 channels, 3 DPC per channel
+ * EX processor:
+ *     - 2 IMC
+ *     - each IMC interfaces with a SMI 2 channel
+ *     - each SMI channel interfaces with a scalable memory buffer
+ *     - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
+ */
+#define HASWELL_DDRCRCLKCONTROLS 0xa10
+#define HASWELL_HASYSDEFEATURE2 0x84
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0    0x2fa0
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1    0x2f60
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA 0x2fa8
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL 0x2f71
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA 0x2f68
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL 0x2f79
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
+static const struct pci_id_descr pci_dev_descr_haswell[] = {
+       /* first item must be the HA */
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0)             },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0)        },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, 1)             },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL, 0)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1)        },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1)          },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1)        },
+};
+
+static const struct pci_id_table pci_dev_descr_haswell_table[] = {
+       PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell),
+       {0,}                    /* 0 terminated list. */
+};
+
 /*
  *     pci_device_id   table for which devices we are looking for
  */
 static const struct pci_device_id sbridge_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
        {0,}                    /* 0 terminated list. */
 };
 
@@ -472,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
                        Ancillary status routines
  ****************************************************************************/
 
-static inline int numrank(u32 mtr)
+static inline int numrank(enum type type, u32 mtr)
 {
        int ranks = (1 << RANK_CNT_BITS(mtr));
+       int max = 4;
 
-       if (ranks > 4) {
-               edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n",
-                        ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
+       if (type == HASWELL)
+               max = 8;
+
+       if (ranks > max) {
+               edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n",
+                        ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr);
                return -EINVAL;
        }
 
@@ -588,10 +660,107 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
        return GET_TOHM(reg);
 }
 
+static u64 rir_limit(u32 reg)
+{
+       return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff;
+}
+
+static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       enum mem_type mtype;
+
+       if (pvt->pci_ddrio) {
+               pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
+                                     &reg);
+               if (GET_BITFIELD(reg, 11, 11))
+                       /* FIXME: Can also be LRDIMM */
+                       mtype = MEM_RDDR3;
+               else
+                       mtype = MEM_DDR3;
+       } else
+               mtype = MEM_UNKNOWN;
+
+       return mtype;
+}
+
+static enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       bool registered = false;
+       enum mem_type mtype = MEM_UNKNOWN;
+
+       if (!pvt->pci_ddrio)
+               goto out;
+
+       pci_read_config_dword(pvt->pci_ddrio,
+                             HASWELL_DDRCRCLKCONTROLS, &reg);
+       /* Is_Rdimm */
+       if (GET_BITFIELD(reg, 16, 16))
+               registered = true;
+
+       pci_read_config_dword(pvt->pci_ta, MCMTR, &reg);
+       if (GET_BITFIELD(reg, 14, 14)) {
+               if (registered)
+                       mtype = MEM_RDDR4;
+               else
+                       mtype = MEM_DDR4;
+       } else {
+               if (registered)
+                       mtype = MEM_RDDR3;
+               else
+                       mtype = MEM_DDR3;
+       }
+
+out:
+       return mtype;
+}
+
+static u8 get_node_id(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
+       return GET_BITFIELD(reg, 0, 2);
+}
+
+static u8 haswell_get_node_id(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
+       return GET_BITFIELD(reg, 0, 3);
+}
+
+static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->info.pci_vtd, TOLM, &reg);
+       return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff;
+}
+
+static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
+{
+       u64 rc;
+       u32 reg;
+
+       pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, &reg);
+       rc = GET_BITFIELD(reg, 26, 31);
+       pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, &reg);
+       rc = ((reg << 6) | rc) << 26;
+
+       return rc | 0x1ffffff;
+}
+
+static u64 haswell_rir_limit(u32 reg)
+{
+       return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1;
+}
+
 static inline u8 sad_pkg_socket(u8 pkg)
 {
        /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
-       return (pkg >> 3) | (pkg & 0x3);
+       return ((pkg >> 3) << 2) | (pkg & 0x3);
 }
 
 static inline u8 sad_pkg_ha(u8 pkg)
@@ -602,44 +771,43 @@ static inline u8 sad_pkg_ha(u8 pkg)
 /****************************************************************************
                        Memory check routines
  ****************************************************************************/
-static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
-                                         unsigned func)
+static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id)
 {
-       struct sbridge_dev *sbridge_dev = get_sbridge_dev(bus);
-       int i;
-
-       if (!sbridge_dev)
-               return NULL;
-
-       for (i = 0; i < sbridge_dev->n_devs; i++) {
-               if (!sbridge_dev->pdev[i])
-                       continue;
+       struct pci_dev *pdev = NULL;
 
-               if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot &&
-                   PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) {
-                       edac_dbg(1, "Associated %02x.%02x.%d with %p\n",
-                                bus, slot, func, sbridge_dev->pdev[i]);
-                       return sbridge_dev->pdev[i];
-               }
-       }
+       do {
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, pdev);
+               if (pdev && pdev->bus->number == bus)
+                       break;
+       } while (pdev);
 
-       return NULL;
+       return pdev;
 }
 
 /**
  * check_if_ecc_is_active() - Checks if ECC is active
- * bus:                Device bus
+ * @bus:       Device bus
+ * @type:      Memory controller type
+ * returns: 0 in case ECC is active, -ENODEV if it can't be determined or
+ *         disabled
  */
-static int check_if_ecc_is_active(const u8 bus)
+static int check_if_ecc_is_active(const u8 bus, enum type type)
 {
        struct pci_dev *pdev = NULL;
-       u32 mcmtr;
+       u32 mcmtr, id;
+
+       if (type == IVY_BRIDGE)
+               id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
+       else if (type == HASWELL)
+               id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
+       else
+               id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
 
-       pdev = get_pdev_slot_func(bus, 15, 0);
+       pdev = get_pdev_same_bus(bus, id);
        if (!pdev) {
                sbridge_printk(KERN_ERR, "Couldn't find PCI device "
-                                       "%2x.%02d.%d!!!\n",
-                                       bus, 15, 0);
+                                       "%04x:%04x! on bus %02d\n",
+                                       PCI_VENDOR_ID_INTEL, id, bus);
                return -ENODEV;
        }
 
@@ -661,11 +829,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        enum edac_type mode;
        enum mem_type mtype;
 
-       pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
+       if (pvt->info.type == HASWELL)
+               pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
+       else
+               pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
+
        pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
-       pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
-       pvt->sbridge_dev->node_id = NODE_ID(reg);
+       pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
        edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
                 pvt->sbridge_dev->mc,
                 pvt->sbridge_dev->node_id,
@@ -698,24 +869,18 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                pvt->is_close_pg = false;
        }
 
-       if (pvt->pci_ddrio) {
-               pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
-                                     &reg);
-               if (IS_RDIMM_ENABLED(reg)) {
-                       /* FIXME: Can also be LRDIMM */
-                       edac_dbg(0, "Memory is registered\n");
-                       mtype = MEM_RDDR3;
-               } else {
-                       edac_dbg(0, "Memory is unregistered\n");
-                       mtype = MEM_DDR3;
-               }
-       } else {
+       mtype = pvt->info.get_memory_type(pvt);
+       if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4)
+               edac_dbg(0, "Memory is registered\n");
+       else if (mtype == MEM_UNKNOWN)
                edac_dbg(0, "Cannot determine memory type\n");
-               mtype = MEM_UNKNOWN;
-       }
+       else
+               edac_dbg(0, "Memory is unregistered\n");
 
-       /* On all supported DDR3 DIMM types, there are 8 banks available */
-       banks = 8;
+       if (mtype == MEM_DDR4 || MEM_RDDR4)
+               banks = 16;
+       else
+               banks = 8;
 
        for (i = 0; i < NUM_CHANNELS; i++) {
                u32 mtr;
@@ -729,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                        if (IS_DIMM_PRESENT(mtr)) {
                                pvt->channel[i].dimms++;
 
-                               ranks = numrank(mtr);
+                               ranks = numrank(pvt->info.type, mtr);
                                rows = numrow(mtr);
                                cols = numcol(mtr);
 
-                               /* DDR3 has 8 I/O banks */
                                size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
                                npages = MiB_TO_PAGES(size);
 
@@ -744,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
                                dimm->nr_pages = npages;
                                dimm->grain = 32;
-                               dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4;
+                               switch (banks) {
+                               case 16:
+                                       dimm->dtype = DEV_X16;
+                                       break;
+                               case 8:
+                                       dimm->dtype = DEV_X8;
+                                       break;
+                               case 4:
+                                       dimm->dtype = DEV_X4;
+                                       break;
+                               }
                                dimm->mtype = mtype;
                                dimm->edac_mode = mode;
                                snprintf(dimm->label, sizeof(dimm->label),
@@ -887,7 +1061,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        if (!IS_RIR_VALID(reg))
                                continue;
 
-                       tmp_mb = RIR_LIMIT(reg) >> 20;
+                       tmp_mb = pvt->info.rir_limit(reg) >> 20;
                        rir_way = 1 << RIR_WAY(reg);
                        mb = div_u64_rem(tmp_mb, 1000, &kb);
                        edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
@@ -936,11 +1110,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        struct mem_ctl_info     *new_mci;
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev          *pci_ha;
-       int                     n_rir, n_sads, n_tads, sad_way, sck_xch;
+       int                     n_rir, n_sads, n_tads, sad_way, sck_xch;
        int                     sad_interl, idx, base_ch;
-       int                     interleave_mode;
+       int                     interleave_mode, shiftup = 0;
        unsigned                sad_interleave[pvt->info.max_interleave];
-       u32                     reg;
+       u32                     reg, dram_rule;
        u8                      ch_way, sck_way, pkg, sad_ha = 0;
        u32                     tad_offset;
        u32                     rir_way;
@@ -987,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                sprintf(msg, "Can't discover the memory socket");
                return -EINVAL;
        }
-       *area_type = get_dram_attr(reg);
-       interleave_mode = INTERLEAVE_MODE(reg);
+       dram_rule = reg;
+       *area_type = get_dram_attr(dram_rule);
+       interleave_mode = INTERLEAVE_MODE(dram_rule);
 
        pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
                              &reg);
@@ -1033,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                *socket = sad_interleave[idx];
                edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
                         idx, sad_way, *socket);
+       } else if (pvt->info.type == HASWELL) {
+               int bits, a7mode = A7MODE(dram_rule);
+
+               if (a7mode) {
+                       /* A7 mode swaps P9 with P6 */
+                       bits = GET_BITFIELD(addr, 7, 8) << 1;
+                       bits |= GET_BITFIELD(addr, 9, 9);
+               } else
+                       bits = GET_BITFIELD(addr, 7, 9);
+
+               if (interleave_mode) {
+                       /* interleave mode will XOR {8,7,6} with {18,17,16} */
+                       idx = GET_BITFIELD(addr, 16, 18);
+                       idx ^= bits;
+               } else
+                       idx = bits;
+
+               pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
+               *socket = sad_pkg_socket(pkg);
+               sad_ha = sad_pkg_ha(pkg);
+
+               if (a7mode) {
+                       /* MCChanShiftUpEnable */
+                       pci_read_config_dword(pvt->pci_ha0,
+                                             HASWELL_HASYSDEFEATURE2, &reg);
+                       shiftup = GET_BITFIELD(reg, 22, 22);
+               }
+
+               edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n",
+                        idx, *socket, sad_ha, shiftup);
        } else {
                /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
                idx = (addr >> 6) & 7;
@@ -1090,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        if (ch_way == 3)
                idx = addr >> 6;
        else
-               idx = addr >> (6 + sck_way);
+               idx = (addr >> (6 + sck_way + shiftup)) & 0x3;
        idx = idx % ch_way;
 
        /*
@@ -1181,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                if (!IS_RIR_VALID(reg))
                        continue;
 
-               limit = RIR_LIMIT(reg);
+               limit = pvt->info.rir_limit(reg);
                mb = div_u64_rem(limit >> 20, 1000, &kb);
                edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
                         n_rir,
@@ -1197,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                return -EINVAL;
        }
        rir_way = RIR_WAY(reg);
+
        if (pvt->is_close_pg)
                idx = (ch_addr >> 6);
        else
@@ -1259,13 +1465,11 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 {
        struct sbridge_dev *sbridge_dev;
        const struct pci_id_descr *dev_descr = &table->descr[devno];
-
        struct pci_dev *pdev = NULL;
        u8 bus = 0;
 
        sbridge_printk(KERN_DEBUG,
-               "Seeking for: dev %02x.%d PCI ID %04x:%04x\n",
-               dev_descr->dev, dev_descr->func,
+               "Seeking for: PCI ID %04x:%04x\n",
                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -1280,12 +1484,12 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
                if (dev_descr->optional)
                        return 0;
 
+               /* if the HA wasn't found */
                if (devno == 0)
                        return -ENODEV;
 
                sbridge_printk(KERN_INFO,
-                       "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
-                       dev_descr->dev, dev_descr->func,
+                       "Device not found: %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
                /* End of list, leave */
@@ -1305,9 +1509,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
        if (sbridge_dev->pdev[devno]) {
                sbridge_printk(KERN_ERR,
-                       "Duplicated device for "
-                       "dev %02x:%d.%d PCI ID %04x:%04x\n",
-                       bus, dev_descr->dev, dev_descr->func,
+                       "Duplicated device for %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
                pci_dev_put(pdev);
                return -ENODEV;
@@ -1315,30 +1517,15 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
        sbridge_dev->pdev[devno] = pdev;
 
-       /* Sanity check */
-       if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
-                       PCI_FUNC(pdev->devfn) != dev_descr->func)) {
-               sbridge_printk(KERN_ERR,
-                       "Device PCI ID %04x:%04x "
-                       "has dev %02x:%d.%d instead of dev %02x:%02x.%d\n",
-                       PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
-                       bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                       bus, dev_descr->dev, dev_descr->func);
-               return -ENODEV;
-       }
-
        /* Be sure that the device is enabled */
        if (unlikely(pci_enable_device(pdev) < 0)) {
                sbridge_printk(KERN_ERR,
-                       "Couldn't enable "
-                       "dev %02x:%d.%d PCI ID %04x:%04x\n",
-                       bus, dev_descr->dev, dev_descr->func,
+                       "Couldn't enable %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
                return -ENODEV;
        }
 
-       edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
-                bus, dev_descr->dev, dev_descr->func,
+       edac_dbg(0, "Detected %04x:%04x\n",
                 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        /*
@@ -1355,10 +1542,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
 /*
  * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's
- *                          device/functions we want to reference for this driver.
- *                          Need to 'get' device 16 func 1 and func 2.
+ *                          devices we want to reference for this driver.
  * @num_mc: pointer to the memory controllers count, to be incremented in case
- *         of success.
+ *         of success.
  * @table: model specific table
  *
  * returns 0 in case of success or error code
@@ -1396,79 +1582,51 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
 {
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev *pdev;
-       int i, func, slot;
+       int i;
 
        for (i = 0; i < sbridge_dev->n_devs; i++) {
                pdev = sbridge_dev->pdev[i];
                if (!pdev)
                        continue;
-               slot = PCI_SLOT(pdev->devfn);
-               func = PCI_FUNC(pdev->devfn);
-               switch (slot) {
-               case 12:
-                       switch (func) {
-                       case 6:
-                               pvt->pci_sad0 = pdev;
-                               break;
-                       case 7:
-                               pvt->pci_sad1 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0:
+                       pvt->pci_sad0 = pdev;
                        break;
-               case 13:
-                       switch (func) {
-                       case 6:
-                               pvt->pci_br0 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1:
+                       pvt->pci_sad1 = pdev;
                        break;
-               case 14:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ha0 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_BR:
+                       pvt->pci_br0 = pdev;
                        break;
-               case 15:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ta = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_ras = pdev;
-                               break;
-                       case 2:
-                       case 3:
-                       case 4:
-                       case 5:
-                               pvt->pci_tad[func - 2] = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
                        break;
-               case 17:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ddrio = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
+                       pvt->pci_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0;
+                       pvt->pci_tad[id] = pdev;
+               }
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO:
+                       pvt->pci_ddrio = pdev;
                        break;
                default:
                        goto error;
                }
 
-               edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+               edac_dbg(0, "Associated PCI %02x:%02x, bus %d with dev = %p\n",
+                        pdev->vendor, pdev->device,
                         sbridge_dev->bus,
-                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
                         pdev);
        }
 
@@ -1488,9 +1646,8 @@ enodev:
        return -ENODEV;
 
 error:
-       sbridge_printk(KERN_ERR, "Device %d, function %d "
-                     "is out of the expected range\n",
-                     slot, func);
+       sbridge_printk(KERN_ERR, "Unexpected device %02x:%02x\n",
+                      PCI_VENDOR_ID_INTEL, pdev->device);
        return -EINVAL;
 }
 
@@ -1499,7 +1656,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
 {
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev *pdev, *tmp;
-       int i, func, slot;
+       int i;
        bool mode_2ha = false;
 
        tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -1513,79 +1670,60 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
                pdev = sbridge_dev->pdev[i];
                if (!pdev)
                        continue;
-               slot = PCI_SLOT(pdev->devfn);
-               func = PCI_FUNC(pdev->devfn);
 
-               switch (slot) {
-               case 14:
-                       if (func == 0) {
-                               pvt->pci_ha0 = pdev;
-                               break;
-                       }
-                       goto error;
-               case 15:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ta = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_ras = pdev;
-                               break;
-                       case 4:
-                       case 5:
-                               /* if we have 2 HAs active, channels 2 and 3
-                                * are in other device */
-                               if (mode_2ha)
-                                       break;
-                               /* fall through */
-                       case 2:
-                       case 3:
-                               pvt->pci_tad[func - 2] = pdev;
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
+                       pvt->pci_ta = pdev;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
+                       /* if we have 2 HAs active, channels 2 and 3
+                        * are in other device */
+                       if (mode_2ha)
                                break;
-                       default:
-                               goto error;
-                       }
+                       /* fall through */
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0;
+                       pvt->pci_tad[id] = pdev;
+               }
                        break;
-               case 17:
-                       if (func == 4) {
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0:
+                       pvt->pci_ddrio = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0:
+                       if (!mode_2ha)
                                pvt->pci_ddrio = pdev;
-                               break;
-                       } else if (func == 0) {
-                               if (!mode_2ha)
-                                       pvt->pci_ddrio = pdev;
-                               break;
-                       }
-                       goto error;
-               case 22:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_sad0 = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_br0 = pdev;
-                               break;
-                       case 2:
-                               pvt->pci_br1 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
                        break;
-               case 28:
-                       if (func == 0) {
-                               pvt->pci_ha1 = pdev;
-                               break;
-                       }
-                       goto error;
-               case 29:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD:
+                       pvt->pci_sad0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_BR0:
+                       pvt->pci_br0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_BR1:
+                       pvt->pci_br1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1:
+                       pvt->pci_ha1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 2;
+
                        /* we shouldn't have this device if we have just one
                         * HA present */
                        WARN_ON(!mode_2ha);
-                       if (func == 2 || func == 3) {
-                               pvt->pci_tad[func] = pdev;
-                               break;
-                       }
-                       goto error;
+                       pvt->pci_tad[id] = pdev;
+               }
+                       break;
                default:
                        goto error;
                }
@@ -1614,11 +1752,111 @@ enodev:
 
 error:
        sbridge_printk(KERN_ERR,
-                      "Device %d, function %d is out of the expected range\n",
-                      slot, func);
+                      "Unexpected device %02x:%02x\n", PCI_VENDOR_ID_INTEL,
+                       pdev->device);
        return -EINVAL;
 }
 
+static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
+                                struct sbridge_dev *sbridge_dev)
+{
+       struct sbridge_pvt *pvt = mci->pvt_info;
+       struct pci_dev *pdev, *tmp;
+       int i;
+       bool mode_2ha = false;
+
+       tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
+                            PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL);
+       if (tmp) {
+               mode_2ha = true;
+               pci_dev_put(tmp);
+       }
+
+       /* there's only one device per system; not tied to any bus */
+       if (pvt->info.pci_vtd == NULL)
+               /* result will be checked later */
+               pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                                  PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC,
+                                                  NULL);
+
+       for (i = 0; i < sbridge_dev->n_devs; i++) {
+               pdev = sbridge_dev->pdev[i];
+               if (!pdev)
+                       continue;
+
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0:
+                       pvt->pci_sad0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1:
+                       pvt->pci_sad1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA:
+                       pvt->pci_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0:
+                       pvt->pci_tad[0] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1:
+                       pvt->pci_tad[1] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2:
+                       if (!mode_2ha)
+                               pvt->pci_tad[2] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3:
+                       if (!mode_2ha)
+                               pvt->pci_tad[3] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
+                       pvt->pci_ddrio = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
+                       pvt->pci_ha1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA:
+                       pvt->pci_ha1_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
+                       if (mode_2ha)
+                               pvt->pci_tad[2] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
+                       if (mode_2ha)
+                               pvt->pci_tad[3] = pdev;
+                       break;
+               default:
+                       break;
+               }
+
+               edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+                        sbridge_dev->bus,
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        pdev);
+       }
+
+       /* Check if everything were registered */
+       if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 ||
+           !pvt->pci_ras  || !pvt->pci_ta || !pvt->info.pci_vtd)
+               goto enodev;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               if (!pvt->pci_tad[i])
+                       goto enodev;
+       }
+       return 0;
+
+enodev:
+       sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+       return -ENODEV;
+}
+
 /****************************************************************************
                        Error check routines
  ****************************************************************************/
@@ -1736,6 +1974,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
         * EDAC core should be handling the channel mask, in order to point
         * to the group of dimm's where the error may be happening.
         */
+       if (!pvt->is_lockstep && !pvt->is_mirrored && !pvt->is_close_pg)
+               channel = first_channel;
+
        snprintf(msg, sizeof(msg),
                 "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
                 overflow ? " OVERFLOW" : "",
@@ -1865,10 +2106,6 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
                          "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
                          mce->time, mce->socketid, mce->apicid);
 
-       /* Only handle if it is the right mc controller */
-       if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc)
-               return NOTIFY_DONE;
-
        smp_rmb();
        if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
                smp_wmb();
@@ -1932,7 +2169,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
        int rc;
 
        /* Check the number of active and not disabled channels */
-       rc = check_if_ecc_is_active(sbridge_dev->bus);
+       rc = check_if_ecc_is_active(sbridge_dev->bus, type);
        if (unlikely(rc < 0))
                return rc;
 
@@ -1971,11 +2208,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
        mci->edac_check = sbridge_check_error;
 
        pvt->info.type = type;
-       if (type == IVY_BRIDGE) {
+       switch (type) {
+       case IVY_BRIDGE:
                pvt->info.rankcfgr = IB_RANK_CFG_A;
                pvt->info.get_tolm = ibridge_get_tolm;
                pvt->info.get_tohm = ibridge_get_tohm;
                pvt->info.dram_rule = ibridge_dram_rule;
+               pvt->info.get_memory_type = get_memory_type;
+               pvt->info.get_node_id = get_node_id;
+               pvt->info.rir_limit = rir_limit;
                pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
                pvt->info.interleave_list = ibridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -1986,11 +2227,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                rc = ibridge_mci_bind_devs(mci, sbridge_dev);
                if (unlikely(rc < 0))
                        goto fail0;
-       } else {
+               break;
+       case SANDY_BRIDGE:
                pvt->info.rankcfgr = SB_RANK_CFG_A;
                pvt->info.get_tolm = sbridge_get_tolm;
                pvt->info.get_tohm = sbridge_get_tohm;
                pvt->info.dram_rule = sbridge_dram_rule;
+               pvt->info.get_memory_type = get_memory_type;
+               pvt->info.get_node_id = get_node_id;
+               pvt->info.rir_limit = rir_limit;
                pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
                pvt->info.interleave_list = sbridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
@@ -2001,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                rc = sbridge_mci_bind_devs(mci, sbridge_dev);
                if (unlikely(rc < 0))
                        goto fail0;
-       }
+               break;
+       case HASWELL:
+               /* rankcfgr isn't used */
+               pvt->info.get_tolm = haswell_get_tolm;
+               pvt->info.get_tohm = haswell_get_tohm;
+               pvt->info.dram_rule = ibridge_dram_rule;
+               pvt->info.get_memory_type = haswell_get_memory_type;
+               pvt->info.get_node_id = haswell_get_node_id;
+               pvt->info.rir_limit = haswell_rir_limit;
+               pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
+               pvt->info.interleave_list = ibridge_interleave_list;
+               pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
+               pvt->info.interleave_pkg = ibridge_interleave_pkg;
+               mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx);
 
+               /* Store pci devices at mci for faster access */
+               rc = haswell_mci_bind_devs(mci, sbridge_dev);
+               if (unlikely(rc < 0))
+                       goto fail0;
+               break;
+       }
 
        /* Get dimm basic config and the memory layout */
        get_dimm_config(mci);
@@ -2037,10 +2301,10 @@ fail0:
 
 static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       int rc;
+       int rc = -ENODEV;
        u8 mc, num_mc = 0;
        struct sbridge_dev *sbridge_dev;
-       enum type type;
+       enum type type = SANDY_BRIDGE;
 
        /* get the pci devices we want to reserve for our use */
        mutex_lock(&sbridge_edac_lock);
@@ -2054,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        probed++;
 
-       if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) {
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
                rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
                type = IVY_BRIDGE;
-       } else {
+               break;
+       case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
                rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
                type = SANDY_BRIDGE;
+               break;
+       case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
+               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
+               type = HASWELL;
+               break;
        }
        if (unlikely(rc < 0))
                goto fail0;
@@ -2068,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
                edac_dbg(0, "Registering MC#%d (%d of %d)\n",
                         mc, mc + 1, num_mc);
+
                sbridge_dev->mc = mc++;
                rc = sbridge_register_mci(sbridge_dev, type);
                if (unlikely(rc < 0))
index 10598dede9e97fdaa108f2e37c2332fb04d9ed4f..68bf06768123bb2d2fa92b0bf7777a28ad08f9c8 100644 (file)
@@ -132,12 +132,12 @@ nvkm_client_notify_new(struct nouveau_client *client,
                if (ret == 0) {
                        client->notify[index] = notify;
                        notify->client = client;
-                       return 0;
+                       return index;
                }
        }
 
        kfree(notify);
-       return 0;
+       return ret;
 }
 
 static int
index 54ec53bc6252495b973499a1f089847674b1847b..cdf9147f32a1e80df5c5e58fa840ce311fa54819 100644 (file)
@@ -163,6 +163,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk20a_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
index db19191176fa513ed958377fdceb1a4e6a735afd..30fd1dc64f9307603e137c43d5f6bf0e76e05d4f 100644 (file)
@@ -68,6 +68,9 @@ nvc0_graph_zbc_color_get(struct nvc0_graph_priv *priv, int format,
                }
        }
 
+       if (zbc < 0)
+               return zbc;
+
        memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
        memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
        priv->zbc_color[zbc].format = format;
@@ -109,6 +112,9 @@ nvc0_graph_zbc_depth_get(struct nvc0_graph_priv *priv, int format,
                }
        }
 
+       if (zbc < 0)
+               return zbc;
+
        priv->zbc_depth[zbc].format = format;
        priv->zbc_depth[zbc].ds = ds;
        priv->zbc_depth[zbc].l2 = l2;
index 4fc6ab12382d9774694e05d3e664014dc7650cc2..1794a05205d8cc5f6e9064e7e790c605ba9327f0 100644 (file)
@@ -14,7 +14,7 @@ struct nouveau_client {
        void *data;
 
        int (*ntfy)(const void *, u32, const void *, u32);
-       struct nvkm_client_notify *notify[8];
+       struct nvkm_client_notify *notify[16];
 };
 
 static inline struct nouveau_client *
index 73b1ed20c8d597b5d6b4c9f67f91b24cb3814d30..8bcbdf39cfb2db0844a5c030494096488cfc40e2 100644 (file)
@@ -99,8 +99,13 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
                  struct nouveau_mem *mem, struct nouveau_object **pobject)
 {
        struct nouveau_object *engine = nv_object(bar);
-       return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
-                                  mem, 0, pobject);
+       int ret = -ENOMEM;
+       if (bar->iomem) {
+               ret = nouveau_object_ctor(parent, engine,
+                                         &nouveau_barobj_oclass,
+                                         mem, 0, pobject);
+       }
+       return ret;
 }
 
 int
@@ -118,9 +123,12 @@ nouveau_bar_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       if (nv_device_resource_len(device, 3) != 0)
+       if (nv_device_resource_len(device, 3) != 0) {
                bar->iomem = ioremap(nv_device_resource_start(device, 3),
                                     nv_device_resource_len(device, 3));
+               if (!bar->iomem)
+                       nv_warn(bar, "PRAMIN ioremap failed\n");
+       }
 
        return 0;
 }
index 946518572346adf5d6cc0675c11552300308c8b2..2b284b19276330aabd6b584c55b21eb727232662 100644 (file)
@@ -554,13 +554,13 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        } else {
                /* otherwise, address lowest common amount from 0GiB */
                ret = nouveau_mm_init(&pfb->vram, rsvd_head,
-                                     (bsize << 8) * parts, 1);
+                                     (bsize << 8) * parts - rsvd_head, 1);
                if (ret)
                        return ret;
 
                /* and the rest starting from (8GiB + common_size) */
                offset = (0x0200000000ULL >> 12) + (bsize << 8);
-               length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+               length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
 
                ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
                if (ret)
index 9e00a1ede1202c93ef2ba190d4a3bd5bc03b183d..b54b582e72c4764e040769718d6dca566f1bb840 100644 (file)
@@ -156,7 +156,7 @@ gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
        if (ret) {
                priv->num_tags = 0;
        } else {
-               u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;
+               u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
 
                tag_base += tag_align - 1;
                ret = do_div(tag_base, tag_align);
index da5d631aa5b9e34e618187e4474ba43e14474227..01da508625f27e4ad1c27393b8eaa928634564aa 100644 (file)
@@ -1228,7 +1228,6 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
        struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
        struct nouveau_drm *drm = nouveau_bdev(bdev);
        struct nouveau_mem *node = mem->mm_node;
-       struct drm_device *dev = drm->dev;
        int ret;
 
        mem->bus.addr = NULL;
@@ -1247,7 +1246,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                if (drm->agp.stat == ENABLED) {
                        mem->bus.offset = mem->start << PAGE_SHIFT;
                        mem->bus.base = drm->agp.base;
-                       mem->bus.is_iomem = !dev->agp->cant_use_aperture;
+                       mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture;
                }
 #endif
                if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype)
index 1cc7b603c75342799835825708e0d6edb144f620..65b4fd53dd4e13186c2d33a072b380e2b8a1fdd1 100644 (file)
@@ -592,7 +592,9 @@ nouveau_display_repin(struct drm_device *dev)
                if (!nouveau_fb || !nouveau_fb->nvbo)
                        continue;
 
-               nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       NV_ERROR(drm, "Could not pin framebuffer\n");
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
index ebfe3180109e8e2bcf2f4a86bf5d7c80a3751e56..8bdd27091db8fd1aa7a34a3174b625c6a6d2a830 100644 (file)
@@ -226,7 +226,7 @@ nouveau_fbcon_accel_restore(struct drm_device *dev)
        }
 }
 
-void
+static void
 nouveau_fbcon_accel_fini(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
@@ -246,7 +246,7 @@ nouveau_fbcon_accel_fini(struct drm_device *dev)
        }
 }
 
-void
+static void
 nouveau_fbcon_accel_init(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
index 0ffeb50d008879feab8755083178bb11dca1e050..246a824c16ca9a88acc05c5f464a0d7a5f387a23 100644 (file)
@@ -149,7 +149,8 @@ power_down:
 static int nouveau_platform_remove(struct platform_device *pdev)
 {
        struct drm_device *drm_dev = platform_get_drvdata(pdev);
-       struct nouveau_device *device = nouveau_dev(drm_dev);
+       struct nouveau_drm *drm = nouveau_drm(drm_dev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
        struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
 
        nouveau_drm_device_remove(drm_dev);
index cc81e0e5fd30652203bc9f2af64db3055c71258d..573491f847921bfc6eec27245b370096664de122 100644 (file)
@@ -428,8 +428,8 @@ struct nv50_disp_dac_pwr_v0 {
 struct nv50_disp_dac_load_v0 {
        __u8  version;
        __u8  load;
-       __u16 data;
-       __u8  pad04[4];
+       __u8  pad02[2];
+       __u32 data;
 };
 
 struct nv50_disp_sor_pwr_v0 {
index 7c06123a559c56ddfa3dd45e30095869ec87a8a6..0898c3155292c54453df568921e546d59bb3db4f 100644 (file)
@@ -87,12 +87,25 @@ nvif_notify_get(struct nvif_notify *notify)
        return 0;
 }
 
+static inline int
+nvif_notify_func(struct nvif_notify *notify, bool keep)
+{
+       int ret = notify->func(notify);
+       if (ret == NVIF_NOTIFY_KEEP ||
+           !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+               if (!keep)
+                       atomic_dec(&notify->putcnt);
+               else
+                       nvif_notify_get_(notify);
+       }
+       return ret;
+}
+
 static void
 nvif_notify_work(struct work_struct *work)
 {
        struct nvif_notify *notify = container_of(work, typeof(*notify), work);
-       if (notify->func(notify) == NVIF_NOTIFY_KEEP)
-               nvif_notify_get_(notify);
+       nvif_notify_func(notify, true);
 }
 
 int
@@ -113,19 +126,15 @@ nvif_notify(const void *header, u32 length, const void *data, u32 size)
        if (!WARN_ON(notify == NULL)) {
                struct nvif_client *client = nvif_client(notify->object);
                if (!WARN_ON(notify->size != size)) {
+                       atomic_inc(&notify->putcnt);
                        if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
-                               atomic_inc(&notify->putcnt);
                                memcpy((void *)notify->data, data, size);
                                schedule_work(&notify->work);
                                return NVIF_NOTIFY_DROP;
                        }
                        notify->data = data;
-                       ret = notify->func(notify);
+                       ret = nvif_notify_func(notify, client->driver->keep);
                        notify->data = NULL;
-                       if (ret != NVIF_NOTIFY_DROP && client->driver->keep) {
-                               atomic_inc(&notify->putcnt);
-                               nvif_notify_get_(notify);
-                       }
                }
        }
 
@@ -228,8 +237,10 @@ nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *),
        if (notify) {
                int ret = nvif_notify_init(object, nvif_notify_del, func, work,
                                           type, data, size, reply, notify);
-               if (ret)
+               if (ret) {
                        kfree(notify);
+                       notify = NULL;
+               }
                *pnotify = notify;
                return ret;
        }
index b0c82206ece204b649a2dad207b6faea405b05c6..dd85b56f6aa502a9ba65dcb9d9e9b2e61da7f664 100644 (file)
@@ -275,8 +275,10 @@ nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass,
        if (object) {
                int ret = nvif_object_init(parent, nvif_object_del, handle,
                                           oclass, data, size, object);
-               if (ret)
+               if (ret) {
                        kfree(object);
+                       object = NULL;
+               }
                *pobject = object;
                return ret;
        }
index 1bdcccc54a1dda0e04d16fc9fbfe2d3d8e1e22b2..f745d2c1325ec8872a376e668cdd71b3c9c523f3 100644 (file)
@@ -28,7 +28,7 @@
 static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+       if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
                hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
                rdesc[11] = rdesc[16] = 0xff;
                rdesc[12] = rdesc[17] = 0x03;
index 60f44cd1b0ed30ec19e986800676311bb72dadac..61b68ca27790d65c270465af7152276d7d7be7c9 100644 (file)
@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
        0xC0                    /*  End Collection                          */
 };
 
+/* Parameter indices */
+enum huion_prm {
+       HUION_PRM_X_LM          = 1,
+       HUION_PRM_Y_LM          = 2,
+       HUION_PRM_PRESSURE_LM   = 4,
+       HUION_PRM_RESOLUTION    = 5,
+       HUION_PRM_NUM
+};
+
 /* Driver data */
 struct huion_drvdata {
        __u8 *rdesc;
@@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
        int rc;
        struct usb_device *usb_dev = hid_to_usb_dev(hdev);
        struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
-       __le16 buf[6];
+       __le16 *buf = NULL;
+       size_t len;
+       s32 params[HUION_PH_ID_NUM];
+       s32 resolution;
+       __u8 *p;
+       s32 v;
 
        /*
         * Read string descriptor containing tablet parameters. The specific
@@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
         * driver traffic.
         * NOTE: This enables fully-functional tablet mode.
         */
+       len = HUION_PRM_NUM * sizeof(*buf);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (buf == NULL) {
+               hid_err(hdev, "failed to allocate parameter buffer\n");
+               rc = -ENOMEM;
+               goto cleanup;
+       }
        rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                                (USB_DT_STRING << 8) + 0x64,
-                               0x0409, buf, sizeof(buf),
+                               0x0409, buf, len,
                                USB_CTRL_GET_TIMEOUT);
-       if (rc == -EPIPE)
-               hid_warn(hdev, "device parameters not found\n");
-       else if (rc < 0)
-               hid_warn(hdev, "failed to get device parameters: %d\n", rc);
-       else if (rc != sizeof(buf))
-               hid_warn(hdev, "invalid device parameters\n");
-       else {
-               s32 params[HUION_PH_ID_NUM];
-               s32 resolution;
-               __u8 *p;
-               s32 v;
+       if (rc == -EPIPE) {
+               hid_err(hdev, "device parameters not found\n");
+               rc = -ENODEV;
+               goto cleanup;
+       } else if (rc < 0) {
+               hid_err(hdev, "failed to get device parameters: %d\n", rc);
+               rc = -ENODEV;
+               goto cleanup;
+       } else if (rc != len) {
+               hid_err(hdev, "invalid device parameters\n");
+               rc = -ENODEV;
+               goto cleanup;
+       }
 
-               /* Extract device parameters */
-               params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
-               params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
-               params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
-               resolution = le16_to_cpu(buf[5]);
-               if (resolution == 0) {
-                       params[HUION_PH_ID_X_PM] = 0;
-                       params[HUION_PH_ID_Y_PM] = 0;
-               } else {
-                       params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
-                                                       1000 / resolution;
-                       params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
-                                                       1000 / resolution;
-               }
+       /* Extract device parameters */
+       params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
+       params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
+       params[HUION_PH_ID_PRESSURE_LM] =
+               le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
+       resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
+       if (resolution == 0) {
+               params[HUION_PH_ID_X_PM] = 0;
+               params[HUION_PH_ID_Y_PM] = 0;
+       } else {
+               params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
+                                               1000 / resolution;
+               params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
+                                               1000 / resolution;
+       }
 
-               /* Allocate fixed report descriptor */
-               drvdata->rdesc = devm_kmalloc(&hdev->dev,
-                                       sizeof(huion_tablet_rdesc_template),
-                                       GFP_KERNEL);
-               if (drvdata->rdesc == NULL) {
-                       hid_err(hdev, "failed to allocate fixed rdesc\n");
-                       return -ENOMEM;
-               }
-               drvdata->rsize = sizeof(huion_tablet_rdesc_template);
+       /* Allocate fixed report descriptor */
+       drvdata->rdesc = devm_kmalloc(&hdev->dev,
+                               sizeof(huion_tablet_rdesc_template),
+                               GFP_KERNEL);
+       if (drvdata->rdesc == NULL) {
+               hid_err(hdev, "failed to allocate fixed rdesc\n");
+               rc = -ENOMEM;
+               goto cleanup;
+       }
+       drvdata->rsize = sizeof(huion_tablet_rdesc_template);
 
-               /* Format fixed report descriptor */
-               memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
-                       drvdata->rsize);
-               for (p = drvdata->rdesc;
-                    p <= drvdata->rdesc + drvdata->rsize - 4;) {
-                       if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
-                           p[3] < sizeof(params)) {
-                               v = params[p[3]];
-                               put_unaligned(cpu_to_le32(v), (s32 *)p);
-                               p += 4;
-                       } else {
-                               p++;
-                       }
+       /* Format fixed report descriptor */
+       memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
+               drvdata->rsize);
+       for (p = drvdata->rdesc;
+            p <= drvdata->rdesc + drvdata->rsize - 4;) {
+               if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
+                   p[3] < sizeof(params)) {
+                       v = params[p[3]];
+                       put_unaligned(cpu_to_le32(v), (s32 *)p);
+                       p += 4;
+               } else {
+                       p++;
                }
        }
 
-       return 0;
+       rc = 0;
+
+cleanup:
+       kfree(buf);
+       return rc;
 }
 
 static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
index e7769636759129f2540c5c670f1cc332180191fe..b92bf01a1ae8122f486ea333288558f082162f5d 100644 (file)
@@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                 *   - change the button usage range to 4-7 for the extra
                 *     buttons
                 */
-               if (*rsize >= 74 &&
+               if (*rsize >= 75 &&
                        rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
                        rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
                        rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
index a976f48263f661248f818685d10b708496298cf0..f91ff145db9a0761ce487aa2b43aee1f2503af2f 100644 (file)
@@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        struct usb_device_descriptor *udesc;
        __u16 bcdDevice, rev_maj, rev_min;
 
-       if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+       if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
                        rdesc[84] == 0x8c && rdesc[85] == 0x02) {
                hid_info(hdev,
                         "fixing up Logitech keyboard report descriptor\n");
                rdesc[84] = rdesc[89] = 0x4d;
                rdesc[85] = rdesc[90] = 0x10;
        }
-       if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+       if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
                        rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
                        rdesc[49] == 0x81 && rdesc[50] == 0x06) {
                hid_info(hdev,
index cc2bd20221989aa0284269cce533c28ab2e7295c..7835717bc02011d4ed2638caca9472021394245b 100644 (file)
@@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
        drv_data = hid_get_drvdata(hid);
        if (!drv_data) {
                hid_err(hid, "Private driver data not found!\n");
-               return 0;
+               return -EINVAL;
        }
 
        entry = drv_data->device_props;
        if (!entry) {
                hid_err(hid, "Device properties not found!\n");
-               return 0;
+               return -EINVAL;
        }
 
        if (range == 0)
index 486dbde2ba2d90d3802e59163870b57c4274fb28..b7ba82960c7925c5d04eb898af55a95b3be058f4 100644 (file)
@@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                return;
        }
 
-       if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
-           (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
-               dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
-                       __func__, dj_report->device_index);
-               return;
-       }
-
        if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
                /* The device is already known. No need to reallocate it. */
                dbg_hid("%s: device is already known\n", __func__);
@@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
        if (!out_buf)
                return -ENOMEM;
 
-       if (count < DJREPORT_SHORT_LENGTH - 2)
+       if (count > DJREPORT_SHORT_LENGTH - 2)
                count = DJREPORT_SHORT_LENGTH - 2;
 
        out_buf[0] = REPORT_ID_DJ_SHORT;
@@ -690,6 +683,12 @@ static int logi_dj_raw_event(struct hid_device *hdev,
         * device (via hid_input_report() ) and return 1 so hid-core does not do
         * anything else with it.
         */
+       if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
+           (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
+               dev_err(&hdev->dev, "%s: invalid device index:%d\n",
+                               __func__, dj_report->device_index);
+               return false;
+       }
 
        spin_lock_irqsave(&djrcv_dev->lock, flags);
        if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
index 9e14c00eb1b6bb105ffd1326dc802183cfeb9a1a..25daf28b26bdf6b4d921e501bb49d4646e9aed55 100644 (file)
@@ -24,7 +24,7 @@
 static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+       if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
                hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
                rdesc[30] = 0x0c;
        }
index 736b2502df4f8b00473889f6abf0ac78dcf72fe3..6aca4f2554bf4d748df6fc629276704e740ea40e 100644 (file)
@@ -25,7 +25,7 @@
 static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+       if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
                        rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
                        rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
                hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
index 0dc25142f451ff8d5fb040249d83d811a029db1d..8389e8109218c7013567b727cdb3ae300c3a51b9 100644 (file)
@@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return ret;
        }
 
-       if (!test_bit(RMI_STARTED, &data->flags)) {
-               hid_hw_stop(hdev);
-               return -EIO;
-       }
+       if (!test_bit(RMI_STARTED, &data->flags))
+               /*
+                * The device maybe in the bootloader if rmi_input_configured
+                * failed to find F11 in the PDT. Print an error, but don't
+                * return an error from rmi_probe so that hidraw will be
+                * accessible from userspace. That way a userspace tool
+                * can be used to reload working firmware on the touchpad.
+                */
+               hid_err(hdev, "Device failed to be properly configured\n");
 
        return 0;
 }
index e244e449cbbadc05ffc40c62e27fa1065c5154ed..2ac25760a9a9da02004299ab702c481d7e712cc5 100644 (file)
@@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
                ret = -EINVAL;
                goto err_stop_hw;
        }
-       sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
-                                               sizeof(struct mfd_cell),
-                                               GFP_KERNEL);
+       sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
+                                                     sizeof(struct mfd_cell),
+                                                     GFP_KERNEL);
        if (sd->hid_sensor_hub_client_devs == NULL) {
                hid_err(hdev, "Failed to allocate memory for mfd cells\n");
                        ret = -ENOMEM;
@@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
 
                if (collection->type == HID_COLLECTION_PHYSICAL) {
 
-                       hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
+                       hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
+                                            GFP_KERNEL);
                        if (!hsdev) {
                                hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
                                ret = -ENOMEM;
-                               goto err_no_mem;
+                               goto err_stop_hw;
                        }
                        hsdev->hdev = hdev;
                        hsdev->vendor_id = hdev->vendor;
@@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
                        if (last_hsdev)
                                last_hsdev->end_collection_index = i;
                        last_hsdev = hsdev;
-                       name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
-                                       collection->usage);
+                       name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+                                             "HID-SENSOR-%x",
+                                             collection->usage);
                        if (name == NULL) {
                                hid_err(hdev, "Failed MFD device name\n");
                                        ret = -ENOMEM;
-                                       kfree(hsdev);
-                                       goto err_no_mem;
+                                       goto err_stop_hw;
                        }
                        sd->hid_sensor_hub_client_devs[
                                sd->hid_sensor_client_cnt].id =
@@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev,
        ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
                sd->hid_sensor_client_cnt, NULL, 0, NULL);
        if (ret < 0)
-               goto err_no_mem;
+               goto err_stop_hw;
 
        return ret;
 
-err_no_mem:
-       for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
-               kfree(sd->hid_sensor_hub_client_devs[i].name);
-               kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
-       }
-       kfree(sd->hid_sensor_hub_client_devs);
 err_stop_hw:
        hid_hw_stop(hdev);
 
@@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
 {
        struct sensor_hub_data *data = hid_get_drvdata(hdev);
        unsigned long flags;
-       int i;
 
        hid_dbg(hdev, " hardware removed\n");
        hid_hw_close(hdev);
@@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
                complete(&data->pending.ready);
        spin_unlock_irqrestore(&data->lock, flags);
        mfd_remove_devices(&hdev->dev);
-       for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
-               kfree(data->hid_sensor_hub_client_devs[i].name);
-               kfree(data->hid_sensor_hub_client_devs[i].platform_data);
-       }
-       kfree(data->hid_sensor_hub_client_devs);
        hid_set_drvdata(hdev, NULL);
        mutex_destroy(&data->mutex);
 }
index 87fc91e1c8de4980d2f8e8721f476b6d21959adf..91072fa54663e747908dd09bb11b431eaa4208c5 100644 (file)
@@ -24,7 +24,7 @@
 static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+       if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
                        rdesc[106] == 0x03) {
                hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
                rdesc[105] = rdesc[110] = 0x03;
index 3e388ec31da84bd5d41b9c6d6771d75ceb2c81a2..f0db7eca902324b84bf97ad915edd05d0c6a35a4 100644 (file)
@@ -1416,6 +1416,7 @@ static void wacom_remove(struct hid_device *hdev)
        kfree(wacom);
 }
 
+#ifdef CONFIG_PM
 static int wacom_resume(struct hid_device *hdev)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
@@ -1436,6 +1437,7 @@ static int wacom_reset_resume(struct hid_device *hdev)
 {
        return wacom_resume(hdev);
 }
+#endif /* CONFIG_PM */
 
 static struct hid_driver wacom_driver = {
        .name =         "wacom",
index 3e3b680dc007319cf14abe35e5a26fc7f7c8a2b4..b51a402752c4c616a0d2a57ba6cd73c983296fc1 100644 (file)
@@ -23,17 +23,14 @@ config I2C
          This I2C support can also be built as a module.  If so, the module
          will be called i2c-core.
 
-config I2C_ACPI
-       bool "I2C ACPI support"
-       select I2C
-       depends on ACPI
+config ACPI_I2C_OPREGION
+       bool "ACPI I2C Operation region support"
+       depends on I2C=y && ACPI
        default y
        help
-         Say Y here if you want to enable ACPI I2C support. This includes support
-         for automatic enumeration of I2C slave devices and support for ACPI I2C
-         Operation Regions. Operation Regions allow firmware (BIOS) code to
-         access I2C slave devices, such as smart batteries through an I2C host
-         controller driver.
+         Say Y here if you want to enable ACPI I2C operation region support.
+         Operation Regions allow firmware (BIOS) code to access I2C slave devices,
+         such as smart batteries through an I2C host controller driver.
 
 if I2C
 
index a1f590cbb435d4c83a507beb4c11a051a77d828e..e0228b228256a8771df7b0be2536c3c42f90448d 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 i2ccore-y := i2c-core.o
-i2ccore-$(CONFIG_I2C_ACPI)     += i2c-acpi.o
+i2ccore-$(CONFIG_ACPI)         += i2c-acpi.o
 
 obj-$(CONFIG_I2C_BOARDINFO)    += i2c-boardinfo.o
 obj-$(CONFIG_I2C)              += i2ccore.o
index 2994690b26e9b18ffc6223df4db9d8d489924079..10467a3277492a6fa98ee597e7b1b33df687ec32 100644 (file)
 
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS             0x0f12
+#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS             0x2292
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS          0x1c22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS             0x1d22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
@@ -828,6 +829,7 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
        { 0, }
 };
 
index e8b61967334bb199cbd551042820647d11aea62f..0dbc18c15c43a8529b4c84a34650887cc7a56019 100644 (file)
@@ -126,6 +126,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adap)
                dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
 }
 
+#ifdef CONFIG_ACPI_I2C_OPREGION
 static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
                u8 cmd, u8 *data, u8 data_len)
 {
@@ -360,3 +361,4 @@ void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
 
        acpi_bus_detach_private_data(handle);
 }
+#endif
index 4d140bbbe1006c172cecd2fd5313778e8eb5db17..9b7ee7e427df4f3b84cf611cf0fb0965d6a5db58 100644 (file)
@@ -89,6 +89,7 @@ struct idle_cpu {
         * Indicate which enable bits to clear here.
         */
        unsigned long auto_demotion_disable_flags;
+       bool byt_auto_demotion_disable_flag;
        bool disable_promotion_to_c1e;
 };
 
@@ -442,6 +443,66 @@ static struct cpuidle_state hsw_cstates[] = {
        {
                .enter = NULL }
 };
+static struct cpuidle_state bdw_cstates[] = {
+       {
+               .name = "C1-BDW",
+               .desc = "MWAIT 0x00",
+               .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 2,
+               .target_residency = 2,
+               .enter = &intel_idle },
+       {
+               .name = "C1E-BDW",
+               .desc = "MWAIT 0x01",
+               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 10,
+               .target_residency = 20,
+               .enter = &intel_idle },
+       {
+               .name = "C3-BDW",
+               .desc = "MWAIT 0x10",
+               .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 40,
+               .target_residency = 100,
+               .enter = &intel_idle },
+       {
+               .name = "C6-BDW",
+               .desc = "MWAIT 0x20",
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 133,
+               .target_residency = 400,
+               .enter = &intel_idle },
+       {
+               .name = "C7s-BDW",
+               .desc = "MWAIT 0x32",
+               .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 166,
+               .target_residency = 500,
+               .enter = &intel_idle },
+       {
+               .name = "C8-BDW",
+               .desc = "MWAIT 0x40",
+               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 300,
+               .target_residency = 900,
+               .enter = &intel_idle },
+       {
+               .name = "C9-BDW",
+               .desc = "MWAIT 0x50",
+               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 600,
+               .target_residency = 1800,
+               .enter = &intel_idle },
+       {
+               .name = "C10-BDW",
+               .desc = "MWAIT 0x60",
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 2600,
+               .target_residency = 7700,
+               .enter = &intel_idle },
+       {
+               .enter = NULL }
+};
 
 static struct cpuidle_state atom_cstates[] = {
        {
@@ -613,6 +674,7 @@ static const struct idle_cpu idle_cpu_snb = {
 static const struct idle_cpu idle_cpu_byt = {
        .state_table = byt_cstates,
        .disable_promotion_to_c1e = true,
+       .byt_auto_demotion_disable_flag = true,
 };
 
 static const struct idle_cpu idle_cpu_ivb = {
@@ -630,6 +692,11 @@ static const struct idle_cpu idle_cpu_hsw = {
        .disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_bdw = {
+       .state_table = bdw_cstates,
+       .disable_promotion_to_c1e = true,
+};
+
 static const struct idle_cpu idle_cpu_avn = {
        .state_table = avn_cstates,
        .disable_promotion_to_c1e = true,
@@ -658,7 +725,10 @@ static const struct x86_cpu_id intel_idle_ids[] = {
        ICPU(0x3f, idle_cpu_hsw),
        ICPU(0x45, idle_cpu_hsw),
        ICPU(0x46, idle_cpu_hsw),
-       ICPU(0x4D, idle_cpu_avn),
+       ICPU(0x4d, idle_cpu_avn),
+       ICPU(0x3d, idle_cpu_bdw),
+       ICPU(0x4f, idle_cpu_bdw),
+       ICPU(0x56, idle_cpu_bdw),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -814,6 +884,11 @@ static int __init intel_idle_cpuidle_driver_init(void)
        if (icpu->auto_demotion_disable_flags)
                on_each_cpu(auto_demotion_disable, NULL, 1);
 
+       if (icpu->byt_auto_demotion_disable_flag) {
+               wrmsrl(MSR_CC6_DEMOTION_POLICY_CONFIG, 0);
+               wrmsrl(MSR_MC6_DEMOTION_POLICY_CONFIG, 0);
+       }
+
        if (icpu->disable_promotion_to_c1e)     /* each-cpu is redundant */
                on_each_cpu(c1e_promotion_disable, NULL, 1);
 
index d398f1321f143f834e5ddc70563ed368ca130c24..c30204f2fa3097a376eec7a32072f0c29b9c1a90 100644 (file)
@@ -236,6 +236,31 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 }
 EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 
+/**
+ * input_mt_drop_unused() - Inactivate slots not seen in this frame
+ * @dev: input device with allocated MT slots
+ *
+ * Lift all slots not seen since the last call to this function.
+ */
+void input_mt_drop_unused(struct input_dev *dev)
+{
+       struct input_mt *mt = dev->mt;
+       int i;
+
+       if (!mt)
+               return;
+
+       for (i = 0; i < mt->num_slots; i++) {
+               if (!input_mt_is_used(mt, &mt->slots[i])) {
+                       input_mt_slot(dev, i);
+                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+               }
+       }
+
+       mt->frame++;
+}
+EXPORT_SYMBOL(input_mt_drop_unused);
+
 /**
  * input_mt_sync_frame() - synchronize mt frame
  * @dev: input device with allocated MT slots
@@ -247,27 +272,18 @@ EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 void input_mt_sync_frame(struct input_dev *dev)
 {
        struct input_mt *mt = dev->mt;
-       struct input_mt_slot *s;
        bool use_count = false;
 
        if (!mt)
                return;
 
-       if (mt->flags & INPUT_MT_DROP_UNUSED) {
-               for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
-                       if (input_mt_is_used(mt, s))
-                               continue;
-                       input_mt_slot(dev, s - mt->slots);
-                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
-               }
-       }
+       if (mt->flags & INPUT_MT_DROP_UNUSED)
+               input_mt_drop_unused(dev);
 
        if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
                use_count = true;
 
        input_mt_report_pointer_emulation(dev, use_count);
-
-       mt->frame++;
 }
 EXPORT_SYMBOL(input_mt_sync_frame);
 
index 9135606c86496511919a5238898aa98cf1c74996..ab0fdcd36e18d7746ce7f8d5e41c51b5dfae9304 100644 (file)
@@ -158,7 +158,7 @@ static unsigned int get_time_pit(void)
 #define GET_TIME(x)    rdtscl(x)
 #define DELTA(x,y)     ((y)-(x))
 #define TIME_NAME      "TSC"
-#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_TILE)
+#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE)
 #define GET_TIME(x)    do { x = get_cycles(); } while (0)
 #define DELTA(x,y)     ((y)-(x))
 #define TIME_NAME      "get_cycles"
index 603fe0dd3682f7cd5baa859de39f37e2253825d9..177602cf7079a41edf22553d348400d8035e649a 100644 (file)
@@ -95,7 +95,8 @@
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
 #define XTYPE_XBOX360W    2
-#define XTYPE_UNKNOWN     3
+#define XTYPE_XBOXONE     3
+#define XTYPE_UNKNOWN     4
 
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
@@ -121,6 +122,7 @@ static const struct xpad_device {
        { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
        { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -231,10 +233,12 @@ static const signed short xpad_abs_triggers[] = {
        -1
 };
 
-/* Xbox 360 has a vendor-specific class, so we cannot match it with only
+/*
+ * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
- * wireless controllers have protocol 129. */
+ * wireless controllers have protocol 129.
+ */
 #define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
        .idVendor = (vend), \
@@ -245,9 +249,20 @@ static const signed short xpad_abs_triggers[] = {
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
 
+/* The Xbox One controller uses subclass 71 and protocol 208. */
+#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
+       .idVendor = (vend), \
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+       .bInterfaceSubClass = 71, \
+       .bInterfaceProtocol = (pr)
+#define XPAD_XBOXONE_VENDOR(vend) \
+       { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) }
+
 static struct usb_device_id xpad_table[] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
+       XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft X-Box One controllers */
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
        { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
@@ -278,12 +293,10 @@ struct usb_xpad {
        struct urb *bulk_out;
        unsigned char *bdata;
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
        struct mutex odata_mutex;
-#endif
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct xpad_led *led;
@@ -470,6 +483,105 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
        xpad360_process_packet(xpad, cmd, &data[4]);
 }
 
+/*
+ *     xpadone_process_buttons
+ *
+ *     Process a button update packet from an Xbox one controller.
+ */
+static void xpadone_process_buttons(struct usb_xpad *xpad,
+                               struct input_dev *dev,
+                               unsigned char *data)
+{
+       /* menu/view buttons */
+       input_report_key(dev, BTN_START,  data[4] & 0x04);
+       input_report_key(dev, BTN_SELECT, data[4] & 0x08);
+
+       /* buttons A,B,X,Y */
+       input_report_key(dev, BTN_A,    data[4] & 0x10);
+       input_report_key(dev, BTN_B,    data[4] & 0x20);
+       input_report_key(dev, BTN_X,    data[4] & 0x40);
+       input_report_key(dev, BTN_Y,    data[4] & 0x80);
+
+       /* digital pad */
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               /* dpad as buttons (left, right, up, down) */
+               input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04);
+               input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08);
+               input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01);
+               input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02);
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[5] & 0x08) - !!(data[5] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[5] & 0x02) - !!(data[5] & 0x01));
+       }
+
+       /* TL/TR */
+       input_report_key(dev, BTN_TL,   data[5] & 0x10);
+       input_report_key(dev, BTN_TR,   data[5] & 0x20);
+
+       /* stick press left/right */
+       input_report_key(dev, BTN_THUMBL, data[5] & 0x40);
+       input_report_key(dev, BTN_THUMBR, data[5] & 0x80);
+
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               /* left stick */
+               input_report_abs(dev, ABS_X,
+                                (__s16) le16_to_cpup((__le16 *)(data + 10)));
+               input_report_abs(dev, ABS_Y,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+
+               /* right stick */
+               input_report_abs(dev, ABS_RX,
+                                (__s16) le16_to_cpup((__le16 *)(data + 14)));
+               input_report_abs(dev, ABS_RY,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 16)));
+       }
+
+       /* triggers left/right */
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_key(dev, BTN_TR2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       } else {
+               input_report_abs(dev, ABS_Z,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_abs(dev, ABS_RZ,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       }
+
+       input_sync(dev);
+}
+
+/*
+ *     xpadone_process_packet
+ *
+ *     Completes a request by converting the data into events for the
+ *     input subsystem. This version is for the Xbox One controller.
+ *
+ *     The report format was gleaned from
+ *     https://github.com/kylelemons/xbox/blob/master/xbox.go
+ */
+
+static void xpadone_process_packet(struct usb_xpad *xpad,
+                               u16 cmd, unsigned char *data)
+{
+       struct input_dev *dev = xpad->dev;
+
+       switch (data[0]) {
+       case 0x20:
+               xpadone_process_buttons(xpad, dev, data);
+               break;
+
+       case 0x07:
+               /* the xbox button has its own special report */
+               input_report_key(dev, BTN_MODE, data[4] & 0x01);
+               input_sync(dev);
+               break;
+       }
+}
+
 static void xpad_irq_in(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -502,6 +614,9 @@ static void xpad_irq_in(struct urb *urb)
        case XTYPE_XBOX360W:
                xpad360w_process_packet(xpad, 0, xpad->idata);
                break;
+       case XTYPE_XBOXONE:
+               xpadone_process_packet(xpad, 0, xpad->idata);
+               break;
        default:
                xpad_process_packet(xpad, 0, xpad->idata);
        }
@@ -535,7 +650,6 @@ static void xpad_bulk_out(struct urb *urb)
        }
 }
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -573,6 +687,7 @@ exit:
 static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 {
        struct usb_endpoint_descriptor *ep_irq_out;
+       int ep_irq_out_idx;
        int error;
 
        if (xpad->xtype == XTYPE_UNKNOWN)
@@ -593,7 +708,10 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
                goto fail2;
        }
 
-       ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
+       /* Xbox One controller has in/out endpoints swapped. */
+       ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
+       ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
+
        usb_fill_int_urb(xpad->irq_out, xpad->udev,
                         usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
                         xpad->odata, XPAD_PKT_LEN,
@@ -621,11 +739,6 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
                                xpad->odata, xpad->odata_dma);
        }
 }
-#else
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_deinit_output(struct usb_xpad *xpad) {}
-static void xpad_stop_output(struct usb_xpad *xpad) {}
-#endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -692,7 +805,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_UNKNOWN)
+       if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -801,6 +914,14 @@ static int xpad_open(struct input_dev *dev)
        if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
                return -EIO;
 
+       if (xpad->xtype == XTYPE_XBOXONE) {
+               /* Xbox one controller needs to be initialized. */
+               xpad->odata[0] = 0x05;
+               xpad->odata[1] = 0x20;
+               xpad->irq_out->transfer_buffer_length = 2;
+               return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
        return 0;
 }
 
@@ -816,6 +937,7 @@ static void xpad_close(struct input_dev *dev)
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
 {
+       struct usb_xpad *xpad = input_get_drvdata(input_dev);
        set_bit(abs, input_dev->absbit);
 
        switch (abs) {
@@ -827,7 +949,10 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
                break;
        case ABS_Z:
        case ABS_RZ:    /* the triggers (if mapped to axes) */
-               input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
+               if (xpad->xtype == XTYPE_XBOXONE)
+                       input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
+               else
+                       input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
                break;
        case ABS_HAT0X:
        case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
@@ -842,6 +967,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_xpad *xpad;
        struct input_dev *input_dev;
        struct usb_endpoint_descriptor *ep_irq_in;
+       int ep_irq_in_idx;
        int i, error;
 
        for (i = 0; xpad_device[i].idVendor; i++) {
@@ -850,6 +976,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        break;
        }
 
+       if (xpad_device[i].xtype == XTYPE_XBOXONE &&
+           intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+               /*
+                * The Xbox One controller lists three interfaces all with the
+                * same interface class, subclass and protocol. Differentiate by
+                * interface number.
+                */
+               return -ENODEV;
+       }
+
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!xpad || !input_dev) {
@@ -920,7 +1056,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                __set_bit(xpad_common_btn[i], input_dev->keybit);
 
        /* set up model-specific ones */
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+           xpad->xtype == XTYPE_XBOXONE) {
                for (i = 0; xpad360_btn[i] >= 0; i++)
                        __set_bit(xpad360_btn[i], input_dev->keybit);
        } else {
@@ -933,7 +1070,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        __set_bit(xpad_btn_pad[i], input_dev->keybit);
        } else {
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
-                   xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+                       xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
        }
 
        if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -956,7 +1093,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        if (error)
                goto fail5;
 
-       ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
+       /* Xbox One controller has in/out endpoints swapped. */
+       ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
+       ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
+
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
                         xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
index f7d7a0d4ab4ec5a7378f061d6d10e70085245625..180b184ab90f31935e1fa9c71bd7eb8fa4e68593 100644 (file)
@@ -64,7 +64,7 @@ struct cap1106_priv {
        struct input_dev *idev;
 
        /* config */
-       unsigned int keycodes[CAP1106_NUM_CHN];
+       unsigned short keycodes[CAP1106_NUM_CHN];
 };
 
 static const struct reg_default cap1106_reg_defaults[] = {
@@ -272,6 +272,12 @@ static int cap1106_i2c_probe(struct i2c_client *i2c_client,
        for (i = 0; i < CAP1106_NUM_CHN; i++)
                __set_bit(priv->keycodes[i], priv->idev->keybit);
 
+       __clear_bit(KEY_RESERVED, priv->idev->keybit);
+
+       priv->idev->keycode = priv->keycodes;
+       priv->idev->keycodesize = sizeof(priv->keycodes[0]);
+       priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes);
+
        priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
        priv->idev->id.product = CAP1106_PRODUCT_ID;
        priv->idev->id.version = rev;
index ef9e0b8a9aa754b6b49e26b7b050c2a7bcf1f078..e8573c68f77e900e83e054c720443328adfa2f7f 100644 (file)
@@ -117,6 +117,9 @@ void synaptics_reset(struct psmouse *psmouse)
 }
 
 #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static bool cr48_profile_sensor;
+
 struct min_max_quirk {
        const char * const *pnp_ids;
        int x_min, x_max, y_min, y_max;
@@ -1152,6 +1155,42 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse,
        priv->agm_pending = false;
 }
 
+static void synaptics_profile_sensor_process(struct psmouse *psmouse,
+                                            struct synaptics_hw_state *sgm,
+                                            int num_fingers)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+       struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
+       struct input_mt_pos pos[2];
+       int slot[2], nsemi, i;
+
+       nsemi = clamp_val(num_fingers, 0, 2);
+
+       for (i = 0; i < nsemi; i++) {
+               pos[i].x = hw[i]->x;
+               pos[i].y = synaptics_invert_y(hw[i]->y);
+       }
+
+       input_mt_assign_slots(dev, slot, pos, nsemi);
+
+       for (i = 0; i < nsemi; i++) {
+               input_mt_slot(dev, slot[i]);
+               input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
+               input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
+               input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
+               input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
+       }
+
+       input_mt_drop_unused(dev);
+       input_mt_report_pointer_emulation(dev, false);
+       input_mt_report_finger_count(dev, num_fingers);
+
+       synaptics_report_buttons(psmouse, sgm);
+
+       input_sync(dev);
+}
+
 /*
  *  called for each full received packet from the touchpad
  */
@@ -1215,6 +1254,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
                finger_width = 0;
        }
 
+       if (cr48_profile_sensor) {
+               synaptics_profile_sensor_process(psmouse, &hw, num_fingers);
+               return;
+       }
+
        if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
                synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
                                              num_fingers);
@@ -1360,6 +1404,9 @@ static void set_input_params(struct psmouse *psmouse,
        set_abs_position_params(dev, priv, ABS_X, ABS_Y);
        input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
+       if (cr48_profile_sensor)
+               input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
        if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
                set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
                                        ABS_MT_POSITION_Y);
@@ -1371,11 +1418,16 @@ static void set_input_params(struct psmouse *psmouse,
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
        } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
-               /* Non-image sensors with AGM use semi-mt */
-               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
-               input_mt_init_slots(dev, 2, 0);
                set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
                                        ABS_MT_POSITION_Y);
+               /*
+                * Profile sensor in CR-48 tracks contacts reasonably well,
+                * other non-image sensors with AGM use semi-mt.
+                */
+               input_mt_init_slots(dev, 2,
+                                   INPUT_MT_POINTER |
+                                   (cr48_profile_sensor ?
+                                       INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
        }
 
        if (SYN_CAP_PALMDETECT(priv->capabilities))
@@ -1577,10 +1629,24 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
        { }
 };
 
+static const struct dmi_system_id __initconst cr48_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               /* Cr-48 Chromebook (Codename Mario) */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
+               },
+       },
+#endif
+       { }
+};
+
 void __init synaptics_module_init(void)
 {
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
        broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+       cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
 }
 
 static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
index 03b85711cb70c9406aae09647d12df68045ff2b3..db178ed2b47ee282c27a5f424f45df168b99a091 100644 (file)
@@ -359,7 +359,6 @@ static int mxt_bootloader_read(struct mxt_data *data,
        msg.buf = val;
 
        ret = i2c_transfer(data->client->adapter, &msg, 1);
-
        if (ret == 1) {
                ret = 0;
        } else {
@@ -414,6 +413,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
        case 0x5b:
                bootloader = appmode - 0x26;
                break;
+
        default:
                dev_err(&data->client->dev,
                        "Appmode i2c address 0x%02x not found\n",
@@ -425,20 +425,20 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
        return 0;
 }
 
-static int mxt_probe_bootloader(struct mxt_data *data, bool retry)
+static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
 {
        struct device *dev = &data->client->dev;
-       int ret;
+       int error;
        u8 val;
        bool crc_failure;
 
-       ret = mxt_lookup_bootloader_address(data, retry);
-       if (ret)
-               return ret;
+       error = mxt_lookup_bootloader_address(data, alt_address);
+       if (error)
+               return error;
 
-       ret = mxt_bootloader_read(data, &val, 1);
-       if (ret)
-               return ret;
+       error = mxt_bootloader_read(data, &val, 1);
+       if (error)
+               return error;
 
        /* Check app crc fail mode */
        crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
@@ -1064,6 +1064,137 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
        return crc;
 }
 
+static int mxt_prepare_cfg_mem(struct mxt_data *data,
+                              const struct firmware *cfg,
+                              unsigned int data_pos,
+                              unsigned int cfg_start_ofs,
+                              u8 *config_mem,
+                              size_t config_mem_size)
+{
+       struct device *dev = &data->client->dev;
+       struct mxt_object *object;
+       unsigned int type, instance, size, byte_offset;
+       int offset;
+       int ret;
+       int i;
+       u16 reg;
+       u8 val;
+
+       while (data_pos < cfg->size) {
+               /* Read type, instance, length */
+               ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
+                            &type, &instance, &size, &offset);
+               if (ret == 0) {
+                       /* EOF */
+                       break;
+               } else if (ret != 3) {
+                       dev_err(dev, "Bad format: failed to parse object\n");
+                       return -EINVAL;
+               }
+               data_pos += offset;
+
+               object = mxt_get_object(data, type);
+               if (!object) {
+                       /* Skip object */
+                       for (i = 0; i < size; i++) {
+                               ret = sscanf(cfg->data + data_pos, "%hhx%n",
+                                            &val, &offset);
+                               if (ret != 1) {
+                                       dev_err(dev, "Bad format in T%d at %d\n",
+                                               type, i);
+                                       return -EINVAL;
+                               }
+                               data_pos += offset;
+                       }
+                       continue;
+               }
+
+               if (size > mxt_obj_size(object)) {
+                       /*
+                        * Either we are in fallback mode due to wrong
+                        * config or config from a later fw version,
+                        * or the file is corrupt or hand-edited.
+                        */
+                       dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
+                                size - mxt_obj_size(object), type);
+               } else if (mxt_obj_size(object) > size) {
+                       /*
+                        * If firmware is upgraded, new bytes may be added to
+                        * end of objects. It is generally forward compatible
+                        * to zero these bytes - previous behaviour will be
+                        * retained. However this does invalidate the CRC and
+                        * will force fallback mode until the configuration is
+                        * updated. We warn here but do nothing else - the
+                        * malloc has zeroed the entire configuration.
+                        */
+                       dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
+                                mxt_obj_size(object) - size, type);
+               }
+
+               if (instance >= mxt_obj_instances(object)) {
+                       dev_err(dev, "Object instances exceeded!\n");
+                       return -EINVAL;
+               }
+
+               reg = object->start_address + mxt_obj_size(object) * instance;
+
+               for (i = 0; i < size; i++) {
+                       ret = sscanf(cfg->data + data_pos, "%hhx%n",
+                                    &val,
+                                    &offset);
+                       if (ret != 1) {
+                               dev_err(dev, "Bad format in T%d at %d\n",
+                                       type, i);
+                               return -EINVAL;
+                       }
+                       data_pos += offset;
+
+                       if (i > mxt_obj_size(object))
+                               continue;
+
+                       byte_offset = reg + i - cfg_start_ofs;
+
+                       if (byte_offset >= 0 && byte_offset < config_mem_size) {
+                               *(config_mem + byte_offset) = val;
+                       } else {
+                               dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
+                                       reg, object->type, byte_offset);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start,
+                             u8 *config_mem, size_t config_mem_size)
+{
+       unsigned int byte_offset = 0;
+       int error;
+
+       /* Write configuration as blocks */
+       while (byte_offset < config_mem_size) {
+               unsigned int size = config_mem_size - byte_offset;
+
+               if (size > MXT_MAX_BLOCK_WRITE)
+                       size = MXT_MAX_BLOCK_WRITE;
+
+               error = __mxt_write_reg(data->client,
+                                       cfg_start + byte_offset,
+                                       size, config_mem + byte_offset);
+               if (error) {
+                       dev_err(&data->client->dev,
+                               "Config write error, ret=%d\n", error);
+                       return error;
+               }
+
+               byte_offset += size;
+       }
+
+       return 0;
+}
+
 /*
  * mxt_update_cfg - download configuration to chip
  *
@@ -1087,26 +1218,20 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 {
        struct device *dev = &data->client->dev;
        struct mxt_info cfg_info;
-       struct mxt_object *object;
        int ret;
        int offset;
        int data_pos;
-       int byte_offset;
        int i;
        int cfg_start_ofs;
        u32 info_crc, config_crc, calculated_crc;
        u8 *config_mem;
        size_t config_mem_size;
-       unsigned int type, instance, size;
-       u8 val;
-       u16 reg;
 
        mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
 
        if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
                dev_err(dev, "Unrecognised config file\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        data_pos = strlen(MXT_CFG_MAGIC);
@@ -1118,8 +1243,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                             &offset);
                if (ret != 1) {
                        dev_err(dev, "Bad format\n");
-                       ret = -EINVAL;
-                       goto release;
+                       return -EINVAL;
                }
 
                data_pos += offset;
@@ -1127,30 +1251,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 
        if (cfg_info.family_id != data->info.family_id) {
                dev_err(dev, "Family ID mismatch!\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        if (cfg_info.variant_id != data->info.variant_id) {
                dev_err(dev, "Variant ID mismatch!\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        /* Read CRCs */
        ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
        if (ret != 1) {
                dev_err(dev, "Bad format: failed to parse Info CRC\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
        data_pos += offset;
 
        ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
        if (ret != 1) {
                dev_err(dev, "Bad format: failed to parse Config CRC\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
        data_pos += offset;
 
@@ -1166,8 +1286,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                } else if (config_crc == data->config_crc) {
                        dev_dbg(dev, "Config CRC 0x%06X: OK\n",
                                 data->config_crc);
-                       ret = 0;
-                       goto release;
+                       return 0;
                } else {
                        dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
                                 data->config_crc, config_crc);
@@ -1186,93 +1305,13 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
        config_mem = kzalloc(config_mem_size, GFP_KERNEL);
        if (!config_mem) {
                dev_err(dev, "Failed to allocate memory\n");
-               ret = -ENOMEM;
-               goto release;
+               return -ENOMEM;
        }
 
-       while (data_pos < cfg->size) {
-               /* Read type, instance, length */
-               ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
-                            &type, &instance, &size, &offset);
-               if (ret == 0) {
-                       /* EOF */
-                       break;
-               } else if (ret != 3) {
-                       dev_err(dev, "Bad format: failed to parse object\n");
-                       ret = -EINVAL;
-                       goto release_mem;
-               }
-               data_pos += offset;
-
-               object = mxt_get_object(data, type);
-               if (!object) {
-                       /* Skip object */
-                       for (i = 0; i < size; i++) {
-                               ret = sscanf(cfg->data + data_pos, "%hhx%n",
-                                            &val,
-                                            &offset);
-                               data_pos += offset;
-                       }
-                       continue;
-               }
-
-               if (size > mxt_obj_size(object)) {
-                       /*
-                        * Either we are in fallback mode due to wrong
-                        * config or config from a later fw version,
-                        * or the file is corrupt or hand-edited.
-                        */
-                       dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
-                                size - mxt_obj_size(object), type);
-               } else if (mxt_obj_size(object) > size) {
-                       /*
-                        * If firmware is upgraded, new bytes may be added to
-                        * end of objects. It is generally forward compatible
-                        * to zero these bytes - previous behaviour will be
-                        * retained. However this does invalidate the CRC and
-                        * will force fallback mode until the configuration is
-                        * updated. We warn here but do nothing else - the
-                        * malloc has zeroed the entire configuration.
-                        */
-                       dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
-                                mxt_obj_size(object) - size, type);
-               }
-
-               if (instance >= mxt_obj_instances(object)) {
-                       dev_err(dev, "Object instances exceeded!\n");
-                       ret = -EINVAL;
-                       goto release_mem;
-               }
-
-               reg = object->start_address + mxt_obj_size(object) * instance;
-
-               for (i = 0; i < size; i++) {
-                       ret = sscanf(cfg->data + data_pos, "%hhx%n",
-                                    &val,
-                                    &offset);
-                       if (ret != 1) {
-                               dev_err(dev, "Bad format in T%d\n", type);
-                               ret = -EINVAL;
-                               goto release_mem;
-                       }
-                       data_pos += offset;
-
-                       if (i > mxt_obj_size(object))
-                               continue;
-
-                       byte_offset = reg + i - cfg_start_ofs;
-
-                       if ((byte_offset >= 0)
-                           && (byte_offset <= config_mem_size)) {
-                               *(config_mem + byte_offset) = val;
-                       } else {
-                               dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
-                                       reg, object->type, byte_offset);
-                               ret = -EINVAL;
-                               goto release_mem;
-                       }
-               }
-       }
+       ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs,
+                                 config_mem, config_mem_size);
+       if (ret)
+               goto release_mem;
 
        /* Calculate crc of the received configs (not the raw config file) */
        if (data->T7_address < cfg_start_ofs) {
@@ -1286,28 +1325,14 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                                           data->T7_address - cfg_start_ofs,
                                           config_mem_size);
 
-       if (config_crc > 0 && (config_crc != calculated_crc))
+       if (config_crc > 0 && config_crc != calculated_crc)
                dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
                         calculated_crc, config_crc);
 
-       /* Write configuration as blocks */
-       byte_offset = 0;
-       while (byte_offset < config_mem_size) {
-               size = config_mem_size - byte_offset;
-
-               if (size > MXT_MAX_BLOCK_WRITE)
-                       size = MXT_MAX_BLOCK_WRITE;
-
-               ret = __mxt_write_reg(data->client,
-                                     cfg_start_ofs + byte_offset,
-                                     size, config_mem + byte_offset);
-               if (ret != 0) {
-                       dev_err(dev, "Config write error, ret=%d\n", ret);
-                       goto release_mem;
-               }
-
-               byte_offset += size;
-       }
+       ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
+                                config_mem, config_mem_size);
+       if (ret)
+               goto release_mem;
 
        mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
 
@@ -1319,8 +1344,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 
 release_mem:
        kfree(config_mem);
-release:
-       release_firmware(cfg);
        return ret;
 }
 
@@ -1422,10 +1445,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 
                switch (object->type) {
                case MXT_GEN_MESSAGE_T5:
-                       if (data->info.family_id == 0x80) {
+                       if (data->info.family_id == 0x80 &&
+                           data->info.version < 0x20) {
                                /*
-                                * On mXT224 read and discard unused CRC byte
-                                * otherwise DMA reads are misaligned
+                                * On mXT224 firmware versions prior to V2.0
+                                * read and discard unused CRC byte otherwise
+                                * DMA reads are misaligned.
                                 */
                                data->T5_msg_size = mxt_obj_size(object);
                        } else {
@@ -1433,6 +1458,7 @@ static int mxt_get_object_table(struct mxt_data *data)
                                data->T5_msg_size = mxt_obj_size(object) - 1;
                        }
                        data->T5_address = object->start_address;
+                       break;
                case MXT_GEN_COMMAND_T6:
                        data->T6_reportid = min_id;
                        data->T6_address = object->start_address;
@@ -1638,46 +1664,45 @@ static int mxt_configure_objects(struct mxt_data *data,
 static void mxt_config_cb(const struct firmware *cfg, void *ctx)
 {
        mxt_configure_objects(ctx, cfg);
+       release_firmware(cfg);
 }
 
 static int mxt_initialize(struct mxt_data *data)
 {
        struct i2c_client *client = data->client;
+       int recovery_attempts = 0;
        int error;
-       bool alt_bootloader_addr = false;
-       bool retry = false;
 
-retry_info:
-       error = mxt_get_info(data);
-       if (error) {
-retry_bootloader:
-               error = mxt_probe_bootloader(data, alt_bootloader_addr);
+       while (1) {
+               error = mxt_get_info(data);
+               if (!error)
+                       break;
+
+               /* Check bootloader state */
+               error = mxt_probe_bootloader(data, false);
                if (error) {
-                       if (alt_bootloader_addr) {
+                       dev_info(&client->dev, "Trying alternate bootloader address\n");
+                       error = mxt_probe_bootloader(data, true);
+                       if (error) {
                                /* Chip is not in appmode or bootloader mode */
                                return error;
                        }
+               }
 
-                       dev_info(&client->dev, "Trying alternate bootloader address\n");
-                       alt_bootloader_addr = true;
-                       goto retry_bootloader;
-               } else {
-                       if (retry) {
-                               dev_err(&client->dev, "Could not recover from bootloader mode\n");
-                               /*
-                                * We can reflash from this state, so do not
-                                * abort init
-                                */
-                               data->in_bootloader = true;
-                               return 0;
-                       }
-
-                       /* Attempt to exit bootloader into app mode */
-                       mxt_send_bootloader_cmd(data, false);
-                       msleep(MXT_FW_RESET_TIME);
-                       retry = true;
-                       goto retry_info;
+               /* OK, we are in bootloader, see if we can recover */
+               if (++recovery_attempts > 1) {
+                       dev_err(&client->dev, "Could not recover from bootloader mode\n");
+                       /*
+                        * We can reflash from this state, so do not
+                        * abort initialization.
+                        */
+                       data->in_bootloader = true;
+                       return 0;
                }
+
+               /* Attempt to exit bootloader into app mode */
+               mxt_send_bootloader_cmd(data, false);
+               msleep(MXT_FW_RESET_TIME);
        }
 
        /* Get object table information */
@@ -1687,13 +1712,18 @@ retry_bootloader:
                return error;
        }
 
-       mxt_acquire_irq(data);
+       error = mxt_acquire_irq(data);
        if (error)
                goto err_free_object_table;
 
-       request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
-                               &data->client->dev, GFP_KERNEL, data,
-                               mxt_config_cb);
+       error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
+                                       &client->dev, GFP_KERNEL, data,
+                                       mxt_config_cb);
+       if (error) {
+               dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
+                       error);
+               goto err_free_object_table;
+       }
 
        return 0;
 
index 5a6d50c004d73c9b2d6ceb2a4b573e1542b11b7f..8857d5b9be71dc03d4494562383fc76c779003ef 100644 (file)
@@ -262,7 +262,6 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
        case M06:
                wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
                wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
-               wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
                wrbuf[2] = value;
                wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
                return edt_ft5x06_ts_readwrite(tsdata->client, 4,
index 18405314168be35fb00640bbf1e7e05ba23a9466..ecb0109a536045019dc3c5b9e2c084c3628f16ce 100644 (file)
@@ -3149,14 +3149,16 @@ free_domains:
 
 static void cleanup_domain(struct protection_domain *domain)
 {
-       struct iommu_dev_data *dev_data, *next;
+       struct iommu_dev_data *entry;
        unsigned long flags;
 
        write_lock_irqsave(&amd_iommu_devtable_lock, flags);
 
-       list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) {
-               __detach_device(dev_data);
-               atomic_set(&dev_data->bind, 0);
+       while (!list_empty(&domain->dev_list)) {
+               entry = list_first_entry(&domain->dev_list,
+                                        struct iommu_dev_data, list);
+               __detach_device(entry);
+               atomic_set(&entry->bind, 0);
        }
 
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
index d1f5caad04f99a8ed2e3781d5bcedce7c324564e..5619f264862d9073a587fd1a2b919f2c61a27523 100644 (file)
@@ -3869,6 +3869,14 @@ static int device_notifier(struct notifier_block *nb,
            action != BUS_NOTIFY_DEL_DEVICE)
                return 0;
 
+       /*
+        * If the device is still attached to a device driver we can't
+        * tear down the domain yet as DMA mappings may still be in use.
+        * Wait for the BUS_NOTIFY_UNBOUND_DRIVER event to do that.
+        */
+       if (action == BUS_NOTIFY_DEL_DEVICE && dev->driver != NULL)
+               return 0;
+
        domain = find_domain(dev);
        if (!domain)
                return 0;
index 169836020208d1a8a5755f16b60f68a66fec6d43..ac4adb337038bc990077a2c0557d1f07d8b1de8e 100644 (file)
@@ -995,7 +995,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
        size_t orig_size = size;
        int ret = 0;
 
-       if (unlikely(domain->ops->unmap == NULL ||
+       if (unlikely(domain->ops->map == NULL ||
                     domain->ops->pgsize_bitmap == 0UL))
                return -ENODEV;
 
index b08c18871323c904f3964e9c8b650366ad2979ef..6703751d87d7fd7314149cfd8ba5bef314927235 100644 (file)
@@ -2953,6 +2953,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                 */
                if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
                        end_reshape(conf);
+                       close_sync(conf);
                        return 0;
                }
 
@@ -3081,6 +3082,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                        }
 
                        r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+                       r10_bio->state = 0;
                        raise_barrier(conf, rb2 != NULL);
                        atomic_set(&r10_bio->remaining, 0);
 
@@ -3269,6 +3271,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                if (sync_blocks < max_sync)
                        max_sync = sync_blocks;
                r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+               r10_bio->state = 0;
 
                r10_bio->mddev = mddev;
                atomic_set(&r10_bio->remaining, 0);
@@ -4384,6 +4387,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
 read_more:
        /* Now schedule reads for blocks from sector_nr to last */
        r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+       r10_bio->state = 0;
        raise_barrier(conf, sectors_done != 0);
        atomic_set(&r10_bio->remaining, 0);
        r10_bio->mddev = mddev;
@@ -4398,6 +4402,7 @@ read_more:
                 * on all the target devices.
                 */
                // FIXME
+               mempool_free(r10_bio, conf->r10buf_pool);
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                return sectors_done;
        }
@@ -4410,7 +4415,7 @@ read_more:
        read_bio->bi_private = r10_bio;
        read_bio->bi_end_io = end_sync_read;
        read_bio->bi_rw = READ;
-       read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+       read_bio->bi_flags &= (~0UL << BIO_RESET_BITS);
        read_bio->bi_flags |= 1 << BIO_UPTODATE;
        read_bio->bi_vcnt = 0;
        read_bio->bi_iter.bi_size = 0;
index 6234b2e84587cd75d37ac50bf5264094e474632a..183588b11fc1d261e173aff9c9e1e63b175ed120 100644 (file)
@@ -2922,7 +2922,7 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
              (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) &&
              !test_bit(R5_OVERWRITE, &fdev[0]->flags)) ||
             (sh->raid_conf->level == 6 && s->failed && s->to_write &&
-             s->to_write < sh->raid_conf->raid_disks - 2 &&
+             s->to_write - s->non_overwrite < sh->raid_conf->raid_disks - 2 &&
              (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))))) {
                /* we would like to get this block, possibly by computing it,
                 * otherwise read it if the backing disk is insync
@@ -3817,6 +3817,8 @@ static void handle_stripe(struct stripe_head *sh)
                                set_bit(R5_Wantwrite, &dev->flags);
                                if (prexor)
                                        continue;
+                               if (s.failed > 1)
+                                       continue;
                                if (!test_bit(R5_Insync, &dev->flags) ||
                                    ((i == sh->pd_idx || i == sh->qd_idx)  &&
                                     s.failed == 0))
index f46a24ffa3fe7be040d488bc49bfba912848fde1..79cb8313c7d8b0b86681bc75867e8b6e5ee746ef 100644 (file)
@@ -453,7 +453,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
                base = dt_mem_next_cell(dt_root_addr_cells, &prop);
                size = dt_mem_next_cell(dt_root_size_cells, &prop);
 
-               if (base && size &&
+               if (size &&
                    early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
                        pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
                                uname, &base, (unsigned long)size / SZ_1M);
index 3e06a699352d0c83a8c660b35d64c97babcc7469..1471e0a223a59286497501e84ed72075aff18b01 100644 (file)
@@ -301,16 +301,17 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        /* Get the reg property (if any) */
        addr = of_get_property(device, "reg", NULL);
 
+       /* Try the new-style interrupts-extended first */
+       res = of_parse_phandle_with_args(device, "interrupts-extended",
+                                       "#interrupt-cells", index, out_irq);
+       if (!res)
+               return of_irq_parse_raw(addr, out_irq);
+
        /* Get the interrupts property */
        intspec = of_get_property(device, "interrupts", &intlen);
-       if (intspec == NULL) {
-               /* Try the new-style interrupts-extended */
-               res = of_parse_phandle_with_args(device, "interrupts-extended",
-                                               "#interrupt-cells", index, out_irq);
-               if (res)
-                       return -EINVAL;
-               return of_irq_parse_raw(addr, out_irq);
-       }
+       if (intspec == NULL)
+               return -EINVAL;
+
        intlen /= sizeof(*intspec);
 
        pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
index d410026678334885bae9e51893fde5f9873a7831..a737cb5974deae12aed1987d5250326ffa350445 100644 (file)
@@ -27,6 +27,7 @@ static struct selftest_results {
 #define NO_OF_NODES 2
 static struct device_node *nodes[NO_OF_NODES];
 static int last_node_index;
+static bool selftest_live_tree;
 
 #define selftest(result, fmt, ...) { \
        if (!(result)) { \
@@ -630,13 +631,6 @@ static int attach_node_and_children(struct device_node *np)
 {
        struct device_node *next, *root = np, *dup;
 
-       if (!np) {
-               pr_warn("%s: No tree to attach; not running tests\n",
-                       __func__);
-               return -ENODATA;
-       }
-
-
        /* skip root node */
        np = np->child;
        /* storing a copy in temporary node */
@@ -672,12 +666,12 @@ static int attach_node_and_children(struct device_node *np)
 static int __init selftest_data_add(void)
 {
        void *selftest_data;
-       struct device_node *selftest_data_node;
+       struct device_node *selftest_data_node, *np;
        extern uint8_t __dtb_testcases_begin[];
        extern uint8_t __dtb_testcases_end[];
        const int size = __dtb_testcases_end - __dtb_testcases_begin;
 
-       if (!size || !of_allnodes) {
+       if (!size) {
                pr_warn("%s: No testcase data to attach; not running tests\n",
                        __func__);
                return -ENODATA;
@@ -692,6 +686,22 @@ static int __init selftest_data_add(void)
                return -ENOMEM;
        }
        of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
+       if (!selftest_data_node) {
+               pr_warn("%s: No tree to attach; not running tests\n", __func__);
+               return -ENODATA;
+       }
+
+       if (!of_allnodes) {
+               /* enabling flag for removing nodes */
+               selftest_live_tree = true;
+               of_allnodes = selftest_data_node;
+
+               for_each_of_allnodes(np)
+                       __of_attach_node_sysfs(np);
+               of_aliases = of_find_node_by_path("/aliases");
+               of_chosen = of_find_node_by_path("/chosen");
+               return 0;
+       }
 
        /* attach the sub-tree to live tree */
        return attach_node_and_children(selftest_data_node);
@@ -723,6 +733,18 @@ static void selftest_data_remove(void)
        struct device_node *np;
        struct property *prop;
 
+       if (selftest_live_tree) {
+               of_node_put(of_aliases);
+               of_node_put(of_chosen);
+               of_aliases = NULL;
+               of_chosen = NULL;
+               for_each_child_of_node(of_allnodes, np)
+                       detach_node_and_children(np);
+               __of_detach_node_sysfs(of_allnodes);
+               of_allnodes = NULL;
+               return;
+       }
+
        while (last_node_index >= 0) {
                if (nodes[last_node_index]) {
                        np = of_find_node_by_path(nodes[last_node_index]->full_name);
index 2d8a4d05d78fc02513fe5a2587e545bc36914f08..8922c376456aee763090296a7045211aaae90839 100644 (file)
@@ -1,9 +1,18 @@
 menu "PCI host controller drivers"
        depends on PCI
 
+config PCI_DRA7XX
+       bool "TI DRA7xx PCIe controller"
+       select PCIE_DW
+       depends on OF && HAS_IOMEM && TI_PIPE3
+       help
+        Enables support for the PCIe controller in the DRA7xx SoC.  There
+        are two instances of PCIe controller in DRA7xx.  This controller can
+        act both as EP and RC.  This reuses the Designware core.
+
 config PCI_MVEBU
        bool "Marvell EBU PCIe controller"
-       depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD
+       depends on ARCH_MVEBU || ARCH_DOVE
        depends on OF
 
 config PCIE_DW
index 0daec7941aba44f30fb17e37857872f2e523fce1..d0e88f114ff93b5e016f7993f012b17ce4ff2631 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
new file mode 100644 (file)
index 0000000..52b34fe
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Kishon Vijay Abraham I <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+/* PCIe controller wrapper DRA7XX configuration registers */
+
+#define        PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN             0x0024
+#define        PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN         0x0028
+#define        ERR_SYS                                         BIT(0)
+#define        ERR_FATAL                                       BIT(1)
+#define        ERR_NONFATAL                                    BIT(2)
+#define        ERR_COR                                         BIT(3)
+#define        ERR_AXI                                         BIT(4)
+#define        ERR_ECRC                                        BIT(5)
+#define        PME_TURN_OFF                                    BIT(8)
+#define        PME_TO_ACK                                      BIT(9)
+#define        PM_PME                                          BIT(10)
+#define        LINK_REQ_RST                                    BIT(11)
+#define        LINK_UP_EVT                                     BIT(12)
+#define        CFG_BME_EVT                                     BIT(13)
+#define        CFG_MSE_EVT                                     BIT(14)
+#define        INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \
+                       ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \
+                       LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT)
+
+#define        PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI              0x0034
+#define        PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI          0x0038
+#define        INTA                                            BIT(0)
+#define        INTB                                            BIT(1)
+#define        INTC                                            BIT(2)
+#define        INTD                                            BIT(3)
+#define        MSI                                             BIT(4)
+#define        LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD)
+
+#define        PCIECTRL_DRA7XX_CONF_DEVICE_CMD                 0x0104
+#define        LTSSM_EN                                        0x1
+
+#define        PCIECTRL_DRA7XX_CONF_PHY_CS                     0x010C
+#define        LINK_UP                                         BIT(16)
+
+struct dra7xx_pcie {
+       void __iomem            *base;
+       struct phy              **phy;
+       int                     phy_count;
+       struct device           *dev;
+       struct pcie_port        pp;
+};
+
+#define to_dra7xx_pcie(x)      container_of((x), struct dra7xx_pcie, pp)
+
+static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset)
+{
+       return readl(pcie->base + offset);
+}
+
+static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->base + offset);
+}
+
+static int dra7xx_pcie_link_up(struct pcie_port *pp)
+{
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+       u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
+
+       return !!(reg & LINK_UP);
+}
+
+static int dra7xx_pcie_establish_link(struct pcie_port *pp)
+{
+       u32 reg;
+       unsigned int retries = 1000;
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+
+       if (dw_pcie_link_up(pp)) {
+               dev_err(pp->dev, "link is already up\n");
+               return 0;
+       }
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
+       reg |= LTSSM_EN;
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+
+       while (retries--) {
+               reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
+               if (reg & LINK_UP)
+                       break;
+               usleep_range(10, 20);
+       }
+
+       if (retries == 0) {
+               dev_err(pp->dev, "link is not up\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
+{
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN,
+                          ~INTERRUPTS);
+       dra7xx_pcie_writel(dra7xx,
+                          PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS);
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI,
+                          ~LEG_EP_INTERRUPTS & ~MSI);
+
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dra7xx_pcie_writel(dra7xx,
+                                  PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI);
+       else
+               dra7xx_pcie_writel(dra7xx,
+                                  PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI,
+                                  LEG_EP_INTERRUPTS);
+}
+
+static void dra7xx_pcie_host_init(struct pcie_port *pp)
+{
+       dw_pcie_setup_rc(pp);
+       dra7xx_pcie_establish_link(pp);
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(pp);
+       dra7xx_pcie_enable_interrupts(pp);
+}
+
+static struct pcie_host_ops dra7xx_pcie_host_ops = {
+       .link_up = dra7xx_pcie_link_up,
+       .host_init = dra7xx_pcie_host_init,
+};
+
+static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+       irq_set_chip_data(irq, domain->host_data);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+       .map = dra7xx_pcie_intx_map,
+};
+
+static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
+{
+       struct device *dev = pp->dev;
+       struct device_node *node = dev->of_node;
+       struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
+
+       if (!pcie_intc_node) {
+               dev_err(dev, "No PCIe Intc node found\n");
+               return PTR_ERR(pcie_intc_node);
+       }
+
+       pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+                                              &intx_domain_ops, pp);
+       if (!pp->irq_domain) {
+               dev_err(dev, "Failed to get a INTx IRQ domain\n");
+               return PTR_ERR(pp->irq_domain);
+       }
+
+       return 0;
+}
+
+static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
+{
+       struct pcie_port *pp = arg;
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+       u32 reg;
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
+
+       switch (reg) {
+       case MSI:
+               dw_handle_msi_irq(pp);
+               break;
+       case INTA:
+       case INTB:
+       case INTC:
+       case INTD:
+               generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
+               break;
+       }
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
+{
+       struct dra7xx_pcie *dra7xx = arg;
+       u32 reg;
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN);
+
+       if (reg & ERR_SYS)
+               dev_dbg(dra7xx->dev, "System Error\n");
+
+       if (reg & ERR_FATAL)
+               dev_dbg(dra7xx->dev, "Fatal Error\n");
+
+       if (reg & ERR_NONFATAL)
+               dev_dbg(dra7xx->dev, "Non Fatal Error\n");
+
+       if (reg & ERR_COR)
+               dev_dbg(dra7xx->dev, "Correctable Error\n");
+
+       if (reg & ERR_AXI)
+               dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n");
+
+       if (reg & ERR_ECRC)
+               dev_dbg(dra7xx->dev, "ECRC Error\n");
+
+       if (reg & PME_TURN_OFF)
+               dev_dbg(dra7xx->dev,
+                       "Power Management Event Turn-Off message received\n");
+
+       if (reg & PME_TO_ACK)
+               dev_dbg(dra7xx->dev,
+                       "Power Management Turn-Off Ack message received\n");
+
+       if (reg & PM_PME)
+               dev_dbg(dra7xx->dev,
+                       "PM Power Management Event message received\n");
+
+       if (reg & LINK_REQ_RST)
+               dev_dbg(dra7xx->dev, "Link Request Reset\n");
+
+       if (reg & LINK_UP_EVT)
+               dev_dbg(dra7xx->dev, "Link-up state change\n");
+
+       if (reg & CFG_BME_EVT)
+               dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n");
+
+       if (reg & CFG_MSE_EVT)
+               dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n");
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg);
+
+       return IRQ_HANDLED;
+}
+
+static int add_pcie_port(struct dra7xx_pcie *dra7xx,
+                         struct platform_device *pdev)
+{
+       int ret;
+       struct pcie_port *pp;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+
+       pp = &dra7xx->pp;
+       pp->dev = dev;
+       pp->ops = &dra7xx_pcie_host_ops;
+
+       pp->irq = platform_get_irq(pdev, 1);
+       if (pp->irq < 0) {
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(&pdev->dev, pp->irq,
+                              dra7xx_pcie_msi_irq_handler, IRQF_SHARED,
+                              "dra7-pcie-msi", pp);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               return ret;
+       }
+
+       if (!IS_ENABLED(CONFIG_PCI_MSI)) {
+               ret = dra7xx_pcie_init_irq_domain(pp);
+               if (ret < 0)
+                       return ret;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics");
+       pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
+       if (!pp->dbi_base)
+               return -ENOMEM;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dra7xx->dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __init dra7xx_pcie_probe(struct platform_device *pdev)
+{
+       u32 reg;
+       int ret;
+       int irq;
+       int i;
+       int phy_count;
+       struct phy **phy;
+       void __iomem *base;
+       struct resource *res;
+       struct dra7xx_pcie *dra7xx;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       char name[10];
+
+       dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
+       if (!dra7xx)
+               return -ENOMEM;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
+                              IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
+       if (ret) {
+               dev_err(dev, "failed to request irq\n");
+               return ret;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf");
+       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+       if (!base)
+               return -ENOMEM;
+
+       phy_count = of_property_count_strings(np, "phy-names");
+       if (phy_count < 0) {
+               dev_err(dev, "unable to find the strings\n");
+               return phy_count;
+       }
+
+       phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL);
+       if (!phy)
+               return -ENOMEM;
+
+       for (i = 0; i < phy_count; i++) {
+               snprintf(name, sizeof(name), "pcie-phy%d", i);
+               phy[i] = devm_phy_get(dev, name);
+               if (IS_ERR(phy[i]))
+                       return PTR_ERR(phy[i]);
+
+               ret = phy_init(phy[i]);
+               if (ret < 0)
+                       goto err_phy;
+
+               ret = phy_power_on(phy[i]);
+               if (ret < 0) {
+                       phy_exit(phy[i]);
+                       goto err_phy;
+               }
+       }
+
+       dra7xx->base = base;
+       dra7xx->phy = phy;
+       dra7xx->dev = dev;
+       dra7xx->phy_count = phy_count;
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(dev, "pm_runtime_get_sync failed\n");
+               goto err_phy;
+       }
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
+       reg &= ~LTSSM_EN;
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+
+       platform_set_drvdata(pdev, dra7xx);
+
+       ret = add_pcie_port(dra7xx, pdev);
+       if (ret < 0)
+               goto err_add_port;
+
+       return 0;
+
+err_add_port:
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+
+err_phy:
+       while (--i >= 0) {
+               phy_power_off(phy[i]);
+               phy_exit(phy[i]);
+       }
+
+       return ret;
+}
+
+static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
+{
+       struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev);
+       struct pcie_port *pp = &dra7xx->pp;
+       struct device *dev = &pdev->dev;
+       int count = dra7xx->phy_count;
+
+       if (pp->irq_domain)
+               irq_domain_remove(pp->irq_domain);
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+       while (count--) {
+               phy_power_off(dra7xx->phy[count]);
+               phy_exit(dra7xx->phy[count]);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id of_dra7xx_pcie_match[] = {
+       { .compatible = "ti,dra7-pcie", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match);
+
+static struct platform_driver dra7xx_pcie_driver = {
+       .remove         = __exit_p(dra7xx_pcie_remove),
+       .driver = {
+               .name   = "dra7-pcie",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_dra7xx_pcie_match,
+       },
+};
+
+module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe);
+
+MODULE_AUTHOR("Kishon Vijay Abraham I <[email protected]>");
+MODULE_DESCRIPTION("TI PCIe controller driver");
+MODULE_LICENSE("GPL v2");
index abd65784618dca13f56960acc051b716ec1bbfd7..0fb0fdb223d5174d6a2e10e750a74194d27a4db6 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
@@ -276,6 +277,7 @@ struct tegra_pcie {
        unsigned int num_supplies;
 
        const struct tegra_pcie_soc_data *soc_data;
+       struct dentry *debugfs;
 };
 
 struct tegra_pcie_port {
@@ -1739,6 +1741,115 @@ static const struct of_device_id tegra_pcie_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
 
+static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct tegra_pcie *pcie = s->private;
+
+       if (list_empty(&pcie->ports))
+               return NULL;
+
+       seq_printf(s, "Index  Status\n");
+
+       return seq_list_start(&pcie->ports, *pos);
+}
+
+static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct tegra_pcie *pcie = s->private;
+
+       return seq_list_next(v, &pcie->ports, pos);
+}
+
+static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
+{
+       bool up = false, active = false;
+       struct tegra_pcie_port *port;
+       unsigned int value;
+
+       port = list_entry(v, struct tegra_pcie_port, list);
+
+       value = readl(port->base + RP_VEND_XP);
+
+       if (value & RP_VEND_XP_DL_UP)
+               up = true;
+
+       value = readl(port->base + RP_LINK_CONTROL_STATUS);
+
+       if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
+               active = true;
+
+       seq_printf(s, "%2u     ", port->index);
+
+       if (up)
+               seq_printf(s, "up");
+
+       if (active) {
+               if (up)
+                       seq_printf(s, ", ");
+
+               seq_printf(s, "active");
+       }
+
+       seq_printf(s, "\n");
+       return 0;
+}
+
+static const struct seq_operations tegra_pcie_ports_seq_ops = {
+       .start = tegra_pcie_ports_seq_start,
+       .next = tegra_pcie_ports_seq_next,
+       .stop = tegra_pcie_ports_seq_stop,
+       .show = tegra_pcie_ports_seq_show,
+};
+
+static int tegra_pcie_ports_open(struct inode *inode, struct file *file)
+{
+       struct tegra_pcie *pcie = inode->i_private;
+       struct seq_file *s;
+       int err;
+
+       err = seq_open(file, &tegra_pcie_ports_seq_ops);
+       if (err)
+               return err;
+
+       s = file->private_data;
+       s->private = pcie;
+
+       return 0;
+}
+
+static const struct file_operations tegra_pcie_ports_ops = {
+       .owner = THIS_MODULE,
+       .open = tegra_pcie_ports_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
+{
+       struct dentry *file;
+
+       pcie->debugfs = debugfs_create_dir("pcie", NULL);
+       if (!pcie->debugfs)
+               return -ENOMEM;
+
+       file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs,
+                                  pcie, &tegra_pcie_ports_ops);
+       if (!file)
+               goto remove;
+
+       return 0;
+
+remove:
+       debugfs_remove_recursive(pcie->debugfs);
+       pcie->debugfs = NULL;
+       return -ENOMEM;
+}
+
 static int tegra_pcie_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
@@ -1793,6 +1904,13 @@ static int tegra_pcie_probe(struct platform_device *pdev)
                goto disable_msi;
        }
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               err = tegra_pcie_debugfs_init(pcie);
+               if (err < 0)
+                       dev_err(&pdev->dev, "failed to setup debugfs: %d\n",
+                               err);
+       }
+
        platform_set_drvdata(pdev, pcie);
        return 0;
 
index 1eaf4df3618a18a57e0eee175272d5a19646f2bf..52bd3a14356310195af1219e74b7e65091da6d88 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pci_regs.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #include "pcie-designware.h"
@@ -217,27 +218,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
        return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val &= ~(1 << bit);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
                            unsigned int nvec, unsigned int pos)
 {
-       unsigned int i, res, bit, val;
+       unsigned int i;
 
        for (i = 0; i < nvec; i++) {
                irq_set_msi_desc_off(irq_base, i, NULL);
                clear_bit(pos + i, pp->msi_irq_in_use);
                /* Disable corresponding interrupt on MSI controller */
-               res = ((pos + i) / 32) * 12;
-               bit = (pos + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val &= ~(1 << bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_clear_irq)
+                       pp->ops->msi_clear_irq(pp, pos + i);
+               else
+                       dw_pcie_msi_clear_irq(pp, pos + i);
        }
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val |= 1 << bit;
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-       int res, bit, irq, pos0, pos1, i;
-       u32 val;
+       int irq, pos0, pos1, i;
        struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
        if (!pp) {
@@ -281,11 +302,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
                }
                set_bit(pos0 + i, pp->msi_irq_in_use);
                /*Enable corresponding interrupt in MSI interrupt controller */
-               res = ((pos0 + i) / 32) * 12;
-               bit = (pos0 + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val |= 1 << bit;
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_set_irq)
+                       pp->ops->msi_set_irq(pp, pos0 + i);
+               else
+                       dw_pcie_msi_set_irq(pp, pos0 + i);
        }
 
        *pos = pos0;
@@ -353,7 +373,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
         */
        desc->msi_attrib.multiple = msgvec;
 
-       msg.address_lo = virt_to_phys((void *)pp->msi_data);
+       if (pp->ops->get_msi_data)
+               msg.address_lo = pp->ops->get_msi_data(pp);
+       else
+               msg.address_lo = virt_to_phys((void *)pp->msi_data);
        msg.address_hi = 0x0;
        msg.data = pos;
        write_msi_msg(irq, &msg);
@@ -396,10 +419,35 @@ static const struct irq_domain_ops msi_domain_ops = {
 int __init dw_pcie_host_init(struct pcie_port *pp)
 {
        struct device_node *np = pp->dev->of_node;
+       struct platform_device *pdev = to_platform_device(pp->dev);
        struct of_pci_range range;
        struct of_pci_range_parser parser;
-       u32 val;
-       int i;
+       struct resource *cfg_res;
+       u32 val, na, ns;
+       const __be32 *addrp;
+       int i, index;
+
+       /* Find the address cell size and the number of cells in order to get
+        * the untranslated address.
+        */
+       of_property_read_u32(np, "#address-cells", &na);
+       ns = of_n_size_cells(np);
+
+       cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+       if (cfg_res) {
+               pp->config.cfg0_size = resource_size(cfg_res)/2;
+               pp->config.cfg1_size = resource_size(cfg_res)/2;
+               pp->cfg0_base = cfg_res->start;
+               pp->cfg1_base = cfg_res->start + pp->config.cfg0_size;
+
+               /* Find the untranslated configuration space address */
+               index = of_property_match_string(np, "reg-names", "config");
+               addrp = of_get_address(np, index, false, false);
+               pp->cfg0_mod_base = of_read_number(addrp, ns);
+               pp->cfg1_mod_base = pp->cfg0_mod_base + pp->config.cfg0_size;
+       } else {
+               dev_err(pp->dev, "missing *config* reg space\n");
+       }
 
        if (of_pci_range_parser_init(&parser, np)) {
                dev_err(pp->dev, "missing ranges property\n");
@@ -422,17 +470,33 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                        pp->config.io_size = resource_size(&pp->io);
                        pp->config.io_bus_addr = range.pci_addr;
                        pp->io_base = range.cpu_addr;
+
+                       /* Find the untranslated IO space address */
+                       pp->io_mod_base = of_read_number(parser.range -
+                                                        parser.np + na, ns);
                }
                if (restype == IORESOURCE_MEM) {
                        of_pci_range_to_resource(&range, np, &pp->mem);
                        pp->mem.name = "MEM";
                        pp->config.mem_size = resource_size(&pp->mem);
                        pp->config.mem_bus_addr = range.pci_addr;
+
+                       /* Find the untranslated MEM space address */
+                       pp->mem_mod_base = of_read_number(parser.range -
+                                                         parser.np + na, ns);
                }
                if (restype == 0) {
                        of_pci_range_to_resource(&range, np, &pp->cfg);
                        pp->config.cfg0_size = resource_size(&pp->cfg)/2;
                        pp->config.cfg1_size = resource_size(&pp->cfg)/2;
+                       pp->cfg0_base = pp->cfg.start;
+                       pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+
+                       /* Find the untranslated configuration space address */
+                       pp->cfg0_mod_base = of_read_number(parser.range -
+                                                          parser.np + na, ns);
+                       pp->cfg1_mod_base = pp->cfg0_mod_base +
+                                           pp->config.cfg0_size;
                }
        }
 
@@ -445,8 +509,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       pp->cfg0_base = pp->cfg.start;
-       pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
        pp->mem_base = pp->mem.start;
 
        pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
@@ -509,9 +571,9 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
        /* Program viewport 0 : OUTBOUND : CFG0 */
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
-       dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->config.cfg0_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -525,9 +587,9 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->config.cfg1_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -540,9 +602,9 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
+       dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->config.mem_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
@@ -556,9 +618,9 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
+       dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->io_mod_base + pp->config.io_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
@@ -656,7 +718,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
        }
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+               if (pp->ops->rd_other_conf)
+                       ret = pp->ops->rd_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_rd_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +745,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
                return PCIBIOS_DEVICE_NOT_FOUND;
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+               if (pp->ops->wr_other_conf)
+                       ret = pp->ops->wr_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_wr_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_wr_own_conf(pp, where, size, val);
index 77f592faa7bf28ee6d86f84cad6ee7cdfd345158..daf81f922cda34e472f4be5c16d5a967f70528da 100644 (file)
@@ -36,11 +36,15 @@ struct pcie_port {
        u8                      root_bus_nr;
        void __iomem            *dbi_base;
        u64                     cfg0_base;
+       u64                     cfg0_mod_base;
        void __iomem            *va_cfg0_base;
        u64                     cfg1_base;
+       u64                     cfg1_mod_base;
        void __iomem            *va_cfg1_base;
        u64                     io_base;
+       u64                     io_mod_base;
        u64                     mem_base;
+       u64                     mem_mod_base;
        struct resource         cfg;
        struct resource         io;
        struct resource         mem;
@@ -61,8 +65,15 @@ struct pcie_host_ops {
                        u32 val, void __iomem *dbi_base);
        int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
        int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+       int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+                       unsigned int devfn, int where, int size, u32 *val);
+       int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+                       unsigned int devfn, int where, int size, u32 val);
        int (*link_up)(struct pcie_port *pp);
        void (*host_init)(struct pcie_port *pp);
+       void (*msi_set_irq)(struct pcie_port *pp, int irq);
+       void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+       u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
index 172f26ce59ac9d2dbf5966a04490065a08ddbaa0..3bbcbf12c1fb7a88899762b417555b88ed08061d 100644 (file)
@@ -652,6 +652,25 @@ config TOSHIBA_BT_RFKILL
          If you have a modern Toshiba laptop with a Bluetooth and an
          RFKill switch (such as the Portege R500), say Y.
 
+config TOSHIBA_HAPS
+       tristate "Toshiba HDD Active Protection Sensor"
+       depends on ACPI
+       ---help---
+         This driver adds support for the built-in accelerometer
+         found on recent Toshiba laptops equiped with HID TOS620A
+         device.
+
+         This driver receives ACPI notify events 0x80 when the sensor
+         detects a sudden move or a harsh vibration, as well as an
+         ACPI notify event 0x81 whenever the movement or vibration has
+         been stabilized.
+
+         Also provides sysfs entries to get/set the desired protection
+         level and reseting the HDD protection interface.
+
+         If you have a recent Toshiba laptop with a built-in accelerometer
+         device, say Y.
+
 config ACPI_CMPC
        tristate "CMPC Laptop Extras"
        depends on X86 && ACPI
index c4ca428fd3db2651706171df439b24b52588e5c0..f82232b1fc4d719491ba5e2550603fed50802e51 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP)  += topstar-laptop.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)        += toshiba_bluetooth.o
+obj-$(CONFIG_TOSHIBA_HAPS)     += toshiba_haps.o
 obj-$(CONFIG_INTEL_SCU_IPC)    += intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
index bbf78b2d6d93f9f020729e3dd07ff210cb048404..96a0b75c52c9a6232c99b18e61751f3eb62e940a 100644 (file)
@@ -96,7 +96,7 @@ enum acer_wmi_event_ids {
        WMID_ACCEL_EVENT = 0x5,
 };
 
-static const struct key_entry acer_wmi_keymap[] = {
+static const struct key_entry acer_wmi_keymap[] __initconst = {
        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
@@ -294,7 +294,7 @@ struct quirk_entry {
 
 static struct quirk_entry *quirks;
 
-static void set_quirks(void)
+static void __init set_quirks(void)
 {
        if (!interface)
                return;
@@ -306,7 +306,7 @@ static void set_quirks(void)
                interface->capability |= ACER_CAP_BRIGHTNESS;
 }
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
@@ -337,7 +337,7 @@ static struct quirk_entry quirk_lenovo_ideapad_s205 = {
 };
 
 /* The Aspire One has a dummy ACPI-WMI interface - disable it */
-static struct dmi_system_id acer_blacklist[] = {
+static const struct dmi_system_id acer_blacklist[] __initconst = {
        {
                .ident = "Acer Aspire One (SSD)",
                .matches = {
@@ -355,7 +355,7 @@ static struct dmi_system_id acer_blacklist[] = {
        {}
 };
 
-static struct dmi_system_id acer_quirks[] = {
+static const struct dmi_system_id acer_quirks[] __initconst = {
        {
                .callback = dmi_matched,
                .ident = "Acer Aspire 1360",
@@ -530,14 +530,15 @@ static struct dmi_system_id acer_quirks[] = {
        {}
 };
 
-static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+static int __init
+video_set_backlight_video_vendor(const struct dmi_system_id *d)
 {
        interface->capability &= ~ACER_CAP_BRIGHTNESS;
        pr_info("Brightness must be controlled by generic video driver\n");
        return 0;
 }
 
-static const struct dmi_system_id video_vendor_dmi_table[] = {
+static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
        {
                .callback = video_set_backlight_video_vendor,
                .ident = "Acer TravelMate 4750",
@@ -582,7 +583,7 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
 };
 
 /* Find which quirks are needed for a particular vendor/ model pair */
-static void find_quirks(void)
+static void __init find_quirks(void)
 {
        if (!force_series) {
                dmi_check_system(acer_quirks);
@@ -749,7 +750,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap)
        return wmab_execute(&args, NULL);
 }
 
-static acpi_status AMW0_find_mailled(void)
+static acpi_status __init AMW0_find_mailled(void)
 {
        struct wmab_args args;
        struct wmab_ret ret;
@@ -781,16 +782,16 @@ static acpi_status AMW0_find_mailled(void)
        return AE_OK;
 }
 
-static int AMW0_set_cap_acpi_check_device_found;
+static int AMW0_set_cap_acpi_check_device_found __initdata;
 
-static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
+static acpi_status __init AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
        u32 level, void *context, void **retval)
 {
        AMW0_set_cap_acpi_check_device_found = 1;
        return AE_OK;
 }
 
-static const struct acpi_device_id norfkill_ids[] = {
+static const struct acpi_device_id norfkill_ids[] __initconst = {
        { "VPC2004", 0},
        { "IBM0068", 0},
        { "LEN0068", 0},
@@ -798,7 +799,7 @@ static const struct acpi_device_id norfkill_ids[] = {
        { "", 0},
 };
 
-static int AMW0_set_cap_acpi_check_device(void)
+static int __init AMW0_set_cap_acpi_check_device(void)
 {
        const struct acpi_device_id *id;
 
@@ -808,7 +809,7 @@ static int AMW0_set_cap_acpi_check_device(void)
        return AMW0_set_cap_acpi_check_device_found;
 }
 
-static acpi_status AMW0_set_capabilities(void)
+static acpi_status __init AMW0_set_capabilities(void)
 {
        struct wmab_args args;
        struct wmab_ret ret;
@@ -1184,7 +1185,7 @@ static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
        return wmid3_set_device_status(value, device);
 }
 
-static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
+static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
 {
        struct hotkey_function_type_aa *type_aa;
 
@@ -1209,7 +1210,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
        commun_fn_key_number = type_aa->commun_fn_key_number;
 }
 
-static acpi_status WMID_set_capabilities(void)
+static acpi_status __init WMID_set_capabilities(void)
 {
        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *obj;
@@ -1658,7 +1659,7 @@ static ssize_t show_bool_threeg(struct device *dev,
        u32 result; \
        acpi_status status;
 
-       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        status = get_u32(&result, ACER_CAP_THREEG);
        if (ACPI_SUCCESS(status))
@@ -1671,7 +1672,7 @@ static ssize_t set_bool_threeg(struct device *dev,
 {
        u32 tmp = simple_strtoul(buf, NULL, 10);
        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        if (ACPI_FAILURE(status))
                return -EINVAL;
@@ -1683,7 +1684,7 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
-       pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        switch (interface->type) {
        case ACER_AMW0:
@@ -1777,7 +1778,7 @@ static void acer_wmi_notify(u32 value, void *context)
        }
 }
 
-static acpi_status
+static acpi_status __init
 wmid3_set_lm_mode(struct lm_input_params *params,
                  struct lm_return_value *return_value)
 {
@@ -1811,7 +1812,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
        return status;
 }
 
-static int acer_wmi_enable_ec_raw(void)
+static int __init acer_wmi_enable_ec_raw(void)
 {
        struct lm_return_value return_value;
        acpi_status status;
@@ -1834,7 +1835,7 @@ static int acer_wmi_enable_ec_raw(void)
        return status;
 }
 
-static int acer_wmi_enable_lm(void)
+static int __init acer_wmi_enable_lm(void)
 {
        struct lm_return_value return_value;
        acpi_status status;
@@ -2043,6 +2044,7 @@ static int acer_platform_remove(struct platform_device *device)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acer_suspend(struct device *dev)
 {
        u32 value;
@@ -2083,6 +2085,10 @@ static int acer_resume(struct device *dev)
 
        return 0;
 }
+#else
+#define acer_suspend   NULL
+#define acer_resume    NULL
+#endif
 
 static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
 
@@ -2120,7 +2126,7 @@ static int remove_sysfs(struct platform_device *device)
        return 0;
 }
 
-static int create_sysfs(void)
+static int __init create_sysfs(void)
 {
        int retval = -ENOMEM;
 
@@ -2149,7 +2155,7 @@ static void remove_debugfs(void)
        debugfs_remove(interface->debug.root);
 }
 
-static int create_debugfs(void)
+static int __init create_debugfs(void)
 {
        interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
        if (!interface->debug.root) {
index 297b6640213f3f7ab45139e835e2ae092517b31a..c5af23b64438514f3d6e95eed62303557be4ff34 100644 (file)
@@ -59,25 +59,33 @@ enum WMAX_CONTROL_STATES {
 
 struct quirk_entry {
        u8 num_zones;
+       u8 hdmi_mux;
 };
 
 static struct quirk_entry *quirks;
 
 static struct quirk_entry quirk_unknown = {
        .num_zones = 2,
+       .hdmi_mux = 0,
 };
 
 static struct quirk_entry quirk_x51_family = {
        .num_zones = 3,
+       .hdmi_mux = 0.
 };
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static struct quirk_entry quirk_asm100 = {
+       .num_zones = 2,
+       .hdmi_mux = 1,
+};
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
 }
 
-static struct dmi_system_id alienware_quirks[] = {
+static const struct dmi_system_id alienware_quirks[] __initconst = {
        {
         .callback = dmi_matched,
         .ident = "Alienware X51 R1",
@@ -96,6 +104,15 @@ static struct dmi_system_id alienware_quirks[] = {
                     },
         .driver_data = &quirk_x51_family,
         },
+       {
+               .callback = dmi_matched,
+               .ident = "Alienware ASM100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
+               },
+               .driver_data = &quirk_asm100,
+       },
        {}
 };
 
@@ -537,7 +554,8 @@ static struct attribute_group hdmi_attribute_group = {
 
 static void remove_hdmi(struct platform_device *dev)
 {
-       sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
+       if (quirks->hdmi_mux > 0)
+               sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
 }
 
 static int create_hdmi(struct platform_device *dev)
@@ -583,7 +601,7 @@ static int __init alienware_wmi_init(void)
        if (ret)
                goto fail_platform_device2;
 
-       if (interface == WMAX) {
+       if (quirks->hdmi_mux > 0) {
                ret = create_hdmi(platform_device);
                if (ret)
                        goto fail_prep_hdmi;
index ddf0eefd862c97b394e084b9433bb579d62c651b..3a4951f46065dc95abf7767572426566027e1381 100644 (file)
@@ -70,17 +70,35 @@ static struct quirk_entry quirk_asus_x55u = {
        .no_display_toggle = true,
 };
 
-static struct quirk_entry quirk_asus_x401u = {
+static struct quirk_entry quirk_asus_wapf4 = {
        .wapf = 4,
 };
 
+static struct quirk_entry quirk_asus_x200ca = {
+       .wapf = 2,
+};
+
 static int dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
 }
 
-static struct dmi_system_id asus_quirks[] = {
+static const struct dmi_system_id asus_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. U32U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
+               },
+               /*
+                * Note this machine has a Brazos APU, and most Brazos Asus
+                * machines need quirk_asus_x55u / wmi_backlight_power but
+                * here acpi-video seems to work fine for backlight control.
+                */
+               .driver_data = &quirk_asus_wapf4,
+       },
        {
                .callback = dmi_matched,
                .ident = "ASUSTeK COMPUTER INC. X401U",
@@ -97,7 +115,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -106,7 +124,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -124,7 +142,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -133,7 +151,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -142,7 +160,25 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X550CC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"),
+               },
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X550CL",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"),
+               },
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -151,7 +187,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -160,7 +196,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -178,7 +214,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -187,7 +223,16 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X75A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X75VBP",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"),
+               },
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -196,7 +241,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -205,7 +250,16 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X200CA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"),
+               },
+               .driver_data = &quirk_asus_x200ca,
        },
        {},
 };
index 3c6ccedc82b6239fdee1bfb6925e0e3b032142c4..21fc932da3a1461d35697cc2ee2c78085128b434 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/platform_device.h>
 #include <linux/thermal.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <acpi/video.h>
 
 #include "asus-wmi.h"
@@ -554,7 +555,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
                        goto error;
        }
 
-       if (wlan_led_presence(asus) && (asus->driver->quirks->wapf == 4)) {
+       if (wlan_led_presence(asus) && (asus->driver->quirks->wapf > 0)) {
                INIT_WORK(&asus->wlan_led_work, wlan_led_update);
 
                asus->wlan_led.name = "asus::wlan";
@@ -884,7 +885,7 @@ static int asus_new_rfkill(struct asus_wmi *asus,
                return -EINVAL;
 
        if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
-                       (asus->driver->quirks->wapf == 4))
+                       (asus->driver->quirks->wapf > 0))
                rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
 
        rfkill_init_sw_state(*rfkill, !result);
@@ -1270,10 +1271,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
        int power;
 
        max = read_brightness_max(asus);
-
-       if (max == -ENODEV)
-               max = 0;
-       else if (max < 0)
+       if (max < 0)
                return max;
 
        power = read_backlight_power(asus);
@@ -1734,6 +1732,7 @@ static int asus_wmi_add(struct platform_device *pdev)
        struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
        struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
        struct asus_wmi *asus;
+       const char *chassis_type;
        acpi_status status;
        int err;
        u32 result;
@@ -1770,6 +1769,11 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_rfkill;
 
+       /* Some Asus desktop boards export an acpi-video backlight interface,
+          stop this from showing up */
+       chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
+       if (chassis_type && !strcmp(chassis_type, "3"))
+               acpi_video_dmi_promote_vendor();
        if (asus->driver->quirks->wmi_backlight_power)
                acpi_video_dmi_promote_vendor();
        if (!acpi_video_backlight_support()) {
index 7297df2ebf503771d080a3467869819d72921b08..26bfd7bb5c1350822b23bb6814dd6784738d91b1 100644 (file)
@@ -1028,7 +1028,7 @@ static int compal_probe(struct platform_device *pdev)
                return err;
 
        hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
-                                                     DRIVER_NAME, data,
+                                                     "compal", data,
                                                      compal_hwmon_groups);
        if (IS_ERR(hwmon_dev)) {
                err = PTR_ERR(hwmon_dev);
index fed4111ac31a6d6fbff0c02a6be563485ccec7dc..233d2ee598a62cdb5c1b05cc0ef77737cb48f98a 100644 (file)
@@ -70,7 +70,7 @@ static struct quirk_entry quirk_dell_vostro_v130 = {
        .touchpad_led = 1,
 };
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
@@ -123,7 +123,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
-static struct dmi_system_id dell_quirks[] = {
+static const struct dmi_system_id dell_quirks[] __initconst = {
        {
                .callback = dmi_matched,
                .ident = "Dell Vostro V130",
@@ -780,7 +780,7 @@ static struct led_classdev touchpad_led = {
        .flags = LED_CORE_SUSPENDRESUME,
 };
 
-static int touchpad_led_init(struct device *dev)
+static int __init touchpad_led_init(struct device *dev)
 {
        return led_classdev_register(dev, &touchpad_led);
 }
index 9b0c57cd1d4a8a9d3c89e8a3aa2e3d1b9758f137..bd533c22be570a736795b2a35a83a7439a1d76d5 100644 (file)
@@ -1053,20 +1053,20 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
        return sprintf(buf, "%d\n", get());
 }
 
-#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get)             \
+#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _get, _set)             \
        static ssize_t show_##_name(struct device *dev,                 \
                                    struct device_attribute *attr,      \
                                    char *buf)                          \
        {                                                               \
-               return show_sys_hwmon(_set, buf);                       \
+               return show_sys_hwmon(_get, buf);                       \
        }                                                               \
        static ssize_t store_##_name(struct device *dev,                \
                                     struct device_attribute *attr,     \
                                     const char *buf, size_t count)     \
        {                                                               \
-               return store_sys_hwmon(_get, buf, count);               \
+               return store_sys_hwmon(_set, buf, count);               \
        }                                                               \
-       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name);
+       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name)
 
 EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
 EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
index 6112933f627834cc1c4561feb68a3edc28492e5e..14fd2ecb06a10de7770c38cadba11091e70be21b 100644 (file)
@@ -145,7 +145,7 @@ static int dmi_matched(const struct dmi_system_id *dmi)
        return 1;
 }
 
-static struct dmi_system_id asus_quirks[] = {
+static const struct dmi_system_id asus_quirks[] = {
        {
                .callback = dmi_matched,
                .ident = "ASUSTeK Computer INC. 1000H",
index e6f336270c2191fd9cd1418f869b5aa4dcc499de..87aa28c4280fe815fa488006c814e026c1c99350 100644 (file)
 #define FUJLAPTOP_DBG_INFO       0x0004
 #define FUJLAPTOP_DBG_TRACE      0x0008
 
-#define dbg_printk(a_dbg_level, format, arg...) \
+#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
        do { if (dbg_level & a_dbg_level) \
                printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
        } while (0)
-#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
-#define vdbg_printk(a_dbg_level, format, arg...) \
-       dbg_printk(a_dbg_level, format, ## arg)
 #else
-#define vdbg_printk(a_dbg_level, format, arg...)
+#define vdbg_printk(a_dbg_level, format, arg...) \
+       do { } while (0)
 #endif
 
 /* Device controlling the backlight and associated keys */
@@ -564,7 +563,7 @@ static struct platform_driver fujitsupf_driver = {
                   }
 };
 
-static void dmi_check_cb_common(const struct dmi_system_id *id)
+static void __init dmi_check_cb_common(const struct dmi_system_id *id)
 {
        pr_info("Identified laptop model '%s'\n", id->ident);
        if (use_alt_lcd_levels == -1) {
@@ -578,7 +577,7 @@ static void dmi_check_cb_common(const struct dmi_system_id *id)
        }
 }
 
-static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
@@ -586,7 +585,7 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
        return 1;
 }
 
-static int dmi_check_cb_s6420(const struct dmi_system_id *id)
+static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
@@ -594,7 +593,7 @@ static int dmi_check_cb_s6420(const struct dmi_system_id *id)
        return 1;
 }
 
-static int dmi_check_cb_p8010(const struct dmi_system_id *id)
+static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_HELP;   /* "Support" */
@@ -603,7 +602,7 @@ static int dmi_check_cb_p8010(const struct dmi_system_id *id)
        return 1;
 }
 
-static struct dmi_system_id fujitsu_dmi_table[] = {
+static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
        {
         .ident = "Fujitsu Siemens S6410",
         .matches = {
index c3784baceae3cca2b9d1d32113016f4562f94e48..53bdbb01bd3f375508e888fe43c726127f44ff45 100644 (file)
@@ -315,21 +315,21 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void fujitsu_dmi_common(const struct dmi_system_id *dmi)
+static void __init fujitsu_dmi_common(const struct dmi_system_id *dmi)
 {
        pr_info("%s\n", dmi->ident);
        memcpy(fujitsu.config.keymap, dmi->driver_data,
                        sizeof(fujitsu.config.keymap));
 }
 
-static int fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
+static int __init fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
        return 1;
 }
 
-static int fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
+static int __init fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
index 484a8673b835d17fa2ef4eb3eea2e6853be08b24..4c559640dcbaf4bf0be8eb1e349dc3e5fa567e47 100644 (file)
@@ -295,7 +295,7 @@ static int hp_wmi_tablet_state(void)
        return (state & 0x4) ? 1 : 0;
 }
 
-static int hp_wmi_bios_2009_later(void)
+static int __init hp_wmi_bios_2009_later(void)
 {
        int state = 0;
        int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state,
@@ -704,7 +704,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_postcode);
 }
 
-static int hp_wmi_rfkill_setup(struct platform_device *device)
+static int __init hp_wmi_rfkill_setup(struct platform_device *device)
 {
        int err;
        int wireless = 0;
@@ -806,7 +806,7 @@ register_wifi_error:
        return err;
 }
 
-static int hp_wmi_rfkill2_setup(struct platform_device *device)
+static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
 {
        int err, i;
        struct bios_rfkill2_state state;
index 3dc934438c28f9082144ded5f346f39e3716f4db..13e14ec1d3d7118c4e4ab63ac98a2ef0c1258118 100644 (file)
@@ -74,7 +74,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
 /* HP-specific accelerometer driver ------------------------------------ */
 
 /* For automatic insertion of the module */
-static struct acpi_device_id lis3lv02d_device_ids[] = {
+static const struct acpi_device_id lis3lv02d_device_ids[] = {
        {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
        {"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
        {"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */
@@ -192,7 +192,7 @@ DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
        },                                              \
        .driver_data = &lis3lv02d_axis_##_axis          \
 }
-static struct dmi_system_id lis3lv02d_dmi_ids[] = {
+static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
        /* product names are truncated to match all kinds of a same model */
        AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
        AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
index b4c495a62eeca14be5bc0c7a191786deafec205c..fc468a3d95cea3a2f4a8bc260717e6b1c920449d 100644 (file)
@@ -87,6 +87,8 @@ struct ideapad_private {
        struct backlight_device *blightdev;
        struct dentry *debug;
        unsigned long cfg;
+       bool has_hw_rfkill_switch;
+       bool has_touchpad_control;
 };
 
 static bool no_bt_rfkill;
@@ -439,7 +441,7 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
        return supported ? attr->mode : 0;
 }
 
-static struct attribute_group ideapad_attribute_group = {
+static const struct attribute_group ideapad_attribute_group = {
        .is_visible = ideapad_is_visible,
        .attrs = ideapad_attributes
 };
@@ -454,7 +456,7 @@ struct ideapad_rfk_data {
        int type;
 };
 
-const struct ideapad_rfk_data ideapad_rfk_data[] = {
+const const struct ideapad_rfk_data ideapad_rfk_data[] = {
        { "ideapad_wlan",    CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
        { "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
        { "ideapad_3g",        CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
@@ -473,12 +475,14 @@ static struct rfkill_ops ideapad_rfk_ops = {
 
 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
 {
-       unsigned long hw_blocked;
+       unsigned long hw_blocked = 0;
        int i;
 
-       if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
-               return;
-       hw_blocked = !hw_blocked;
+       if (priv->has_hw_rfkill_switch) {
+               if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
+                       return;
+               hw_blocked = !hw_blocked;
+       }
 
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
                if (priv->rfk[i])
@@ -763,6 +767,9 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
 {
        unsigned long value;
 
+       if (!priv->has_touchpad_control)
+               return;
+
        /* Without reading from EC touchpad LED doesn't switch state */
        if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
                /* Some IdeaPads don't really turn off touchpad - they only
@@ -821,14 +828,39 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
        }
 }
 
-/* Blacklist for devices where the ideapad rfkill interface does not work */
-static struct dmi_system_id rfkill_blacklist[] = {
-       /* The Lenovo Yoga 2 11 always reports everything as blocked */
+/*
+ * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
+ * always results in 0 on these models, causing ideapad_laptop to wrongly
+ * report all radios as hardware-blocked.
+ */
+static struct dmi_system_id no_hw_rfkill_list[] = {
        {
-               .ident = "Lenovo Yoga 2 11",
+               .ident = "Lenovo Yoga 2 11 / 13 / Pro",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
+               },
+       },
+       {}
+};
+
+/*
+ * Some models don't offer touchpad ctrl through the ideapad interface, causing
+ * ideapad_sync_touchpad_state to send wrong touchpad enable/disable events.
+ */
+static struct dmi_system_id no_touchpad_ctrl_list[] = {
+       {
+               .ident = "Lenovo Yoga 1 series",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga"),
+               },
+       },
+       {
+               .ident = "Lenovo Yoga 2 11 / 13 / Pro",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
                },
        },
        {}
@@ -856,6 +888,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        priv->cfg = cfg;
        priv->adev = adev;
        priv->platform_device = pdev;
+       priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
+       priv->has_touchpad_control = !dmi_check_system(no_touchpad_ctrl_list);
 
        ret = ideapad_sysfs_init(priv);
        if (ret)
@@ -869,11 +903,17 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        if (ret)
                goto input_failed;
 
-       if (!dmi_check_system(rfkill_blacklist)) {
-               for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
-                       if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
-                               ideapad_register_rfkill(priv, i);
-       }
+       /*
+        * On some models without a hw-switch (the yoga 2 13 at least)
+        * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
+        */
+       if (!priv->has_hw_rfkill_switch)
+               write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
+
+       for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
+               if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
+                       ideapad_register_rfkill(priv, i);
+
        ideapad_sync_rfk_state(priv);
        ideapad_sync_touchpad_state(priv);
 
index a0d1f576cf406e0c292982ca1b29a40ae58f870b..c0242ed13d9eb8127d0056c22b62186367d5581a 100644 (file)
@@ -269,7 +269,7 @@ struct ips_mcp_limits {
 
 /* Max temps are -10 degrees C to avoid PROCHOT# */
 
-struct ips_mcp_limits ips_sv_limits = {
+static struct ips_mcp_limits ips_sv_limits = {
        .mcp_power_limit = 35000,
        .core_power_limit = 29000,
        .mch_power_limit = 20000,
@@ -277,7 +277,7 @@ struct ips_mcp_limits ips_sv_limits = {
        .mch_temp_limit = 90
 };
 
-struct ips_mcp_limits ips_lv_limits = {
+static struct ips_mcp_limits ips_lv_limits = {
        .mcp_power_limit = 25000,
        .core_power_limit = 21000,
        .mch_power_limit = 13000,
@@ -285,7 +285,7 @@ struct ips_mcp_limits ips_lv_limits = {
        .mch_temp_limit = 90
 };
 
-struct ips_mcp_limits ips_ulv_limits = {
+static struct ips_mcp_limits ips_ulv_limits = {
        .mcp_power_limit = 18000,
        .core_power_limit = 14000,
        .mch_power_limit = 11000,
index 9c5a07417b2b4a1e39c68a5998d972bc31e8eda0..26ad9ff12ac59f3dee03495a2e01f9b5489fc808 100644 (file)
@@ -2389,7 +2389,7 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd,
                lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
        }
        for (i = 0; i < LID_RESUME_MAX &&
-                       lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
+                       lid_ctl->attrs[i].attr.name; i++) {
                result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
                if (result)
                        goto liderror;
index d82f196e3cfe7044266b0d022a48f8866fa1dc5a..3bbc6eb60de56d5ebb55daa80b183f8296520325 100644 (file)
@@ -3174,7 +3174,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                KEY_UNKNOWN,
 
                /* Extra keys in use since the X240 / T440 / T540 */
-               KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER,
+               KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE,
                },
        };
 
@@ -6144,7 +6144,7 @@ static int brightness_set(unsigned int value)
 {
        int res;
 
-       if (value > bright_maxlvl || value < 0)
+       if (value > bright_maxlvl)
                return -EINVAL;
 
        vdbg_printk(TPACPI_DBG_BRGHT,
@@ -6860,7 +6860,7 @@ static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
        return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
 }
 
-static struct snd_kcontrol_new volume_alsa_control_vol = {
+static struct snd_kcontrol_new volume_alsa_control_vol __initdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Volume",
        .index = 0,
@@ -6869,7 +6869,7 @@ static struct snd_kcontrol_new volume_alsa_control_vol = {
        .get = volume_alsa_vol_get,
 };
 
-static struct snd_kcontrol_new volume_alsa_control_mute = {
+static struct snd_kcontrol_new volume_alsa_control_mute __initdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Switch",
        .index = 0,
index 76441dcbe5ffcd83abbecbedbfd91852b5301c67..b062d3d7b37304e9e724fd869419febfae522c19 100644 (file)
@@ -222,6 +222,12 @@ static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
                },
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
+               },
+       },
        {}
 };
 
@@ -229,6 +235,7 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
        { KE_KEY, 0x157, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
+       { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
        { KE_KEY, 0x139, { KEY_ZOOMRESET } },
        { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
@@ -872,7 +879,9 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
 
 static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
 {
-       u32 hci_result;
+       u32 in[HCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status;
 
        if (dev->tr_backlight_supported) {
                bool enable = !value;
@@ -883,9 +892,20 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
                        value--;
        }
 
-       value = value << HCI_LCD_BRIGHTNESS_SHIFT;
-       hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT;
+       status = hci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+               pr_err("ACPI call to set brightness failed");
+               return -EIO;
+       }
+       /* Extra check for "incomplete" backlight method, where the AML code
+        * doesn't check for HCI_SET or HCI_GET and returns HCI_SUCCESS,
+        * the actual brightness, and in some cases the max brightness.
+        */
+       if (out[2] > 0  || out[3] == 0xE000)
+               return -ENODEV;
+
+       return out[0] == HCI_SUCCESS ? 0 : -EIO;
 }
 
 static int set_lcd_status(struct backlight_device *bd)
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
new file mode 100644 (file)
index 0000000..65300b6
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Toshiba HDD Active Protection Sensor (HAPS) driver
+ *
+ * Copyright (C) 2014 Azael Avalos <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+
+MODULE_AUTHOR("Azael Avalos <[email protected]>");
+MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
+MODULE_LICENSE("GPL");
+
+struct toshiba_haps_dev {
+       struct acpi_device *acpi_dev;
+
+       int protection_level;
+};
+
+static struct toshiba_haps_dev *toshiba_haps;
+
+/* HAPS functions */
+static int toshiba_haps_reset_protection(acpi_handle handle)
+{
+       acpi_status status;
+
+       status = acpi_evaluate_object(handle, "RSSS", NULL, NULL);
+       if (ACPI_FAILURE(status)) {
+               pr_err("Unable to reset the HDD protection\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int toshiba_haps_protection_level(acpi_handle handle, int level)
+{
+       acpi_status status;
+
+       status = acpi_execute_simple_method(handle, "PTLV", level);
+       if (ACPI_FAILURE(status)) {
+               pr_err("Error while setting the protection level\n");
+               return -EIO;
+       }
+
+       pr_info("HDD protection level set to: %d\n", level);
+
+       return 0;
+}
+
+/* sysfs files */
+static ssize_t protection_level_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%i\n", haps->protection_level);
+}
+
+static ssize_t protection_level_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+       int level, ret;
+
+       if (sscanf(buf, "%d", &level) != 1 || level < 0 || level > 3)
+               return -EINVAL;
+
+       /* Set the sensor level.
+        * Acceptable levels are:
+        * 0 - Disabled | 1 - Low | 2 - Medium | 3 - High
+        */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle, level);
+       if (ret != 0)
+               return ret;
+
+       haps->protection_level = level;
+
+       return count;
+}
+
+static ssize_t reset_protection_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+       int reset, ret;
+
+       if (sscanf(buf, "%d", &reset) != 1 || reset != 1)
+               return -EINVAL;
+
+       /* Reset the protection interface */
+       ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
+       if (ret != 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(protection_level, S_IRUGO | S_IWUSR,
+                  protection_level_show, protection_level_store);
+static DEVICE_ATTR(reset_protection, S_IWUSR, NULL, reset_protection_store);
+
+static struct attribute *haps_attributes[] = {
+       &dev_attr_protection_level.attr,
+       &dev_attr_reset_protection.attr,
+       NULL,
+};
+
+static struct attribute_group haps_attr_group = {
+       .attrs = haps_attributes,
+};
+
+/*
+ * ACPI stuff
+ */
+static void toshiba_haps_notify(struct acpi_device *device, u32 event)
+{
+       pr_info("Received event: 0x%x", event);
+
+       acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                       dev_name(&device->dev),
+                                       event, 0);
+}
+
+static int toshiba_haps_remove(struct acpi_device *device)
+{
+       sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
+
+       if (toshiba_haps)
+               toshiba_haps = NULL;
+
+       return 0;
+}
+
+/* Helper function */
+static int toshiba_haps_available(acpi_handle handle)
+{
+       acpi_status status;
+       u64 hdd_present;
+
+       /*
+        * A non existent device as well as having (only)
+        * Solid State Drives can cause the call to fail.
+        */
+       status = acpi_evaluate_integer(handle, "_STA", NULL,
+                                      &hdd_present);
+       if (ACPI_FAILURE(status) || !hdd_present) {
+               pr_info("HDD protection not available or using SSD\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int toshiba_haps_add(struct acpi_device *acpi_dev)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       if (toshiba_haps)
+               return -EBUSY;
+
+       if (!toshiba_haps_available(acpi_dev->handle))
+               return -ENODEV;
+
+       pr_info("Toshiba HDD Active Protection Sensor device\n");
+
+       haps = kzalloc(sizeof(struct toshiba_haps_dev), GFP_KERNEL);
+       if (!haps)
+               return -ENOMEM;
+
+       haps->acpi_dev = acpi_dev;
+       haps->protection_level = 2;
+       acpi_dev->driver_data = haps;
+       dev_set_drvdata(&acpi_dev->dev, haps);
+
+       /* Set the protection level, currently at level 2 (Medium) */
+       ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
+       if (ret != 0)
+               return ret;
+
+       ret = sysfs_create_group(&acpi_dev->dev.kobj, &haps_attr_group);
+       if (ret)
+               return ret;
+
+       toshiba_haps = haps;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int toshiba_haps_suspend(struct device *device)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       haps = acpi_driver_data(to_acpi_device(device));
+
+       /* Deactivate the protection on suspend */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
+
+       return ret;
+}
+
+static int toshiba_haps_resume(struct device *device)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       haps = acpi_driver_data(to_acpi_device(device));
+
+       /* Set the stored protection level */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
+                                           haps->protection_level);
+
+       /* Reset the protection on resume */
+       ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
+       if (ret != 0)
+               return ret;
+
+       return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(toshiba_haps_pm,
+                        toshiba_haps_suspend, toshiba_haps_resume);
+
+static const struct acpi_device_id haps_device_ids[] = {
+       {"TOS620A", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, haps_device_ids);
+
+static struct acpi_driver toshiba_haps_driver = {
+       .name = "Toshiba HAPS",
+       .owner = THIS_MODULE,
+       .ids = haps_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+       .ops = {
+               .add =          toshiba_haps_add,
+               .remove =       toshiba_haps_remove,
+               .notify =       toshiba_haps_notify,
+       },
+       .drv.pm = &toshiba_haps_pm,
+};
+
+module_acpi_driver(toshiba_haps_driver);
index 43d13295e63d53a50b62dae995d3a63b7e112a3a..737e56d46f61950826419bbef2d9fb66d69abcc1 100644 (file)
@@ -256,10 +256,6 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
        block = &wblock->gblock;
        handle = wblock->handle;
 
-       if (!block)
-               return AE_NOT_EXIST;
-
-
        snprintf(method, 5, "WE%02X", block->notify_id);
        status = acpi_execute_simple_method(handle, method, enable);
 
index f9f3a1224dfa94339e81f5db92c879af049d5d57..ea025e4806b61bb53471e79765bb3c165e31eb8f 100644 (file)
@@ -2097,7 +2097,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
                                  conn->ping_timeout, conn->recv_timeout,
                                  last_recv, conn->last_ping, jiffies);
                spin_unlock(&session->frwd_lock);
-               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+               iscsi_conn_failure(conn, ISCSI_ERR_NOP_TIMEDOUT);
                return;
        }
 
index d3a08aea09487e955d51b394b300826183b5c296..7abbf284da1afb7bb1d140a05d48c1f156d37c72 100644 (file)
@@ -526,18 +526,19 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
 {
        struct pm8001_ioctl_payload     *payload;
        DECLARE_COMPLETION_ONSTACK(completion);
-       u8              *ioctlbuffer = NULL;
-       u32             length = 0;
-       u32             ret = 0;
+       u8              *ioctlbuffer;
+       u32             ret;
+       u32             length = 1024 * 5 + sizeof(*payload) - 1;
+
+       if (pm8001_ha->fw_image->size > 4096) {
+               pm8001_ha->fw_status = FAIL_FILE_SIZE;
+               return -EFAULT;
+       }
 
-       length = 1024 * 5 + sizeof(*payload) - 1;
        ioctlbuffer = kzalloc(length, GFP_KERNEL);
-       if (!ioctlbuffer)
+       if (!ioctlbuffer) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
                return -ENOMEM;
-       if ((pm8001_ha->fw_image->size <= 0) ||
-           (pm8001_ha->fw_image->size > 4096)) {
-               ret = FAIL_FILE_SIZE;
-               goto out;
        }
        payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
        memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
@@ -547,6 +548,10 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
        payload->minor_function = 0x1;
        pm8001_ha->nvmd_completion = &completion;
        ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
+       if (ret) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+               goto out;
+       }
        wait_for_completion(&completion);
 out:
        kfree(ioctlbuffer);
@@ -557,35 +562,31 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
 {
        struct pm8001_ioctl_payload     *payload;
        DECLARE_COMPLETION_ONSTACK(completion);
-       u8              *ioctlbuffer = NULL;
-       u32             length = 0;
+       u8              *ioctlbuffer;
        struct fw_control_info  *fwControl;
-       u32             loopNumber, loopcount = 0;
-       u32             sizeRead = 0;
        u32             partitionSize, partitionSizeTmp;
-       u32             ret = 0;
-       u32             partitionNumber = 0;
+       u32             loopNumber, loopcount;
        struct pm8001_fw_image_header *image_hdr;
+       u32             sizeRead = 0;
+       u32             ret = 0;
+       u32             length = 1024 * 16 + sizeof(*payload) - 1;
 
-       length = 1024 * 16 + sizeof(*payload) - 1;
+       if (pm8001_ha->fw_image->size < 28) {
+               pm8001_ha->fw_status = FAIL_FILE_SIZE;
+               return -EFAULT;
+       }
        ioctlbuffer = kzalloc(length, GFP_KERNEL);
-       image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
-       if (!ioctlbuffer)
+       if (!ioctlbuffer) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
                return -ENOMEM;
-       if (pm8001_ha->fw_image->size < 28) {
-               ret = FAIL_FILE_SIZE;
-               goto out;
        }
-
+       image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
        while (sizeRead < pm8001_ha->fw_image->size) {
                partitionSizeTmp =
                        *(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
                partitionSize = be32_to_cpu(partitionSizeTmp);
-               loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE;
-               if (loopcount % IOCTL_BUF_SIZE)
-                       loopcount++;
-               if (loopcount == 0)
-                       loopcount++;
+               loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,
+                                       IOCTL_BUF_SIZE);
                for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
                        payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
                        payload->length = 1024*16;
@@ -617,18 +618,18 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
 
                pm8001_ha->nvmd_completion = &completion;
                ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
-               if (ret)
-                       break;
+               if (ret) {
+                       pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+                       goto out;
+               }
                wait_for_completion(&completion);
                if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {
-                       ret = fwControl->retcode;
-                       break;
+                       pm8001_ha->fw_status = fwControl->retcode;
+                       ret = -EFAULT;
+                       goto out;
+               }
                }
        }
-       if (ret)
-               break;
-       partitionNumber++;
-}
 out:
        kfree(ioctlbuffer);
        return ret;
@@ -643,22 +644,29 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
        char *cmd_ptr, *filename_ptr;
        int res, i;
        int flash_command = FLASH_CMD_NONE;
-       int err = 0;
+       int ret;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+       /* this test protects us from running two flash processes at once,
+        * so we should start with this test */
+       if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)
+               return -EINPROGRESS;
+       pm8001_ha->fw_status = FLASH_IN_PROGRESS;
 
+       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
        if (!cmd_ptr) {
-               err = FAIL_OUT_MEMORY;
-               goto out;
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+               return -ENOMEM;
        }
 
        filename_ptr = cmd_ptr + count;
        res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
        if (res != 2) {
-               err = FAIL_PARAMETERS;
-               goto out1;
+               pm8001_ha->fw_status = FAIL_PARAMETERS;
+               ret = -EINVAL;
+               goto out;
        }
 
        for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
@@ -669,50 +677,38 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
                }
        }
        if (flash_command == FLASH_CMD_NONE) {
-               err = FAIL_PARAMETERS;
-               goto out1;
+               pm8001_ha->fw_status = FAIL_PARAMETERS;
+               ret = -EINVAL;
+               goto out;
        }
 
-       if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) {
-               err = FLASH_IN_PROGRESS;
-               goto out1;
-       }
-       err = request_firmware(&pm8001_ha->fw_image,
+       ret = request_firmware(&pm8001_ha->fw_image,
                               filename_ptr,
                               pm8001_ha->dev);
 
-       if (err) {
+       if (ret) {
                PM8001_FAIL_DBG(pm8001_ha,
-                       pm8001_printk("Failed to load firmware image file %s,"
-                       " error %d\n", filename_ptr, err));
-               err = FAIL_OPEN_BIOS_FILE;
-               goto out1;
+                       pm8001_printk(
+                       "Failed to load firmware image file %s, error %d\n",
+                       filename_ptr, ret));
+               pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;
+               goto out;
        }
 
-       switch (flash_command) {
-       case FLASH_CMD_UPDATE:
-               pm8001_ha->fw_status = FLASH_IN_PROGRESS;
-               err = pm8001_update_flash(pm8001_ha);
-               break;
-       case FLASH_CMD_SET_NVMD:
-               pm8001_ha->fw_status = FLASH_IN_PROGRESS;
-               err = pm8001_set_nvmd(pm8001_ha);
-               break;
-       default:
-               pm8001_ha->fw_status = FAIL_PARAMETERS;
-               err = FAIL_PARAMETERS;
-               break;
-       }
+       if (FLASH_CMD_UPDATE == flash_command)
+               ret = pm8001_update_flash(pm8001_ha);
+       else
+               ret = pm8001_set_nvmd(pm8001_ha);
+
        release_firmware(pm8001_ha->fw_image);
-out1:
-       kfree(cmd_ptr);
 out:
-       pm8001_ha->fw_status = err;
+       kfree(cmd_ptr);
 
-       if (!err)
-               return count;
-       else
-               return -err;
+       if (ret)
+               return ret;
+
+       pm8001_ha->fw_status = FLASH_OK;
+       return count;
 }
 
 static ssize_t pm8001_show_update_fw(struct device *cdev,
index 173831016f5f6d3093959d934e0fe598f19b6ffa..dd12c6fe57a67227d51138c8fd7498530078d188 100644 (file)
@@ -4824,7 +4824,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
        rc = pm8001_tag_alloc(pm8001_ha, &tag);
        if (rc) {
                kfree(fw_control_context);
-               return rc;
+               return -EBUSY;
        }
        ccb = &pm8001_ha->ccb_info[tag];
        ccb->fw_control_context = fw_control_context;
@@ -4946,7 +4946,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
        rc = pm8001_tag_alloc(pm8001_ha, &tag);
        if (rc) {
                kfree(fw_control_context);
-               return rc;
+               return -EBUSY;
        }
        ccb = &pm8001_ha->ccb_info[tag];
        ccb->fw_control_context = fw_control_context;
index e49623a897a733d778ca24f8f80a49db16b4aa31..666bf5af06e2d29d26fae7b563a111740c14c9ce 100644 (file)
@@ -748,34 +748,35 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
                sizeof(pm8001_ha->msix_entries[0]);
        for (i = 0; i < max_entry ; i++)
                pm8001_ha->msix_entries[i].entry = i;
-       rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries,
+       rc = pci_enable_msix_exact(pm8001_ha->pdev, pm8001_ha->msix_entries,
                number_of_intr);
        pm8001_ha->number_of_intr = number_of_intr;
-       if (!rc) {
-               PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
-                       "pci_enable_msix request ret:%d no of intr %d\n",
-                                       rc, pm8001_ha->number_of_intr));
+       if (rc)
+               return rc;
 
+       PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
+               "pci_enable_msix_exact request ret:%d no of intr %d\n",
+                               rc, pm8001_ha->number_of_intr));
 
-               for (i = 0; i < number_of_intr; i++) {
-                       snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
-                                       DRV_NAME"%d", i);
-                       pm8001_ha->irq_vector[i].irq_id = i;
-                       pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
+       for (i = 0; i < number_of_intr; i++) {
+               snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
+                               DRV_NAME"%d", i);
+               pm8001_ha->irq_vector[i].irq_id = i;
+               pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
 
-                       rc = request_irq(pm8001_ha->msix_entries[i].vector,
-                               pm8001_interrupt_handler_msix, flag,
-                               intr_drvname[i], &(pm8001_ha->irq_vector[i]));
-                       if (rc) {
-                               for (j = 0; j < i; j++)
-                                       free_irq(
-                                       pm8001_ha->msix_entries[j].vector,
+               rc = request_irq(pm8001_ha->msix_entries[i].vector,
+                       pm8001_interrupt_handler_msix, flag,
+                       intr_drvname[i], &(pm8001_ha->irq_vector[i]));
+               if (rc) {
+                       for (j = 0; j < i; j++) {
+                               free_irq(pm8001_ha->msix_entries[j].vector,
                                        &(pm8001_ha->irq_vector[i]));
-                               pci_disable_msix(pm8001_ha->pdev);
-                               break;
                        }
+                       pci_disable_msix(pm8001_ha->pdev);
+                       break;
                }
        }
+
        return rc;
 }
 #endif
index 6f12f859b11db787e3b8add134f4d7515cf5ecf4..4180d6d9fe782460d1e09b8d5aa70b9a003c862a 100644 (file)
@@ -334,6 +334,12 @@ void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha)
        /* Allocate memory for saving the template */
        md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size,
                                    &md_tmp_dma, GFP_KERNEL);
+       if (!md_tmp) {
+               ql4_printk(KERN_INFO, ha,
+                          "scsi%ld: Failed to allocate DMA memory\n",
+                          ha->host_no);
+               return;
+       }
 
        /* Request template */
        status =  qla4xxx_get_minidump_template(ha, md_tmp_dma);
index fdfae79924ac1df54e6c3b7e66e7afc53fff0736..c291fdff1b338a2ff0ec50930f82298dab279e07 100644 (file)
@@ -1620,8 +1620,8 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
                goto exit_get_chap;
        }
 
-       strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
-       strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+       strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+       strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
        chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
 
 exit_get_chap:
@@ -1663,8 +1663,8 @@ int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, char *password,
        else
                chap_table->flags |= BIT_7; /* local */
        chap_table->secret_len = strlen(password);
-       strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN);
-       strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN);
+       strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN - 1);
+       strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN - 1);
        chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
 
        if (is_qla40XX(ha)) {
@@ -1742,8 +1742,8 @@ int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
                goto exit_unlock_uni_chap;
        }
 
-       strncpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
-       strncpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
+       strlcpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
+       strlcpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
 
        rval = QLA_SUCCESS;
 
@@ -2295,7 +2295,7 @@ int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param)
        if (param == SET_DRVR_VERSION) {
                mbox_cmd[1] = SET_DRVR_VERSION;
                strncpy((char *)&mbox_cmd[2], QLA4XXX_DRIVER_VERSION,
-                       MAX_DRVR_VER_LEN);
+                       MAX_DRVR_VER_LEN - 1);
        } else {
                ql4_printk(KERN_ERR, ha, "%s: invalid parameter 0x%x\n",
                           __func__, param);
index 9dbdb4be2d8f7258a75043738d819dffcd410146..7c3365864242c9aa7367a030c465f3b4cf5925f9 100644 (file)
@@ -4221,7 +4221,7 @@ qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
        for (i = 0; i < QLA_MSIX_ENTRIES; i++)
                entries[i].entry = qla4_8xxx_msix_entries[i].entry;
 
-       ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+       ret = pci_enable_msix_exact(ha->pdev, entries, ARRAY_SIZE(entries));
        if (ret) {
                ql4_printk(KERN_WARNING, ha,
                    "MSI-X: Failed to enable support -- %d/%d\n",
index c5d9564d455ce6ddadd759c884fa13212f09d543..199fcf79a051870c654429c4a9bc92d6baa8b4e5 100644 (file)
@@ -756,9 +756,9 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
                        continue;
 
                chap_rec->chap_tbl_idx = i;
-               strncpy(chap_rec->username, chap_table->name,
+               strlcpy(chap_rec->username, chap_table->name,
                        ISCSI_CHAP_AUTH_NAME_MAX_LEN);
-               strncpy(chap_rec->password, chap_table->secret,
+               strlcpy(chap_rec->password, chap_table->secret,
                        QL4_CHAP_MAX_SECRET_LEN);
                chap_rec->password_length = chap_table->secret_len;
 
@@ -1050,6 +1050,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
        if (!ql_iscsi_stats) {
                ql4_printk(KERN_ERR, ha,
                           "Unable to allocate memory for iscsi stats\n");
+               ret = -ENOMEM;
                goto exit_host_stats;
        }
 
@@ -1058,6 +1059,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
        if (ret != QLA_SUCCESS) {
                ql4_printk(KERN_ERR, ha,
                           "Unable to retrieve iscsi stats\n");
+               ret = -EIO;
                goto exit_host_stats;
        }
        host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames);
@@ -6027,8 +6029,8 @@ static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
                if (!(chap_table->flags & BIT_6)) /* Not BIDI */
                        continue;
 
-               strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
-               strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+               strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+               strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
                ret = 0;
                break;
        }
@@ -6258,8 +6260,8 @@ static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
 
        tddb->tpgt = sess->tpgt;
        tddb->port = conn->persistent_port;
-       strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
-       strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
+       strlcpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
+       strlcpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
 }
 
 static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
@@ -7764,7 +7766,7 @@ static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
                goto exit_ddb_logout;
        }
 
-       strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
+       strlcpy(flash_tddb->iscsi_name, fnode_sess->targetname,
                ISCSI_NAME_SIZE);
 
        if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
index df3306019a7eeaf2009411ba0328dc7450fc6034..d81f3cc43ff1d3e834fcb6d2dc6460810d167ee8 100644 (file)
@@ -377,6 +377,10 @@ scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
                pool->slab_flags |= SLAB_CACHE_DMA;
                pool->gfp_mask = __GFP_DMA;
        }
+
+       if (hostt->cmd_size)
+               hostt->cmd_pool = pool;
+
        return pool;
 }
 
@@ -421,8 +425,10 @@ out:
 out_free_slab:
        kmem_cache_destroy(pool->cmd_slab);
 out_free_pool:
-       if (hostt->cmd_size)
+       if (hostt->cmd_size) {
                scsi_free_host_cmd_pool(pool);
+               hostt->cmd_pool = NULL;
+       }
        goto out;
 }
 
@@ -444,8 +450,10 @@ static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
        if (!--pool->users) {
                kmem_cache_destroy(pool->cmd_slab);
                kmem_cache_destroy(pool->sense_slab);
-               if (hostt->cmd_size)
+               if (hostt->cmd_size) {
                        scsi_free_host_cmd_pool(pool);
+                       hostt->cmd_pool = NULL;
+               }
        }
        mutex_unlock(&host_cmd_pool_mutex);
 }
index 9c44392b748ff88044eeec12eb4dcdb6615e398c..ce62e8798cc80da072b452bced0a26fb44b5eb11 100644 (file)
@@ -1774,7 +1774,7 @@ static void scsi_request_fn(struct request_queue *q)
        blk_requeue_request(q, req);
        atomic_dec(&sdev->device_busy);
 out_delay:
-       if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev))
+       if (!atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev))
                blk_delay_queue(q, SCSI_QUEUE_DELAY);
 }
 
index b481e62a12cc96945a937972f5c12ebaca488819..67d43e35693df9e9e119bb6a4c2faac56f1bc260 100644 (file)
@@ -3429,7 +3429,7 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
        char *buf;
 
        if (!transport->get_host_stats)
-               return -EINVAL;
+               return -ENOSYS;
 
        priv = iscsi_if_transport_lookup(transport);
        if (!priv)
@@ -3467,6 +3467,10 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                memset(buf, 0, host_stats_size);
 
                err = transport->get_host_stats(shost, buf, host_stats_size);
+               if (err) {
+                       kfree_skb(skbhost_stats);
+                       goto exit_host_stats;
+               }
 
                actual_size = nlmsg_total_size(sizeof(*ev) + host_stats_size);
                skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size));
index 4e76fe863fc4561933e09a646183038bde22d61b..d8dcf36aed11ec5250b8e710cd2796544fac5d23 100644 (file)
@@ -1006,7 +1006,7 @@ static int port_detect \
           sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
-      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %llu.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
    for (i = 0; i <= sh[j]->max_channel; i++)
@@ -1285,7 +1285,7 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct
    cpp->cpp_index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
 
-   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%llu.\n",
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%u.\n",
                         BN(j), i, SCpnt->device->channel, SCpnt->device->id,
                         (u8)SCpnt->device->lun);
 
index bd7ec2cc2674d73ab71405769ce53b922a0c0082..ae635872affb4b9a3fa993652cfad3009894532a 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -192,7 +192,6 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
        }
 
        file->f_flags = O_RDWR;
-       file->private_data = ctx;
        return file;
 }
 
@@ -202,7 +201,7 @@ static struct dentry *aio_mount(struct file_system_type *fs_type,
        static const struct dentry_operations ops = {
                .d_dname        = simple_dname,
        };
-       return mount_pseudo(fs_type, "aio:", NULL, &ops, 0xa10a10a1);
+       return mount_pseudo(fs_type, "aio:", NULL, &ops, AIO_RING_MAGIC);
 }
 
 /* aio_setup
@@ -556,8 +555,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
        struct aio_ring *ring;
 
        spin_lock(&mm->ioctx_lock);
-       rcu_read_lock();
-       table = rcu_dereference(mm->ioctx_table);
+       table = rcu_dereference_raw(mm->ioctx_table);
 
        while (1) {
                if (table)
@@ -565,7 +563,6 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                                if (!table->table[i]) {
                                        ctx->id = i;
                                        table->table[i] = ctx;
-                                       rcu_read_unlock();
                                        spin_unlock(&mm->ioctx_lock);
 
                                        /* While kioctx setup is in progress,
@@ -579,8 +576,6 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                                }
 
                new_nr = (table ? table->nr : 1) * 4;
-
-               rcu_read_unlock();
                spin_unlock(&mm->ioctx_lock);
 
                table = kzalloc(sizeof(*table) + sizeof(struct kioctx *) *
@@ -591,8 +586,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                table->nr = new_nr;
 
                spin_lock(&mm->ioctx_lock);
-               rcu_read_lock();
-               old = rcu_dereference(mm->ioctx_table);
+               old = rcu_dereference_raw(mm->ioctx_table);
 
                if (!old) {
                        rcu_assign_pointer(mm->ioctx_table, table);
@@ -739,12 +733,9 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
 
 
        spin_lock(&mm->ioctx_lock);
-       rcu_read_lock();
-       table = rcu_dereference(mm->ioctx_table);
-
+       table = rcu_dereference_raw(mm->ioctx_table);
        WARN_ON(ctx != table->table[ctx->id]);
        table->table[ctx->id] = NULL;
-       rcu_read_unlock();
        spin_unlock(&mm->ioctx_lock);
 
        /* percpu_ref_kill() will do the necessary call_rcu() */
@@ -793,40 +784,30 @@ EXPORT_SYMBOL(wait_on_sync_kiocb);
  */
 void exit_aio(struct mm_struct *mm)
 {
-       struct kioctx_table *table;
-       struct kioctx *ctx;
-       unsigned i = 0;
-
-       while (1) {
-               rcu_read_lock();
-               table = rcu_dereference(mm->ioctx_table);
-
-               do {
-                       if (!table || i >= table->nr) {
-                               rcu_read_unlock();
-                               rcu_assign_pointer(mm->ioctx_table, NULL);
-                               if (table)
-                                       kfree(table);
-                               return;
-                       }
+       struct kioctx_table *table = rcu_dereference_raw(mm->ioctx_table);
+       int i;
 
-                       ctx = table->table[i++];
-               } while (!ctx);
+       if (!table)
+               return;
 
-               rcu_read_unlock();
+       for (i = 0; i < table->nr; ++i) {
+               struct kioctx *ctx = table->table[i];
 
+               if (!ctx)
+                       continue;
                /*
-                * We don't need to bother with munmap() here -
-                * exit_mmap(mm) is coming and it'll unmap everything.
-                * Since aio_free_ring() uses non-zero ->mmap_size
-                * as indicator that it needs to unmap the area,
-                * just set it to 0; aio_free_ring() is the only
-                * place that uses ->mmap_size, so it's safe.
+                * We don't need to bother with munmap() here - exit_mmap(mm)
+                * is coming and it'll unmap everything. And we simply can't,
+                * this is not necessarily our ->mm.
+                * Since kill_ioctx() uses non-zero ->mmap_size as indicator
+                * that it needs to unmap the area, just set it to 0.
                 */
                ctx->mmap_size = 0;
-
                kill_ioctx(mm, ctx, NULL);
        }
+
+       RCU_INIT_POINTER(mm->ioctx_table, NULL);
+       kfree(table);
 }
 
 static void put_reqs_available(struct kioctx *ctx, unsigned nr)
@@ -834,10 +815,8 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr)
        struct kioctx_cpu *kcpu;
        unsigned long flags;
 
-       preempt_disable();
-       kcpu = this_cpu_ptr(ctx->cpu);
-
        local_irq_save(flags);
+       kcpu = this_cpu_ptr(ctx->cpu);
        kcpu->reqs_available += nr;
 
        while (kcpu->reqs_available >= ctx->req_batch * 2) {
@@ -846,7 +825,6 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr)
        }
 
        local_irq_restore(flags);
-       preempt_enable();
 }
 
 static bool get_reqs_available(struct kioctx *ctx)
@@ -855,10 +833,8 @@ static bool get_reqs_available(struct kioctx *ctx)
        bool ret = false;
        unsigned long flags;
 
-       preempt_disable();
-       kcpu = this_cpu_ptr(ctx->cpu);
-
        local_irq_save(flags);
+       kcpu = this_cpu_ptr(ctx->cpu);
        if (!kcpu->reqs_available) {
                int old, avail = atomic_read(&ctx->reqs_available);
 
@@ -878,7 +854,6 @@ static bool get_reqs_available(struct kioctx *ctx)
        kcpu->reqs_available--;
 out:
        local_irq_restore(flags);
-       preempt_enable();
        return ret;
 }
 
@@ -1047,7 +1022,7 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 }
 EXPORT_SYMBOL(aio_complete);
 
-/* aio_read_events
+/* aio_read_events_ring
  *     Pull an event off of the ioctx's event ring.  Returns the number of
  *     events fetched
  */
@@ -1270,12 +1245,12 @@ static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
        if (compat)
                ret = compat_rw_copy_check_uvector(rw,
                                (struct compat_iovec __user *)buf,
-                               *nr_segs, 1, *iovec, iovec);
+                               *nr_segs, UIO_FASTIOV, *iovec, iovec);
        else
 #endif
                ret = rw_copy_check_uvector(rw,
                                (struct iovec __user *)buf,
-                               *nr_segs, 1, *iovec, iovec);
+                               *nr_segs, UIO_FASTIOV, *iovec, iovec);
        if (ret < 0)
                return ret;
 
@@ -1299,9 +1274,8 @@ static ssize_t aio_setup_single_vector(struct kiocb *kiocb,
 }
 
 /*
- * aio_setup_iocb:
- *     Performs the initial checks and aio retry method
- *     setup for the kiocb at the time of io submission.
+ * aio_run_iocb:
+ *     Performs the initial checks and io submission.
  */
 static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
                            char __user *buf, bool compat)
@@ -1313,7 +1287,7 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
        fmode_t mode;
        aio_rw_op *rw_op;
        rw_iter_op *iter_op;
-       struct iovec inline_vec, *iovec = &inline_vec;
+       struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
        struct iov_iter iter;
 
        switch (opcode) {
@@ -1348,7 +1322,7 @@ rw_common:
                if (!ret)
                        ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
                if (ret < 0) {
-                       if (iovec != &inline_vec)
+                       if (iovec != inline_vecs)
                                kfree(iovec);
                        return ret;
                }
@@ -1395,7 +1369,7 @@ rw_common:
                return -EINVAL;
        }
 
-       if (iovec != &inline_vec)
+       if (iovec != inline_vecs)
                kfree(iovec);
 
        if (ret != -EIOCBQUEUED) {
index e25564bfcb463383e94eba0ce7f2f3769898afe7..54a201dac7f9455bd1e294c2731d5b47226b7bef 100644 (file)
@@ -276,9 +276,8 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                        }
                        if (ret > 0)
                                goto next;
-                       ret = ulist_add_merge(parents, eb->start,
-                                             (uintptr_t)eie,
-                                             (u64 *)&old, GFP_NOFS);
+                       ret = ulist_add_merge_ptr(parents, eb->start,
+                                                 eie, (void **)&old, GFP_NOFS);
                        if (ret < 0)
                                break;
                        if (!ret && extent_item_pos) {
@@ -1001,16 +1000,19 @@ again:
                                        ret = -EIO;
                                        goto out;
                                }
+                               btrfs_tree_read_lock(eb);
+                               btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
                                ret = find_extent_in_eb(eb, bytenr,
                                                        *extent_item_pos, &eie);
+                               btrfs_tree_read_unlock_blocking(eb);
                                free_extent_buffer(eb);
                                if (ret < 0)
                                        goto out;
                                ref->inode_list = eie;
                        }
-                       ret = ulist_add_merge(refs, ref->parent,
-                                             (uintptr_t)ref->inode_list,
-                                             (u64 *)&eie, GFP_NOFS);
+                       ret = ulist_add_merge_ptr(refs, ref->parent,
+                                                 ref->inode_list,
+                                                 (void **)&eie, GFP_NOFS);
                        if (ret < 0)
                                goto out;
                        if (!ret && extent_item_pos) {
index 4794923c410cec258ae30aa929f3fc0bde5ba069..43527fd78825b690503347426118e09f76017c95 100644 (file)
@@ -84,12 +84,6 @@ struct btrfs_inode {
         */
        struct list_head delalloc_inodes;
 
-       /*
-        * list for tracking inodes that must be sent to disk before a
-        * rename or truncate commit
-        */
-       struct list_head ordered_operations;
-
        /* node for the red-black tree that links inodes in subvolume root */
        struct rb_node rb_node;
 
index aeab453b8e24482cd9f956a87882ea23549921f2..44ee5d2e52a41935828ac954ebeefe8ce17568e6 100644 (file)
@@ -280,9 +280,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
-               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+               ret = btrfs_inc_ref(trans, root, cow, 1);
        else
-               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+               ret = btrfs_inc_ref(trans, root, cow, 0);
 
        if (ret)
                return ret;
@@ -1035,14 +1035,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if ((owner == root->root_key.objectid ||
                     root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
                    !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
-                       ret = btrfs_inc_ref(trans, root, buf, 1, 1);
+                       ret = btrfs_inc_ref(trans, root, buf, 1);
                        BUG_ON(ret); /* -ENOMEM */
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID) {
-                               ret = btrfs_dec_ref(trans, root, buf, 0, 1);
+                               ret = btrfs_dec_ref(trans, root, buf, 0);
                                BUG_ON(ret); /* -ENOMEM */
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                                BUG_ON(ret); /* -ENOMEM */
                        }
                        new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
@@ -1050,9 +1050,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 0);
                        BUG_ON(ret); /* -ENOMEM */
                }
                if (new_flags != 0) {
@@ -1069,11 +1069,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 0);
                        BUG_ON(ret); /* -ENOMEM */
-                       ret = btrfs_dec_ref(trans, root, buf, 1, 1);
+                       ret = btrfs_dec_ref(trans, root, buf, 1);
                        BUG_ON(ret); /* -ENOMEM */
                }
                clean_tree_block(trans, root, buf);
index be91397f4e927de9e88f9e72f5559d8eae2e4d1a..8e29b614fe93d9b8cc22c9eb5d54377d617bb9e7 100644 (file)
@@ -3326,9 +3326,9 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
                         u64 min_alloc_size, u64 empty_size, u64 hint_byte,
                         struct btrfs_key *ins, int is_data, int delalloc);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota);
+                 struct extent_buffer *buf, int full_backref);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota);
+                 struct extent_buffer *buf, int full_backref);
 int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes, u64 flags,
index 08e65e9cf2aa97cb009249f5bf231d07e2c1f890..d0ed9e664f7d4d26c69a12498f80b3ad59809a43 100644 (file)
@@ -60,8 +60,6 @@ static void end_workqueue_fn(struct btrfs_work *work);
 static void free_fs_root(struct btrfs_root *root);
 static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
                                    int read_only);
-static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
-                                            struct btrfs_root *root);
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                      struct btrfs_root *root);
@@ -3829,34 +3827,6 @@ static void btrfs_error_commit_super(struct btrfs_root *root)
        btrfs_cleanup_transaction(root);
 }
 
-static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
-                                            struct btrfs_root *root)
-{
-       struct btrfs_inode *btrfs_inode;
-       struct list_head splice;
-
-       INIT_LIST_HEAD(&splice);
-
-       mutex_lock(&root->fs_info->ordered_operations_mutex);
-       spin_lock(&root->fs_info->ordered_root_lock);
-
-       list_splice_init(&t->ordered_operations, &splice);
-       while (!list_empty(&splice)) {
-               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
-                                        ordered_operations);
-
-               list_del_init(&btrfs_inode->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-
-               btrfs_invalidate_inodes(btrfs_inode->root);
-
-               spin_lock(&root->fs_info->ordered_root_lock);
-       }
-
-       spin_unlock(&root->fs_info->ordered_root_lock);
-       mutex_unlock(&root->fs_info->ordered_operations_mutex);
-}
-
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
 {
        struct btrfs_ordered_extent *ordered;
@@ -4093,8 +4063,6 @@ again:
 void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                   struct btrfs_root *root)
 {
-       btrfs_destroy_ordered_operations(cur_trans, root);
-
        btrfs_destroy_delayed_refs(cur_trans, root);
 
        cur_trans->state = TRANS_STATE_COMMIT_START;
index 813537f362f9ea318c05dd0c6a6030c2fbe08381..102ed3143976fa9cfe98e21f237f45ed7fbed3c2 100644 (file)
@@ -3057,7 +3057,7 @@ out:
 static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          int full_backref, int inc, int no_quota)
+                          int full_backref, int inc)
 {
        u64 bytenr;
        u64 num_bytes;
@@ -3111,7 +3111,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        key.offset -= btrfs_file_extent_offset(buf, fi);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, key.objectid,
-                                          key.offset, no_quota);
+                                          key.offset, 1);
                        if (ret)
                                goto fail;
                } else {
@@ -3119,7 +3119,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        num_bytes = btrfs_level_size(root, level - 1);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, level - 1, 0,
-                                          no_quota);
+                                          1);
                        if (ret)
                                goto fail;
                }
@@ -3130,15 +3130,15 @@ fail:
 }
 
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota)
+                 struct extent_buffer *buf, int full_backref)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 1, no_quota);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 1);
 }
 
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota)
+                 struct extent_buffer *buf, int full_backref)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 0, no_quota);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 0);
 }
 
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
@@ -7478,6 +7478,220 @@ reada:
        wc->reada_slot = slot;
 }
 
+static int account_leaf_items(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
+                             struct extent_buffer *eb)
+{
+       int nr = btrfs_header_nritems(eb);
+       int i, extent_type, ret;
+       struct btrfs_key key;
+       struct btrfs_file_extent_item *fi;
+       u64 bytenr, num_bytes;
+
+       for (i = 0; i < nr; i++) {
+               btrfs_item_key_to_cpu(eb, &key, i);
+
+               if (key.type != BTRFS_EXTENT_DATA_KEY)
+                       continue;
+
+               fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item);
+               /* filter out non qgroup-accountable extents  */
+               extent_type = btrfs_file_extent_type(eb, fi);
+
+               if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+                       continue;
+
+               bytenr = btrfs_file_extent_disk_bytenr(eb, fi);
+               if (!bytenr)
+                       continue;
+
+               num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi);
+
+               ret = btrfs_qgroup_record_ref(trans, root->fs_info,
+                                             root->objectid,
+                                             bytenr, num_bytes,
+                                             BTRFS_QGROUP_OPER_SUB_SUBTREE, 0);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/*
+ * Walk up the tree from the bottom, freeing leaves and any interior
+ * nodes which have had all slots visited. If a node (leaf or
+ * interior) is freed, the node above it will have it's slot
+ * incremented. The root node will never be freed.
+ *
+ * At the end of this function, we should have a path which has all
+ * slots incremented to the next position for a search. If we need to
+ * read a new node it will be NULL and the node above it will have the
+ * correct slot selected for a later read.
+ *
+ * If we increment the root nodes slot counter past the number of
+ * elements, 1 is returned to signal completion of the search.
+ */
+static int adjust_slots_upwards(struct btrfs_root *root,
+                               struct btrfs_path *path, int root_level)
+{
+       int level = 0;
+       int nr, slot;
+       struct extent_buffer *eb;
+
+       if (root_level == 0)
+               return 1;
+
+       while (level <= root_level) {
+               eb = path->nodes[level];
+               nr = btrfs_header_nritems(eb);
+               path->slots[level]++;
+               slot = path->slots[level];
+               if (slot >= nr || level == 0) {
+                       /*
+                        * Don't free the root -  we will detect this
+                        * condition after our loop and return a
+                        * positive value for caller to stop walking the tree.
+                        */
+                       if (level != root_level) {
+                               btrfs_tree_unlock_rw(eb, path->locks[level]);
+                               path->locks[level] = 0;
+
+                               free_extent_buffer(eb);
+                               path->nodes[level] = NULL;
+                               path->slots[level] = 0;
+                       }
+               } else {
+                       /*
+                        * We have a valid slot to walk back down
+                        * from. Stop here so caller can process these
+                        * new nodes.
+                        */
+                       break;
+               }
+
+               level++;
+       }
+
+       eb = path->nodes[root_level];
+       if (path->slots[root_level] >= btrfs_header_nritems(eb))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * root_eb is the subtree root and is locked before this function is called.
+ */
+static int account_shared_subtree(struct btrfs_trans_handle *trans,
+                                 struct btrfs_root *root,
+                                 struct extent_buffer *root_eb,
+                                 u64 root_gen,
+                                 int root_level)
+{
+       int ret = 0;
+       int level;
+       struct extent_buffer *eb = root_eb;
+       struct btrfs_path *path = NULL;
+
+       BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL);
+       BUG_ON(root_eb == NULL);
+
+       if (!root->fs_info->quota_enabled)
+               return 0;
+
+       if (!extent_buffer_uptodate(root_eb)) {
+               ret = btrfs_read_buffer(root_eb, root_gen);
+               if (ret)
+                       goto out;
+       }
+
+       if (root_level == 0) {
+               ret = account_leaf_items(trans, root, root_eb);
+               goto out;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * Walk down the tree.  Missing extent blocks are filled in as
+        * we go. Metadata is accounted every time we read a new
+        * extent block.
+        *
+        * When we reach a leaf, we account for file extent items in it,
+        * walk back up the tree (adjusting slot pointers as we go)
+        * and restart the search process.
+        */
+       extent_buffer_get(root_eb); /* For path */
+       path->nodes[root_level] = root_eb;
+       path->slots[root_level] = 0;
+       path->locks[root_level] = 0; /* so release_path doesn't try to unlock */
+walk_down:
+       level = root_level;
+       while (level >= 0) {
+               if (path->nodes[level] == NULL) {
+                       int child_bsize = root->nodesize;
+                       int parent_slot;
+                       u64 child_gen;
+                       u64 child_bytenr;
+
+                       /* We need to get child blockptr/gen from
+                        * parent before we can read it. */
+                       eb = path->nodes[level + 1];
+                       parent_slot = path->slots[level + 1];
+                       child_bytenr = btrfs_node_blockptr(eb, parent_slot);
+                       child_gen = btrfs_node_ptr_generation(eb, parent_slot);
+
+                       eb = read_tree_block(root, child_bytenr, child_bsize,
+                                            child_gen);
+                       if (!eb || !extent_buffer_uptodate(eb)) {
+                               ret = -EIO;
+                               goto out;
+                       }
+
+                       path->nodes[level] = eb;
+                       path->slots[level] = 0;
+
+                       btrfs_tree_read_lock(eb);
+                       btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+                       path->locks[level] = BTRFS_READ_LOCK_BLOCKING;
+
+                       ret = btrfs_qgroup_record_ref(trans, root->fs_info,
+                                               root->objectid,
+                                               child_bytenr,
+                                               child_bsize,
+                                               BTRFS_QGROUP_OPER_SUB_SUBTREE,
+                                               0);
+                       if (ret)
+                               goto out;
+
+               }
+
+               if (level == 0) {
+                       ret = account_leaf_items(trans, root, path->nodes[level]);
+                       if (ret)
+                               goto out;
+
+                       /* Nonzero return here means we completed our search */
+                       ret = adjust_slots_upwards(root, path, root_level);
+                       if (ret)
+                               break;
+
+                       /* Restart search with new slots */
+                       goto walk_down;
+               }
+
+               level--;
+       }
+
+       ret = 0;
+out:
+       btrfs_free_path(path);
+
+       return ret;
+}
+
 /*
  * helper to process tree block while walking down the tree.
  *
@@ -7532,9 +7746,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
        /* wc->stage == UPDATE_BACKREF */
        if (!(wc->flags[level] & flag)) {
                BUG_ON(!path->locks[level]);
-               ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
+               ret = btrfs_inc_ref(trans, root, eb, 1);
                BUG_ON(ret); /* -ENOMEM */
-               ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
+               ret = btrfs_dec_ref(trans, root, eb, 0);
                BUG_ON(ret); /* -ENOMEM */
                ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
                                                  eb->len, flag,
@@ -7581,6 +7795,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        int level = wc->level;
        int reada = 0;
        int ret = 0;
+       bool need_account = false;
 
        generation = btrfs_node_ptr_generation(path->nodes[level],
                                               path->slots[level]);
@@ -7626,6 +7841,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
 
        if (wc->stage == DROP_REFERENCE) {
                if (wc->refs[level - 1] > 1) {
+                       need_account = true;
                        if (level == 1 &&
                            (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
                                goto skip;
@@ -7689,6 +7905,16 @@ skip:
                        parent = 0;
                }
 
+               if (need_account) {
+                       ret = account_shared_subtree(trans, root, next,
+                                                    generation, level - 1);
+                       if (ret) {
+                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                                       "%d accounting shared subtree. Quota "
+                                       "is out of sync, rescan required.\n",
+                                       root->fs_info->sb->s_id, ret);
+                       }
+               }
                ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
                                root->root_key.objectid, level - 1, 0, 0);
                BUG_ON(ret); /* -ENOMEM */
@@ -7769,12 +7995,17 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
        if (wc->refs[level] == 1) {
                if (level == 0) {
                        if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
-                               ret = btrfs_dec_ref(trans, root, eb, 1,
-                                                   wc->for_reloc);
+                               ret = btrfs_dec_ref(trans, root, eb, 1);
                        else
-                               ret = btrfs_dec_ref(trans, root, eb, 0,
-                                                   wc->for_reloc);
+                               ret = btrfs_dec_ref(trans, root, eb, 0);
                        BUG_ON(ret); /* -ENOMEM */
+                       ret = account_leaf_items(trans, root, eb);
+                       if (ret) {
+                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                                       "%d accounting leaf items. Quota "
+                                       "is out of sync, rescan required.\n",
+                                       root->fs_info->sb->s_id, ret);
+                       }
                }
                /* make block locked assertion in clean_tree_block happy */
                if (!path->locks[level] &&
@@ -7900,6 +8131,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        int level;
        bool root_dropped = false;
 
+       btrfs_debug(root->fs_info, "Drop subvolume %llu", root->objectid);
+
        path = btrfs_alloc_path();
        if (!path) {
                err = -ENOMEM;
@@ -8025,6 +8258,24 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                goto out_end_trans;
                        }
 
+                       /*
+                        * Qgroup update accounting is run from
+                        * delayed ref handling. This usually works
+                        * out because delayed refs are normally the
+                        * only way qgroup updates are added. However,
+                        * we may have added updates during our tree
+                        * walk so run qgroups here to make sure we
+                        * don't lose any updates.
+                        */
+                       ret = btrfs_delayed_qgroup_accounting(trans,
+                                                             root->fs_info);
+                       if (ret)
+                               printk_ratelimited(KERN_ERR "BTRFS: Failure %d "
+                                                  "running qgroup updates "
+                                                  "during snapshot delete. "
+                                                  "Quota is out of sync, "
+                                                  "rescan required.\n", ret);
+
                        btrfs_end_transaction_throttle(trans, tree_root);
                        if (!for_reloc && btrfs_need_cleaner_sleep(root)) {
                                pr_debug("BTRFS: drop snapshot early exit\n");
@@ -8078,6 +8329,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        }
        root_dropped = true;
 out_end_trans:
+       ret = btrfs_delayed_qgroup_accounting(trans, tree_root->fs_info);
+       if (ret)
+               printk_ratelimited(KERN_ERR "BTRFS: Failure %d "
+                                  "running qgroup updates "
+                                  "during snapshot delete. "
+                                  "Quota is out of sync, "
+                                  "rescan required.\n", ret);
+
        btrfs_end_transaction_throttle(trans, tree_root);
 out_free:
        kfree(wc);
index f46cfe45d68629ff1a05406ef693cf73a6036381..54c84daec9b515f73f8f1178a1e4ea9485d20e3f 100644 (file)
@@ -756,7 +756,7 @@ again:
                                found_next = 1;
                        if (ret != 0)
                                goto insert;
-                       slot = 0;
+                       slot = path->slots[0];
                }
                btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
                if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
index 1f2b99cb55eaef682c51ae3c8b227e88aafbf7e7..d3afac292d677e0ed492255ca7cb3890cde717b1 100644 (file)
@@ -1838,33 +1838,9 @@ out:
 
 int btrfs_release_file(struct inode *inode, struct file *filp)
 {
-       /*
-        * ordered_data_close is set by settattr when we are about to truncate
-        * a file from a non-zero size to a zero size.  This tries to
-        * flush down new bytes that may have been written if the
-        * application were using truncate to replace a file in place.
-        */
-       if (test_and_clear_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
-                              &BTRFS_I(inode)->runtime_flags)) {
-               struct btrfs_trans_handle *trans;
-               struct btrfs_root *root = BTRFS_I(inode)->root;
-
-               /*
-                * We need to block on a committing transaction to keep us from
-                * throwing a ordered operation on to the list and causing
-                * something like sync to deadlock trying to flush out this
-                * inode.
-                */
-               trans = btrfs_start_transaction(root, 0);
-               if (IS_ERR(trans))
-                       return PTR_ERR(trans);
-               btrfs_add_ordered_operation(trans, BTRFS_I(inode)->root, inode);
-               btrfs_end_transaction(trans, root);
-               if (inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
-                       filemap_flush(inode->i_mapping);
-       }
        if (filp->private_data)
                btrfs_ioctl_trans_end(filp);
+       filemap_flush(inode->i_mapping);
        return 0;
 }
 
index 3183742d6f0d74d131c16e29dde59205f3e7f8a4..03708ef3deefb11edd7998ee831bf370e6ad8a66 100644 (file)
@@ -709,6 +709,18 @@ retry:
                                unlock_extent(io_tree, async_extent->start,
                                              async_extent->start +
                                              async_extent->ram_size - 1);
+
+                               /*
+                                * we need to redirty the pages if we decide to
+                                * fallback to uncompressed IO, otherwise we
+                                * will not submit these pages down to lower
+                                * layers.
+                                */
+                               extent_range_redirty_for_io(inode,
+                                               async_extent->start,
+                                               async_extent->start +
+                                               async_extent->ram_size - 1);
+
                                goto retry;
                        }
                        goto out_free;
@@ -7938,27 +7950,6 @@ static int btrfs_truncate(struct inode *inode)
                                      min_size);
        BUG_ON(ret);
 
-       /*
-        * setattr is responsible for setting the ordered_data_close flag,
-        * but that is only tested during the last file release.  That
-        * could happen well after the next commit, leaving a great big
-        * window where new writes may get lost if someone chooses to write
-        * to this file after truncating to zero
-        *
-        * The inode doesn't have any dirty data here, and so if we commit
-        * this is a noop.  If someone immediately starts writing to the inode
-        * it is very likely we'll catch some of their writes in this
-        * transaction, and the commit will find this file on the ordered
-        * data list with good things to send down.
-        *
-        * This is a best effort solution, there is still a window where
-        * using truncate to replace the contents of the file will
-        * end up with a zero length file after a crash.
-        */
-       if (inode->i_size == 0 && test_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
-                                          &BTRFS_I(inode)->runtime_flags))
-               btrfs_add_ordered_operation(trans, root, inode);
-
        /*
         * So if we truncate and then write and fsync we normally would just
         * write the extents that changed, which is a problem if we need to
@@ -8106,7 +8097,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        mutex_init(&ei->delalloc_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->delalloc_inodes);
-       INIT_LIST_HEAD(&ei->ordered_operations);
        RB_CLEAR_NODE(&ei->rb_node);
 
        return inode;
@@ -8146,17 +8136,6 @@ void btrfs_destroy_inode(struct inode *inode)
        if (!root)
                goto free;
 
-       /*
-        * Make sure we're properly removed from the ordered operation
-        * lists.
-        */
-       smp_mb();
-       if (!list_empty(&BTRFS_I(inode)->ordered_operations)) {
-               spin_lock(&root->fs_info->ordered_root_lock);
-               list_del_init(&BTRFS_I(inode)->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-       }
-
        if (test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                     &BTRFS_I(inode)->runtime_flags)) {
                btrfs_info(root->fs_info, "inode %llu still on the orphan list",
@@ -8338,12 +8317,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        ret = 0;
 
        /*
-        * we're using rename to replace one file with another.
-        * and the replacement file is large.  Start IO on it now so
-        * we don't add too much work to the end of the transaction
+        * we're using rename to replace one file with another.  Start IO on it
+        * now so  we don't add too much work to the end of the transaction
         */
-       if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size &&
-           old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+       if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
                filemap_flush(old_inode->i_mapping);
 
        /* close the racy window with snapshot create/destroy ioctl */
@@ -8391,12 +8368,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 */
                btrfs_pin_log_trans(root);
        }
-       /*
-        * make sure the inode gets flushed if it is replacing
-        * something.
-        */
-       if (new_inode && new_inode->i_size && S_ISREG(old_inode->i_mode))
-               btrfs_add_ordered_operation(trans, root, old_inode);
 
        inode_inc_iversion(old_dir);
        inode_inc_iversion(new_dir);
index 7187b14faa6cd0c1c846fcfb155f431102ce8bad..963895c1f801dcbbde3ce9c5e621c91308793f7a 100644 (file)
@@ -571,18 +571,6 @@ void btrfs_remove_ordered_extent(struct inode *inode,
 
        trace_btrfs_ordered_extent_remove(inode, entry);
 
-       /*
-        * we have no more ordered extents for this inode and
-        * no dirty pages.  We can safely remove it from the
-        * list of ordered extents
-        */
-       if (RB_EMPTY_ROOT(&tree->tree) &&
-           !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
-               spin_lock(&root->fs_info->ordered_root_lock);
-               list_del_init(&BTRFS_I(inode)->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-       }
-
        if (!root->nr_ordered_extents) {
                spin_lock(&root->fs_info->ordered_root_lock);
                BUG_ON(list_empty(&root->ordered_root));
@@ -686,81 +674,6 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr)
        mutex_unlock(&fs_info->ordered_operations_mutex);
 }
 
-/*
- * this is used during transaction commit to write all the inodes
- * added to the ordered operation list.  These files must be fully on
- * disk before the transaction commits.
- *
- * we have two modes here, one is to just start the IO via filemap_flush
- * and the other is to wait for all the io.  When we wait, we have an
- * extra check to make sure the ordered operation list really is empty
- * before we return
- */
-int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, int wait)
-{
-       struct btrfs_inode *btrfs_inode;
-       struct inode *inode;
-       struct btrfs_transaction *cur_trans = trans->transaction;
-       struct list_head splice;
-       struct list_head works;
-       struct btrfs_delalloc_work *work, *next;
-       int ret = 0;
-
-       INIT_LIST_HEAD(&splice);
-       INIT_LIST_HEAD(&works);
-
-       mutex_lock(&root->fs_info->ordered_extent_flush_mutex);
-       spin_lock(&root->fs_info->ordered_root_lock);
-       list_splice_init(&cur_trans->ordered_operations, &splice);
-       while (!list_empty(&splice)) {
-               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
-                                  ordered_operations);
-               inode = &btrfs_inode->vfs_inode;
-
-               list_del_init(&btrfs_inode->ordered_operations);
-
-               /*
-                * the inode may be getting freed (in sys_unlink path).
-                */
-               inode = igrab(inode);
-               if (!inode)
-                       continue;
-
-               if (!wait)
-                       list_add_tail(&BTRFS_I(inode)->ordered_operations,
-                                     &cur_trans->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-
-               work = btrfs_alloc_delalloc_work(inode, wait, 1);
-               if (!work) {
-                       spin_lock(&root->fs_info->ordered_root_lock);
-                       if (list_empty(&BTRFS_I(inode)->ordered_operations))
-                               list_add_tail(&btrfs_inode->ordered_operations,
-                                             &splice);
-                       list_splice_tail(&splice,
-                                        &cur_trans->ordered_operations);
-                       spin_unlock(&root->fs_info->ordered_root_lock);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               list_add_tail(&work->list, &works);
-               btrfs_queue_work(root->fs_info->flush_workers,
-                                &work->work);
-
-               cond_resched();
-               spin_lock(&root->fs_info->ordered_root_lock);
-       }
-       spin_unlock(&root->fs_info->ordered_root_lock);
-out:
-       list_for_each_entry_safe(work, next, &works, list) {
-               list_del_init(&work->list);
-               btrfs_wait_and_free_delalloc_work(work);
-       }
-       mutex_unlock(&root->fs_info->ordered_extent_flush_mutex);
-       return ret;
-}
-
 /*
  * Used to start IO or wait for a given ordered extent to finish.
  *
@@ -1120,42 +1033,6 @@ out:
        return index;
 }
 
-
-/*
- * add a given inode to the list of inodes that must be fully on
- * disk before a transaction commit finishes.
- *
- * This basically gives us the ext3 style data=ordered mode, and it is mostly
- * used to make sure renamed files are fully on disk.
- *
- * It is a noop if the inode is already fully on disk.
- *
- * If trans is not null, we'll do a friendly check for a transaction that
- * is already flushing things and force the IO down ourselves.
- */
-void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, struct inode *inode)
-{
-       struct btrfs_transaction *cur_trans = trans->transaction;
-       u64 last_mod;
-
-       last_mod = max(BTRFS_I(inode)->generation, BTRFS_I(inode)->last_trans);
-
-       /*
-        * if this file hasn't been changed since the last transaction
-        * commit, we can safely return without doing anything
-        */
-       if (last_mod <= root->fs_info->last_trans_committed)
-               return;
-
-       spin_lock(&root->fs_info->ordered_root_lock);
-       if (list_empty(&BTRFS_I(inode)->ordered_operations)) {
-               list_add_tail(&BTRFS_I(inode)->ordered_operations,
-                             &cur_trans->ordered_operations);
-       }
-       spin_unlock(&root->fs_info->ordered_root_lock);
-}
-
 int __init ordered_data_init(void)
 {
        btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
index 246897058efb009ffd521cee2d61cb60fc0bde0f..d81a274d621ee47cf2510b2323997d67567a3a88 100644 (file)
@@ -190,11 +190,6 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
                           u32 *sum, int len);
-int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, int wait);
-void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root,
-                                struct inode *inode);
 int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr);
 void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr);
 void btrfs_get_logged_extents(struct inode *inode,
index 98cb6b2630f9aac60972b5aea3c372e9e99eeba5..b497498484bebaf5774aa3c4d016a5e4f0b05ff1 100644 (file)
@@ -1201,6 +1201,50 @@ out:
        mutex_unlock(&fs_info->qgroup_ioctl_lock);
        return ret;
 }
+
+static int comp_oper_exist(struct btrfs_qgroup_operation *oper1,
+                          struct btrfs_qgroup_operation *oper2)
+{
+       /*
+        * Ignore seq and type here, we're looking for any operation
+        * at all related to this extent on that root.
+        */
+       if (oper1->bytenr < oper2->bytenr)
+               return -1;
+       if (oper1->bytenr > oper2->bytenr)
+               return 1;
+       if (oper1->ref_root < oper2->ref_root)
+               return -1;
+       if (oper1->ref_root > oper2->ref_root)
+               return 1;
+       return 0;
+}
+
+static int qgroup_oper_exists(struct btrfs_fs_info *fs_info,
+                             struct btrfs_qgroup_operation *oper)
+{
+       struct rb_node *n;
+       struct btrfs_qgroup_operation *cur;
+       int cmp;
+
+       spin_lock(&fs_info->qgroup_op_lock);
+       n = fs_info->qgroup_op_tree.rb_node;
+       while (n) {
+               cur = rb_entry(n, struct btrfs_qgroup_operation, n);
+               cmp = comp_oper_exist(cur, oper);
+               if (cmp < 0) {
+                       n = n->rb_right;
+               } else if (cmp) {
+                       n = n->rb_left;
+               } else {
+                       spin_unlock(&fs_info->qgroup_op_lock);
+                       return -EEXIST;
+               }
+       }
+       spin_unlock(&fs_info->qgroup_op_lock);
+       return 0;
+}
+
 static int comp_oper(struct btrfs_qgroup_operation *oper1,
                     struct btrfs_qgroup_operation *oper2)
 {
@@ -1290,6 +1334,23 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
        oper->seq = atomic_inc_return(&fs_info->qgroup_op_seq);
        INIT_LIST_HEAD(&oper->elem.list);
        oper->elem.seq = 0;
+
+       if (type == BTRFS_QGROUP_OPER_SUB_SUBTREE) {
+               /*
+                * If any operation for this bytenr/ref_root combo
+                * exists, then we know it's not exclusively owned and
+                * shouldn't be queued up.
+                *
+                * This also catches the case where we have a cloned
+                * extent that gets queued up multiple times during
+                * drop snapshot.
+                */
+               if (qgroup_oper_exists(fs_info, oper)) {
+                       kfree(oper);
+                       return 0;
+               }
+       }
+
        ret = insert_qgroup_oper(fs_info, oper);
        if (ret) {
                /* Shouldn't happen so have an assert for developers */
@@ -1883,6 +1944,111 @@ out:
        return ret;
 }
 
+/*
+ * Process a reference to a shared subtree. This type of operation is
+ * queued during snapshot removal when we encounter extents which are
+ * shared between more than one root.
+ */
+static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
+                                    struct btrfs_fs_info *fs_info,
+                                    struct btrfs_qgroup_operation *oper)
+{
+       struct ulist *roots = NULL;
+       struct ulist_node *unode;
+       struct ulist_iterator uiter;
+       struct btrfs_qgroup_list *glist;
+       struct ulist *parents;
+       int ret = 0;
+       int err;
+       struct btrfs_qgroup *qg;
+       u64 root_obj = 0;
+       struct seq_list elem = {};
+
+       parents = ulist_alloc(GFP_NOFS);
+       if (!parents)
+               return -ENOMEM;
+
+       btrfs_get_tree_mod_seq(fs_info, &elem);
+       ret = btrfs_find_all_roots(trans, fs_info, oper->bytenr,
+                                  elem.seq, &roots);
+       btrfs_put_tree_mod_seq(fs_info, &elem);
+       if (ret < 0)
+               return ret;
+
+       if (roots->nnodes != 1)
+               goto out;
+
+       ULIST_ITER_INIT(&uiter);
+       unode = ulist_next(roots, &uiter); /* Only want 1 so no need to loop */
+       /*
+        * If we find our ref root then that means all refs
+        * this extent has to the root have not yet been
+        * deleted. In that case, we do nothing and let the
+        * last ref for this bytenr drive our update.
+        *
+        * This can happen for example if an extent is
+        * referenced multiple times in a snapshot (clone,
+        * etc). If we are in the middle of snapshot removal,
+        * queued updates for such an extent will find the
+        * root if we have not yet finished removing the
+        * snapshot.
+        */
+       if (unode->val == oper->ref_root)
+               goto out;
+
+       root_obj = unode->val;
+       BUG_ON(!root_obj);
+
+       spin_lock(&fs_info->qgroup_lock);
+       qg = find_qgroup_rb(fs_info, root_obj);
+       if (!qg)
+               goto out_unlock;
+
+       qg->excl += oper->num_bytes;
+       qg->excl_cmpr += oper->num_bytes;
+       qgroup_dirty(fs_info, qg);
+
+       /*
+        * Adjust counts for parent groups. First we find all
+        * parents, then in the 2nd loop we do the adjustment
+        * while adding parents of the parents to our ulist.
+        */
+       list_for_each_entry(glist, &qg->groups, next_group) {
+               err = ulist_add(parents, glist->group->qgroupid,
+                               ptr_to_u64(glist->group), GFP_ATOMIC);
+               if (err < 0) {
+                       ret = err;
+                       goto out_unlock;
+               }
+       }
+
+       ULIST_ITER_INIT(&uiter);
+       while ((unode = ulist_next(parents, &uiter))) {
+               qg = u64_to_ptr(unode->aux);
+               qg->excl += oper->num_bytes;
+               qg->excl_cmpr += oper->num_bytes;
+               qgroup_dirty(fs_info, qg);
+
+               /* Add any parents of the parents */
+               list_for_each_entry(glist, &qg->groups, next_group) {
+                       err = ulist_add(parents, glist->group->qgroupid,
+                                       ptr_to_u64(glist->group), GFP_ATOMIC);
+                       if (err < 0) {
+                               ret = err;
+                               goto out_unlock;
+                       }
+               }
+       }
+
+out_unlock:
+       spin_unlock(&fs_info->qgroup_lock);
+
+out:
+       ulist_free(roots);
+       ulist_free(parents);
+       return ret;
+}
+
 /*
  * btrfs_qgroup_account_ref is called for every ref that is added to or deleted
  * from the fs. First, all roots referencing the extent are searched, and
@@ -1920,6 +2086,9 @@ static int btrfs_qgroup_account(struct btrfs_trans_handle *trans,
        case BTRFS_QGROUP_OPER_SUB_SHARED:
                ret = qgroup_shared_accounting(trans, fs_info, oper);
                break;
+       case BTRFS_QGROUP_OPER_SUB_SUBTREE:
+               ret = qgroup_subtree_accounting(trans, fs_info, oper);
+               break;
        default:
                ASSERT(0);
        }
index 5952ff1fbd7a5290d8fe563d8463100af58098d2..18cc68ca309054e84ce8248d78059fe3170be3ac 100644 (file)
@@ -44,6 +44,7 @@ enum btrfs_qgroup_operation_type {
        BTRFS_QGROUP_OPER_ADD_SHARED,
        BTRFS_QGROUP_OPER_SUB_EXCL,
        BTRFS_QGROUP_OPER_SUB_SHARED,
+       BTRFS_QGROUP_OPER_SUB_SUBTREE,
 };
 
 struct btrfs_qgroup_operation {
index 67b48b9a03e044eb2d83ab28447c8ead9db5192b..c4124de4435bffed06afc3a76ea6aba49a7c5317 100644 (file)
@@ -1665,6 +1665,21 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
        return 0;
 }
 
+/*
+ * Calculate numbers for 'df', pessimistic in case of mixed raid profiles.
+ *
+ * If there's a redundant raid level at DATA block groups, use the respective
+ * multiplier to scale the sizes.
+ *
+ * Unused device space usage is based on simulating the chunk allocator
+ * algorithm that respects the device sizes, order of allocations and the
+ * 'alloc_start' value, this is a close approximation of the actual use but
+ * there are other factors that may change the result (like a new metadata
+ * chunk).
+ *
+ * FIXME: not accurate for mixed block groups, total and free/used are ok,
+ * available appears slightly larger.
+ */
 static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
@@ -1675,6 +1690,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        u64 total_free_data = 0;
        int bits = dentry->d_sb->s_blocksize_bits;
        __be32 *fsid = (__be32 *)fs_info->fsid;
+       unsigned factor = 1;
+       struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        int ret;
 
        /* holding chunk_muext to avoid allocating new chunks */
@@ -1682,30 +1699,52 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
                if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
+                       int i;
+
                        total_free_data += found->disk_total - found->disk_used;
                        total_free_data -=
                                btrfs_account_ro_block_groups_free_space(found);
+
+                       for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
+                               if (!list_empty(&found->block_groups[i])) {
+                                       switch (i) {
+                                       case BTRFS_RAID_DUP:
+                                       case BTRFS_RAID_RAID1:
+                                       case BTRFS_RAID_RAID10:
+                                               factor = 2;
+                                       }
+                               }
+                       }
                }
 
                total_used += found->disk_used;
        }
+
        rcu_read_unlock();
 
-       buf->f_namelen = BTRFS_NAME_LEN;
-       buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
-       buf->f_bfree = buf->f_blocks - (total_used >> bits);
-       buf->f_bsize = dentry->d_sb->s_blocksize;
-       buf->f_type = BTRFS_SUPER_MAGIC;
+       buf->f_blocks = div_u64(btrfs_super_total_bytes(disk_super), factor);
+       buf->f_blocks >>= bits;
+       buf->f_bfree = buf->f_blocks - (div_u64(total_used, factor) >> bits);
+
+       /* Account global block reserve as used, it's in logical size already */
+       spin_lock(&block_rsv->lock);
+       buf->f_bfree -= block_rsv->size >> bits;
+       spin_unlock(&block_rsv->lock);
+
        buf->f_bavail = total_free_data;
        ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
        if (ret) {
                mutex_unlock(&fs_info->chunk_mutex);
                return ret;
        }
-       buf->f_bavail += total_free_data;
+       buf->f_bavail += div_u64(total_free_data, factor);
        buf->f_bavail = buf->f_bavail >> bits;
        mutex_unlock(&fs_info->chunk_mutex);
 
+       buf->f_type = BTRFS_SUPER_MAGIC;
+       buf->f_bsize = dentry->d_sb->s_blocksize;
+       buf->f_namelen = BTRFS_NAME_LEN;
+
        /* We treat it as constant endianness (it doesn't matter _which_)
           because we want the fsid to come out the same whether mounted
           on a big-endian or little-endian host */
index 5f379affdf236119f4ab031ad6843a822a0ec24c..d89c6d3542cab4c55372954ae97e9e32ec1ba443 100644 (file)
@@ -218,7 +218,6 @@ loop:
        spin_lock_init(&cur_trans->delayed_refs.lock);
 
        INIT_LIST_HEAD(&cur_trans->pending_snapshots);
-       INIT_LIST_HEAD(&cur_trans->ordered_operations);
        INIT_LIST_HEAD(&cur_trans->pending_chunks);
        INIT_LIST_HEAD(&cur_trans->switch_commits);
        list_add_tail(&cur_trans->list, &fs_info->trans_list);
@@ -1612,27 +1611,6 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 }
 
-static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
-                                         struct btrfs_root *root)
-{
-       int ret;
-
-       ret = btrfs_run_delayed_items(trans, root);
-       if (ret)
-               return ret;
-
-       /*
-        * rename don't use btrfs_join_transaction, so, once we
-        * set the transaction to blocked above, we aren't going
-        * to get any new ordered operations.  We can safely run
-        * it here and no for sure that nothing new will be added
-        * to the list
-        */
-       ret = btrfs_run_ordered_operations(trans, root, 1);
-
-       return ret;
-}
-
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
@@ -1653,13 +1631,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_transaction *prev_trans = NULL;
        int ret;
 
-       ret = btrfs_run_ordered_operations(trans, root, 0);
-       if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
-               btrfs_end_transaction(trans, root);
-               return ret;
-       }
-
        /* Stop the commit early if ->aborted is set */
        if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
                ret = cur_trans->aborted;
@@ -1740,7 +1711,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        if (ret)
                goto cleanup_transaction;
 
-       ret = btrfs_flush_all_pending_stuffs(trans, root);
+       ret = btrfs_run_delayed_items(trans, root);
        if (ret)
                goto cleanup_transaction;
 
@@ -1748,7 +1719,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                   extwriter_counter_read(cur_trans) == 0);
 
        /* some pending stuffs might be added after the previous flush. */
-       ret = btrfs_flush_all_pending_stuffs(trans, root);
+       ret = btrfs_run_delayed_items(trans, root);
        if (ret)
                goto cleanup_transaction;
 
index 7dd558ed0716526fa5700c179d2f0606b8a53219..579be51b27e5ee0970feb4fb21ddf54a1d621a12 100644 (file)
@@ -55,7 +55,6 @@ struct btrfs_transaction {
        wait_queue_head_t writer_wait;
        wait_queue_head_t commit_wait;
        struct list_head pending_snapshots;
-       struct list_head ordered_operations;
        struct list_head pending_chunks;
        struct list_head switch_commits;
        struct btrfs_delayed_ref_root delayed_refs;
index 7f78cbf5cf413636e7b6072efca05110dce8b211..4c29db604bbe135fb1bdb3743c7eee408499d25c 100644 (file)
@@ -57,6 +57,21 @@ void ulist_free(struct ulist *ulist);
 int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask);
 int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
                    u64 *old_aux, gfp_t gfp_mask);
+
+/* just like ulist_add_merge() but take a pointer for the aux data */
+static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux,
+                                     void **old_aux, gfp_t gfp_mask)
+{
+#if BITS_PER_LONG == 32
+       u64 old64 = (uintptr_t)*old_aux;
+       int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask);
+       *old_aux = (void *)((uintptr_t)old64);
+       return ret;
+#else
+       return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask);
+#endif
+}
+
 struct ulist_node *ulist_next(struct ulist *ulist,
                              struct ulist_iterator *uiter);
 
index ac4f260155c875b80d9d6611af1139438e62fc91..889b9845575079517e92ee387fe5c863751c3848 100644 (file)
@@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
+static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
+{
+       struct super_block *sb = file->f_path.dentry->d_sb;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       if (server->ops->fallocate)
+               return server->ops->fallocate(file, tcon, mode, off, len);
+
+       return -EOPNOTSUPP;
+}
+
 static int cifs_permission(struct inode *inode, int mask)
 {
        struct cifs_sb_info *cifs_sb;
@@ -812,8 +825,9 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
        if (!(S_ISREG(inode->i_mode)))
                return -EINVAL;
 
-       /* check if file is oplocked */
-       if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
+       /* Check if file is oplocked if this is request for new lease */
+       if (arg == F_UNLCK ||
+           ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
            ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
                return generic_setlease(file, arg, lease);
        else if (tlink_tcon(cfile->tlink)->local_lease &&
@@ -908,6 +922,7 @@ const struct file_operations cifs_file_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_strict_ops = {
@@ -927,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_direct_ops = {
@@ -947,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_nobrl_ops = {
@@ -965,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -983,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1002,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_dir_ops = {
index 0012e1e291d427cbb4a6696792cb85743231ec1e..dfc731b02aa9b3daca3a15d95346bcd82cc2b3d5 100644 (file)
@@ -409,6 +409,10 @@ struct smb_version_operations {
        /* get mtu credits */
        int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
                                unsigned int *, unsigned int *);
+       /* check if we need to issue closedir */
+       bool (*dir_needs_close)(struct cifsFileInfo *);
+       long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
+                         loff_t);
 };
 
 struct smb_version_values {
@@ -883,6 +887,7 @@ struct cifs_tcon {
                                for this mount even if server would support */
        bool local_lease:1; /* check leases (only) on local system not remote */
        bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
+       bool broken_sparse_sup; /* if server or share does not support sparse */
        bool need_reconnect:1; /* connection reset, tid now invalid */
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
index 33df36ef9d52037e69857f1dc7b1c9591acb8251..5f9822ac0245dcd637838b3fda843b3cc4d09901 100644 (file)
@@ -2253,6 +2253,29 @@ typedef struct {
 /* minimum includes first three fields, and empty FS Name */
 #define MIN_FS_ATTR_INFO_SIZE 12
 
+
+/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */
+#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000
+#define FILE_SUPPORTS_USN_JOURNAL      0x02000000
+#define FILE_SUPPORTS_OPEN_BY_FILE_ID  0x01000000
+#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000
+#define FILE_SUPPORTS_HARD_LINKS       0x00400000
+#define FILE_SUPPORTS_TRANSACTIONS     0x00200000
+#define FILE_SEQUENTIAL_WRITE_ONCE     0x00100000
+#define FILE_READ_ONLY_VOLUME          0x00080000
+#define FILE_NAMED_STREAMS             0x00040000
+#define FILE_SUPPORTS_ENCRYPTION       0x00020000
+#define FILE_SUPPORTS_OBJECT_IDS       0x00010000
+#define FILE_VOLUME_IS_COMPRESSED      0x00008000
+#define FILE_SUPPORTS_REMOTE_STORAGE   0x00000100
+#define FILE_SUPPORTS_REPARSE_POINTS   0x00000080
+#define FILE_SUPPORTS_SPARSE_FILES     0x00000040
+#define FILE_VOLUME_QUOTAS             0x00000020
+#define FILE_FILE_COMPRESSION          0x00000010
+#define FILE_PERSISTENT_ACLS           0x00000008
+#define FILE_UNICODE_ON_DISK           0x00000004
+#define FILE_CASE_PRESERVED_NAMES      0x00000002
+#define FILE_CASE_SENSITIVE_SEARCH     0x00000001
 typedef struct {
        __le32 Attributes;
        __le32 MaxPathNameComponentLength;
index 4ab2f79ffa7a4eb7f2e6ac3a2a8d67131d8f8080..d5fec92e036068b98bf2e3426e3f8d159b70e048 100644 (file)
@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 
        cifs_dbg(FYI, "Freeing private data in close dir\n");
        spin_lock(&cifs_file_list_lock);
-       if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+       if (server->ops->dir_needs_close(cfile)) {
                cfile->invalidHandle = true;
                spin_unlock(&cifs_file_list_lock);
                if (server->ops->close_dir)
index 426d6c6ad8bfacfa188f2eb2dfb5385620559f44..949ec909ec9ab94747ed332cc96cdcdbc29fd47b 100644 (file)
@@ -1727,6 +1727,12 @@ unlink_target:
                                    target_dentry, to_name);
        }
 
+       /* force revalidate to go get info when needed */
+       CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
+
+       source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
+               target_dir->i_mtime = current_fs_time(source_dir->i_sb);
+
 cifs_rename_exit:
        kfree(info_buf_source);
        kfree(from_name);
index 81340c6253eb36bcaf922c8e1b955e5d493099ca..b7415d596dbd478926d75cdaca022ac8960a65c3 100644 (file)
@@ -574,13 +574,6 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
                cinode->oplock = 0;
 }
 
-static int
-cifs_oplock_break_wait(void *unused)
-{
-       schedule();
-       return signal_pending(current) ? -ERESTARTSYS : 0;
-}
-
 /*
  * We wait for oplock breaks to be processed before we attempt to perform
  * writes.
index b15862e0f68c3c749a7cf6278dc6d3666ba71ccc..798c80a41c886b3fba7e66f8264066902d35b8cb 100644 (file)
@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
                /* close and restart search */
                cifs_dbg(FYI, "search backing up - close and restart search\n");
                spin_lock(&cifs_file_list_lock);
-               if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+               if (server->ops->dir_needs_close(cfile)) {
                        cfile->invalidHandle = true;
                        spin_unlock(&cifs_file_list_lock);
                        if (server->ops->close)
index 5e8c22d6c7b9dc96f4079a9579fd8b5c68143af8..1a6df4b03f67cae97688d7a9578d7317a88419bf 100644 (file)
@@ -1015,6 +1015,12 @@ cifs_wp_retry_size(struct inode *inode)
        return CIFS_SB(inode->i_sb)->wsize;
 }
 
+static bool
+cifs_dir_needs_close(struct cifsFileInfo *cfile)
+{
+       return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -1086,6 +1092,7 @@ struct smb_version_operations smb1_operations = {
        .create_mf_symlink = cifs_create_mf_symlink,
        .is_read_op = cifs_is_read_op,
        .wp_retry_size = cifs_wp_retry_size,
+       .dir_needs_close = cifs_dir_needs_close,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = CIFSSMBQAllEAs,
        .set_EA = CIFSSMBSetEA,
index e31a9dfdcd39a8cf7a68d18a45922f9001b918d6..af59d03db49280488a33abe5ec372599aa8ad4ed 100644 (file)
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
        {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
        {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
        {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
-       {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"},
+       {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
        {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
        {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
        {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
@@ -298,7 +298,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
        {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"},
        {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"},
        {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"},
-       {STATUS_INVALID_DEVICE_REQUEST, -EIO, "STATUS_INVALID_DEVICE_REQUEST"},
+       {STATUS_INVALID_DEVICE_REQUEST, -EOPNOTSUPP, "STATUS_INVALID_DEVICE_REQUEST"},
        {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"},
        {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"},
        {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"},
index f2e6ac29a8d661b82f4ba1712dee36a842d6f7cd..4aa7a0f07d6eace61da47500bb6e83a5bd39e294 100644 (file)
@@ -178,9 +178,24 @@ smb2_check_message(char *buf, unsigned int length)
                /* Windows 7 server returns 24 bytes more */
                if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
                        return 0;
-               /* server can return one byte more */
+               /* server can return one byte more due to implied bcc[0] */
                if (clc_len == 4 + len + 1)
                        return 0;
+
+               /*
+                * MacOS server pads after SMB2.1 write response with 3 bytes
+                * of junk. Other servers match RFC1001 len to actual
+                * SMB2/SMB3 frame length (header + smb2 response specific data)
+                * Log the server error (once), but allow it and continue
+                * since the frame is parseable.
+                */
+               if (clc_len < 4 /* RFC1001 header size */ + len) {
+                       printk_once(KERN_WARNING
+                               "SMB2 server sent bad RFC1001 len %d not %d\n",
+                               len, clc_len - 4);
+                       return 0;
+               }
+
                return 1;
        }
        return 0;
index 77f8aeb9c2fc7ecb9a2c45785a65d6e9a45700fa..5a48aa290dfe83fdab6f9af322aadcdd0ebe3b3b 100644 (file)
@@ -731,11 +731,72 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
        return SMB2_write(xid, parms, written, iov, nr_segs);
 }
 
+/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */
+static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse)
+{
+       struct cifsInodeInfo *cifsi;
+       int rc;
+
+       cifsi = CIFS_I(inode);
+
+       /* if file already sparse don't bother setting sparse again */
+       if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse)
+               return true; /* already sparse */
+
+       if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse)
+               return true; /* already not sparse */
+
+       /*
+        * Can't check for sparse support on share the usual way via the
+        * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
+        * since Samba server doesn't set the flag on the share, yet
+        * supports the set sparse FSCTL and returns sparse correctly
+        * in the file attributes. If we fail setting sparse though we
+        * mark that server does not support sparse files for this share
+        * to avoid repeatedly sending the unsupported fsctl to server
+        * if the file is repeatedly extended.
+        */
+       if (tcon->broken_sparse_sup)
+               return false;
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
+                       true /* is_fctl */, &setsparse, 1, NULL, NULL);
+       if (rc) {
+               tcon->broken_sparse_sup = true;
+               cifs_dbg(FYI, "set sparse rc = %d\n", rc);
+               return false;
+       }
+
+       if (setsparse)
+               cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
+       else
+               cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE);
+
+       return true;
+}
+
 static int
 smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
                   struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
 {
        __le64 eof = cpu_to_le64(size);
+       struct inode *inode;
+
+       /*
+        * If extending file more than one page make sparse. Many Linux fs
+        * make files sparse by default when extending via ftruncate
+        */
+       inode = cfile->dentry->d_inode;
+
+       if (!set_alloc && (size > inode->i_size + 8192)) {
+               __u8 set_sparse = 1;
+
+               /* whether set sparse succeeds or not, extend the file */
+               smb2_set_sparse(xid, tcon, cfile, inode, set_sparse);
+       }
+
        return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                            cfile->fid.volatile_fid, cfile->pid, &eof, false);
 }
@@ -954,6 +1015,105 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
+static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+                           loff_t offset, loff_t len, bool keep_size)
+{
+       struct inode *inode;
+       struct cifsInodeInfo *cifsi;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct file_zero_data_information fsctl_buf;
+       long rc;
+       unsigned int xid;
+
+       xid = get_xid();
+
+       inode = cfile->dentry->d_inode;
+       cifsi = CIFS_I(inode);
+
+       /* if file not oplocked can't be sure whether asking to extend size */
+       if (!CIFS_CACHE_READ(cifsi))
+               if (keep_size == false)
+                       return -EOPNOTSUPP;
+
+       /* 
+        * Must check if file sparse since fallocate -z (zero range) assumes
+        * non-sparse allocation
+        */
+       if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))
+               return -EOPNOTSUPP;
+
+       /*
+        * need to make sure we are not asked to extend the file since the SMB3
+        * fsctl does not change the file size. In the future we could change
+        * this to zero the first part of the range then set the file size
+        * which for a non sparse file would zero the newly extended range
+        */
+       if (keep_size == false)
+               if (i_size_read(inode) < offset + len)
+                       return -EOPNOTSUPP;
+
+       cifs_dbg(FYI, "offset %lld len %lld", offset, len);
+
+       fsctl_buf.FileOffset = cpu_to_le64(offset);
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                       true /* is_fctl */, (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information), NULL, NULL);
+       free_xid(xid);
+       return rc;
+}
+
+static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
+                           loff_t offset, loff_t len)
+{
+       struct inode *inode;
+       struct cifsInodeInfo *cifsi;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct file_zero_data_information fsctl_buf;
+       long rc;
+       unsigned int xid;
+       __u8 set_sparse = 1;
+
+       xid = get_xid();
+
+       inode = cfile->dentry->d_inode;
+       cifsi = CIFS_I(inode);
+
+       /* Need to make file sparse, if not already, before freeing range. */
+       /* Consider adding equivalent for compressed since it could also work */
+       if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
+               return -EOPNOTSUPP;
+
+       cifs_dbg(FYI, "offset %lld len %lld", offset, len);
+
+       fsctl_buf.FileOffset = cpu_to_le64(offset);
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                       true /* is_fctl */, (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information), NULL, NULL);
+       free_xid(xid);
+       return rc;
+}
+
+static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
+                          loff_t off, loff_t len)
+{
+       /* KEEP_SIZE already checked for by do_fallocate */
+       if (mode & FALLOC_FL_PUNCH_HOLE)
+               return smb3_punch_hole(file, tcon, off, len);
+       else if (mode & FALLOC_FL_ZERO_RANGE) {
+               if (mode & FALLOC_FL_KEEP_SIZE)
+                       return smb3_zero_range(file, tcon, off, len, true);
+               return smb3_zero_range(file, tcon, off, len, false);
+       }
+
+       return -EOPNOTSUPP;
+}
+
 static void
 smb2_downgrade_oplock(struct TCP_Server_Info *server,
                        struct cifsInodeInfo *cinode, bool set_level2)
@@ -1161,6 +1321,12 @@ smb2_wp_retry_size(struct inode *inode)
                     SMB2_MAX_BUFFER_SIZE);
 }
 
+static bool
+smb2_dir_needs_close(struct cifsFileInfo *cfile)
+{
+       return !cfile->invalidHandle;
+}
+
 struct smb_version_operations smb20_operations = {
        .compare_fids = smb2_compare_fids,
        .setup_request = smb2_setup_request,
@@ -1236,6 +1402,7 @@ struct smb_version_operations smb20_operations = {
        .parse_lease_buf = smb2_parse_lease_buf,
        .clone_range = smb2_clone_range,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
 };
 
 struct smb_version_operations smb21_operations = {
@@ -1313,6 +1480,7 @@ struct smb_version_operations smb21_operations = {
        .parse_lease_buf = smb2_parse_lease_buf,
        .clone_range = smb2_clone_range,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
 };
 
 struct smb_version_operations smb30_operations = {
@@ -1393,6 +1561,8 @@ struct smb_version_operations smb30_operations = {
        .clone_range = smb2_clone_range,
        .validate_negotiate = smb3_validate_negotiate,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
+       .fallocate = smb3_fallocate,
 };
 
 struct smb_version_values smb20_values = {
index 42ebc1a8be6cb241c5ee77e1944f063ae15a472d..fa0dd044213b9dc7dab5ec26d37c469627e9ca49 100644 (file)
@@ -907,7 +907,8 @@ tcon_exit:
 tcon_error_exit:
        if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
                cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-               tcon->bad_network_name = true;
+               if (tcon)
+                       tcon->bad_network_name = true;
        }
        goto tcon_exit;
 }
@@ -1224,7 +1225,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        cifs_dbg(FYI, "SMB2 IOCTL\n");
 
-       *out_data = NULL;
+       if (out_data != NULL)
+               *out_data = NULL;
+
        /* zero out returned data len, in case of error */
        if (plen)
                *plen = 0;
@@ -2177,6 +2180,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
 
        if (rc) {
+               if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
+                       srch_inf->endOfSearch = true;
+                       rc = 0;
+               }
                cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
                goto qdir_exit;
        }
@@ -2214,11 +2221,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        else
                cifs_dbg(VFS, "illegal search buffer type\n");
 
-       if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
-               srch_inf->endOfSearch = 1;
-       else
-               srch_inf->endOfSearch = 0;
-
        return rc;
 
 qdir_exit:
index 69f3595d3952b74a595650103a791aec839f69a5..fbe486c285a90aff757a43569330fb32c9bbb50d 100644 (file)
@@ -573,6 +573,12 @@ struct copychunk_ioctl {
        __u32 Reserved2;
 } __packed;
 
+/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */
+struct file_zero_data_information {
+       __le64  FileOffset;
+       __le64  BeyondFinalZero;
+} __packed;
+
 struct copychunk_ioctl_rsp {
        __le32 ChunksWritten;
        __le32 ChunkBytesWritten;
index 0e538b5c96221f61f55f9a8bff58d6d88cfc836b..83efa59535bedf988292548c0fcba1526fcdde1c 100644 (file)
@@ -63,7 +63,7 @@
 #define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
 #define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
 #define FSCTL_SET_SPARSE             0x000900C4 /* BB add struct */
-#define FSCTL_SET_ZERO_DATA          0x000900C8 /* BB add struct */
+#define FSCTL_SET_ZERO_DATA          0x000980C8
 #define FSCTL_SET_ENCRYPTION         0x000900D7 /* BB add struct */
 #define FSCTL_ENCRYPTION_FSCTL_IO    0x000900DB /* BB add struct */
 #define FSCTL_WRITE_RAW_ENCRYPTED    0x000900DF /* BB add struct */
index 08cdfe5461e3f726650c1216f801d6620694ea5f..622e8824902432e5aae886ce68dca464f504fda3 100644 (file)
@@ -2828,8 +2828,9 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
                 */
                overhead += ngroups * (2 + sbi->s_itb_per_group);
 
-               /* Add the journal blocks as well */
-                overhead += sbi->s_journal->j_maxlen;
+               /* Add the internal journal blocks as well */
+               if (sbi->s_journal && !sbi->journal_bdev)
+                       overhead += sbi->s_journal->j_maxlen;
 
                sbi->s_overhead_last = overhead;
                smp_wmb();
index 4556ce1af5b04f5a4f0cd0b4e1ae0515435a1857..5ddaf8625d3b7a1ab3d0128a91dbd3b84b8b9b0b 100644 (file)
@@ -61,7 +61,7 @@ static void isofs_put_super(struct super_block *sb)
        return;
 }
 
-static int isofs_read_inode(struct inode *);
+static int isofs_read_inode(struct inode *, int relocated);
 static int isofs_statfs (struct dentry *, struct kstatfs *);
 
 static struct kmem_cache *isofs_inode_cachep;
@@ -1259,7 +1259,7 @@ out_toomany:
        goto out;
 }
 
-static int isofs_read_inode(struct inode *inode)
+static int isofs_read_inode(struct inode *inode, int relocated)
 {
        struct super_block *sb = inode->i_sb;
        struct isofs_sb_info *sbi = ISOFS_SB(sb);
@@ -1404,7 +1404,7 @@ static int isofs_read_inode(struct inode *inode)
         */
 
        if (!high_sierra) {
-               parse_rock_ridge_inode(de, inode);
+               parse_rock_ridge_inode(de, inode, relocated);
                /* if we want uid/gid set, override the rock ridge setting */
                if (sbi->s_uid_set)
                        inode->i_uid = sbi->s_uid;
@@ -1483,9 +1483,10 @@ static int isofs_iget5_set(struct inode *ino, void *data)
  * offset that point to the underlying meta-data for the inode.  The
  * code below is otherwise similar to the iget() code in
  * include/linux/fs.h */
-struct inode *isofs_iget(struct super_block *sb,
-                        unsigned long block,
-                        unsigned long offset)
+struct inode *__isofs_iget(struct super_block *sb,
+                          unsigned long block,
+                          unsigned long offset,
+                          int relocated)
 {
        unsigned long hashval;
        struct inode *inode;
@@ -1507,7 +1508,7 @@ struct inode *isofs_iget(struct super_block *sb,
                return ERR_PTR(-ENOMEM);
 
        if (inode->i_state & I_NEW) {
-               ret = isofs_read_inode(inode);
+               ret = isofs_read_inode(inode, relocated);
                if (ret < 0) {
                        iget_failed(inode);
                        inode = ERR_PTR(ret);
index 99167238518d61a30c4a5e6bfc838291d6206a5d..0ac4c1f73fbd6c2616e04ad6310995426c03da68 100644 (file)
@@ -107,7 +107,7 @@ extern int iso_date(char *, int);
 
 struct inode;          /* To make gcc happy */
 
-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
+extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
 extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
 extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
 
@@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int
 extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
-extern struct inode *isofs_iget(struct super_block *sb,
-                                unsigned long block,
-                                unsigned long offset);
+struct inode *__isofs_iget(struct super_block *sb,
+                          unsigned long block,
+                          unsigned long offset,
+                          int relocated);
+
+static inline struct inode *isofs_iget(struct super_block *sb,
+                                      unsigned long block,
+                                      unsigned long offset)
+{
+       return __isofs_iget(sb, block, offset, 0);
+}
+
+static inline struct inode *isofs_iget_reloc(struct super_block *sb,
+                                            unsigned long block,
+                                            unsigned long offset)
+{
+       return __isofs_iget(sb, block, offset, 1);
+}
 
 /* Because the inode number is no longer relevant to finding the
  * underlying meta-data for an inode, we are free to choose a more
index c0bf42472e408fd16911cee33f3d9079943aa46a..f488bbae541ac8d5db4eb7e963c33452ebb3e937 100644 (file)
@@ -288,12 +288,16 @@ eio:
        goto out;
 }
 
+#define RR_REGARD_XA 1
+#define RR_RELOC_DE 2
+
 static int
 parse_rock_ridge_inode_internal(struct iso_directory_record *de,
-                               struct inode *inode, int regard_xa)
+                               struct inode *inode, int flags)
 {
        int symlink_len = 0;
        int cnt, sig;
+       unsigned int reloc_block;
        struct inode *reloc;
        struct rock_ridge *rr;
        int rootflag;
@@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
 
        init_rock_state(&rs, inode);
        setup_rock_ridge(de, inode, &rs);
-       if (regard_xa) {
+       if (flags & RR_REGARD_XA) {
                rs.chr += 14;
                rs.len -= 14;
                if (rs.len < 0)
@@ -485,12 +489,22 @@ repeat:
                                        "relocated directory\n");
                        goto out;
                case SIG('C', 'L'):
-                       ISOFS_I(inode)->i_first_extent =
-                           isonum_733(rr->u.CL.location);
-                       reloc =
-                           isofs_iget(inode->i_sb,
-                                      ISOFS_I(inode)->i_first_extent,
-                                      0);
+                       if (flags & RR_RELOC_DE) {
+                               printk(KERN_ERR
+                                      "ISOFS: Recursive directory relocation "
+                                      "is not supported\n");
+                               goto eio;
+                       }
+                       reloc_block = isonum_733(rr->u.CL.location);
+                       if (reloc_block == ISOFS_I(inode)->i_iget5_block &&
+                           ISOFS_I(inode)->i_iget5_offset == 0) {
+                               printk(KERN_ERR
+                                      "ISOFS: Directory relocation points to "
+                                      "itself\n");
+                               goto eio;
+                       }
+                       ISOFS_I(inode)->i_first_extent = reloc_block;
+                       reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0);
                        if (IS_ERR(reloc)) {
                                ret = PTR_ERR(reloc);
                                goto out;
@@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
        return rpnt;
 }
 
-int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
+int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode,
+                          int relocated)
 {
-       int result = parse_rock_ridge_inode_internal(de, inode, 0);
+       int flags = relocated ? RR_RELOC_DE : 0;
+       int result = parse_rock_ridge_inode_internal(de, inode, flags);
 
        /*
         * if rockridge flag was reset and we didn't look for attributes
@@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
         */
        if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
            && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
-               result = parse_rock_ridge_inode_internal(de, inode, 14);
+               result = parse_rock_ridge_inode_internal(de, inode,
+                                                        flags | RR_REGARD_XA);
        }
        return result;
 }
index a6f54802d277304b2f483eb61af3ae6b574a79f9..cb66fb05ad4a97e6ed9e975dc631c09b42d7fc03 100644 (file)
@@ -247,6 +247,18 @@ void locks_free_lock(struct file_lock *fl)
 }
 EXPORT_SYMBOL(locks_free_lock);
 
+static void
+locks_dispose_list(struct list_head *dispose)
+{
+       struct file_lock *fl;
+
+       while (!list_empty(dispose)) {
+               fl = list_first_entry(dispose, struct file_lock, fl_block);
+               list_del_init(&fl->fl_block);
+               locks_free_lock(fl);
+       }
+}
+
 void locks_init_lock(struct file_lock *fl)
 {
        memset(fl, 0, sizeof(struct file_lock));
@@ -285,7 +297,8 @@ EXPORT_SYMBOL(__locks_copy_lock);
 
 void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
-       locks_release_private(new);
+       /* "new" must be a freshly-initialized lock */
+       WARN_ON_ONCE(new->fl_ops);
 
        __locks_copy_lock(new, fl);
        new->fl_file = fl->fl_file;
@@ -650,12 +663,16 @@ static void locks_unlink_lock(struct file_lock **thisfl_p)
  *
  * Must be called with i_lock held!
  */
-static void locks_delete_lock(struct file_lock **thisfl_p)
+static void locks_delete_lock(struct file_lock **thisfl_p,
+                             struct list_head *dispose)
 {
        struct file_lock *fl = *thisfl_p;
 
        locks_unlink_lock(thisfl_p);
-       locks_free_lock(fl);
+       if (dispose)
+               list_add(&fl->fl_block, dispose);
+       else
+               locks_free_lock(fl);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -811,6 +828,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
        struct inode * inode = file_inode(filp);
        int error = 0;
        int found = 0;
+       LIST_HEAD(dispose);
 
        if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
                new_fl = locks_alloc_lock();
@@ -833,7 +851,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                if (request->fl_type == fl->fl_type)
                        goto out;
                found = 1;
-               locks_delete_lock(before);
+               locks_delete_lock(before, &dispose);
                break;
        }
 
@@ -880,6 +898,7 @@ out:
        spin_unlock(&inode->i_lock);
        if (new_fl)
                locks_free_lock(new_fl);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -893,6 +912,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        struct file_lock **before;
        int error;
        bool added = false;
+       LIST_HEAD(dispose);
 
        /*
         * We may need two file_lock structures for this operation,
@@ -988,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        else
                                request->fl_end = fl->fl_end;
                        if (added) {
-                               locks_delete_lock(before);
+                               locks_delete_lock(before, &dispose);
                                continue;
                        }
                        request = fl;
@@ -1018,21 +1038,24 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                 * one (This may happen several times).
                                 */
                                if (added) {
-                                       locks_delete_lock(before);
+                                       locks_delete_lock(before, &dispose);
                                        continue;
                                }
-                               /* Replace the old lock with the new one.
-                                * Wake up anybody waiting for the old one,
-                                * as the change in lock type might satisfy
-                                * their needs.
+                               /*
+                                * Replace the old lock with new_fl, and
+                                * remove the old one. It's safe to do the
+                                * insert here since we know that we won't be
+                                * using new_fl later, and that the lock is
+                                * just replacing an existing lock.
                                 */
-                               locks_wake_up_blocks(fl);
-                               fl->fl_start = request->fl_start;
-                               fl->fl_end = request->fl_end;
-                               fl->fl_type = request->fl_type;
-                               locks_release_private(fl);
-                               locks_copy_private(fl, request);
-                               request = fl;
+                               error = -ENOLCK;
+                               if (!new_fl)
+                                       goto out;
+                               locks_copy_lock(new_fl, request);
+                               request = new_fl;
+                               new_fl = NULL;
+                               locks_delete_lock(before, &dispose);
+                               locks_insert_lock(before, request);
                                added = true;
                        }
                }
@@ -1093,6 +1116,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                locks_free_lock(new_fl);
        if (new_fl2)
                locks_free_lock(new_fl2);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -1268,7 +1292,7 @@ int lease_modify(struct file_lock **before, int arg)
                        printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
                        fl->fl_fasync = NULL;
                }
-               locks_delete_lock(before);
+               locks_delete_lock(before, NULL);
        }
        return 0;
 }
@@ -1737,13 +1761,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
        ret = fl;
        spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, &ret);
-       if (error) {
-               spin_unlock(&inode->i_lock);
-               locks_free_lock(fl);
-               goto out_free_fasync;
-       }
-       if (ret != fl)
-               locks_free_lock(fl);
+       if (error)
+               goto out_unlock;
+       if (ret == fl)
+               fl = NULL;
 
        /*
         * fasync_insert_entry() returns the old entry if any.
@@ -1755,9 +1776,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                new = NULL;
 
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
+out_unlock:
        spin_unlock(&inode->i_lock);
-
-out_free_fasync:
+       if (fl)
+               locks_free_lock(fl);
        if (new)
                fasync_free(new);
        return error;
@@ -2320,6 +2342,7 @@ void locks_remove_file(struct file *filp)
        struct inode * inode = file_inode(filp);
        struct file_lock *fl;
        struct file_lock **before;
+       LIST_HEAD(dispose);
 
        if (!inode->i_flock)
                return;
@@ -2365,12 +2388,13 @@ void locks_remove_file(struct file *filp)
                                fl->fl_type, fl->fl_flags,
                                fl->fl_start, fl->fl_end);
 
-                       locks_delete_lock(before);
+                       locks_delete_lock(before, &dispose);
                        continue;
                }
                before = &fl->fl_next;
        }
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
 }
 
 /**
@@ -2452,7 +2476,11 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                        seq_puts(f, "FLOCK  ADVISORY  ");
                }
        } else if (IS_LEASE(fl)) {
-               seq_puts(f, "LEASE  ");
+               if (fl->fl_flags & FL_DELEG)
+                       seq_puts(f, "DELEG  ");
+               else
+                       seq_puts(f, "LEASE  ");
+
                if (lease_breaking(fl))
                        seq_puts(f, "BREAKING  ");
                else if (fl->fl_file)
index 9737cba1357d754f4b1ea8927af83326865b8e54..83a06001742bfaab6781bc26509517196fc3af16 100644 (file)
@@ -1014,7 +1014,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi)
-               goto out_no_entry;
+               goto out_fail;
        cfi.icb.extLength = cpu_to_le32(sb->s_blocksize);
        cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        if (UDF_SB(inode->i_sb)->s_lvid_bh) {
@@ -1036,6 +1036,7 @@ out:
 
 out_no_entry:
        up_write(&iinfo->i_data_sem);
+out_fail:
        inode_dec_link_count(inode);
        iput(inode);
        goto out;
index 8e6c20af11a2c835b2489875513845161abb362c..e1e68da6f35c2edd71a08c47ddede967c90db3f9 100644 (file)
@@ -194,6 +194,9 @@ static inline char *mc_event_error_type(const unsigned int err_type)
  * @MEM_DDR3:          DDR3 RAM
  * @MEM_RDDR3:         Registered DDR3 RAM
  *                     This is a variant of the DDR3 memories.
+ * @MEM_DDR4:          DDR4 RAM
+ * @MEM_RDDR4:         Registered DDR4 RAM
+ *                     This is a variant of the DDR4 memories.
  */
 enum mem_type {
        MEM_EMPTY = 0,
@@ -213,6 +216,8 @@ enum mem_type {
        MEM_XDR,
        MEM_DDR3,
        MEM_RDDR3,
+       MEM_DDR4,
+       MEM_RDDR4,
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
index ea507665896cfa774cf3fe7226b9da77d7bc9622..a95efeb53a8b76da08450f47f614f9713dc89a9f 100644 (file)
@@ -577,16 +577,20 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
 }
 #endif /* CONFIG_OF */
 
-#ifdef CONFIG_I2C_ACPI
-int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
-void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
+#ifdef CONFIG_ACPI
 void acpi_i2c_register_devices(struct i2c_adapter *adap);
 #else
 static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
+#endif /* CONFIG_ACPI */
+
+#ifdef CONFIG_ACPI_I2C_OPREGION
+int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
+void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
+#else
 static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
 { }
 static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
 { return 0; }
-#endif
+#endif /* CONFIG_ACPI_I2C_OPREGION */
 
 #endif /* _LINUX_I2C_H */
index 1b1dfa80d9fffe2b28cfd5f02c64a3bad3c932d4..f583ff63977608827cd2e7e56fe4f344cdf4d7ed 100644 (file)
@@ -105,6 +105,7 @@ void input_mt_report_slot_state(struct input_dev *dev,
 
 void input_mt_report_finger_count(struct input_dev *dev, int count);
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
+void input_mt_drop_unused(struct input_dev *dev);
 
 void input_mt_sync_frame(struct input_dev *dev);
 
index fd0421c6d40a1dbce334ba1e3c423cee4a744434..95ed9424a11af26d21ba83865386d9e1e573231c 100644 (file)
@@ -527,6 +527,7 @@ enum iscsi_err {
        ISCSI_ERR_XMIT_FAILED           = ISCSI_ERR_BASE + 19,
        ISCSI_ERR_TCP_CONN_CLOSE        = ISCSI_ERR_BASE + 20,
        ISCSI_ERR_SCSI_EH_SESSION_RST   = ISCSI_ERR_BASE + 21,
+       ISCSI_ERR_NOP_TIMEDOUT          = ISCSI_ERR_BASE + 22,
 };
 
 /*
index f1afd607f043cc6aa0a9da0649b1dc92eeaad275..11d11bc5c78f2d480ecac331cbf5d73f58001bb7 100644 (file)
@@ -703,9 +703,11 @@ __SYSCALL(__NR_renameat2, sys_renameat2)
 __SYSCALL(__NR_seccomp, sys_seccomp)
 #define __NR_getrandom 278
 __SYSCALL(__NR_getrandom, sys_getrandom)
+#define __NR_memfd_create 279
+__SYSCALL(__NR_memfd_create, sys_memfd_create)
 
 #undef __NR_syscalls
-#define __NR_syscalls 279
+#define __NR_syscalls 280
 
 /*
  * All syscalls below here should go away really,
index 6f69463f006653bb7f572ef71aa1034de3d69e9f..03214bd288e9a90876aa5f1c92b8ebd596520e54 100644 (file)
@@ -3304,6 +3304,11 @@ static int load_module(struct load_info *info, const char __user *uargs,
        mutex_lock(&module_mutex);
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
+
+       /* we can't deallocate the module until we clear memory protection */
+       unset_module_init_ro_nx(mod);
+       unset_module_core_ro_nx(mod);
+
  ddebug_cleanup:
        dynamic_debug_remove(info->debug);
        synchronize_sched();
index 62b8869f5a4c43737dc3e89e9cc408c535676ed2..279bc565ac7e9a01a7d0a8093041d734d31aaefe 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "mpu401.h"
 
-typedef struct uart401_devc
+struct uart401_devc
 {
        int             base;
        int             irq;
@@ -41,14 +41,13 @@ typedef struct uart401_devc
        int             my_dev;
        int             share_irq;
        spinlock_t      lock;
-}
-uart401_devc;
+};
 
 #define        DATAPORT   (devc->base)
 #define        COMDPORT   (devc->base+1)
 #define        STATPORT   (devc->base+1)
 
-static int uart401_status(uart401_devc * devc)
+static int uart401_status(struct uart401_devc *devc)
 {
        return inb(STATPORT);
 }
@@ -56,17 +55,17 @@ static int uart401_status(uart401_devc * devc)
 #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
 #define output_ready(devc)     (!(uart401_status(devc)&OUTPUT_READY))
 
-static void uart401_cmd(uart401_devc * devc, unsigned char cmd)
+static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd)
 {
        outb((cmd), COMDPORT);
 }
 
-static int uart401_read(uart401_devc * devc)
+static int uart401_read(struct uart401_devc *devc)
 {
        return inb(DATAPORT);
 }
 
-static void uart401_write(uart401_devc * devc, unsigned char byte)
+static void uart401_write(struct uart401_devc *devc, unsigned char byte)
 {
        outb((byte), DATAPORT);
 }
@@ -77,10 +76,10 @@ static void uart401_write(uart401_devc * devc, unsigned char byte)
 #define        MPU_RESET       0xFF
 #define        UART_MODE_ON    0x3F
 
-static int      reset_uart401(uart401_devc * devc);
-static void     enter_uart_mode(uart401_devc * devc);
+static int      reset_uart401(struct uart401_devc *devc);
+static void     enter_uart_mode(struct uart401_devc *devc);
 
-static void uart401_input_loop(uart401_devc * devc)
+static void uart401_input_loop(struct uart401_devc *devc)
 {
        int work_limit=30000;
        
@@ -99,7 +98,7 @@ static void uart401_input_loop(uart401_devc * devc)
 
 irqreturn_t uart401intr(int irq, void *dev_id)
 {
-       uart401_devc *devc = dev_id;
+       struct uart401_devc *devc = dev_id;
 
        if (devc == NULL)
        {
@@ -118,7 +117,8 @@ uart401_open(int dev, int mode,
             void            (*output) (int dev)
 )
 {
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        if (devc->opened)
                return -EBUSY;
@@ -138,7 +138,8 @@ uart401_open(int dev, int mode,
 
 static void uart401_close(int dev)
 {
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        reset_uart401(devc);
        devc->opened = 0;
@@ -148,7 +149,8 @@ static int uart401_out(int dev, unsigned char midi_byte)
 {
        int timeout;
        unsigned long flags;
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        if (devc->disabled)
                return 1;
@@ -219,7 +221,7 @@ static const struct midi_operations uart401_operations =
        .buffer_status  = uart401_buffer_status,
 };
 
-static void enter_uart_mode(uart401_devc * devc)
+static void enter_uart_mode(struct uart401_devc *devc)
 {
        int ok, timeout;
        unsigned long flags;
@@ -241,7 +243,7 @@ static void enter_uart_mode(uart401_devc * devc)
        spin_unlock_irqrestore(&devc->lock,flags);
 }
 
-static int reset_uart401(uart401_devc * devc)
+static int reset_uart401(struct uart401_devc *devc)
 {
        int ok, timeout, n;
 
@@ -285,7 +287,7 @@ static int reset_uart401(uart401_devc * devc)
 
 int probe_uart401(struct address_info *hw_config, struct module *owner)
 {
-       uart401_devc *devc;
+       struct uart401_devc *devc;
        char *name = "MPU-401 (UART) MIDI";
        int ok = 0;
        unsigned long flags;
@@ -300,7 +302,7 @@ int probe_uart401(struct address_info *hw_config, struct module *owner)
                return 0;
        }
 
-       devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL);
+       devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL);
        if (!devc) {
                printk(KERN_WARNING "uart401: Can't allocate memory\n");
                goto cleanup_region;
@@ -392,7 +394,7 @@ cleanup_region:
 
 void unload_uart401(struct address_info *hw_config)
 {
-       uart401_devc *devc;
+       struct uart401_devc *devc;
        int n=hw_config->slots[4];
        
        /* Not set up */
index 672af8b56542ddf8e04639dca07959dcb1d1ac79..b36ea47527e87f567cd5c97ee7b9d3297676f092 100644 (file)
@@ -92,7 +92,7 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = {
        0x0000          /* Monitor               */
 };
 
-typedef struct {
+struct wavnc_info {
        struct address_info  hw;        /* hardware */
        char            *chip_name;
 
@@ -119,7 +119,7 @@ typedef struct {
        unsigned int    line_mute_state :1;/* set by ioctl or autoselect */
        unsigned int    use_slider      :1;/* use slider setting for o/p vol */
 #endif
-} wavnc_info;
+};
 
 /*
  * This is the implementation specific mixer information.
@@ -129,29 +129,30 @@ struct waveartist_mixer_info {
        unsigned int    recording_devs;    /* Recordable devies */
        unsigned int    stereo_devs;       /* Stereo devices    */
 
-       unsigned int    (*select_input)(wavnc_info *, unsigned int,
+       unsigned int    (*select_input)(struct wavnc_info *, unsigned int,
                                        unsigned char *, unsigned char *);
-       int             (*decode_mixer)(wavnc_info *, int,
+       int             (*decode_mixer)(struct wavnc_info *, int,
                                        unsigned char, unsigned char);
-       int             (*get_mixer)(wavnc_info *, int);
+       int             (*get_mixer)(struct wavnc_info *, int);
 };
 
-typedef struct wavnc_port_info {
+struct wavnc_port_info {
        int             open_mode;
        int             speed;
        int             channels;
        int             audio_format;
-} wavnc_port_info;
+};
 
 static int             nr_waveartist_devs;
-static wavnc_info      adev_info[MAX_AUDIO_DEV];
+static struct wavnc_info       adev_info[MAX_AUDIO_DEV];
 static DEFINE_SPINLOCK(waveartist_lock);
 
 #ifndef CONFIG_ARCH_NETWINDER
 #define machine_is_netwinder() 0
 #else
 static struct timer_list vnc_timer;
-static void vnc_configure_mixer(wavnc_info *devc, unsigned int input_mask);
+static void vnc_configure_mixer(struct wavnc_info *devc,
+                               unsigned int input_mask);
 static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg);
 static void vnc_slider_tick(unsigned long data);
 #endif
@@ -169,7 +170,7 @@ waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char
 /* Toggle IRQ acknowledge line
  */
 static inline void
-waveartist_iack(wavnc_info *devc)
+waveartist_iack(struct wavnc_info *devc)
 {
        unsigned int ctlr_port = devc->hw.io_base + CTLR;
        int old_ctlr;
@@ -188,7 +189,7 @@ waveartist_sleep(int timeout_ms)
 }
 
 static int
-waveartist_reset(wavnc_info *devc)
+waveartist_reset(struct wavnc_info *devc)
 {
        struct address_info *hw = &devc->hw;
        unsigned int timeout, res = -1;
@@ -223,7 +224,7 @@ waveartist_reset(wavnc_info *devc)
  * and can send or receive multiple words.
  */
 static int
-waveartist_cmd(wavnc_info *devc,
+waveartist_cmd(struct wavnc_info *devc,
                int nr_cmd, unsigned int *cmd,
                int nr_resp, unsigned int *resp)
 {
@@ -299,7 +300,7 @@ waveartist_cmd(wavnc_info *devc,
  * Send one command word
  */
 static inline int
-waveartist_cmd1(wavnc_info *devc, unsigned int cmd)
+waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd)
 {
        return waveartist_cmd(devc, 1, &cmd, 0, NULL);
 }
@@ -308,7 +309,7 @@ waveartist_cmd1(wavnc_info *devc, unsigned int cmd)
  * Send one command, receive one word
  */
 static inline unsigned int
-waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd)
+waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd)
 {
        unsigned int ret;
 
@@ -322,7 +323,7 @@ waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd)
  * word (and throw it away)
  */
 static inline int
-waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg)
+waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg)
 {
        unsigned int vals[2];
 
@@ -336,7 +337,7 @@ waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg)
  * Send a triple command
  */
 static inline int
-waveartist_cmd3(wavnc_info *devc, unsigned int cmd,
+waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd,
                unsigned int arg1, unsigned int arg2)
 {
        unsigned int vals[3];
@@ -349,7 +350,7 @@ waveartist_cmd3(wavnc_info *devc, unsigned int cmd,
 }
 
 static int
-waveartist_getrev(wavnc_info *devc, char *rev)
+waveartist_getrev(struct wavnc_info *devc, char *rev)
 {
        unsigned int temp[2];
        unsigned int cmd = WACMD_GETREV;
@@ -371,15 +372,15 @@ static void waveartist_trigger(int dev, int state);
 static int
 waveartist_open(int dev, int mode)
 {
-       wavnc_info      *devc;
-       wavnc_port_info *portc;
+       struct wavnc_info       *devc;
+       struct wavnc_port_info  *portc;
        unsigned long   flags;
 
        if (dev < 0 || dev >= num_audiodevs)
                return -ENXIO;
 
-       devc  = (wavnc_info *) audio_devs[dev]->devc;
-       portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       devc  = (struct wavnc_info *) audio_devs[dev]->devc;
+       portc = (struct wavnc_port_info *) audio_devs[dev]->portc;
 
        spin_lock_irqsave(&waveartist_lock, flags);
        if (portc->open_mode || (devc->open_mode & mode)) {
@@ -404,8 +405,10 @@ waveartist_open(int dev, int mode)
 static void
 waveartist_close(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -422,8 +425,10 @@ waveartist_close(int dev)
 static void
 waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
        unsigned int    count = __count; 
 
@@ -467,8 +472,10 @@ waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag)
 static void
 waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
        unsigned int    count = __count;
 
@@ -514,7 +521,7 @@ waveartist_ioctl(int dev, unsigned int cmd, void __user * arg)
 }
 
 static unsigned int
-waveartist_get_speed(wavnc_port_info *portc)
+waveartist_get_speed(struct wavnc_port_info *portc)
 {
        unsigned int speed;
 
@@ -542,7 +549,7 @@ waveartist_get_speed(wavnc_port_info *portc)
 }
 
 static unsigned int
-waveartist_get_bits(wavnc_port_info *portc)
+waveartist_get_bits(struct wavnc_port_info *portc)
 {
        unsigned int bits;
 
@@ -560,8 +567,10 @@ static int
 waveartist_prepare_for_input(int dev, int bsize, int bcount)
 {
        unsigned long   flags;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned int    speed, bits;
 
        if (devc->audio_mode)
@@ -615,8 +624,10 @@ static int
 waveartist_prepare_for_output(int dev, int bsize, int bcount)
 {
        unsigned long   flags;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned int    speed, bits;
 
        /*
@@ -660,8 +671,9 @@ waveartist_prepare_for_output(int dev, int bsize, int bcount)
 static void
 waveartist_halt(int dev)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
+       struct wavnc_info       *devc;
 
        if (portc->open_mode & OPEN_WRITE)
                waveartist_halt_output(dev);
@@ -669,14 +681,15 @@ waveartist_halt(int dev)
        if (portc->open_mode & OPEN_READ)
                waveartist_halt_input(dev);
 
-       devc = (wavnc_info *) audio_devs[dev]->devc;
+       devc = (struct wavnc_info *) audio_devs[dev]->devc;
        devc->audio_mode = 0;
 }
 
 static void
 waveartist_halt_input(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -703,7 +716,8 @@ waveartist_halt_input(int dev)
 static void
 waveartist_halt_output(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -727,8 +741,10 @@ waveartist_halt_output(int dev)
 static void
 waveartist_trigger(int dev, int state)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned long   flags;
 
        if (debug_flg & DEBUG_TRIGGER) {
@@ -764,7 +780,8 @@ waveartist_trigger(int dev, int state)
 static int
 waveartist_set_speed(int dev, int arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg <= 0)
                return portc->speed;
@@ -782,7 +799,8 @@ waveartist_set_speed(int dev, int arg)
 static short
 waveartist_set_channels(int dev, short arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg != 1 && arg != 2)
                return portc->channels;
@@ -794,7 +812,8 @@ waveartist_set_channels(int dev, short arg)
 static unsigned int
 waveartist_set_bits(int dev, unsigned int arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg == 0)
                return portc->audio_format;
@@ -829,7 +848,7 @@ static struct audio_driver waveartist_audio_driver = {
 static irqreturn_t
 waveartist_intr(int irq, void *dev_id)
 {
-       wavnc_info *devc = dev_id;
+       struct wavnc_info *devc = dev_id;
        int        irqstatus, status;
 
        spin_lock(&waveartist_lock);
@@ -912,7 +931,7 @@ static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = {
 };
 
 static void
-waveartist_mixer_update(wavnc_info *devc, int whichDev)
+waveartist_mixer_update(struct wavnc_info *devc, int whichDev)
 {
        unsigned int lev_left, lev_right;
 
@@ -973,7 +992,8 @@ waveartist_mixer_update(wavnc_info *devc, int whichDev)
  * relevant *_select_input function has done that for us.
  */
 static void
-waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev)
+waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev,
+                      char right_dev)
 {
        unsigned int reg_08, reg_09;
 
@@ -996,7 +1016,7 @@ waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev)
  *  SOUND_MASK_MIC     Mic             Microphone
  */
 static unsigned int
-waveartist_select_input(wavnc_info *devc, unsigned int recmask,
+waveartist_select_input(struct wavnc_info *devc, unsigned int recmask,
                        unsigned char *dev_l, unsigned char *dev_r)
 {
        unsigned int recdev = ADC_MUX_NONE;
@@ -1024,7 +1044,8 @@ waveartist_select_input(wavnc_info *devc, unsigned int recmask,
 }
 
 static int
-waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
+waveartist_decode_mixer(struct wavnc_info *devc, int dev,
+                       unsigned char lev_l,
                        unsigned char lev_r)
 {
        switch (dev) {
@@ -1050,7 +1071,7 @@ waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
        return dev;
 }
 
-static int waveartist_get_mixer(wavnc_info *devc, int dev)
+static int waveartist_get_mixer(struct wavnc_info *devc, int dev)
 {
        return devc->levels[dev];
 }
@@ -1068,7 +1089,7 @@ static const struct waveartist_mixer_info waveartist_mixer = {
 };
 
 static void
-waveartist_set_recmask(wavnc_info *devc, unsigned int recmask)
+waveartist_set_recmask(struct wavnc_info *devc, unsigned int recmask)
 {
        unsigned char dev_l, dev_r;
 
@@ -1092,7 +1113,7 @@ waveartist_set_recmask(wavnc_info *devc, unsigned int recmask)
 }
 
 static int
-waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level)
+waveartist_set_mixer(struct wavnc_info *devc, int dev, unsigned int level)
 {
        unsigned int lev_left  = level & 0x00ff;
        unsigned int lev_right = (level & 0xff00) >> 8;
@@ -1120,7 +1141,7 @@ waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level)
 static int
 waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
 {
-       wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+       struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc;
        int ret = 0, val, nr;
 
        /*
@@ -1204,7 +1225,7 @@ static struct mixer_operations waveartist_mixer_operations =
 };
 
 static void
-waveartist_mixer_reset(wavnc_info *devc)
+waveartist_mixer_reset(struct wavnc_info *devc)
 {
        int i;
 
@@ -1241,9 +1262,9 @@ waveartist_mixer_reset(wavnc_info *devc)
                waveartist_mixer_update(devc, i);
 }
 
-static int __init waveartist_init(wavnc_info *devc)
+static int __init waveartist_init(struct wavnc_info *devc)
 {
-       wavnc_port_info *portc;
+       struct wavnc_port_info *portc;
        char rev[3], dev_name[64];
        int my_dev;
 
@@ -1261,7 +1282,7 @@ static int __init waveartist_init(wavnc_info *devc)
        conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq,
                     devc->hw.dma, devc->hw.dma2);
 
-       portc = kzalloc(sizeof(wavnc_port_info), GFP_KERNEL);
+       portc = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL);
        if (portc == NULL)
                goto nomem;
 
@@ -1330,7 +1351,7 @@ nomem:
 
 static int __init probe_waveartist(struct address_info *hw_config)
 {
-       wavnc_info *devc = &adev_info[nr_waveartist_devs];
+       struct wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
        if (nr_waveartist_devs >= MAX_AUDIO_DEV) {
                printk(KERN_WARNING "waveartist: too many audio devices\n");
@@ -1367,7 +1388,7 @@ static int __init probe_waveartist(struct address_info *hw_config)
 static void __init
 attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix)
 {
-       wavnc_info *devc = &adev_info[nr_waveartist_devs];
+       struct wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
        /*
         * NOTE! If irq < 0, there is another driver which has allocated the
@@ -1410,7 +1431,7 @@ attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *m
 
 static void __exit unload_waveartist(struct address_info *hw)
 {
-       wavnc_info *devc = NULL;
+       struct wavnc_info *devc = NULL;
        int i;
 
        for (i = 0; i < nr_waveartist_devs; i++)
@@ -1478,7 +1499,7 @@ static void __exit unload_waveartist(struct address_info *hw)
 #define VNC_DISABLE_AUTOSWITCH 0x80
 
 static inline void
-vnc_mute_spkr(wavnc_info *devc)
+vnc_mute_spkr(struct wavnc_info *devc)
 {
        unsigned long flags;
 
@@ -1488,7 +1509,7 @@ vnc_mute_spkr(wavnc_info *devc)
 }
 
 static void
-vnc_mute_lout(wavnc_info *devc)
+vnc_mute_lout(struct wavnc_info *devc)
 {
        unsigned int left, right;
 
@@ -1507,7 +1528,7 @@ vnc_mute_lout(wavnc_info *devc)
 }
 
 static int
-vnc_volume_slider(wavnc_info *devc)
+vnc_volume_slider(struct wavnc_info *devc)
 {
        static signed int old_slider_volume;
        unsigned long flags;
@@ -1567,7 +1588,7 @@ vnc_volume_slider(wavnc_info *devc)
  *  SOUND_MASK_MIC     Right Mic       Builtin microphone
  */
 static unsigned int
-netwinder_select_input(wavnc_info *devc, unsigned int recmask,
+netwinder_select_input(struct wavnc_info *devc, unsigned int recmask,
                       unsigned char *dev_l, unsigned char *dev_r)
 {
        unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE;
@@ -1604,7 +1625,7 @@ netwinder_select_input(wavnc_info *devc, unsigned int recmask,
 }
 
 static int
-netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
+netwinder_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l,
                       unsigned char lev_r)
 {
        switch (dev) {
@@ -1643,7 +1664,7 @@ netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
        return dev;
 }
 
-static int netwinder_get_mixer(wavnc_info *devc, int dev)
+static int netwinder_get_mixer(struct wavnc_info *devc, int dev)
 {
        int levels;
 
@@ -1703,7 +1724,7 @@ static const struct waveartist_mixer_info netwinder_mixer = {
 };
 
 static void
-vnc_configure_mixer(wavnc_info *devc, unsigned int recmask)
+vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask)
 {
        if (!devc->no_autoselect) {
                if (devc->handset_detect) {
@@ -1729,7 +1750,7 @@ vnc_configure_mixer(wavnc_info *devc, unsigned int recmask)
 }
 
 static int
-vnc_slider(wavnc_info *devc)
+vnc_slider(struct wavnc_info *devc)
 {
        signed int slider_volume;
        unsigned int temp, old_hs, old_td;
@@ -1795,7 +1816,7 @@ vnc_slider_tick(unsigned long data)
 static int
 vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg)
 {
-       wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+       struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc;
        int val;
 
        switch (cmd) {
index 5db1948699d88c37ba02735fc949c6642f474914..aa302fb03fc5bfe582b2f27dd3616a5b4ef039aa 100644 (file)
@@ -265,6 +265,7 @@ enum {
        AZX_DRIVER_TERA,
        AZX_DRIVER_CTX,
        AZX_DRIVER_CTHDA,
+       AZX_DRIVER_CMEDIA,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -330,6 +331,7 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_TERA] = "HDA Teradici", 
        [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_CTHDA] = "HDA Creative",
+       [AZX_DRIVER_CMEDIA] = "HDA C-Media",
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -1373,6 +1375,7 @@ static void azx_check_snoop_available(struct azx *chip)
                snoop = false;
                break;
        case AZX_DRIVER_CTHDA:
+       case AZX_DRIVER_CMEDIA:
                snoop = false;
                break;
        }
@@ -2154,6 +2157,10 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
          AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
+       /* CM8888 */
+       { PCI_DEVICE(0x13f6, 0x5011),
+         .driver_data = AZX_DRIVER_CMEDIA |
+         AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB },
        /* Vortex86MX */
        { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* VMware HDAudio */
index 4f3aba78f720ceb6a7bf97470e5bd5e72eea4a89..5d8455e2dacd709c308d215a44155134e15319cd 100644 (file)
@@ -4376,6 +4376,9 @@ static void ca0132_download_dsp(struct hda_codec *codec)
        return; /* NOP */
 #endif
 
+       if (spec->dsp_state == DSP_DOWNLOAD_FAILED)
+               return; /* don't retry failures */
+
        chipio_enable_clocks(codec);
        spec->dsp_state = DSP_DOWNLOADING;
        if (!ca0132_download_dsp_images(codec))
@@ -4552,7 +4555,8 @@ static int ca0132_init(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       spec->dsp_state = DSP_DOWNLOAD_INIT;
+       if (spec->dsp_state != DSP_DOWNLOAD_FAILED)
+               spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
 
        snd_hda_power_up(codec);
@@ -4663,6 +4667,7 @@ static int patch_ca0132(struct hda_codec *codec)
        codec->spec = spec;
        spec->codec = codec;
 
+       spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->num_mixers = 1;
        spec->mixers[0] = ca0132_mixer;
 
index ed3d133ffbb6567ccf2d76f13e3bcc3fcfde418b..c895a8f211922415b1498a2092772149d9ab13c7 100644 (file)
@@ -75,15 +75,62 @@ static int patch_cmi9880(struct hda_codec *codec)
        return err;
 }
 
+static int patch_cmi8888(struct hda_codec *codec)
+{
+       struct cmi_spec *spec;
+       struct auto_pin_cfg *cfg;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       cfg = &spec->gen.autocfg;
+       snd_hda_gen_spec_init(&spec->gen);
+
+       /* mask NID 0x10 from the playback volume selection;
+        * it's a headphone boost volume handled manually below
+        */
+       spec->gen.out_vol_mask = (1ULL << 0x10);
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               goto error;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               goto error;
+
+       if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
+           AC_JACK_HP_OUT) {
+               static const struct snd_kcontrol_new amp_kctl =
+                       HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
+                                        0x10, 0, HDA_OUTPUT);
+               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       codec->patch_ops = cmi_auto_patch_ops;
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
 /*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
+       { .id = 0x13f68888, .name = "CMI8888", .patch = patch_cmi8888 },
        { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
        { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
        {} /* terminator */
 };
 
+MODULE_ALIAS("snd-hda-codec-id:13f68888");
 MODULE_ALIAS("snd-hda-codec-id:13f69880");
 MODULE_ALIAS("snd-hda-codec-id:434d4980");
 
index 7627a69ca6d78313a36bb4c93eae37b158f2ad67..6f2fa838b63532852ab535ab9ff189b99c52edea 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -859,6 +860,11 @@ static int patch_conexant_auto(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
+       if (codec->vendor_id == 0x14f15051) {
+               /* minimum value is actually mute */
+               spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+       }
+
        codec->patch_ops = cx_auto_patch_ops;
 
        /* Some laptops with Conexant chips show stalls in S3 resume,
index 36badba2dcec8bde02b67229e4bb8bcd1a3ad3fb..99d7d7fecaad09934090eb6575cfb43131f2dfb4 100644 (file)
@@ -50,6 +50,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec))
 
 #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882)
+#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883)
+#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec))
 
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
@@ -1459,7 +1461,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                            mux_idx);
 
        /* configure unused pins to choose other converters */
-       if (is_haswell_plus(codec) || is_valleyview(codec))
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
                intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
 
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
@@ -1598,7 +1600,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
                 *   and this can make HW reset converter selection on a pin.
                 */
                if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
-                       if (is_haswell_plus(codec) || is_valleyview(codec)) {
+                       if (is_haswell_plus(codec) ||
+                               is_valleyview_plus(codec)) {
                                intel_verify_pin_cvt_connect(codec, per_pin);
                                intel_not_share_assigned_cvt(codec, pin_nid,
                                                        per_pin->mux_idx);
@@ -1779,7 +1782,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        bool non_pcm;
        int pinctl;
 
-       if (is_haswell_plus(codec) || is_valleyview(codec)) {
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
                /* Verify pin:cvt selections to avoid silent audio after S3.
                 * After S3, the audio driver restores pin:cvt selections
                 * but this can happen before gfx is ready and such selection
@@ -2330,9 +2333,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                intel_haswell_fixup_enable_dp12(codec);
        }
 
-       if (is_haswell(codec) || is_valleyview(codec)) {
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
                codec->depop_delay = 0;
-       }
 
        if (hdmi_parse_codec(codec) < 0) {
                codec->spec = NULL;
index 654c8f16d150cc8f8763edc5b26c75c6cfc879a6..d71270a3f73f7ec1826397fe45c00e53fa143a1a 100644 (file)
@@ -181,6 +181,8 @@ static void alc_fix_pll(struct hda_codec *codec)
                            spec->pll_coef_idx);
        val = snd_hda_codec_read(codec, spec->pll_nid, 0,
                                 AC_VERB_GET_PROC_COEF, 0);
+       if (val == -1)
+               return;
        snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
                            spec->pll_coef_idx);
        snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
@@ -2782,9 +2784,32 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
+static int find_ext_mic_pin(struct hda_codec *codec);
+
+static void alc286_shutup(struct hda_codec *codec)
+{
+       int i;
+       int mic_pin = find_ext_mic_pin(codec);
+       /* don't shut up pins when unloading the driver; otherwise it breaks
+        * the default pin setup at the next load of the driver
+        */
+       if (codec->bus->shutdown)
+               return;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               /* use read here for syncing after issuing each verb */
+               if (pin->nid != mic_pin)
+                       snd_hda_codec_read(codec, pin->nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+       codec->pins_shutup = 1;
+}
+
 static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
        int val = alc_read_coef_idx(codec, 0x04);
+       if (val == -1)
+               return;
        if (power_up)
                val |= 1 << 11;
        else
@@ -3243,6 +3268,15 @@ static int alc269_resume(struct hda_codec *codec)
        snd_hda_codec_resume_cache(codec);
        alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
+
+       /* on some machine, the BIOS will clear the codec gpio data when enter
+        * suspend, and won't restore the data after resume, so we restore it
+        * in the driver.
+        */
+       if (spec->gpio_led)
+               snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA,
+                           spec->gpio_led);
+
        if (spec->has_alc5505_dsp)
                alc5505_dsp_resume(codec);
 
@@ -4072,7 +4106,7 @@ static unsigned int alc_power_filter_xps13(struct hda_codec *codec,
 
        /* Avoid pop noises when headphones are plugged in */
        if (spec->gen.hp_jack_present)
-               if (nid == codec->afg || nid == 0x02)
+               if (nid == codec->afg || nid == 0x02 || nid == 0x15)
                        return AC_PWRST_D0;
        return power_state;
 }
@@ -4082,8 +4116,19 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec,
 {
        if (action == HDA_FIXUP_ACT_PROBE) {
                struct alc_spec *spec = codec->spec;
+               struct hda_input_mux *imux = &spec->gen.input_mux;
+               int i;
+
                spec->shutup = alc_no_shutup;
                codec->power_filter = alc_power_filter_xps13;
+
+               /* Make the internal mic the default input source. */
+               for (i = 0; i < imux->num_items; i++) {
+                       if (spec->gen.imux_pins[i] == 0x12) {
+                               spec->gen.cur_mux[0] = i;
+                               break;
+                       }
+               }
        }
 }
 
@@ -5279,27 +5324,30 @@ static void alc269_fill_coef(struct hda_codec *codec)
        if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
                val = alc_read_coef_idx(codec, 0x04);
                /* Power up output pin */
-               alc_write_coef_idx(codec, 0x04, val | (1<<11));
+               if (val != -1)
+                       alc_write_coef_idx(codec, 0x04, val | (1<<11));
        }
 
        if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
                val = alc_read_coef_idx(codec, 0xd);
-               if ((val & 0x0c00) >> 10 != 0x1) {
+               if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
                        /* Capless ramp up clock control */
                        alc_write_coef_idx(codec, 0xd, val | (1<<10));
                }
                val = alc_read_coef_idx(codec, 0x17);
-               if ((val & 0x01c0) >> 6 != 0x4) {
+               if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
                        /* Class D power on reset */
                        alc_write_coef_idx(codec, 0x17, val | (1<<7));
                }
        }
 
        val = alc_read_coef_idx(codec, 0xd); /* Class D */
-       alc_write_coef_idx(codec, 0xd, val | (1<<14));
+       if (val != -1)
+               alc_write_coef_idx(codec, 0xd, val | (1<<14));
 
        val = alc_read_coef_idx(codec, 0x4); /* HP */
-       alc_write_coef_idx(codec, 0x4, val | (1<<11));
+       if (val != -1)
+               alc_write_coef_idx(codec, 0x4, val | (1<<11));
 }
 
 /*
@@ -5384,6 +5432,7 @@ static int patch_alc269(struct hda_codec *codec)
        case 0x10ec0286:
        case 0x10ec0288:
                spec->codec_variant = ALC269_TYPE_ALC286;
+               spec->shutup = alc286_shutup;
                break;
        case 0x10ec0255:
                spec->codec_variant = ALC269_TYPE_ALC255;
index bd41ee4da078c6c7808364db38d344eab4151a75..2c71f16bd6613fc3e07ca63c4a5b1d8f85efa874 100644 (file)
@@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        else
                rates = &arizona_48k_bclk_rates[0];
 
+       wl = snd_pcm_format_width(params_format(params));
+
        if (tdm_slots) {
                arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
                                tdm_slots, tdm_width);
@@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
                channels = tdm_slots;
        } else {
                bclk_target = snd_soc_params_to_bclk(params);
+               tdm_width = wl;
        }
 
        if (chan_limit && chan_limit < channels) {
@@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
                        rates[bclk], rates[bclk] / lrclk);
 
-       wl = snd_pcm_format_width(params_format(params));
-       frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
+       frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
 
        reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
 
index 163ec3855fd4027e01a1067fa6842688f0175f4b..0c8aefab404ca15cabfaaf43a36d1885983476ed 100644 (file)
@@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds =
                        pcm512x_ramp_step_text);
 
 static const struct snd_kcontrol_new pcm512x_controls[] = {
-SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
                 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
 SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
               PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
 SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
               PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
           PCM512x_RQMR_SHIFT, 1, 1),
 
 SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
index c28508da34cf3ba4354ba6d54de685a03d112ca4..6a6b2ff7d7d73daf4b6742242af4247e5585ebcc 100644 (file)
@@ -403,7 +403,8 @@ out:
        return ret;
 }
 
-static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+                                     int div, bool explicit)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
@@ -420,7 +421,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
                               ACLKXDIV(div - 1), ACLKXDIV_MASK);
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
                               ACLKRDIV(div - 1), ACLKRDIV_MASK);
-               mcasp->bclk_div = div;
+               if (explicit)
+                       mcasp->bclk_div = div;
                break;
 
        case 2:         /* BCLK/LRCLK ratio */
@@ -434,6 +436,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
        return 0;
 }
 
+static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+                                   int div)
+{
+       return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1);
+}
+
 static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                                    unsigned int freq, int dir)
 {
@@ -738,7 +746,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                 "Inaccurate BCLK: %u Hz / %u != %u Hz\n",
                                 mcasp->sysclk_freq, div, bclk_freq);
                }
-               davinci_mcasp_set_clkdiv(cpu_dai, 1, div);
+               __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
        }
 
        ret = mcasp_common_hw_param(mcasp, substream->stream,
index f54a8fc992913ee837ee8c2914599274982bbba2..f3012b645b51fcfdcdbc5c2e60b8f1d5db11724f 100644 (file)
@@ -49,7 +49,6 @@ config SND_SOC_FSL_ESAI
        tristate "Enhanced Serial Audio Interface (ESAI) module support"
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
-       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Enhanced Synchronous Audio Interface
          (ESAI) support for the Freescale CPUs.
index 72d154e7dd03c3695860dd4da8b00fd6bc2ff3c5..a3b29ed84963459baada6cc9d8ab742f696ee44e 100644 (file)
@@ -18,7 +18,6 @@
 
 #include "fsl_esai.h"
 #include "imx-pcm.h"
-#include "fsl_utils.h"
 
 #define FSL_ESAI_RATES         SNDRV_PCM_RATE_8000_192000
 #define FSL_ESAI_FORMATS       (SNDRV_PCM_FMTBIT_S8 | \
@@ -607,7 +606,6 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = {
        .hw_params = fsl_esai_hw_params,
        .set_sysclk = fsl_esai_set_dai_sysclk,
        .set_fmt = fsl_esai_set_dai_fmt,
-       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
 };
 
index 42edc6f4fc4a839d49140710adcf191f19b7e4a4..03d0a166b6359243a12e046aa64264dc647f4cdd 100644 (file)
@@ -246,8 +246,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
 };
 
 static struct sst_acpi_mach baytrail_machines[] = {
-       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
-       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" },
+       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
        {}
 };
 
index 67673a2c0f415d9f120bf375a3f2a9ca722d7c9a..b4ad98c43e5c6d53a1654e75bc4577d82f15b305 100644 (file)
@@ -817,7 +817,7 @@ static struct sst_dsp_device byt_dev = {
        .ops = &sst_byt_ops,
 };
 
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
 {
        struct sst_byt *byt = pdata->dsp;
 
@@ -826,14 +826,6 @@ int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
        sst_byt_drop_all(byt);
        dev_dbg(byt->dev, "dsp in reset\n");
 
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
-
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
        dev_dbg(byt->dev, "free all blocks and unload fw\n");
        sst_fw_unload(byt->fw);
 
index 06a4d202689b3780e13d37a55594862735c0d129..8faff6dcf25d0c1328c799cf40b78620aa3c59d9 100644 (file)
@@ -66,7 +66,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
 void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
 struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
index 599401c0c6551d59b1166359e0df5a45e74c8f8d..eab1c7d8518782b01e517e562c6dd7f9eb686d5c 100644 (file)
@@ -59,6 +59,9 @@ struct sst_byt_priv_data {
 
        /* DAI data */
        struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+
+       /* flag indicating is stream context restore needed after suspend */
+       bool restore_stream;
 };
 
 /* this may get called several times by oss emulation */
@@ -184,7 +187,10 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                sst_byt_stream_start(byt, pcm_data->stream, 0);
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
-               schedule_work(&pcm_data->work);
+               if (pdata->restore_stream == true)
+                       schedule_work(&pcm_data->work);
+               else
+                       sst_byt_stream_resume(byt, pcm_data->stream);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                sst_byt_stream_resume(byt, pcm_data->stream);
@@ -193,6 +199,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                sst_byt_stream_stop(byt, pcm_data->stream);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               pdata->restore_stream = false;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                sst_byt_stream_pause(byt, pcm_data->stream);
                break;
@@ -404,26 +411,10 @@ static const struct snd_soc_component_driver byt_dai_component = {
 };
 
 #ifdef CONFIG_PM
-static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       int ret;
-
-       dev_dbg(dev, "suspending noirq\n");
-
-       /* at this point all streams will be stopped and context saved */
-       ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to suspend %d\n", ret);
-               return ret;
-       }
-
-       return ret;
-}
-
 static int sst_byt_pcm_dev_suspend_late(struct device *dev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
        int ret;
 
        dev_dbg(dev, "suspending late\n");
@@ -434,34 +425,30 @@ static int sst_byt_pcm_dev_suspend_late(struct device *dev)
                return ret;
        }
 
+       priv_data->restore_stream = true;
+
        return ret;
 }
 
 static int sst_byt_pcm_dev_resume_early(struct device *dev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
 
        dev_dbg(dev, "resume early\n");
 
        /* load fw and boot DSP */
-       return sst_byt_dsp_boot(dev, sst_pdata);
-}
-
-static int sst_byt_pcm_dev_resume(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-
-       dev_dbg(dev, "resume\n");
+       ret = sst_byt_dsp_boot(dev, sst_pdata);
+       if (ret)
+               return ret;
 
        /* wait for FW to finish booting */
        return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
 }
 
 static const struct dev_pm_ops sst_byt_pm_ops = {
-       .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
        .suspend_late = sst_byt_pcm_dev_suspend_late,
        .resume_early = sst_byt_pcm_dev_resume_early,
-       .resume = sst_byt_pcm_dev_resume,
 };
 
 #define SST_BYT_PM_OPS (&sst_byt_pm_ops)
index 0109f6c2334e528e757b0f128fbf2dddbd3f29de..a8e0974330749f86c894ce520ff43d7c4d0960cc 100644 (file)
@@ -765,9 +765,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
                          SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
                          SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-                           SNDRV_PCM_FMTBIT_S24_LE |   \
-                           SNDRV_PCM_FMTBIT_S32_LE)
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .startup        = pxa_ssp_startup,
index 8348352dc2c62c484a1efba6f04c290367b93864..177bd8639ef93e6b97a20e1cd022224e62cf14bf 100644 (file)
@@ -2860,12 +2860,14 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val;
-       int ret = 0;
 
-       if (e->reg != SND_SOC_NOPM)
-               ret = soc_dapm_read(dapm, e->reg, &reg_val);
-       else
+       if (e->reg != SND_SOC_NOPM) {
+               int ret = soc_dapm_read(dapm, e->reg, &reg_val);
+               if (ret)
+                       return ret;
+       } else {
                reg_val = dapm_kcontrol_get_value(kcontrol);
+       }
 
        val = (reg_val >> e->shift_l) & e->mask;
        ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
@@ -2875,7 +2877,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
                ucontrol->value.enumerated.item[1] = val;
        }
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 
index f652b10ce90582c2a2b72d8d11c74309ae2f0d3e..223c47b33ba30e767c7af227c974a57471d02b90 100644 (file)
@@ -1580,6 +1580,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* BOSS ME-25 */
+       USB_DEVICE(0x0582, 0x0113),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* only 44.1 kHz works at the moment */
        USB_DEVICE(0x0582, 0x0120),
index d0396af99fa06570c71c110b6ba9b81e6a40dd76..5b1b807265a15e826e174a197c06b6c0788ff9b7 100644 (file)
@@ -267,90 +267,90 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
 /*
  * Example Format w/ field column widths:
  *
- * Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     SMI   %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
- * 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567
+ *  Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     SMI   %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
+ * 123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
  */
 
 void print_header(void)
 {
        if (show_pkg)
-               outp += sprintf(outp, "Package ");
+               outp += sprintf(outp, " Package");
        if (show_core)
-               outp += sprintf(outp, "    Core ");
+               outp += sprintf(outp, "    Core");
        if (show_cpu)
-               outp += sprintf(outp, "    CPU ");
+               outp += sprintf(outp, "     CPU");
        if (has_aperf)
-               outp += sprintf(outp, "Avg_MHz ");
+               outp += sprintf(outp, " Avg_MHz");
        if (do_nhm_cstates)
-               outp += sprintf(outp, "  %%Busy ");
+               outp += sprintf(outp, "   %%Busy");
        if (has_aperf)
-               outp += sprintf(outp, "Bzy_MHz ");
-       outp += sprintf(outp, "TSC_MHz ");
+               outp += sprintf(outp, " Bzy_MHz");
+       outp += sprintf(outp, " TSC_MHz");
        if (do_smi)
-               outp += sprintf(outp, "    SMI ");
+               outp += sprintf(outp, "     SMI");
        if (extra_delta_offset32)
-               outp += sprintf(outp, " count 0x%03X ", extra_delta_offset32);
+               outp += sprintf(outp, "  count 0x%03X", extra_delta_offset32);
        if (extra_delta_offset64)
-               outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64);
+               outp += sprintf(outp, "  COUNT 0x%03X", extra_delta_offset64);
        if (extra_msr_offset32)
-               outp += sprintf(outp, "  MSR 0x%03X ", extra_msr_offset32);
+               outp += sprintf(outp, "   MSR 0x%03X", extra_msr_offset32);
        if (extra_msr_offset64)
-               outp += sprintf(outp, "          MSR 0x%03X ", extra_msr_offset64);
+               outp += sprintf(outp, "           MSR 0x%03X", extra_msr_offset64);
        if (do_nhm_cstates)
-               outp += sprintf(outp, " CPU%%c1 ");
+               outp += sprintf(outp, "  CPU%%c1");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, " CPU%%c3 ");
+               outp += sprintf(outp, "  CPU%%c3");
        if (do_nhm_cstates)
-               outp += sprintf(outp, " CPU%%c6 ");
+               outp += sprintf(outp, "  CPU%%c6");
        if (do_snb_cstates)
-               outp += sprintf(outp, " CPU%%c7 ");
+               outp += sprintf(outp, "  CPU%%c7");
 
        if (do_dts)
-               outp += sprintf(outp, "CoreTmp ");
+               outp += sprintf(outp, " CoreTmp");
        if (do_ptm)
-               outp += sprintf(outp, " PkgTmp ");
+               outp += sprintf(outp, "  PkgTmp");
 
        if (do_snb_cstates)
-               outp += sprintf(outp, "Pkg%%pc2 ");
+               outp += sprintf(outp, " Pkg%%pc2");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, "Pkg%%pc3 ");
+               outp += sprintf(outp, " Pkg%%pc3");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, "Pkg%%pc6 ");
+               outp += sprintf(outp, " Pkg%%pc6");
        if (do_snb_cstates)
-               outp += sprintf(outp, "Pkg%%pc7 ");
+               outp += sprintf(outp, " Pkg%%pc7");
        if (do_c8_c9_c10) {
-               outp += sprintf(outp, "Pkg%%pc8 ");
-               outp += sprintf(outp, "Pkg%%pc9 ");
-               outp += sprintf(outp, "Pk%%pc10 ");
+               outp += sprintf(outp, " Pkg%%pc8");
+               outp += sprintf(outp, " Pkg%%pc9");
+               outp += sprintf(outp, " Pk%%pc10");
        }
 
        if (do_rapl && !rapl_joules) {
                if (do_rapl & RAPL_PKG)
-                       outp += sprintf(outp, "PkgWatt ");
+                       outp += sprintf(outp, " PkgWatt");
                if (do_rapl & RAPL_CORES)
-                       outp += sprintf(outp, "CorWatt ");
+                       outp += sprintf(outp, " CorWatt");
                if (do_rapl & RAPL_GFX)
-                       outp += sprintf(outp, "GFXWatt ");
+                       outp += sprintf(outp, " GFXWatt");
                if (do_rapl & RAPL_DRAM)
-                       outp += sprintf(outp, "RAMWatt ");
+                       outp += sprintf(outp, " RAMWatt");
                if (do_rapl & RAPL_PKG_PERF_STATUS)
-                       outp += sprintf(outp, "  PKG_%% ");
+                       outp += sprintf(outp, "   PKG_%%");
                if (do_rapl & RAPL_DRAM_PERF_STATUS)
-                       outp += sprintf(outp, "  RAM_%% ");
+                       outp += sprintf(outp, "   RAM_%%");
        } else {
                if (do_rapl & RAPL_PKG)
-                       outp += sprintf(outp, "  Pkg_J ");
+                       outp += sprintf(outp, "   Pkg_J");
                if (do_rapl & RAPL_CORES)
-                       outp += sprintf(outp, "  Cor_J ");
+                       outp += sprintf(outp, "   Cor_J");
                if (do_rapl & RAPL_GFX)
-                       outp += sprintf(outp, "  GFX_J ");
+                       outp += sprintf(outp, "   GFX_J");
                if (do_rapl & RAPL_DRAM)
-                       outp += sprintf(outp, "  RAM_W ");
+                       outp += sprintf(outp, "   RAM_W");
                if (do_rapl & RAPL_PKG_PERF_STATUS)
-                       outp += sprintf(outp, "  PKG_%% ");
+                       outp += sprintf(outp, "   PKG_%%");
                if (do_rapl & RAPL_DRAM_PERF_STATUS)
-                       outp += sprintf(outp, "  RAM_%% ");
-               outp += sprintf(outp, "  time ");
+                       outp += sprintf(outp, "   RAM_%%");
+               outp += sprintf(outp, "   time");
 
        }
        outp += sprintf(outp, "\n");
index bf06577fea51c22ab944edb9560e56f01aae2f94..5819a2708d7edd5823d9e5885a6b7c3796b387ad 100644 (file)
@@ -526,8 +526,10 @@ static int assign_guest_irq(struct kvm *kvm,
                dev->irq_requested_type |= guest_irq_type;
                if (dev->ack_notifier.gsi != -1)
                        kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
-       } else
+       } else {
                kvm_free_irq_source_id(kvm, dev->irq_source_id);
+               dev->irq_source_id = -1;
+       }
 
        return r;
 }
index 0df7d4b34dfec96345d359bf08562309d8607f40..714b949323120aee855dd7e57db549cac31e8183 100644 (file)
@@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
        return pfn;
 }
 
+static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
+{
+       unsigned long i;
+
+       for (i = 0; i < npages; ++i)
+               kvm_release_pfn_clean(pfn + i);
+}
+
 int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
 {
        gfn_t gfn, end_gfn;
@@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
                if (r) {
                        printk(KERN_ERR "kvm_iommu_map_address:"
                               "iommu failed to map pfn=%llx\n", pfn);
+                       kvm_unpin_pages(kvm, pfn, page_size);
                        goto unmap_pages;
                }
 
@@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
        return 0;
 
 unmap_pages:
-       kvm_iommu_put_pages(kvm, slot->base_gfn, gfn);
+       kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn);
        return r;
 }
 
@@ -266,14 +275,6 @@ out_unlock:
        return r;
 }
 
-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
-{
-       unsigned long i;
-
-       for (i = 0; i < npages; ++i)
-               kvm_release_pfn_clean(pfn + i);
-}
-
 static void kvm_iommu_put_pages(struct kvm *kvm,
                                gfn_t base_gfn, unsigned long npages)
 {
This page took 0.722501 seconds and 4 git commands to generate.