]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'extcon-next-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Jan 2017 10:05:04 +0000 (11:05 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Jan 2017 10:05:04 +0000 (11:05 +0100)
Chanwoo writes:

Update extcon for 4.11

Detailed description for this pull request:
1. Add the new extcon driver.
- Intel INT3496 ACPI USB id detection driver detects whether
  EXTCON_USB_HOST is attached or detached. (extcon-intel-int3496.c)

2. Add the new type of external connector.
- EXTCON_CHG_USB_PD (USB Power Delivery) provides the increased
  power more than 7.5W to device with larger power demand.

3. Add the description for EXTCON_CHG_USB_(SDP|ACA|SLOW|FAST)
- EXTCON_CHG_USB_SDP should always appear together with EXTCON_USB
- EXTCON_CHG_USB_ACA would normally appear with EXTCON_USB_HOST.
- EXTCON_CHG_USB_SLOW can provide at least 500mA of current at 5V
- EXTCON_CHG_USB_FAST can provide at least 1A of current at 5V.

4. Modify the connector name of EXTCON_USB_HOST
- "USB_HOST" -> "USB-HOST"

5. Update the extcon core
- Move the private extcon structure into driver/extcon directory.
  The 'struct extcon_dev' should be only handled by extcon core
  to prevent the direct access and to maintain the integrity of it.
- Remove the ambigous operation of extcon_register_notifier()
  in case of the 'extcon_dev' instance is NULL. The user of
  extcon_register_notifier() have to specify the correct instance
  of the provider extcon driver.

6. Update the extcon drivers and fix the minor issues
- Update the extcon-axp288 driver to remove the unncessary code.
- Add pinctrl operation during suspend mode to extcon-usb-gpio driver.
- Clean up the extcon-arizona/adc-jack driver.
- Use the dev_dbg() for debug messsage on extcon-palmas driver.
- Return the error code on failure of extcon_sync()

351 files changed:
.mailmap
Documentation/ABI/testing/sysfs-devices-deferred_probe [deleted file]
Documentation/devicetree/bindings/i2c/i2c.txt
Documentation/devicetree/bindings/misc/idt_89hpesx.txt [new file with mode: 0644]
Documentation/vm/page_frags [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/da8xx-dt.c
arch/arm64/include/asm/assembler.h
arch/arm64/mm/hugetlbpage.c
arch/x86/Kbuild
arch/x86/boot/string.c
arch/x86/boot/string.h
arch/x86/crypto/aesni-intel_glue.c
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/rapl.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/hyperv/Makefile [new file with mode: 0644]
arch/x86/hyperv/hv_init.c [new file with mode: 0644]
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/microcode_intel.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/stacktrace.h
arch/x86/include/asm/switch_to.h
arch/x86/include/uapi/asm/hyperv.h
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/tsc.c
arch/x86/kernel/unwind_frame.c
arch/x86/kvm/emulate.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/x86.c
arch/x86/mm/mpx.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/quirks.c
arch/x86/platform/intel-mid/device_libs/Makefile
arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c [moved from arch/x86/platform/intel-mid/device_libs/platform_spidev.c with 91% similarity]
block/blk-lib.c
block/blk-zoned.c
block/partition-generic.c
drivers/auxdisplay/Kconfig
drivers/base/base.h
drivers/base/core.c
drivers/base/dd.c
drivers/block/nbd.c
drivers/block/virtio_blk.c
drivers/block/zram/zram_drv.c
drivers/char/Kconfig
drivers/char/apm-emulation.c
drivers/char/ds1302.c
drivers/char/mem.c
drivers/char/mmtimer.c
drivers/char/ppdev.c
drivers/dma/dw/Kconfig
drivers/dma/ioat/hw.h
drivers/dma/ioat/init.c
drivers/dma/omap-dma.c
drivers/dma/pl330.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/stm32-dma.c
drivers/dma/ti-dma-crossbar.c
drivers/firmware/efi/fake_mem.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/memmap.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/si_dpm.c
drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/meson/meson_plane.c
drivers/gpu/drm/meson/meson_venc.c
drivers/gpu/drm/meson/meson_venc_cvbs.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_ringbuffer.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/hid/hid-core.c
drivers/hid/hid-cypress.c
drivers/hid/hid-ids.h
drivers/hid/i2c-hid/i2c-hid.c
drivers/hv/channel.c
drivers/hv/channel_mgmt.c
drivers/hv/connection.c
drivers/hv/hv.c
drivers/hv/hv_fcopy.c
drivers/hv/hv_kvp.c
drivers/hv/hv_snapshot.c
drivers/hv/hv_util.c
drivers/hv/hyperv_vmbus.h
drivers/hv/ring_buffer.c
drivers/hv/vmbus_drv.c
drivers/hwtracing/coresight/coresight-stm.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/input/joydev.c
drivers/input/joystick/xpad.c
drivers/input/misc/adxl34x-i2c.c
drivers/input/mouse/alps.h
drivers/input/mouse/synaptics_i2c.c
drivers/input/rmi4/Kconfig
drivers/input/serio/i8042-x86ia64io.h
drivers/input/touchscreen/elants_i2c.c
drivers/md/md.h
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5-cache.c
drivers/md/raid5.c
drivers/memory/ti-aemif.c
drivers/misc/eeprom/Kconfig
drivers/misc/eeprom/Makefile
drivers/misc/eeprom/idt_89hpesx.c [new file with mode: 0644]
drivers/misc/genwqe/card_base.c
drivers/misc/lkdtm_bugs.c
drivers/misc/mei/bus-fixup.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/debugfs.c
drivers/misc/mei/hbm.c
drivers/misc/mei/hw.h
drivers/misc/mei/mei_dev.h
drivers/misc/mic/vop/vop_vringh.c
drivers/misc/sram.c
drivers/net/appletalk/ipddp.c
drivers/net/dsa/bcm_sf2.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
drivers/net/phy/Kconfig
drivers/net/phy/dp83867.c
drivers/net/phy/marvell.c
drivers/net/phy/phy.c
drivers/net/usb/r8152.c
drivers/net/vrf.c
drivers/net/wireless/intersil/orinoco/mic.c
drivers/net/wireless/intersil/orinoco/mic.h
drivers/net/wireless/intersil/orinoco/orinoco.h
drivers/net/wireless/realtek/rtlwifi/usb.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/remoteproc/remoteproc_core.c
drivers/rpmsg/rpmsg_core.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/qedi/Kconfig
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/scsi/snic/snic_main.c
drivers/target/target_core_transport.c
drivers/target/target_core_xcopy.c
drivers/target/target_core_xcopy.h
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/atmel_serial.c
drivers/tty/sysrq.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/musb/musb_debugfs.c
drivers/usb/serial/ch341.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/wusbcore/crypto.c
drivers/vfio/vfio_iommu_type1.c
drivers/vme/bridges/vme_ca91cx42.c
fs/aio.c
fs/binfmt_elf.c
fs/btrfs/async-thread.c
fs/btrfs/extent-tree.c
fs/btrfs/inode.c
fs/btrfs/tree-log.c
fs/btrfs/uuid-tree.c
fs/ceph/addr.c
fs/ceph/mds_client.c
fs/coredump.c
fs/dax.c
fs/dcache.c
fs/direct-io.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/libfs.c
fs/namespace.c
fs/ocfs2/dlmglue.c
fs/ocfs2/stackglue.c
fs/ocfs2/stackglue.h
fs/posix_acl.c
fs/proc/proc_sysctl.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_log.c
include/linux/blkdev.h
include/linux/coredump.h
include/linux/efi.h
include/linux/gfp.h
include/linux/hyperv.h
include/linux/i2c.h
include/linux/jump_label_ratelimit.h
include/linux/memcontrol.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/netdevice.h
include/linux/perf_event.h
include/linux/platform_data/ti-aemif.h [new file with mode: 0644]
include/linux/remoteproc.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/swap.h
include/linux/timerfd.h
include/linux/vme.h
include/sound/hdmi-codec.h
include/sound/soc.h
include/target/target_core_base.h
include/trace/events/btrfs.h
include/trace/events/mmflags.h
include/uapi/linux/Kbuild
include/uapi/linux/timerfd.h [new file with mode: 0644]
init/Kconfig
ipc/sem.c
kernel/bpf/arraymap.c
kernel/bpf/hashtab.c
kernel/capability.c
kernel/events/core.c
kernel/jump_label.c
kernel/memremap.c
kernel/pid_namespace.c
kernel/signal.c
kernel/time/tick-sched.c
kernel/time/tick-sched.h
lib/Kconfig.debug
lib/iov_iter.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/khugepaged.c
mm/memcontrol.c
mm/memory.c
mm/page_alloc.c
mm/slab.c
mm/swapfile.c
mm/vmscan.c
net/Kconfig
net/bridge/br_netfilter_hooks.c
net/core/dev.c
net/core/flow_dissector.c
net/core/skbuff.c
net/core/sock.c
net/dsa/dsa2.c
net/ipv4/fib_semantics.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_vti.c
net/ipv6/route.c
net/iucv/af_iucv.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_payload.c
net/netfilter/nft_queue.c
net/netfilter/nft_quota.c
net/netlabel/netlabel_kapi.c
net/qrtr/qrtr.c
net/sctp/outqueue.c
net/socket.c
net/wireless/nl80211.c
samples/bpf/sock_example.h
samples/bpf/trace_output_user.c
samples/vfio-mdev/mtty.c
scripts/checkkconfigsymbols.py
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/codecs/rt5645.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm_adsp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst.c
sound/soc/sh/rcar/core.c
sound/soc/soc-core.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/usb/quirks.c
tools/lib/subcmd/parse-options.c
tools/lib/subcmd/parse-options.h
tools/lib/traceevent/plugin_sched_switch.c
tools/perf/Documentation/perf-record.txt
tools/perf/Makefile.perf
tools/perf/builtin-kmem.c
tools/perf/builtin-record.c
tools/perf/builtin-sched.c
tools/perf/util/probe-event.c
tools/perf/util/symbol-elf.c
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/test_kmod.sh
tools/testing/selftests/net/run_netsocktests
tools/testing/selftests/x86/protection_keys.c
virt/lib/irqbypass.c

index 02d261407683dcfa483cf15247b2cf31cff0432a..67dc22ffc9a80cb4fd6abeeba3d2ec7f7ae2ba19 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -137,6 +137,7 @@ Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
 Rudolf Marek <R.Marek@sh.cvut.cz>
 Rui Saraiva <rmps@joel.ist.utl.pt>
 Sachin P Sant <ssant@in.ibm.com>
+Sarangdhar Joshi <spjoshi@codeaurora.org>
 Sam Ravnborg <sam@mars.ravnborg.org>
 Santosh Shilimkar <ssantosh@kernel.org>
 Santosh Shilimkar <santosh.shilimkar@oracle.org>
@@ -150,10 +151,13 @@ Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
 Simon Kelley <simon@thekelleys.org.uk>
 Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
 Stephen Hemminger <shemminger@osdl.org>
+Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
+Subhash Jadavani <subhashj@codeaurora.org>
 Sudeep Holla <sudeep.holla@arm.com> Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
 Sumit Semwal <sumit.semwal@ti.com>
 Tejun Heo <htejun@gmail.com>
 Thomas Graf <tgraf@suug.ch>
+Thomas Pedersen <twp@codeaurora.org>
 Tony Luck <tony.luck@intel.com>
 Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
 Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
diff --git a/Documentation/ABI/testing/sysfs-devices-deferred_probe b/Documentation/ABI/testing/sysfs-devices-deferred_probe
deleted file mode 100644 (file)
index 58553d7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-What:          /sys/devices/.../deferred_probe
-Date:          August 2016
-Contact:       Ben Hutchings <ben.hutchings@codethink.co.uk>
-Description:
-               The /sys/devices/.../deferred_probe attribute is
-               present for all devices.  If a driver detects during
-               probing a device that a related device is not yet
-               ready, it may defer probing of the first device.  The
-               kernel will retry probing the first device after any
-               other device is successfully probed.  This attribute
-               reads as 1 if probing of this device is currently
-               deferred, or 0 otherwise.
index 5fa691e6f6388320acd4199995ef0072e9e70faa..cee9d5055fa27c7593f5a9da09661c4f7eed9647 100644 (file)
@@ -62,6 +62,9 @@ wants to support one of the below features, it should adapt the bindings below.
        "irq" and "wakeup" names are recognized by I2C core, other names are
        left to individual drivers.
 
+- host-notify
+       device uses SMBus host notify protocol instead of interrupt line.
+
 - multi-master
        states that there is another master active on this bus. The OS can use
        this information to adapt power management to keep the arbitration awake
@@ -81,6 +84,11 @@ Binding may contain optional "interrupts" property, describing interrupts
 used by the device. I2C core will assign "irq" interrupt (or the very first
 interrupt if not using interrupt names) as primary interrupt for the slave.
 
+Alternatively, devices supporting SMbus Host Notify, and connected to
+adapters that support this feature, may use "host-notify" property. I2C
+core will create a virtual interrupt for Host Notify and assign it as
+primary interrupt for the slave.
+
 Also, if device is marked as a wakeup source, I2C core will set up "wakeup"
 interrupt for the device. If "wakeup" interrupt name is not present in the
 binding, then primary interrupt will be used as wakeup interrupt.
diff --git a/Documentation/devicetree/bindings/misc/idt_89hpesx.txt b/Documentation/devicetree/bindings/misc/idt_89hpesx.txt
new file mode 100644 (file)
index 0000000..b9093b7
--- /dev/null
@@ -0,0 +1,44 @@
+EEPROM / CSR SMBus-slave interface of IDT 89HPESx devices
+
+Required properties:
+  - compatible : should be "<manufacturer>,<type>"
+                Basically there is only one manufacturer: idt, but some
+                compatible devices may be produced in future. Following devices
+                are supported: 89hpes8nt2, 89hpes12nt3, 89hpes24nt6ag2,
+                89hpes32nt8ag2, 89hpes32nt8bg2, 89hpes12nt12g2, 89hpes16nt16g2,
+                89hpes24nt24g2, 89hpes32nt24ag2, 89hpes32nt24bg2;
+                89hpes12n3, 89hpes12n3a, 89hpes24n3, 89hpes24n3a;
+                89hpes32h8, 89hpes32h8g2, 89hpes48h12, 89hpes48h12g2,
+                89hpes48h12ag2, 89hpes16h16, 89hpes22h16, 89hpes22h16g2,
+                89hpes34h16, 89hpes34h16g2, 89hpes64h16, 89hpes64h16g2,
+                89hpes64h16ag2;
+                89hpes12t3g2, 89hpes24t3g2, 89hpes16t4, 89hpes4t4g2,
+                89hpes10t4g2, 89hpes16t4g2, 89hpes16t4ag2, 89hpes5t5,
+                89hpes6t5, 89hpes8t5, 89hpes8t5a, 89hpes24t6, 89hpes6t6g2,
+                89hpes24t6g2, 89hpes16t7, 89hpes32t8, 89hpes32t8g2,
+                89hpes48t12, 89hpes48t12g2.
+  - reg :       I2C address of the IDT 89HPESx device.
+
+Optionally there can be EEPROM-compatible subnode:
+  - compatible:  There are five EEPROM devices supported: 24c32, 24c64, 24c128,
+                24c256 and 24c512 differed by size.
+  - reg:         Custom address of EEPROM device (If not specified IDT 89HPESx
+    (optional)  device will try to communicate with EEPROM sited by default
+                address - 0x50)
+  - read-only :         Parameterless property disables writes to the EEPROM
+    (optional)
+
+Example:
+       idt@60 {
+               compatible = "idt,89hpes32nt8ag2";
+               reg = <0x74>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               eeprom@50 {
+                       compatible = "onsemi,24c64";
+                       reg = <0x50>;
+                       read-only;
+               };
+       };
+
diff --git a/Documentation/vm/page_frags b/Documentation/vm/page_frags
new file mode 100644 (file)
index 0000000..a671456
--- /dev/null
@@ -0,0 +1,42 @@
+Page fragments
+--------------
+
+A page fragment is an arbitrary-length arbitrary-offset area of memory
+which resides within a 0 or higher order compound page.  Multiple
+fragments within that page are individually refcounted, in the page's
+reference counter.
+
+The page_frag functions, page_frag_alloc and page_frag_free, provide a
+simple allocation framework for page fragments.  This is used by the
+network stack and network device drivers to provide a backing region of
+memory for use as either an sk_buff->head, or to be used in the "frags"
+portion of skb_shared_info.
+
+In order to make use of the page fragment APIs a backing page fragment
+cache is needed.  This provides a central point for the fragment allocation
+and tracks allows multiple calls to make use of a cached page.  The
+advantage to doing this is that multiple calls to get_page can be avoided
+which can be expensive at allocation time.  However due to the nature of
+this caching it is required that any calls to the cache be protected by
+either a per-cpu limitation, or a per-cpu limitation and forcing interrupts
+to be disabled when executing the fragment allocation.
+
+The network stack uses two separate caches per CPU to handle fragment
+allocation.  The netdev_alloc_cache is used by callers making use of the
+__netdev_alloc_frag and __netdev_alloc_skb calls.  The napi_alloc_cache is
+used by callers of the __napi_alloc_frag and __napi_alloc_skb calls.  The
+main difference between these two calls is the context in which they may be
+called.  The "netdev" prefixed functions are usable in any context as these
+functions will disable interrupts, while the "napi" prefixed functions are
+only usable within the softirq context.
+
+Many network device drivers use a similar methodology for allocating page
+fragments, but the page fragments are cached at the ring or descriptor
+level.  In order to enable these cases it is necessary to provide a generic
+way of tearing down a page cache.  For this reason __page_frag_cache_drain
+was implemented.  It allows for freeing multiple references from a single
+page via a single call.  The advantage to doing this is that it allows for
+cleaning up the multiple references that were added to a page in order to
+avoid calling get_page per allocation.
+
+Alexander Duyck, Nov 29, 2016.
index 5f0420a0da5b674b314718fa5393201aa61815b7..be8de24fd6dd80ac9916c1c4ba10d0f5fd242986 100644 (file)
@@ -81,7 +81,6 @@ Descriptions of section entries:
        Q: Patchwork web based patch tracking system site
        T: SCM tree type and location.
           Type is one of: git, hg, quilt, stgit, topgit
-       B: Bug tracking system location.
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -2194,14 +2193,6 @@ L:       alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/atmel
 
-ATMEL DMA DRIVER
-M:     Nicolas Ferre <nicolas.ferre@atmel.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Supported
-F:     drivers/dma/at_hdmac.c
-F:     drivers/dma/at_hdmac_regs.h
-F:     include/linux/platform_data/dma-atmel.h
-
 ATMEL XDMA DRIVER
 M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 L:     linux-arm-kernel@lists.infradead.org
@@ -4117,7 +4108,7 @@ F:        drivers/gpu/drm/cirrus/
 RADEON and AMDGPU DRM DRIVERS
 M:     Alex Deucher <alexander.deucher@amd.com>
 M:     Christian König <christian.koenig@amd.com>
-L:     dri-devel@lists.freedesktop.org
+L:     amd-gfx@lists.freedesktop.org
 T:     git git://people.freedesktop.org/~agd5f/linux
 S:     Supported
 F:     drivers/gpu/drm/radeon/
@@ -5971,6 +5962,7 @@ S:        Maintained
 F:     arch/x86/include/asm/mshyperv.h
 F:     arch/x86/include/uapi/asm/hyperv.h
 F:     arch/x86/kernel/cpu/mshyperv.c
+F:     arch/x86/hyperv
 F:     drivers/hid/hid-hyperv.c
 F:     drivers/hv/
 F:     drivers/input/serio/hyperv-keyboard.c
@@ -8179,6 +8171,15 @@ S:       Maintained
 F:     drivers/tty/serial/atmel_serial.c
 F:     include/linux/atmel_serial.h
 
+MICROCHIP / ATMEL DMA DRIVER
+M:     Ludovic Desroches <ludovic.desroches@microchip.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     dmaengine@vger.kernel.org
+S:     Supported
+F:     drivers/dma/at_hdmac.c
+F:     drivers/dma/at_hdmac_regs.h
+F:     include/linux/platform_data/dma-atmel.h
+
 MICROCHIP / ATMEL ISC DRIVER
 M:     Songjun Wu <songjun.wu@microchip.com>
 L:     linux-media@vger.kernel.org
index 5f1a84735ff61a18fddd4bbad964f8ac89ecc8e4..96e2352d10a8cc830812b819cfebb888603c4038 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 10
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc4
 NAME = Roaring Lionus
 
 # *DOCUMENTATION*
index 1d873d15b545c26a97eefdf15d92d437ff2e1701..9780829f8a0572219bae198715036c4d878a5af8 100644 (file)
@@ -557,15 +557,7 @@ static struct clk_lookup da850_clks[] = {
        CLK("da830-mmc.0",      NULL,           &mmcsd0_clk),
        CLK("da830-mmc.1",      NULL,           &mmcsd1_clk),
        CLK("ti-aemif",         NULL,           &aemif_clk),
-       /*
-        * The only user of this clock is davinci_nand and it get's it through
-        * con_id. The nand node itself is created from within the aemif
-        * driver to guarantee that it's probed after the aemif timing
-        * parameters are configured. of_dev_auxdata is not accessible from
-        * the aemif driver and can't be passed to of_platform_populate(). For
-        * that reason we're leaving the dev_id here as NULL.
-        */
-       CLK(NULL,               "aemif",        &aemif_nand_clk),
+       CLK("davinci-nand.0",   "aemif",        &aemif_nand_clk),
        CLK("ohci-da8xx",       "usb11",        &usb11_clk),
        CLK("musb-da8xx",       "usb20",        &usb20_clk),
        CLK("spi_davinci.0",    NULL,           &spi0_clk),
index 9ee44da6eb7b85312b30260e29a295b1162f9112..06205fe4c1202942918d669425538280f8cbbf4d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
+#include <linux/platform_data/ti-aemif.h>
 
 #include <asm/mach/arch.h>
 
 #include "cp_intc.h"
 #include <mach/da8xx.h>
 
+static struct of_dev_auxdata da850_aemif_auxdata_lookup[] = {
+       OF_DEV_AUXDATA("ti,davinci-nand", 0x62000000, "davinci-nand.0", NULL),
+       {}
+};
+
+static struct aemif_platform_data aemif_data = {
+       .dev_lookup = da850_aemif_auxdata_lookup,
+};
+
 static struct of_dev_auxdata da850_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("ti,davinci-i2c", 0x01c22000, "i2c_davinci.1", NULL),
        OF_DEV_AUXDATA("ti,davinci-i2c", 0x01e28000, "i2c_davinci.2", NULL),
@@ -37,7 +47,7 @@ static struct of_dev_auxdata da850_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("ti,davinci-dm6467-emac", 0x01e20000, "davinci_emac.1",
                       NULL),
        OF_DEV_AUXDATA("ti,da830-mcasp-audio", 0x01d00000, "davinci-mcasp.0", NULL),
-       OF_DEV_AUXDATA("ti,da850-aemif", 0x68000000, "ti-aemif", NULL),
+       OF_DEV_AUXDATA("ti,da850-aemif", 0x68000000, "ti-aemif", &aemif_data),
        OF_DEV_AUXDATA("ti,da850-tilcdc", 0x01e13000, "da8xx_lcdc.0", NULL),
        OF_DEV_AUXDATA("ti,da830-ohci", 0x01e25000, "ohci-da8xx", NULL),
        OF_DEV_AUXDATA("ti,da830-musb", 0x01e00000, "musb-da8xx", NULL),
index 446f6c46d4b17b352ef695665409c6863d470706..3a4301163e04a26d979bf506f8c4a537a2dd9715 100644 (file)
@@ -164,22 +164,25 @@ lr        .req    x30             // link register
 
 /*
  * Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
- * <symbol> is within the range +/- 4 GB of the PC.
+ * <symbol> is within the range +/- 4 GB of the PC when running
+ * in core kernel context. In module context, a movz/movk sequence
+ * is used, since modules may be loaded far away from the kernel
+ * when KASLR is in effect.
  */
        /*
         * @dst: destination register (64 bit wide)
         * @sym: name of the symbol
-        * @tmp: optional scratch register to be used if <dst> == sp, which
-        *       is not allowed in an adrp instruction
         */
-       .macro  adr_l, dst, sym, tmp=
-       .ifb    \tmp
+       .macro  adr_l, dst, sym
+#ifndef MODULE
        adrp    \dst, \sym
        add     \dst, \dst, :lo12:\sym
-       .else
-       adrp    \tmp, \sym
-       add     \dst, \tmp, :lo12:\sym
-       .endif
+#else
+       movz    \dst, #:abs_g3:\sym
+       movk    \dst, #:abs_g2_nc:\sym
+       movk    \dst, #:abs_g1_nc:\sym
+       movk    \dst, #:abs_g0_nc:\sym
+#endif
        .endm
 
        /*
@@ -190,6 +193,7 @@ lr  .req    x30             // link register
         *       the address
         */
        .macro  ldr_l, dst, sym, tmp=
+#ifndef MODULE
        .ifb    \tmp
        adrp    \dst, \sym
        ldr     \dst, [\dst, :lo12:\sym]
@@ -197,6 +201,15 @@ lr .req    x30             // link register
        adrp    \tmp, \sym
        ldr     \dst, [\tmp, :lo12:\sym]
        .endif
+#else
+       .ifb    \tmp
+       adr_l   \dst, \sym
+       ldr     \dst, [\dst]
+       .else
+       adr_l   \tmp, \sym
+       ldr     \dst, [\tmp]
+       .endif
+#endif
        .endm
 
        /*
@@ -206,8 +219,13 @@ lr .req    x30             // link register
         *       while <src> needs to be preserved.
         */
        .macro  str_l, src, sym, tmp
+#ifndef MODULE
        adrp    \tmp, \sym
        str     \src, [\tmp, :lo12:\sym]
+#else
+       adr_l   \tmp, \sym
+       str     \src, [\tmp]
+#endif
        .endm
 
        /*
index 964b7549af5cc7f827c57fe17709e7575a471c56..e25584d723960e73fb8eec8d1a5f48fa57197582 100644 (file)
@@ -239,7 +239,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                ncontig = find_num_contig(vma->vm_mm, addr, cpte,
                                          *cpte, &pgsize);
                for (i = 0; i < ncontig; ++i, ++cpte, addr += pgsize) {
-                       changed = ptep_set_access_flags(vma, addr, cpte,
+                       changed |= ptep_set_access_flags(vma, addr, cpte,
                                                        pfn_pte(pfn,
                                                                hugeprot),
                                                        dirty);
index eb3abf8ac44eb33f333ed29727dfd49ba6bfbf38..586b786b3edf9a6930bfdf05c47b4c8e0c57e718 100644 (file)
@@ -7,6 +7,9 @@ obj-$(CONFIG_KVM) += kvm/
 # Xen paravirtualization support
 obj-$(CONFIG_XEN) += xen/
 
+# Hyper-V paravirtualization support
+obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/
+
 # lguest paravirtualization support
 obj-$(CONFIG_LGUEST_GUEST) += lguest/
 
index cc3bd583dce1abc5fafe6b92417b8a713cd4cdfd..9e240fcba784b085bd55e77dc79c08d21d1a23e2 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include "ctype.h"
+#include "string.h"
 
 int memcmp(const void *s1, const void *s2, size_t len)
 {
index 725e820602b1781308b863a10c105dd3d2734d31..113588ddb43f8d7e7be66283118a2f33c46fb7e1 100644 (file)
@@ -18,4 +18,13 @@ int memcmp(const void *s1, const void *s2, size_t len);
 #define memset(d,c,l) __builtin_memset(d,c,l)
 #define memcmp __builtin_memcmp
 
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern size_t strlen(const char *s);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strnlen(const char *s, size_t maxlen);
+extern unsigned int atou(const char *s);
+extern unsigned long long simple_strtoull(const char *cp, char **endp,
+                                         unsigned int base);
+
 #endif /* BOOT_STRING_H */
index 31c34ee131f34505872a018b75a8489f1ac9c854..6ef688a1ef3e0f022032e5317662b9011c8f74c4 100644 (file)
@@ -1020,7 +1020,8 @@ struct {
        const char *basename;
        struct simd_skcipher_alg *simd;
 } aesni_simd_skciphers2[] = {
-#if IS_ENABLED(CONFIG_CRYPTO_PCBC)
+#if (defined(MODULE) && IS_ENABLED(CONFIG_CRYPTO_PCBC)) || \
+    IS_BUILTIN(CONFIG_CRYPTO_PCBC)
        {
                .algname        = "pcbc(aes)",
                .drvname        = "pcbc-aes-aesni",
index 701d29f8e4d300ac01553e5d8317a5e40dbdcc6d..57f7ec35216ef5e2a78efa0d303f8f343b010d68 100644 (file)
@@ -254,23 +254,6 @@ ENTRY(__switch_to_asm)
        jmp     __switch_to
 END(__switch_to_asm)
 
-/*
- * The unwinder expects the last frame on the stack to always be at the same
- * offset from the end of the page, which allows it to validate the stack.
- * Calling schedule_tail() directly would break that convention because its an
- * asmlinkage function so its argument has to be pushed on the stack.  This
- * wrapper creates a proper "end of stack" frame header before the call.
- */
-ENTRY(schedule_tail_wrapper)
-       FRAME_BEGIN
-
-       pushl   %eax
-       call    schedule_tail
-       popl    %eax
-
-       FRAME_END
-       ret
-ENDPROC(schedule_tail_wrapper)
 /*
  * A newly forked process directly context switches into this address.
  *
@@ -279,15 +262,24 @@ ENDPROC(schedule_tail_wrapper)
  * edi: kernel thread arg
  */
 ENTRY(ret_from_fork)
-       call    schedule_tail_wrapper
+       FRAME_BEGIN             /* help unwinder find end of stack */
+
+       /*
+        * schedule_tail() is asmlinkage so we have to put its 'prev' argument
+        * on the stack.
+        */
+       pushl   %eax
+       call    schedule_tail
+       popl    %eax
 
        testl   %ebx, %ebx
        jnz     1f              /* kernel threads are uncommon */
 
 2:
        /* When we fork, we trace the syscall return in the child, too. */
-       movl    %esp, %eax
+       leal    FRAME_OFFSET(%esp), %eax
        call    syscall_return_slowpath
+       FRAME_END
        jmp     restore_all
 
        /* kernel thread */
index 5b219707c2f236cfcf1a856cf9a5023dd93775c3..044d18ebc43ce96a512abd1e5f36eb8dfaee0636 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/smap.h>
 #include <asm/pgtable_types.h>
 #include <asm/export.h>
+#include <asm/frame.h>
 #include <linux/err.h>
 
 .code64
@@ -408,17 +409,19 @@ END(__switch_to_asm)
  * r12: kernel thread arg
  */
 ENTRY(ret_from_fork)
+       FRAME_BEGIN                     /* help unwinder find end of stack */
        movq    %rax, %rdi
-       call    schedule_tail                   /* rdi: 'prev' task parameter */
+       call    schedule_tail           /* rdi: 'prev' task parameter */
 
-       testq   %rbx, %rbx                      /* from kernel_thread? */
-       jnz     1f                              /* kernel threads are uncommon */
+       testq   %rbx, %rbx              /* from kernel_thread? */
+       jnz     1f                      /* kernel threads are uncommon */
 
 2:
-       movq    %rsp, %rdi
+       leaq    FRAME_OFFSET(%rsp),%rdi /* pt_regs pointer */
        call    syscall_return_slowpath /* returns with IRQs disabled */
        TRACE_IRQS_ON                   /* user mode is traced as IRQS on */
        SWAPGS
+       FRAME_END
        jmp     restore_regs_and_iret
 
 1:
index 019c5887b698af2a5fbf322c7cc5d6d3f8ab7e57..1635c0c8df23a697a93a8a7bd0dbbfd534c3caef 100644 (file)
@@ -505,6 +505,10 @@ int x86_pmu_hw_config(struct perf_event *event)
 
                if (event->attr.precise_ip > precise)
                        return -EOPNOTSUPP;
+
+               /* There's no sense in having PEBS for non sampling events: */
+               if (!is_sampling_event(event))
+                       return -EINVAL;
        }
        /*
         * check that PEBS LBR correction does not conflict with
index 86138267b68a77753737ffd4c4be2ece6a24cc84..d611cab214a6050555eb4c5f6f5638ca46b4659e 100644 (file)
@@ -3987,7 +3987,7 @@ __init int intel_pmu_init(void)
                     x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC);
                x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC;
        }
-       x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
+       x86_pmu.intel_ctrl = (1ULL << x86_pmu.num_counters) - 1;
 
        if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) {
                WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
index fec8a461bdef6da49c0e7f46c655f235e7fc1275..1076c9a77292d77e5dbb34adbd5ce526121daa73 100644 (file)
@@ -434,6 +434,7 @@ static struct pmu cstate_core_pmu = {
        .stop           = cstate_pmu_event_stop,
        .read           = cstate_pmu_event_update,
        .capabilities   = PERF_PMU_CAP_NO_INTERRUPT,
+       .module         = THIS_MODULE,
 };
 
 static struct pmu cstate_pkg_pmu = {
@@ -447,6 +448,7 @@ static struct pmu cstate_pkg_pmu = {
        .stop           = cstate_pmu_event_stop,
        .read           = cstate_pmu_event_update,
        .capabilities   = PERF_PMU_CAP_NO_INTERRUPT,
+       .module         = THIS_MODULE,
 };
 
 static const struct cstate_model nhm_cstates __initconst = {
index be202390bbd37b00106864123a647786497ce2cd..9dfeeeca0ea8f11a3beb4c23eeb1d115e77189db 100644 (file)
@@ -1389,9 +1389,13 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
                        continue;
 
                /* log dropped samples number */
-               if (error[bit])
+               if (error[bit]) {
                        perf_log_lost_samples(event, error[bit]);
 
+                       if (perf_event_account_interrupt(event))
+                               x86_pmu_stop(event, 0);
+               }
+
                if (counts[bit]) {
                        __intel_pmu_pebs_event(event, iregs, base,
                                               top, bit, counts[bit]);
index bd34124449b08a4be95f114b3295c22e4d57cd34..17c3564d087a48bc24e41417fe6f128b5d7b9f0d 100644 (file)
@@ -697,6 +697,7 @@ static int __init init_rapl_pmus(void)
        rapl_pmus->pmu.start            = rapl_pmu_event_start;
        rapl_pmus->pmu.stop             = rapl_pmu_event_stop;
        rapl_pmus->pmu.read             = rapl_pmu_event_read;
+       rapl_pmus->pmu.module           = THIS_MODULE;
        return 0;
 }
 
index 97c246f84dea1e79d0f4517376763dcb88a18aea..8c4ccdc3a3f3607ee0af4f4006029df3000e0839 100644 (file)
@@ -733,6 +733,7 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu)
                        .start          = uncore_pmu_event_start,
                        .stop           = uncore_pmu_event_stop,
                        .read           = uncore_pmu_event_read,
+                       .module         = THIS_MODULE,
                };
        } else {
                pmu->pmu = *pmu->type->pmu;
index e6832be714bc6e76965e1faa7cedcc3ad309c8fa..dae2fedc16015e691ad6ae85ce4bc4122011eefc 100644 (file)
@@ -2686,7 +2686,7 @@ static struct intel_uncore_type *hswep_msr_uncores[] = {
 
 void hswep_uncore_cpu_init(void)
 {
-       int pkg = topology_phys_to_logical_pkg(0);
+       int pkg = boot_cpu_data.logical_proc_id;
 
        if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
                hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
new file mode 100644 (file)
index 0000000..171ae09
--- /dev/null
@@ -0,0 +1 @@
+obj-y          := hv_init.o
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
new file mode 100644 (file)
index 0000000..d289bc2
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * X86 specific Hyper-V initialization code.
+ *
+ * Copyright (C) 2016, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <kys@microsoft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/hypervisor.h>
+#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/clockchips.h>
+
+
+#ifdef CONFIG_X86_64
+
+static struct ms_hyperv_tsc_page *tsc_pg;
+
+static u64 read_hv_clock_tsc(struct clocksource *arg)
+{
+       u64 current_tick;
+
+       if (tsc_pg->tsc_sequence != 0) {
+               /*
+                * Use the tsc page to compute the value.
+                */
+
+               while (1) {
+                       u64 tmp;
+                       u32 sequence = tsc_pg->tsc_sequence;
+                       u64 cur_tsc;
+                       u64 scale = tsc_pg->tsc_scale;
+                       s64 offset = tsc_pg->tsc_offset;
+
+                       rdtscll(cur_tsc);
+                       /* current_tick = ((cur_tsc *scale) >> 64) + offset */
+                       asm("mulq %3"
+                               : "=d" (current_tick), "=a" (tmp)
+                               : "a" (cur_tsc), "r" (scale));
+
+                       current_tick += offset;
+                       if (tsc_pg->tsc_sequence == sequence)
+                               return current_tick;
+
+                       if (tsc_pg->tsc_sequence != 0)
+                               continue;
+                       /*
+                        * Fallback using MSR method.
+                        */
+                       break;
+               }
+       }
+       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+       return current_tick;
+}
+
+static struct clocksource hyperv_cs_tsc = {
+               .name           = "hyperv_clocksource_tsc_page",
+               .rating         = 400,
+               .read           = read_hv_clock_tsc,
+               .mask           = CLOCKSOURCE_MASK(64),
+               .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+#endif
+
+static u64 read_hv_clock_msr(struct clocksource *arg)
+{
+       u64 current_tick;
+       /*
+        * Read the partition counter to get the current tick count. This count
+        * is set to 0 when the partition is created and is incremented in
+        * 100 nanosecond units.
+        */
+       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+       return current_tick;
+}
+
+static struct clocksource hyperv_cs_msr = {
+       .name           = "hyperv_clocksource_msr",
+       .rating         = 400,
+       .read           = read_hv_clock_msr,
+       .mask           = CLOCKSOURCE_MASK(64),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void *hypercall_pg;
+/*
+ * This function is to be invoked early in the boot sequence after the
+ * hypervisor has been detected.
+ *
+ * 1. Setup the hypercall page.
+ * 2. Register Hyper-V specific clocksource.
+ */
+void hyperv_init(void)
+{
+       u64 guest_id;
+       union hv_x64_msr_hypercall_contents hypercall_msr;
+
+       if (x86_hyper != &x86_hyper_ms_hyperv)
+               return;
+
+       /*
+        * Setup the hypercall page and enable hypercalls.
+        * 1. Register the guest ID
+        * 2. Enable the hypercall and register the hypercall page
+        */
+       guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+       wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
+
+       hypercall_pg  = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
+       if (hypercall_pg == NULL) {
+               wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
+               return;
+       }
+
+       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+       hypercall_msr.enable = 1;
+       hypercall_msr.guest_physical_address = vmalloc_to_pfn(hypercall_pg);
+       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+       /*
+        * Register Hyper-V specific clocksource.
+        */
+#ifdef CONFIG_X86_64
+       if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
+               union hv_x64_msr_hypercall_contents tsc_msr;
+
+               tsc_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
+               if (!tsc_pg) {
+                       clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
+                       return;
+               }
+
+               rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
+
+               tsc_msr.enable = 1;
+               tsc_msr.guest_physical_address = vmalloc_to_pfn(tsc_pg);
+
+               wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
+               clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
+               return;
+       }
+#endif
+       /*
+        * For 32 bit guests just use the MSR based mechanism for reading
+        * the partition counter.
+        */
+
+       if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
+               clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
+}
+
+/*
+ * hv_do_hypercall- Invoke the specified hypercall
+ */
+u64 hv_do_hypercall(u64 control, void *input, void *output)
+{
+       u64 input_address = (input) ? virt_to_phys(input) : 0;
+       u64 output_address = (output) ? virt_to_phys(output) : 0;
+#ifdef CONFIG_X86_64
+       u64 hv_status = 0;
+
+       if (!hypercall_pg)
+               return (u64)ULLONG_MAX;
+
+       __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
+       __asm__ __volatile__("call *%3" : "=a" (hv_status) :
+                            "c" (control), "d" (input_address),
+                            "m" (hypercall_pg));
+
+       return hv_status;
+
+#else
+
+       u32 control_hi = control >> 32;
+       u32 control_lo = control & 0xFFFFFFFF;
+       u32 hv_status_hi = 1;
+       u32 hv_status_lo = 1;
+       u32 input_address_hi = input_address >> 32;
+       u32 input_address_lo = input_address & 0xFFFFFFFF;
+       u32 output_address_hi = output_address >> 32;
+       u32 output_address_lo = output_address & 0xFFFFFFFF;
+
+       if (!hypercall_pg)
+               return (u64)ULLONG_MAX;
+
+       __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
+                             "=a"(hv_status_lo) : "d" (control_hi),
+                             "a" (control_lo), "b" (input_address_hi),
+                             "c" (input_address_lo), "D"(output_address_hi),
+                             "S"(output_address_lo), "m" (hypercall_pg));
+
+       return hv_status_lo | ((u64)hv_status_hi << 32);
+#endif /* !x86_64 */
+}
+EXPORT_SYMBOL_GPL(hv_do_hypercall);
+
+void hyperv_report_panic(struct pt_regs *regs)
+{
+       static bool panic_reported;
+
+       /*
+        * We prefer to report panic on 'die' chain as we have proper
+        * registers to report, but if we miss it (e.g. on BUG()) we need
+        * to report it on 'panic'.
+        */
+       if (panic_reported)
+               return;
+       panic_reported = true;
+
+       wrmsrl(HV_X64_MSR_CRASH_P0, regs->ip);
+       wrmsrl(HV_X64_MSR_CRASH_P1, regs->ax);
+       wrmsrl(HV_X64_MSR_CRASH_P2, regs->bx);
+       wrmsrl(HV_X64_MSR_CRASH_P3, regs->cx);
+       wrmsrl(HV_X64_MSR_CRASH_P4, regs->dx);
+
+       /*
+        * Let Hyper-V know there is crash data available
+        */
+       wrmsrl(HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
+}
+EXPORT_SYMBOL_GPL(hyperv_report_panic);
+
+bool hv_is_hypercall_page_setup(void)
+{
+       union hv_x64_msr_hypercall_contents hypercall_msr;
+
+       /* Check if the hypercall page is setup */
+       hypercall_msr.as_uint64 = 0;
+       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+       if (!hypercall_msr.enable)
+               return false;
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(hv_is_hypercall_page_setup);
index 34a46dc076d3610212e6f5c9f0abfb2ab9bc3629..8167fdb67ae846a0da668006159abfc56f3d99fc 100644 (file)
@@ -57,7 +57,7 @@
 #define INTEL_FAM6_ATOM_SILVERMONT2    0x4D /* Avaton/Rangely */
 #define INTEL_FAM6_ATOM_AIRMONT                0x4C /* CherryTrail / Braswell */
 #define INTEL_FAM6_ATOM_MERRIFIELD     0x4A /* Tangier */
-#define INTEL_FAM6_ATOM_MOOREFIELD     0x5A /* Annidale */
+#define INTEL_FAM6_ATOM_MOOREFIELD     0x5A /* Anniedale */
 #define INTEL_FAM6_ATOM_GOLDMONT       0x5C
 #define INTEL_FAM6_ATOM_DENVERTON      0x5F /* Goldmont Microserver */
 
index 195becc6f78074f23f25dc7d5d14da4bd90aac76..e793fc9a9b20c36d2e0d0e8e2a359fd1c70f2d8e 100644 (file)
@@ -52,6 +52,21 @@ struct extended_sigtable {
 
 #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
 
+static inline u32 intel_get_microcode_revision(void)
+{
+       u32 rev, dummy;
+
+       native_wrmsrl(MSR_IA32_UCODE_REV, 0);
+
+       /* As documented in the SDM: Do a CPUID 1 here */
+       native_cpuid_eax(1);
+
+       /* get the current revision from MSR 0x8B */
+       native_rdmsr(MSR_IA32_UCODE_REV, dummy, rev);
+
+       return rev;
+}
+
 #ifdef CONFIG_MICROCODE_INTEL
 extern void __init load_ucode_intel_bsp(void);
 extern void load_ucode_intel_ap(void);
index aaf59b7da98a2c7898390512c77601cd38b79eb1..42505d1158d6fcf71a9ba30eb98b682a1ed16aa3 100644 (file)
@@ -5,6 +5,25 @@
 #include <linux/interrupt.h>
 #include <asm/hyperv.h>
 
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HVCPUID_VERSION_FEATURES).
+ */
+enum hv_cpuid_function {
+       HVCPUID_VERSION_FEATURES                = 0x00000001,
+       HVCPUID_VENDOR_MAXFUNCTION              = 0x40000000,
+       HVCPUID_INTERFACE                       = 0x40000001,
+
+       /*
+        * The remaining functions depend on the value of
+        * HVCPUID_INTERFACE
+        */
+       HVCPUID_VERSION                         = 0x40000002,
+       HVCPUID_FEATURES                        = 0x40000003,
+       HVCPUID_ENLIGHTENMENT_INFO              = 0x40000004,
+       HVCPUID_IMPLEMENTATION_LIMITS           = 0x40000005,
+};
+
 struct ms_hyperv_info {
        u32 features;
        u32 misc_features;
@@ -13,6 +32,128 @@ struct ms_hyperv_info {
 
 extern struct ms_hyperv_info ms_hyperv;
 
+/*
+ * Declare the MSR used to setup pages used to communicate with the hypervisor.
+ */
+union hv_x64_msr_hypercall_contents {
+       u64 as_uint64;
+       struct {
+               u64 enable:1;
+               u64 reserved:11;
+               u64 guest_physical_address:52;
+       };
+};
+
+/*
+ * TSC page layout.
+ */
+
+struct ms_hyperv_tsc_page {
+       volatile u32 tsc_sequence;
+       u32 reserved1;
+       volatile u64 tsc_scale;
+       volatile s64 tsc_offset;
+       u64 reserved2[509];
+};
+
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0  - Distro specific identification
+ *
+ *
+ */
+
+#define HV_LINUX_VENDOR_ID              0x8800
+
+/*
+ * Generate the guest ID based on the guideline described above.
+ */
+
+static inline  __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
+                                      __u64 d_info2)
+{
+       __u64 guest_id = 0;
+
+       guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 56);
+       guest_id |= (d_info1 << 48);
+       guest_id |= (kernel_version << 16);
+       guest_id |= d_info2;
+
+       return guest_id;
+}
+
+
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
+{
+       /*
+        * On crash we're reading some other CPU's message page and we need
+        * to be careful: this other CPU may already had cleared the header
+        * and the host may already had delivered some other message there.
+        * In case we blindly write msg->header.message_type we're going
+        * to lose it. We can still lose a message of the same type but
+        * we count on the fact that there can only be one
+        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
+        * on crash.
+        */
+       if (cmpxchg(&msg->header.message_type, old_msg_type,
+                   HVMSG_NONE) != old_msg_type)
+               return;
+
+       /*
+        * Make sure the write to MessageType (ie set to
+        * HVMSG_NONE) happens before we read the
+        * MessagePending and EOMing. Otherwise, the EOMing
+        * will not deliver any more messages since there is
+        * no empty slot
+        */
+       mb();
+
+       if (msg->header.message_flags.msg_pending) {
+               /*
+                * This will cause message queue rescan to
+                * possibly deliver another msg from the
+                * hypervisor
+                */
+               wrmsrl(HV_X64_MSR_EOM, 0);
+       }
+}
+
+#define hv_get_current_tick(tick) rdmsrl(HV_X64_MSR_TIME_REF_COUNT, tick)
+#define hv_init_timer(timer, tick) wrmsrl(timer, tick)
+#define hv_init_timer_config(config, val) wrmsrl(config, val)
+
+#define hv_get_simp(val) rdmsrl(HV_X64_MSR_SIMP, val)
+#define hv_set_simp(val) wrmsrl(HV_X64_MSR_SIMP, val)
+
+#define hv_get_siefp(val) rdmsrl(HV_X64_MSR_SIEFP, val)
+#define hv_set_siefp(val) wrmsrl(HV_X64_MSR_SIEFP, val)
+
+#define hv_get_synic_state(val) rdmsrl(HV_X64_MSR_SCONTROL, val)
+#define hv_set_synic_state(val) wrmsrl(HV_X64_MSR_SCONTROL, val)
+
+#define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index)
+
+#define hv_get_synint_state(int_num, val) rdmsrl(int_num, val)
+#define hv_set_synint_state(int_num, val) wrmsrl(int_num, val)
+
 void hyperv_callback_vector(void);
 #ifdef CONFIG_TRACING
 #define trace_hyperv_callback_vector hyperv_callback_vector
@@ -25,4 +166,10 @@ void hv_setup_kexec_handler(void (*handler)(void));
 void hv_remove_kexec_handler(void);
 void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
 void hv_remove_crash_handler(void);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+void hyperv_init(void);
+void hyperv_report_panic(struct pt_regs *regs);
+bool hv_is_hypercall_page_setup(void);
+#endif
 #endif
index eaf100508c36203ad888c0b4484ba264e20bd0ad..1be64da0384ed8d5dea85563633c2740f5587888 100644 (file)
@@ -219,6 +219,24 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
            : "memory");
 }
 
+#define native_cpuid_reg(reg)                                  \
+static inline unsigned int native_cpuid_##reg(unsigned int op) \
+{                                                              \
+       unsigned int eax = op, ebx, ecx = 0, edx;               \
+                                                               \
+       native_cpuid(&eax, &ebx, &ecx, &edx);                   \
+                                                               \
+       return reg;                                             \
+}
+
+/*
+ * Native CPUID functions returning a single datum.
+ */
+native_cpuid_reg(eax)
+native_cpuid_reg(ebx)
+native_cpuid_reg(ecx)
+native_cpuid_reg(edx)
+
 static inline void load_cr3(pgd_t *pgdir)
 {
        write_cr3(__pa(pgdir));
index a3269c897ec578508fd41c6f7ab9b3622934e623..2e41c50ddf47f414c8f2e4b0a99965ceafffb4bf 100644 (file)
@@ -58,7 +58,7 @@ get_frame_pointer(struct task_struct *task, struct pt_regs *regs)
        if (task == current)
                return __builtin_frame_address(0);
 
-       return (unsigned long *)((struct inactive_task_frame *)task->thread.sp)->bp;
+       return &((struct inactive_task_frame *)task->thread.sp)->bp;
 }
 #else
 static inline unsigned long *
index 5cb436acd46315b75ba40aacc780373ea2cc4f7c..fcc5cd387fd17a59e5f28ba5fc8fb65fc57ae5af 100644 (file)
@@ -36,7 +36,10 @@ static inline void prepare_switch_to(struct task_struct *prev,
 
 asmlinkage void ret_from_fork(void);
 
-/* data that is pointed to by thread.sp */
+/*
+ * This is the structure pointed to by thread.sp for an inactive task.  The
+ * order of the fields must match the code in __switch_to_asm().
+ */
 struct inactive_task_frame {
 #ifdef CONFIG_X86_64
        unsigned long r15;
@@ -48,6 +51,11 @@ struct inactive_task_frame {
        unsigned long di;
 #endif
        unsigned long bx;
+
+       /*
+        * These two fields must be together.  They form a stack frame header,
+        * needed by get_frame_pointer().
+        */
        unsigned long bp;
        unsigned long ret_addr;
 };
index 9b1a91834ac8062ce19f3bab02449ced5978fc99..3a20ccf787b886ab7023c693c355af041e8c93a8 100644 (file)
@@ -73,6 +73,9 @@
   */
 #define HV_X64_MSR_STAT_PAGES_AVAILABLE                (1 << 8)
 
+/* Crash MSR available */
+#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10)
+
 /*
  * Feature identification: EBX indicates which flags were specified at
  * partition creation. The format is the same as the partition creation
  */
 #define HV_X64_RELAXED_TIMING_RECOMMENDED      (1 << 5)
 
+/*
+ * Crash notification flag.
+ */
+#define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63)
+
 /* MSR used to identify the guest OS. */
 #define HV_X64_MSR_GUEST_OS_ID                 0x40000000
 
index 71cae73a507617a2559aa0815a9e178a22f33385..1d3167269a6717902149171fe755123a5c654eb6 100644 (file)
@@ -309,15 +309,8 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
 
        /* get information required for multi-node processors */
        if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               u32 eax, ebx, ecx, edx;
 
-               cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
-               node_id = ecx & 7;
-
-               /* get compute unit information */
-               smp_num_siblings = ((ebx >> 8) & 3) + 1;
-               c->x86_max_cores /= smp_num_siblings;
-               c->cpu_core_id = ebx & 0xff;
+               node_id = cpuid_ecx(0x8000001e) & 7;
 
                /*
                 * We may have multiple LLCs if L3 caches exist, so check if we
index dc1697ca5191ce87cd9f27a78236ede3897243ab..9bab7a8a42936e32270e3573a17a1cd87fb580e0 100644 (file)
@@ -1221,7 +1221,7 @@ static __init int setup_disablecpuid(char *arg)
 {
        int bit;
 
-       if (get_option(&arg, &bit) && bit < NCAPINTS*32)
+       if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32)
                setup_clear_cpu_cap(bit);
        else
                return 0;
index fcd484d2bb034a4533d3c4355d3ace82c92060dd..203f860d2ab3339c11ddc34d976f56ffa6ef069c 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/bugs.h>
 #include <asm/cpu.h>
 #include <asm/intel-family.h>
+#include <asm/microcode_intel.h>
 
 #ifdef CONFIG_X86_64
 #include <linux/topology.h>
@@ -78,14 +79,8 @@ static void early_init_intel(struct cpuinfo_x86 *c)
                (c->x86 == 0x6 && c->x86_model >= 0x0e))
                set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 
-       if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64)) {
-               unsigned lower_word;
-
-               wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-               /* Required by the SDM */
-               sync_core();
-               rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
-       }
+       if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64))
+               c->microcode = intel_get_microcode_revision();
 
        /*
         * Atom erratum AAE44/AAF40/AAG38/AAH41:
index b624b54912e11e4e58992b9e1ca2d7cab20ce9e4..3f329b74e040c23b6b85dfd12a85f80d630c63ac 100644 (file)
@@ -150,7 +150,7 @@ static struct ucode_patch *__alloc_microcode_buf(void *data, unsigned int size)
 {
        struct ucode_patch *p;
 
-       p = kzalloc(size, GFP_KERNEL);
+       p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
        if (!p)
                return ERR_PTR(-ENOMEM);
 
@@ -368,26 +368,6 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
        return patch;
 }
 
-static void cpuid_1(void)
-{
-       /*
-        * According to the Intel SDM, Volume 3, 9.11.7:
-        *
-        *   CPUID returns a value in a model specific register in
-        *   addition to its usual register return values. The
-        *   semantics of CPUID cause it to deposit an update ID value
-        *   in the 64-bit model-specific register at address 08BH
-        *   (IA32_BIOS_SIGN_ID). If no update is present in the
-        *   processor, the value in the MSR remains unmodified.
-        *
-        * Use native_cpuid -- this code runs very early and we don't
-        * want to mess with paravirt.
-        */
-       unsigned int eax = 1, ebx, ecx = 0, edx;
-
-       native_cpuid(&eax, &ebx, &ecx, &edx);
-}
-
 static int collect_cpu_info_early(struct ucode_cpu_info *uci)
 {
        unsigned int val[2];
@@ -410,15 +390,8 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
                native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
                csig.pf = 1 << ((val[1] >> 18) & 7);
        }
-       native_wrmsrl(MSR_IA32_UCODE_REV, 0);
-
-       /* As documented in the SDM: Do a CPUID 1 here */
-       cpuid_1();
 
-       /* get the current revision from MSR 0x8B */
-       native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
-       csig.rev = val[1];
+       csig.rev = intel_get_microcode_revision();
 
        uci->cpu_sig = csig;
        uci->valid = 1;
@@ -602,7 +575,7 @@ static inline void print_ucode(struct ucode_cpu_info *uci)
 static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
 {
        struct microcode_intel *mc;
-       unsigned int val[2];
+       u32 rev;
 
        mc = uci->mc;
        if (!mc)
@@ -610,21 +583,16 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
 
        /* write microcode via MSR 0x79 */
        native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
-       native_wrmsrl(MSR_IA32_UCODE_REV, 0);
 
-       /* As documented in the SDM: Do a CPUID 1 here */
-       cpuid_1();
-
-       /* get the current revision from MSR 0x8B */
-       native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-       if (val[1] != mc->hdr.rev)
+       rev = intel_get_microcode_revision();
+       if (rev != mc->hdr.rev)
                return -1;
 
 #ifdef CONFIG_X86_64
        /* Flush global tlb. This is precaution. */
        flush_tlb_early();
 #endif
-       uci->cpu_sig.rev = val[1];
+       uci->cpu_sig.rev = rev;
 
        if (early)
                print_ucode(uci);
@@ -804,8 +772,8 @@ static int apply_microcode_intel(int cpu)
        struct microcode_intel *mc;
        struct ucode_cpu_info *uci;
        struct cpuinfo_x86 *c;
-       unsigned int val[2];
        static int prev_rev;
+       u32 rev;
 
        /* We should bind the task to the CPU */
        if (WARN_ON(raw_smp_processor_id() != cpu))
@@ -822,33 +790,28 @@ static int apply_microcode_intel(int cpu)
 
        /* write microcode via MSR 0x79 */
        wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
-       wrmsrl(MSR_IA32_UCODE_REV, 0);
-
-       /* As documented in the SDM: Do a CPUID 1 here */
-       cpuid_1();
 
-       /* get the current revision from MSR 0x8B */
-       rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+       rev = intel_get_microcode_revision();
 
-       if (val[1] != mc->hdr.rev) {
+       if (rev != mc->hdr.rev) {
                pr_err("CPU%d update to revision 0x%x failed\n",
                       cpu, mc->hdr.rev);
                return -1;
        }
 
-       if (val[1] != prev_rev) {
+       if (rev != prev_rev) {
                pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n",
-                       val[1],
+                       rev,
                        mc->hdr.date & 0xffff,
                        mc->hdr.date >> 24,
                        (mc->hdr.date >> 16) & 0xff);
-               prev_rev = val[1];
+               prev_rev = rev;
        }
 
        c = &cpu_data(cpu);
 
-       uci->cpu_sig.rev = val[1];
-       c->microcode = val[1];
+       uci->cpu_sig.rev = rev;
+       c->microcode = rev;
 
        return 0;
 }
@@ -860,7 +823,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
        u8 *ucode_ptr = data, *new_mc = NULL, *mc = NULL;
        int new_rev = uci->cpu_sig.rev;
        unsigned int leftover = size;
-       unsigned int curr_mc_size = 0;
+       unsigned int curr_mc_size = 0, new_mc_size = 0;
        unsigned int csig, cpf;
 
        while (leftover) {
@@ -901,6 +864,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
                        vfree(new_mc);
                        new_rev = mc_header.rev;
                        new_mc  = mc;
+                       new_mc_size = mc_size;
                        mc = NULL;      /* trigger new vmalloc */
                }
 
@@ -926,7 +890,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
         * permanent memory. So it will be loaded early when a CPU is hot added
         * or resumes.
         */
-       save_mc_for_early(new_mc, curr_mc_size);
+       save_mc_for_early(new_mc, new_mc_size);
 
        pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
                 cpu, new_rev, uci->cpu_sig.rev);
index 65e20c97e04b1e2591a356eda4e922ed92ec0310..b5375b9497b3aed6fa2f54f85f9667b243c18f46 100644 (file)
@@ -133,26 +133,6 @@ static uint32_t  __init ms_hyperv_platform(void)
        return 0;
 }
 
-static u64 read_hv_clock(struct clocksource *arg)
-{
-       u64 current_tick;
-       /*
-        * Read the partition counter to get the current tick count. This count
-        * is set to 0 when the partition is created and is incremented in
-        * 100 nanosecond units.
-        */
-       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
-       return current_tick;
-}
-
-static struct clocksource hyperv_cs = {
-       .name           = "hyperv_clocksource",
-       .rating         = 400, /* use this when running on Hyperv*/
-       .read           = read_hv_clock,
-       .mask           = CLOCKSOURCE_MASK(64),
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
 static unsigned char hv_get_nmi_reason(void)
 {
        return 0;
@@ -180,6 +160,11 @@ static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs)
 
 static void __init ms_hyperv_init_platform(void)
 {
+       int hv_host_info_eax;
+       int hv_host_info_ebx;
+       int hv_host_info_ecx;
+       int hv_host_info_edx;
+
        /*
         * Extract the features and hints
         */
@@ -190,6 +175,21 @@ static void __init ms_hyperv_init_platform(void)
        pr_info("HyperV: features 0x%x, hints 0x%x\n",
                ms_hyperv.features, ms_hyperv.hints);
 
+       /*
+        * Extract host information.
+        */
+       if (cpuid_eax(HVCPUID_VENDOR_MAXFUNCTION) >= HVCPUID_VERSION) {
+               hv_host_info_eax = cpuid_eax(HVCPUID_VERSION);
+               hv_host_info_ebx = cpuid_ebx(HVCPUID_VERSION);
+               hv_host_info_ecx = cpuid_ecx(HVCPUID_VERSION);
+               hv_host_info_edx = cpuid_edx(HVCPUID_VERSION);
+
+               pr_info("Hyper-V Host Build:%d-%d.%d-%d-%d.%d\n",
+                       hv_host_info_eax, hv_host_info_ebx >> 16,
+                       hv_host_info_ebx & 0xFFFF, hv_host_info_ecx,
+                       hv_host_info_edx >> 24, hv_host_info_edx & 0xFFFFFF);
+       }
+
 #ifdef CONFIG_X86_LOCAL_APIC
        if (ms_hyperv.features & HV_X64_MSR_APIC_FREQUENCY_AVAILABLE) {
                /*
@@ -208,9 +208,6 @@ static void __init ms_hyperv_init_platform(void)
                             "hv_nmi_unknown");
 #endif
 
-       if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
-               clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
-
 #ifdef CONFIG_X86_IO_APIC
        no_timer_check = 1;
 #endif
@@ -227,6 +224,13 @@ static void __init ms_hyperv_init_platform(void)
         */
        if (efi_enabled(EFI_BOOT))
                x86_platform.get_nmi_reason = hv_get_nmi_reason;
+
+#if IS_ENABLED(CONFIG_HYPERV)
+       /*
+        * Setup the hook to get control post apic initialization.
+        */
+       x86_platform.apic_post_init = hyperv_init;
+#endif
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
index be3a49ee035650f1f1eac68c07ad0e8898c40585..e41af597aed8e2e454965f8459f26b372c091b4f 100644 (file)
@@ -694,6 +694,7 @@ unsigned long native_calibrate_tsc(void)
                        crystal_khz = 24000;    /* 24.0 MHz */
                        break;
                case INTEL_FAM6_SKYLAKE_X:
+               case INTEL_FAM6_ATOM_DENVERTON:
                        crystal_khz = 25000;    /* 25.0 MHz */
                        break;
                case INTEL_FAM6_ATOM_GOLDMONT:
index 4443e499f2790923e6510bc57a88d5a9e0578051..23d15565d02ad780529091e5004557081bb62844 100644 (file)
@@ -6,6 +6,21 @@
 
 #define FRAME_HEADER_SIZE (sizeof(long) * 2)
 
+/*
+ * This disables KASAN checking when reading a value from another task's stack,
+ * since the other task could be running on another CPU and could have poisoned
+ * the stack in the meantime.
+ */
+#define READ_ONCE_TASK_STACK(task, x)                  \
+({                                                     \
+       unsigned long val;                              \
+       if (task == current)                            \
+               val = READ_ONCE(x);                     \
+       else                                            \
+               val = READ_ONCE_NOCHECK(x);             \
+       val;                                            \
+})
+
 static void unwind_dump(struct unwind_state *state, unsigned long *sp)
 {
        static bool dumped_before = false;
@@ -48,7 +63,8 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
        if (state->regs && user_mode(state->regs))
                return 0;
 
-       addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, *addr_p,
+       addr = READ_ONCE_TASK_STACK(state->task, *addr_p);
+       addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, addr,
                                     addr_p);
 
        return __kernel_text_address(addr) ? addr : 0;
@@ -162,7 +178,7 @@ bool unwind_next_frame(struct unwind_state *state)
        if (state->regs)
                next_bp = (unsigned long *)state->regs->bp;
        else
-               next_bp = (unsigned long *)*state->bp;
+               next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task,*state->bp);
 
        /* is the next frame pointer an encoded pointer to pt_regs? */
        regs = decode_frame_pointer(next_bp);
@@ -207,6 +223,16 @@ bool unwind_next_frame(struct unwind_state *state)
        return true;
 
 bad_address:
+       /*
+        * When unwinding a non-current task, the task might actually be
+        * running on another CPU, in which case it could be modifying its
+        * stack while we're reading it.  This is generally not a problem and
+        * can be ignored as long as the caller understands that unwinding
+        * another task will not always succeed.
+        */
+       if (state->task != current)
+               goto the_end;
+
        if (state->regs) {
                printk_deferred_once(KERN_WARNING
                        "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
index 56628a44668b7ec43cee087af817ebb1725cf7cd..cedbba0f3402d2343ce069fe3ed6a07f44f68907 100644 (file)
@@ -818,6 +818,20 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
        return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
 }
 
+static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
+                              struct segmented_address addr,
+                              void *data,
+                              unsigned int size)
+{
+       int rc;
+       ulong linear;
+
+       rc = linearize(ctxt, addr, size, true, &linear);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+       return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception);
+}
+
 /*
  * Prefetch the remaining bytes of the instruction without crossing page
  * boundary if they are not in fetch_cache yet.
@@ -1571,7 +1585,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                                    &ctxt->exception);
 }
 
-/* Does not support long mode */
 static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                                     u16 selector, int seg, u8 cpl,
                                     enum x86_transfer_type transfer,
@@ -1608,20 +1621,34 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
 
        rpl = selector & 3;
 
-       /* NULL selector is not valid for TR, CS and SS (except for long mode) */
-       if ((seg == VCPU_SREG_CS
-            || (seg == VCPU_SREG_SS
-                && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
-            || seg == VCPU_SREG_TR)
-           && null_selector)
-               goto exception;
-
        /* TR should be in GDT only */
        if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
                goto exception;
 
-       if (null_selector) /* for NULL selector skip all following checks */
+       /* NULL selector is not valid for TR, CS and (except for long mode) SS */
+       if (null_selector) {
+               if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
+                       goto exception;
+
+               if (seg == VCPU_SREG_SS) {
+                       if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
+                               goto exception;
+
+                       /*
+                        * ctxt->ops->set_segment expects the CPL to be in
+                        * SS.DPL, so fake an expand-up 32-bit data segment.
+                        */
+                       seg_desc.type = 3;
+                       seg_desc.p = 1;
+                       seg_desc.s = 1;
+                       seg_desc.dpl = cpl;
+                       seg_desc.d = 1;
+                       seg_desc.g = 1;
+               }
+
+               /* Skip all following checks */
                goto load;
+       }
 
        ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
        if (ret != X86EMUL_CONTINUE)
@@ -1737,6 +1764,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                                   u16 selector, int seg)
 {
        u8 cpl = ctxt->ops->cpl(ctxt);
+
+       /*
+        * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
+        * they can load it at CPL<3 (Intel's manual says only LSS can,
+        * but it's wrong).
+        *
+        * However, the Intel manual says that putting IST=1/DPL=3 in
+        * an interrupt gate will result in SS=3 (the AMD manual instead
+        * says it doesn't), so allow SS=3 in __load_segment_descriptor
+        * and only forbid it here.
+        */
+       if (seg == VCPU_SREG_SS && selector == 3 &&
+           ctxt->mode == X86EMUL_MODE_PROT64)
+               return emulate_exception(ctxt, GP_VECTOR, 0, true);
+
        return __load_segment_descriptor(ctxt, selector, seg, cpl,
                                         X86_TRANSFER_NONE, NULL);
 }
@@ -3685,8 +3727,8 @@ static int emulate_store_desc_ptr(struct x86_emulate_ctxt *ctxt,
        }
        /* Disable writeback. */
        ctxt->dst.type = OP_NONE;
-       return segmented_write(ctxt, ctxt->dst.addr.mem,
-                              &desc_ptr, 2 + ctxt->op_bytes);
+       return segmented_write_std(ctxt, ctxt->dst.addr.mem,
+                                  &desc_ptr, 2 + ctxt->op_bytes);
 }
 
 static int em_sgdt(struct x86_emulate_ctxt *ctxt)
@@ -3932,7 +3974,7 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt)
        else
                size = offsetof(struct fxregs_state, xmm_space[0]);
 
-       return segmented_write(ctxt, ctxt->memop.addr.mem, &fx_state, size);
+       return segmented_write_std(ctxt, ctxt->memop.addr.mem, &fx_state, size);
 }
 
 static int fxrstor_fixup(struct x86_emulate_ctxt *ctxt,
@@ -3974,7 +4016,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       rc = segmented_read(ctxt, ctxt->memop.addr.mem, &fx_state, 512);
+       rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, 512);
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
index 5fe290c1b7d892729e7cfd637433b8171423f407..2f6ef5121a4ca36ac73639e5ffc6aa86624067d2 100644 (file)
@@ -2426,3 +2426,9 @@ void kvm_lapic_init(void)
        jump_label_rate_limit(&apic_hw_disabled, HZ);
        jump_label_rate_limit(&apic_sw_disabled, HZ);
 }
+
+void kvm_lapic_exit(void)
+{
+       static_key_deferred_flush(&apic_hw_disabled);
+       static_key_deferred_flush(&apic_sw_disabled);
+}
index e0c80233b3e17a1793cbafd422688091034b15c5..ff8039d616723fd79c493c0a1369658e440224b2 100644 (file)
@@ -110,6 +110,7 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
 
 int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
 void kvm_lapic_init(void);
+void kvm_lapic_exit(void);
 
 #define VEC_POS(v) ((v) & (32 - 1))
 #define REG_POS(v) (((v) >> 5) << 4)
index 2f22810a7e0c8e3106c77849a6a3ea78a2b00a0c..57d8a856cdc5ce938efb73fd8fae144867abde76 100644 (file)
@@ -3342,6 +3342,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 
        switch (cap->cap) {
        case KVM_CAP_HYPERV_SYNIC:
+               if (!irqchip_in_kernel(vcpu->kvm))
+                       return -EINVAL;
                return kvm_hv_activate_synic(vcpu);
        default:
                return -EINVAL;
@@ -6045,6 +6047,7 @@ int kvm_arch_init(void *opaque)
 
 void kvm_arch_exit(void)
 {
+       kvm_lapic_exit();
        perf_unregister_guest_info_callbacks(&kvm_guest_cbs);
 
        if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
index 324e5713d386f0ed235b0394f71c0290df870fae..af59f808742f94df84ab0aaed1ac2db3ea27e016 100644 (file)
@@ -293,7 +293,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
         * We were not able to extract an address from the instruction,
         * probably because there was something invalid in it.
         */
-       if (info->si_addr == (void *)-1) {
+       if (info->si_addr == (void __user *)-1) {
                err = -EINVAL;
                goto err_out;
        }
index e76d1af60f7ad76a12fa4f01cf61b3c508ae0453..bb660e53cbd6ba51eace412622fdd7342939ddc1 100644 (file)
@@ -1172,6 +1172,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
                set_memory_ro((unsigned long)header, header->pages);
                prog->bpf_func = (void *)image;
                prog->jited = 1;
+       } else {
+               prog = orig_prog;
        }
 
 out_addrs:
index 936a488d6cf6df3c2aadbbdbc036b8eb06701cb0..274dfc48184977db435a9c5c78607cd8a182067c 100644 (file)
@@ -210,6 +210,70 @@ int __init efi_memblock_x86_reserve_range(void)
        return 0;
 }
 
+#define OVERFLOW_ADDR_SHIFT    (64 - EFI_PAGE_SHIFT)
+#define OVERFLOW_ADDR_MASK     (U64_MAX << OVERFLOW_ADDR_SHIFT)
+#define U64_HIGH_BIT           (~(U64_MAX >> 1))
+
+static bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i)
+{
+       u64 end = (md->num_pages << EFI_PAGE_SHIFT) + md->phys_addr - 1;
+       u64 end_hi = 0;
+       char buf[64];
+
+       if (md->num_pages == 0) {
+               end = 0;
+       } else if (md->num_pages > EFI_PAGES_MAX ||
+                  EFI_PAGES_MAX - md->num_pages <
+                  (md->phys_addr >> EFI_PAGE_SHIFT)) {
+               end_hi = (md->num_pages & OVERFLOW_ADDR_MASK)
+                       >> OVERFLOW_ADDR_SHIFT;
+
+               if ((md->phys_addr & U64_HIGH_BIT) && !(end & U64_HIGH_BIT))
+                       end_hi += 1;
+       } else {
+               return true;
+       }
+
+       pr_warn_once(FW_BUG "Invalid EFI memory map entries:\n");
+
+       if (end_hi) {
+               pr_warn("mem%02u: %s range=[0x%016llx-0x%llx%016llx] (invalid)\n",
+                       i, efi_md_typeattr_format(buf, sizeof(buf), md),
+                       md->phys_addr, end_hi, end);
+       } else {
+               pr_warn("mem%02u: %s range=[0x%016llx-0x%016llx] (invalid)\n",
+                       i, efi_md_typeattr_format(buf, sizeof(buf), md),
+                       md->phys_addr, end);
+       }
+       return false;
+}
+
+static void __init efi_clean_memmap(void)
+{
+       efi_memory_desc_t *out = efi.memmap.map;
+       const efi_memory_desc_t *in = out;
+       const efi_memory_desc_t *end = efi.memmap.map_end;
+       int i, n_removal;
+
+       for (i = n_removal = 0; in < end; i++) {
+               if (efi_memmap_entry_valid(in, i)) {
+                       if (out != in)
+                               memcpy(out, in, efi.memmap.desc_size);
+                       out = (void *)out + efi.memmap.desc_size;
+               } else {
+                       n_removal++;
+               }
+               in = (void *)in + efi.memmap.desc_size;
+       }
+
+       if (n_removal > 0) {
+               u64 size = efi.memmap.nr_map - n_removal;
+
+               pr_warn("Removing %d invalid memory map entries.\n", n_removal);
+               efi_memmap_install(efi.memmap.phys_map, size);
+       }
+}
+
 void __init efi_print_memmap(void)
 {
        efi_memory_desc_t *md;
@@ -472,6 +536,8 @@ void __init efi_init(void)
                }
        }
 
+       efi_clean_memmap();
+
        if (efi_enabled(EFI_DBG))
                efi_print_memmap();
 }
index 10aca63a50d7bbff9fa94dec60e0df00591ccbd5..30031d5293c483202c526d5045cda23be6617359 100644 (file)
@@ -214,7 +214,7 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
 
        new_size = efi.memmap.desc_size * num_entries;
 
-       new_phys = memblock_alloc(new_size, 0);
+       new_phys = efi_memmap_alloc(num_entries);
        if (!new_phys) {
                pr_err("Could not allocate boot services memmap\n");
                return;
@@ -355,7 +355,7 @@ void __init efi_free_boot_services(void)
        }
 
        new_size = efi.memmap.desc_size * num_entries;
-       new_phys = memblock_alloc(new_size, 0);
+       new_phys = efi_memmap_alloc(num_entries);
        if (!new_phys) {
                pr_err("Failed to allocate new EFI memmap\n");
                return;
index 61b5ed2b7d400339053d933d82c3938c94bbc766..90e4f2a6625b6ae2a87cf7c5ec9792a5459cd0e1 100644 (file)
@@ -15,7 +15,7 @@ obj-$(subst m,y,$(CONFIG_INTEL_MID_POWER_BUTTON)) += platform_msic_power_btn.o
 obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o
 obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o
 # SPI Devices
-obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o
+obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_mrfld_spidev.o
 # I2C Devices
 obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o
 obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o
similarity index 91%
rename from arch/x86/platform/intel-mid/device_libs/platform_spidev.c
rename to arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c
index 30c601b399ee70907c47d31e5dab3d4802c9218b..27186ad654c97846a42ef61f850d48affd602048 100644 (file)
@@ -11,6 +11,7 @@
  * of the License.
  */
 
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
 #include <linux/spi/pxa2xx_spi.h>
@@ -34,6 +35,9 @@ static void __init *spidev_platform_data(void *info)
 {
        struct spi_board_info *spi_info = info;
 
+       if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
+               return ERR_PTR(-ENODEV);
+
        spi_info->mode = SPI_MODE_0;
        spi_info->controller_data = &spidev_spi_chip;
 
index ed89c8f4b2a0497af0e45f075e4781dbb5cf87d2..f8c82a9b401222c84d5d014ac339439a1708caba 100644 (file)
@@ -301,13 +301,6 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
        if ((sector | nr_sects) & bs_mask)
                return -EINVAL;
 
-       if (discard) {
-               ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask,
-                               BLKDEV_DISCARD_ZERO, biop);
-               if (ret == 0 || (ret && ret != -EOPNOTSUPP))
-                       goto out;
-       }
-
        ret = __blkdev_issue_write_zeroes(bdev, sector, nr_sects, gfp_mask,
                        biop);
        if (ret == 0 || (ret && ret != -EOPNOTSUPP))
@@ -370,6 +363,12 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
        struct bio *bio = NULL;
        struct blk_plug plug;
 
+       if (discard) {
+               if (!blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask,
+                               BLKDEV_DISCARD_ZERO))
+                       return 0;
+       }
+
        blk_start_plug(&plug);
        ret = __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask,
                        &bio, discard);
index 472211fa183a6488ef93676a2f89b2f345947c9a..3bd15d8095b101233455d7985b834f828d89be92 100644 (file)
@@ -16,7 +16,7 @@
 static inline sector_t blk_zone_start(struct request_queue *q,
                                      sector_t sector)
 {
-       sector_t zone_mask = blk_queue_zone_size(q) - 1;
+       sector_t zone_mask = blk_queue_zone_sectors(q) - 1;
 
        return sector & ~zone_mask;
 }
@@ -222,7 +222,7 @@ int blkdev_reset_zones(struct block_device *bdev,
                return -EINVAL;
 
        /* Check alignment (handle eventual smaller last zone) */
-       zone_sectors = blk_queue_zone_size(q);
+       zone_sectors = blk_queue_zone_sectors(q);
        if (sector & (zone_sectors - 1))
                return -EINVAL;
 
index d7beb6bbbf668fe62083cece4d7a6cb1eafe9443..7afb9907821fb7abe61d76ac1f3ce408bb14dbd5 100644 (file)
@@ -434,7 +434,7 @@ static bool part_zone_aligned(struct gendisk *disk,
                              struct block_device *bdev,
                              sector_t from, sector_t size)
 {
-       unsigned int zone_size = bdev_zone_size(bdev);
+       unsigned int zone_sectors = bdev_zone_sectors(bdev);
 
        /*
         * If this function is called, then the disk is a zoned block device
@@ -446,7 +446,7 @@ static bool part_zone_aligned(struct gendisk *disk,
         * regular block devices (no zone operation) and their zone size will
         * be reported as 0. Allow this case.
         */
-       if (!zone_size)
+       if (!zone_sectors)
                return true;
 
        /*
@@ -455,24 +455,24 @@ static bool part_zone_aligned(struct gendisk *disk,
         * use it. Check the zone size too: it should be a power of 2 number
         * of sectors.
         */
-       if (WARN_ON_ONCE(!is_power_of_2(zone_size))) {
+       if (WARN_ON_ONCE(!is_power_of_2(zone_sectors))) {
                u32 rem;
 
-               div_u64_rem(from, zone_size, &rem);
+               div_u64_rem(from, zone_sectors, &rem);
                if (rem)
                        return false;
                if ((from + size) < get_capacity(disk)) {
-                       div_u64_rem(size, zone_size, &rem);
+                       div_u64_rem(size, zone_sectors, &rem);
                        if (rem)
                                return false;
                }
 
        } else {
 
-               if (from & (zone_size - 1))
+               if (from & (zone_sectors - 1))
                        return false;
                if ((from + size) < get_capacity(disk) &&
-                   (size & (zone_size - 1)))
+                   (size & (zone_sectors - 1)))
                        return false;
 
        }
index 4ef4c5caed4f57bece96aa4efdae4a2ea34313f1..8a8e403644d6e0d6ce838105dfceb30ae5625460 100644 (file)
@@ -132,9 +132,9 @@ config HT16K33
        tristate "Holtek Ht16K33 LED controller with keyscan"
        depends on FB && OF && I2C && INPUT
        select FB_SYS_FOPS
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
        select INPUT_MATRIXKMAP
        select FB_BACKLIGHT
        help
index ada9dce34e6d8a8373d3d08d5c28b3f6b55ac427..e19b1008e5fb08b1099e5f5d8f0dc86dfc24bde5 100644 (file)
@@ -141,8 +141,6 @@ extern void device_unblock_probing(void);
 extern struct kset *devices_kset;
 extern void devices_kset_move_last(struct device *dev);
 
-extern struct device_attribute dev_attr_deferred_probe;
-
 #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
 extern void module_add_driver(struct module *mod, struct device_driver *drv);
 extern void module_remove_driver(struct device_driver *drv);
index 020ea7f0552073c62c91e55d62e0c0151917251e..8c25e68e67d7354005dc81a92342eb10519449ed 100644 (file)
@@ -1060,14 +1060,8 @@ static int device_add_attrs(struct device *dev)
                        goto err_remove_dev_groups;
        }
 
-       error = device_create_file(dev, &dev_attr_deferred_probe);
-       if (error)
-               goto err_remove_online;
-
        return 0;
 
- err_remove_online:
-       device_remove_file(dev, &dev_attr_online);
  err_remove_dev_groups:
        device_remove_groups(dev, dev->groups);
  err_remove_type_groups:
@@ -1085,7 +1079,6 @@ static void device_remove_attrs(struct device *dev)
        struct class *class = dev->class;
        const struct device_type *type = dev->type;
 
-       device_remove_file(dev, &dev_attr_deferred_probe);
        device_remove_file(dev, &dev_attr_online);
        device_remove_groups(dev, dev->groups);
 
index a8b258e5407bae02c48b03b39941ee238c22a2e3..a1fbf55c4d3abbea786ef5585b96d769ca3a144a 100644 (file)
@@ -53,19 +53,6 @@ static LIST_HEAD(deferred_probe_pending_list);
 static LIST_HEAD(deferred_probe_active_list);
 static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
 
-static ssize_t deferred_probe_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       bool value;
-
-       mutex_lock(&deferred_probe_mutex);
-       value = !list_empty(&dev->p->deferred_probe);
-       mutex_unlock(&deferred_probe_mutex);
-
-       return sprintf(buf, "%d\n", value);
-}
-DEVICE_ATTR_RO(deferred_probe);
-
 /*
  * In some cases, like suspend to RAM or hibernation, It might be reasonable
  * to prohibit probing of devices as it could be unsafe.
index 38c576f76d36fca1f43bc37b6c733ba6bb222849..50a2020b5b724fd657c01b6d1a27c33a68a27fd0 100644 (file)
@@ -1042,6 +1042,7 @@ static int __init nbd_init(void)
                return -ENOMEM;
 
        for (i = 0; i < nbds_max; i++) {
+               struct request_queue *q;
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
                        goto out;
@@ -1067,12 +1068,13 @@ static int __init nbd_init(void)
                 * every gendisk to have its very own request_queue struct.
                 * These structs are big so we dynamically allocate them.
                 */
-               disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set);
-               if (!disk->queue) {
+               q = blk_mq_init_queue(&nbd_dev[i].tag_set);
+               if (IS_ERR(q)) {
                        blk_mq_free_tag_set(&nbd_dev[i].tag_set);
                        put_disk(disk);
                        goto out;
                }
+               disk->queue = q;
 
                /*
                 * Tell the block layer that we are not a rotational device
index 5545a679abd8887123fc83d57beb37dede77a685..10332c24f9610d7e80b154bf36eebb0354ac4576 100644 (file)
@@ -56,6 +56,7 @@ struct virtblk_req {
        struct virtio_blk_outhdr out_hdr;
        struct virtio_scsi_inhdr in_hdr;
        u8 status;
+       u8 sense[SCSI_SENSE_BUFFERSIZE];
        struct scatterlist sg[];
 };
 
@@ -102,7 +103,8 @@ static int __virtblk_add_req(struct virtqueue *vq,
        }
 
        if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
-               sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
+               memcpy(vbr->sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
+               sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE);
                sgs[num_out + num_in++] = &sense;
                sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
                sgs[num_out + num_in++] = &inhdr;
@@ -628,11 +630,12 @@ static int virtblk_probe(struct virtio_device *vdev)
        if (err)
                goto out_put_disk;
 
-       q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
+       q = blk_mq_init_queue(&vblk->tag_set);
        if (IS_ERR(q)) {
                err = -ENOMEM;
                goto out_free_tags;
        }
+       vblk->disk->queue = q;
 
        q->queuedata = vblk;
 
index 15f58ab44d0b429fc7b5ebf0ba7e1cdfcc6c914d..e5ab7d9e8c452f2feac3e2f374c6e1639317756b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/genhd.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
+#include <linux/backing-dev.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/err.h>
@@ -112,6 +113,14 @@ static inline bool is_partial_io(struct bio_vec *bvec)
        return bvec->bv_len != PAGE_SIZE;
 }
 
+static void zram_revalidate_disk(struct zram *zram)
+{
+       revalidate_disk(zram->disk);
+       /* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */
+       zram->disk->queue->backing_dev_info.capabilities |=
+               BDI_CAP_STABLE_WRITES;
+}
+
 /*
  * Check if request is within bounds and aligned on zram logical blocks.
  */
@@ -1095,15 +1104,9 @@ static ssize_t disksize_store(struct device *dev,
        zram->comp = comp;
        zram->disksize = disksize;
        set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+       zram_revalidate_disk(zram);
        up_write(&zram->init_lock);
 
-       /*
-        * Revalidate disk out of the init_lock to avoid lockdep splat.
-        * It's okay because disk's capacity is protected by init_lock
-        * so that revalidate_disk always sees up-to-date capacity.
-        */
-       revalidate_disk(zram->disk);
-
        return len;
 
 out_destroy_comp:
@@ -1149,7 +1152,7 @@ static ssize_t reset_store(struct device *dev,
        /* Make sure all the pending I/O are finished */
        fsync_bdev(bdev);
        zram_reset_device(zram);
-       revalidate_disk(zram->disk);
+       zram_revalidate_disk(zram);
        bdput(bdev);
 
        mutex_lock(&bdev->bd_mutex);
index fde005ef9d36a96d02be8680cb1845fc042296fa..4ee2a10207d0eee59163ce52ef5d8643e7acc7ca 100644 (file)
@@ -571,9 +571,12 @@ config TELCLOCK
          controlling the behavior of this hardware.
 
 config DEVPORT
-       bool
+       bool "/dev/port character device"
        depends on ISA || PCI
        default y
+       help
+         Say Y here if you want to support the /dev/port device. The /dev/port
+         device is similar to /dev/mem, but for I/O ports.
 
 source "drivers/s390/char/Kconfig"
 
index dd9dfa15e9d13364b1ce2ea65de957bdd21a6ee4..1dfb9f8de1715a6afcfe2828138e678e28602da1 100644 (file)
 #include <linux/kthread.h>
 #include <linux/delay.h>
 
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV  134
-
 /*
  * One option can be changed at boot time as follows:
  *     apm=on/off                      enable/disable APM
index 7d34b203718af7bd9fd5c3a00ca294e5c7a8dea8..c614a56e68ccb6f2562f8635a90b10f162740c1f 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
 #include <linux/mutex.h>
index 5bb1985ec484aef267e3c551c3068ec0dee14b1c..6d9cc2d39d22306fd68f30bac6f4a60e6cfa5a87 100644 (file)
@@ -381,9 +381,6 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
        char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
        int err = 0;
 
-       if (!pfn_valid(PFN_DOWN(p)))
-               return -EIO;
-
        read = 0;
        if (p < (unsigned long) high_memory) {
                low_count = count;
@@ -412,6 +409,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
                         * by the kernel or data corruption may occur
                         */
                        kbuf = xlate_dev_kmem_ptr((void *)p);
+                       if (!virt_addr_valid(kbuf))
+                               return -ENXIO;
 
                        if (copy_to_user(buf, kbuf, sz))
                                return -EFAULT;
@@ -482,6 +481,8 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
                 * corruption may occur.
                 */
                ptr = xlate_dev_kmem_ptr((void *)p);
+               if (!virt_addr_valid(ptr))
+                       return -ENXIO;
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
@@ -512,9 +513,6 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
        char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
        int err = 0;
 
-       if (!pfn_valid(PFN_DOWN(p)))
-               return -EIO;
-
        if (p < (unsigned long) high_memory) {
                unsigned long to_write = min_t(unsigned long, count,
                                               (unsigned long)high_memory - p);
index f786b18ac5008d598cd4a0217a73bb69bc042c34..b708c85dc9c1d7b5d243c4add03cc2fe5936141a 100644 (file)
@@ -463,9 +463,9 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 static struct miscdevice mmtimer_miscdev = {
-       SGI_MMTIMER,
-       MMTIMER_NAME,
-       &mmtimer_fops
+       .minor = SGI_MMTIMER,
+       .name = MMTIMER_NAME,
+       .fops = &mmtimer_fops
 };
 
 static struct timespec sgi_clock_offset;
index 02819e0703c8eef503baf8333c88f105a591444b..87885d146dbb02ed9ed08979dda96579bd5bc652 100644 (file)
@@ -290,6 +290,7 @@ static int register_device(int minor, struct pp_struct *pp)
        struct pardevice *pdev = NULL;
        char *name;
        struct pardev_cb ppdev_cb;
+       int rc = 0;
 
        name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
        if (name == NULL)
@@ -298,8 +299,8 @@ static int register_device(int minor, struct pp_struct *pp)
        port = parport_find_number(minor);
        if (!port) {
                pr_warn("%s: no associated port!\n", name);
-               kfree(name);
-               return -ENXIO;
+               rc = -ENXIO;
+               goto err;
        }
 
        memset(&ppdev_cb, 0, sizeof(ppdev_cb));
@@ -308,16 +309,18 @@ static int register_device(int minor, struct pp_struct *pp)
        ppdev_cb.private = pp;
        pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
        parport_put_port(port);
-       kfree(name);
 
        if (!pdev) {
                pr_warn("%s: failed to register device!\n", name);
-               return -ENXIO;
+               rc = -ENXIO;
+               goto err;
        }
 
        pp->pdev = pdev;
        dev_dbg(&pdev->dev, "registered pardevice\n");
-       return 0;
+err:
+       kfree(name);
+       return rc;
 }
 
 static enum ieee1284_phase init_phase(int mode)
index e00c9b022964702c076b1a192df35b9bbbf7e113..5a37b9fcf40ddf813a6cf5d2c401bc221fd5e83b 100644 (file)
@@ -24,5 +24,5 @@ config DW_DMAC_PCI
        select DW_DMAC_CORE
        help
          Support the Synopsys DesignWare AHB DMA controller on the
-         platfroms that enumerate it as a PCI device. For example,
+         platforms that enumerate it as a PCI device. For example,
          Intel Medfield has integrated this GPDMA controller.
index 8e67895bcca3a2db74e5b72e00374e2118ce95f7..abcc51b343cecd1629700233e8ca9d8882da2dff 100644 (file)
@@ -64,6 +64,8 @@
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX8  0x6f2e
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX9  0x6f2f
 
+#define PCI_DEVICE_ID_INTEL_IOAT_SKX   0x2021
+
 #define IOAT_VER_1_2            0x12    /* Version 1.2 */
 #define IOAT_VER_2_0            0x20    /* Version 2.0 */
 #define IOAT_VER_3_0            0x30    /* Version 3.0 */
index 90eddd9f07e4fc1b354bad70a935a8cfec20e246..cc5259b881d47ffa48322e2a537397317e8b8be1 100644 (file)
@@ -106,6 +106,8 @@ static struct pci_device_id ioat_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) },
+
        /* I/OAT v3.3 platforms */
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) },
@@ -243,10 +245,15 @@ static bool is_bdx_ioat(struct pci_dev *pdev)
        }
 }
 
+static inline bool is_skx_ioat(struct pci_dev *pdev)
+{
+       return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false;
+}
+
 static bool is_xeon_cb32(struct pci_dev *pdev)
 {
        return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
-               is_hsw_ioat(pdev) || is_bdx_ioat(pdev);
+               is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev);
 }
 
 bool is_bwd_ioat(struct pci_dev *pdev)
@@ -693,7 +700,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c)
        /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
        ioat_chan->completion =
                dma_pool_zalloc(ioat_chan->ioat_dma->completion_pool,
-                               GFP_KERNEL, &ioat_chan->completion_dma);
+                               GFP_NOWAIT, &ioat_chan->completion_dma);
        if (!ioat_chan->completion)
                return -ENOMEM;
 
@@ -703,7 +710,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c)
               ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
 
        order = IOAT_MAX_ORDER;
-       ring = ioat_alloc_ring(c, order, GFP_KERNEL);
+       ring = ioat_alloc_ring(c, order, GFP_NOWAIT);
        if (!ring)
                return -ENOMEM;
 
@@ -1357,6 +1364,8 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        device->version = readb(device->reg_base + IOAT_VER_OFFSET);
        if (device->version >= IOAT_VER_3_0) {
+               if (is_skx_ioat(pdev))
+                       device->version = IOAT_VER_3_2;
                err = ioat3_dma_probe(device, ioat_dca_enabled);
 
                if (device->version >= IOAT_VER_3_3)
index ac68666cd3f4e99cd3bc2f4ae346f5e78cd218ce..daf479cce69158e480757d269630d4bed7d6bca2 100644 (file)
@@ -938,21 +938,14 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
                d->ccr |= CCR_DST_AMODE_POSTINC;
                if (port_window) {
                        d->ccr |= CCR_SRC_AMODE_DBLIDX;
-                       d->ei = 1;
-                       /*
-                        * One frame covers the port_window and by  configure
-                        * the source frame index to be -1 * (port_window - 1)
-                        * we instruct the sDMA that after a frame is processed
-                        * it should move back to the start of the window.
-                        */
-                       d->fi = -(port_window_bytes - 1);
 
                        if (port_window_bytes >= 64)
-                               d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED;
+                               d->csdp |= CSDP_SRC_BURST_64;
                        else if (port_window_bytes >= 32)
-                               d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED;
+                               d->csdp |= CSDP_SRC_BURST_32;
                        else if (port_window_bytes >= 16)
-                               d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED;
+                               d->csdp |= CSDP_SRC_BURST_16;
+
                } else {
                        d->ccr |= CCR_SRC_AMODE_CONSTANT;
                }
@@ -962,13 +955,21 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
                d->ccr |= CCR_SRC_AMODE_POSTINC;
                if (port_window) {
                        d->ccr |= CCR_DST_AMODE_DBLIDX;
+                       d->ei = 1;
+                       /*
+                        * One frame covers the port_window and by  configure
+                        * the source frame index to be -1 * (port_window - 1)
+                        * we instruct the sDMA that after a frame is processed
+                        * it should move back to the start of the window.
+                        */
+                       d->fi = -(port_window_bytes - 1);
 
                        if (port_window_bytes >= 64)
-                               d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED;
+                               d->csdp |= CSDP_DST_BURST_64;
                        else if (port_window_bytes >= 32)
-                               d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED;
+                               d->csdp |= CSDP_DST_BURST_32;
                        else if (port_window_bytes >= 16)
-                               d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED;
+                               d->csdp |= CSDP_DST_BURST_16;
                } else {
                        d->ccr |= CCR_DST_AMODE_CONSTANT;
                }
@@ -1017,7 +1018,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
                osg->addr = sg_dma_address(sgent);
                osg->en = en;
                osg->fn = sg_dma_len(sgent) / frame_bytes;
-               if (port_window && dir == DMA_MEM_TO_DEV) {
+               if (port_window && dir == DMA_DEV_TO_MEM) {
                        osg->ei = 1;
                        /*
                         * One frame covers the port_window and by  configure
@@ -1452,6 +1453,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        struct omap_dmadev *od;
        struct resource *res;
        int rc, i, irq;
+       u32 lch_count;
 
        od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
        if (!od)
@@ -1494,20 +1496,31 @@ static int omap_dma_probe(struct platform_device *pdev)
        spin_lock_init(&od->lock);
        spin_lock_init(&od->irq_lock);
 
-       if (!pdev->dev.of_node) {
-               od->dma_requests = od->plat->dma_attr->lch_count;
-               if (unlikely(!od->dma_requests))
-                       od->dma_requests = OMAP_SDMA_REQUESTS;
-       } else if (of_property_read_u32(pdev->dev.of_node, "dma-requests",
-                                       &od->dma_requests)) {
+       /* Number of DMA requests */
+       od->dma_requests = OMAP_SDMA_REQUESTS;
+       if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
+                                                     "dma-requests",
+                                                     &od->dma_requests)) {
                dev_info(&pdev->dev,
                         "Missing dma-requests property, using %u.\n",
                         OMAP_SDMA_REQUESTS);
-               od->dma_requests = OMAP_SDMA_REQUESTS;
        }
 
-       od->lch_map = devm_kcalloc(&pdev->dev, od->dma_requests,
-                                  sizeof(*od->lch_map), GFP_KERNEL);
+       /* Number of available logical channels */
+       if (!pdev->dev.of_node) {
+               lch_count = od->plat->dma_attr->lch_count;
+               if (unlikely(!lch_count))
+                       lch_count = OMAP_SDMA_CHANNELS;
+       } else if (of_property_read_u32(pdev->dev.of_node, "dma-channels",
+                                       &lch_count)) {
+               dev_info(&pdev->dev,
+                        "Missing dma-channels property, using %u.\n",
+                        OMAP_SDMA_CHANNELS);
+               lch_count = OMAP_SDMA_CHANNELS;
+       }
+
+       od->lch_map = devm_kcalloc(&pdev->dev, lch_count, sizeof(*od->lch_map),
+                                  GFP_KERNEL);
        if (!od->lch_map)
                return -ENOMEM;
 
index 87fd01539fcb74daa0c80a62a268311b7125dce1..740bbb942594873b08deecb59c801460dcc868ab 100644 (file)
@@ -448,6 +448,9 @@ struct dma_pl330_chan {
 
        /* for cyclic capability */
        bool cyclic;
+
+       /* for runtime pm tracking */
+       bool active;
 };
 
 struct pl330_dmac {
@@ -2033,6 +2036,7 @@ static void pl330_tasklet(unsigned long data)
                _stop(pch->thread);
                spin_unlock(&pch->thread->dmac->lock);
                power_down = true;
+               pch->active = false;
        } else {
                /* Make sure the PL330 Channel thread is active */
                spin_lock(&pch->thread->dmac->lock);
@@ -2052,6 +2056,7 @@ static void pl330_tasklet(unsigned long data)
                        desc->status = PREP;
                        list_move_tail(&desc->node, &pch->work_list);
                        if (power_down) {
+                               pch->active = true;
                                spin_lock(&pch->thread->dmac->lock);
                                _start(pch->thread);
                                spin_unlock(&pch->thread->dmac->lock);
@@ -2166,6 +2171,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
        unsigned long flags;
        struct pl330_dmac *pl330 = pch->dmac;
        LIST_HEAD(list);
+       bool power_down = false;
 
        pm_runtime_get_sync(pl330->ddma.dev);
        spin_lock_irqsave(&pch->lock, flags);
@@ -2176,6 +2182,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
        pch->thread->req[0].desc = NULL;
        pch->thread->req[1].desc = NULL;
        pch->thread->req_running = -1;
+       power_down = pch->active;
+       pch->active = false;
 
        /* Mark all desc done */
        list_for_each_entry(desc, &pch->submitted_list, node) {
@@ -2193,6 +2201,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
        list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
        spin_unlock_irqrestore(&pch->lock, flags);
        pm_runtime_mark_last_busy(pl330->ddma.dev);
+       if (power_down)
+               pm_runtime_put_autosuspend(pl330->ddma.dev);
        pm_runtime_put_autosuspend(pl330->ddma.dev);
 
        return 0;
@@ -2357,6 +2367,7 @@ static void pl330_issue_pending(struct dma_chan *chan)
                 * updated on work_list emptiness status.
                 */
                WARN_ON(list_empty(&pch->submitted_list));
+               pch->active = true;
                pm_runtime_get_sync(pch->dmac->ddma.dev);
        }
        list_splice_tail_init(&pch->submitted_list, &pch->work_list);
index 2e441d0ccd79a37a5486d394310839c2cdc47f01..4c357d47546594c6bd0c9b1ca16e27c658a720cf 100644 (file)
@@ -986,6 +986,7 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
 {
        struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
        struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
+       struct rcar_dmac_chan_map *map = &rchan->map;
        struct rcar_dmac_desc_page *page, *_page;
        struct rcar_dmac_desc *desc;
        LIST_HEAD(list);
@@ -1019,6 +1020,13 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
                free_page((unsigned long)page);
        }
 
+       /* Remove slave mapping if present. */
+       if (map->slave.xfer_size) {
+               dma_unmap_resource(chan->device->dev, map->addr,
+                                  map->slave.xfer_size, map->dir, 0);
+               map->slave.xfer_size = 0;
+       }
+
        pm_runtime_put(chan->device->dev);
 }
 
index 3688d0873a3e1c844470c31105ecabd3b5d49be3..3056ce7f8c69d01c61fe3ab0eeff6ad299f538f7 100644 (file)
@@ -880,7 +880,7 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c,
        struct virt_dma_desc *vdesc;
        enum dma_status status;
        unsigned long flags;
-       u32 residue;
+       u32 residue = 0;
 
        status = dma_cookie_status(c, cookie, state);
        if ((status == DMA_COMPLETE) || (!state))
@@ -888,16 +888,12 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c,
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
        vdesc = vchan_find_desc(&chan->vchan, cookie);
-       if (cookie == chan->desc->vdesc.tx.cookie) {
+       if (chan->desc && cookie == chan->desc->vdesc.tx.cookie)
                residue = stm32_dma_desc_residue(chan, chan->desc,
                                                 chan->next_sg);
-       } else if (vdesc) {
+       else if (vdesc)
                residue = stm32_dma_desc_residue(chan,
                                                 to_stm32_dma_desc(vdesc), 0);
-       } else {
-               residue = 0;
-       }
-
        dma_set_residue(state, residue);
 
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
@@ -972,21 +968,18 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
        struct stm32_dma_chan *chan;
        struct dma_chan *c;
 
-       if (dma_spec->args_count < 3)
+       if (dma_spec->args_count < 4)
                return NULL;
 
        cfg.channel_id = dma_spec->args[0];
        cfg.request_line = dma_spec->args[1];
        cfg.stream_config = dma_spec->args[2];
-       cfg.threshold = 0;
+       cfg.threshold = dma_spec->args[3];
 
        if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >=
                                STM32_DMA_MAX_REQUEST_ID))
                return NULL;
 
-       if (dma_spec->args_count > 3)
-               cfg.threshold = dma_spec->args[3];
-
        chan = &dmadev->chan[cfg.channel_id];
 
        c = dma_get_slave_channel(&chan->vchan.chan);
index 3f24aeb48c0e6735f13995ded459cac776b2620f..2403475a37cf9203eb0651ae7f412ef5f63f45d6 100644 (file)
@@ -149,6 +149,7 @@ static int ti_am335x_xbar_probe(struct platform_device *pdev)
        match = of_match_node(ti_am335x_master_match, dma_node);
        if (!match) {
                dev_err(&pdev->dev, "DMA master is not supported\n");
+               of_node_put(dma_node);
                return -EINVAL;
        }
 
@@ -339,6 +340,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
        match = of_match_node(ti_dra7_master_match, dma_node);
        if (!match) {
                dev_err(&pdev->dev, "DMA master is not supported\n");
+               of_node_put(dma_node);
                return -EINVAL;
        }
 
index 520a40e5e0e431129cf1fe66a7604d32d7e20061..6c7d60c239b5b459b1f45e1d1110f7ed5a265cb6 100644 (file)
@@ -71,8 +71,7 @@ void __init efi_fake_memmap(void)
        }
 
        /* allocate memory for new EFI memmap */
-       new_memmap_phy = memblock_alloc(efi.memmap.desc_size * new_nr_map,
-                                       PAGE_SIZE);
+       new_memmap_phy = efi_memmap_alloc(new_nr_map);
        if (!new_memmap_phy)
                return;
 
index b98824e3800abbb57b110d7cc92c0ca8417791d2..0e2a96b12cb3647635db19912ec0ab4004f71572 100644 (file)
@@ -39,14 +39,6 @@ efi_status_t efi_file_close(void *handle);
 
 unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
 
-efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
-                       unsigned long orig_fdt_size,
-                       void *fdt, int new_fdt_size, char *cmdline_ptr,
-                       u64 initrd_addr, u64 initrd_size,
-                       efi_memory_desc_t *memory_map,
-                       unsigned long map_size, unsigned long desc_size,
-                       u32 desc_ver);
-
 efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
                                            void *handle,
                                            unsigned long *new_fdt_addr,
index a6a93116a8f053f6c14911376ffa6da7f1dff44e..921dfa047202952c9064cd39971e68e0e3c28b49 100644 (file)
 
 #include "efistub.h"
 
-efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
-                       unsigned long orig_fdt_size,
-                       void *fdt, int new_fdt_size, char *cmdline_ptr,
-                       u64 initrd_addr, u64 initrd_size,
-                       efi_memory_desc_t *memory_map,
-                       unsigned long map_size, unsigned long desc_size,
-                       u32 desc_ver)
+static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+                              unsigned long orig_fdt_size,
+                              void *fdt, int new_fdt_size, char *cmdline_ptr,
+                              u64 initrd_addr, u64 initrd_size)
 {
        int node, num_rsv;
        int status;
@@ -101,25 +98,23 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
        if (status)
                goto fdt_set_fail;
 
-       fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+       fdt_val64 = U64_MAX; /* placeholder */
        status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
                             &fdt_val64,  sizeof(fdt_val64));
        if (status)
                goto fdt_set_fail;
 
-       fdt_val32 = cpu_to_fdt32(map_size);
+       fdt_val32 = U32_MAX; /* placeholder */
        status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
                             &fdt_val32,  sizeof(fdt_val32));
        if (status)
                goto fdt_set_fail;
 
-       fdt_val32 = cpu_to_fdt32(desc_size);
        status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
                             &fdt_val32, sizeof(fdt_val32));
        if (status)
                goto fdt_set_fail;
 
-       fdt_val32 = cpu_to_fdt32(desc_ver);
        status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
                             &fdt_val32, sizeof(fdt_val32));
        if (status)
@@ -148,6 +143,43 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
        return EFI_LOAD_ERROR;
 }
 
+static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
+{
+       int node = fdt_path_offset(fdt, "/chosen");
+       u64 fdt_val64;
+       u32 fdt_val32;
+       int err;
+
+       if (node < 0)
+               return EFI_LOAD_ERROR;
+
+       fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
+       err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-start",
+                                 &fdt_val64, sizeof(fdt_val64));
+       if (err)
+               return EFI_LOAD_ERROR;
+
+       fdt_val32 = cpu_to_fdt32(*map->map_size);
+       err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-size",
+                                 &fdt_val32, sizeof(fdt_val32));
+       if (err)
+               return EFI_LOAD_ERROR;
+
+       fdt_val32 = cpu_to_fdt32(*map->desc_size);
+       err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-size",
+                                 &fdt_val32, sizeof(fdt_val32));
+       if (err)
+               return EFI_LOAD_ERROR;
+
+       fdt_val32 = cpu_to_fdt32(*map->desc_ver);
+       err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-ver",
+                                 &fdt_val32, sizeof(fdt_val32));
+       if (err)
+               return EFI_LOAD_ERROR;
+
+       return EFI_SUCCESS;
+}
+
 #ifndef EFI_FDT_ALIGN
 #define EFI_FDT_ALIGN EFI_PAGE_SIZE
 #endif
@@ -243,20 +275,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
                        goto fail;
                }
 
-               /*
-                * Now that we have done our final memory allocation (and free)
-                * we can get the memory map key  needed for
-                * exit_boot_services().
-                */
-               status = efi_get_memory_map(sys_table, &map);
-               if (status != EFI_SUCCESS)
-                       goto fail_free_new_fdt;
-
                status = update_fdt(sys_table,
                                    (void *)fdt_addr, fdt_size,
                                    (void *)*new_fdt_addr, new_fdt_size,
-                                   cmdline_ptr, initrd_addr, initrd_size,
-                                   memory_map, map_size, desc_size, desc_ver);
+                                   cmdline_ptr, initrd_addr, initrd_size);
 
                /* Succeeding the first time is the expected case. */
                if (status == EFI_SUCCESS)
@@ -266,20 +288,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
                        /*
                         * We need to allocate more space for the new
                         * device tree, so free existing buffer that is
-                        * too small.  Also free memory map, as we will need
-                        * to get new one that reflects the free/alloc we do
-                        * on the device tree buffer.
+                        * too small.
                         */
                        efi_free(sys_table, new_fdt_size, *new_fdt_addr);
-                       sys_table->boottime->free_pool(memory_map);
                        new_fdt_size += EFI_PAGE_SIZE;
                } else {
                        pr_efi_err(sys_table, "Unable to construct new device tree.\n");
-                       goto fail_free_mmap;
+                       goto fail_free_new_fdt;
                }
        }
 
-       sys_table->boottime->free_pool(memory_map);
        priv.runtime_map = runtime_map;
        priv.runtime_entry_count = &runtime_entry_count;
        status = efi_exit_boot_services(sys_table, handle, &map, &priv,
@@ -288,6 +306,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
        if (status == EFI_SUCCESS) {
                efi_set_virtual_address_map_t *svam;
 
+               status = update_fdt_memmap((void *)*new_fdt_addr, &map);
+               if (status != EFI_SUCCESS) {
+                       /*
+                        * The kernel won't get far without the memory map, but
+                        * may still be able to print something meaningful so
+                        * return success here.
+                        */
+                       return EFI_SUCCESS;
+               }
+
                /* Install the new virtual address map */
                svam = sys_table->runtime->set_virtual_address_map;
                status = svam(runtime_entry_count * desc_size, desc_size,
@@ -319,9 +347,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
 
        pr_efi_err(sys_table, "Exit boot services failed.\n");
 
-fail_free_mmap:
-       sys_table->boottime->free_pool(memory_map);
-
 fail_free_new_fdt:
        efi_free(sys_table, new_fdt_size, *new_fdt_addr);
 
index f03ddecd232b542ce4c7163506b69da0d29ad2c7..78686443cb378abf616c7cfe595b82d3a51c9cd6 100644 (file)
@@ -9,6 +9,44 @@
 #include <linux/efi.h>
 #include <linux/io.h>
 #include <asm/early_ioremap.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+
+static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
+{
+       return memblock_alloc(size, 0);
+}
+
+static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
+{
+       unsigned int order = get_order(size);
+       struct page *p = alloc_pages(GFP_KERNEL, order);
+
+       if (!p)
+               return 0;
+
+       return PFN_PHYS(page_to_pfn(p));
+}
+
+/**
+ * efi_memmap_alloc - Allocate memory for the EFI memory map
+ * @num_entries: Number of entries in the allocated map.
+ *
+ * Depending on whether mm_init() has already been invoked or not,
+ * either memblock or "normal" page allocation is used.
+ *
+ * Returns the physical address of the allocated memory map on
+ * success, zero on failure.
+ */
+phys_addr_t __init efi_memmap_alloc(unsigned int num_entries)
+{
+       unsigned long size = num_entries * efi.memmap.desc_size;
+
+       if (slab_is_available())
+               return __efi_memmap_alloc_late(size);
+
+       return __efi_memmap_alloc_early(size);
+}
 
 /**
  * __efi_memmap_init - Common code for mapping the EFI memory map
index 1e8fde8cb803d7406dd98d51673b63eb69fdfd23..2292742eac8f5441642469f8fa05e04ca0979afb 100644 (file)
@@ -205,7 +205,7 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
        return 0;
 }
 
-static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
+static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
 {
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
index f4c26c7826cdfc0b5163632e596c0e664586549b..86bf3b84ada56d42758c2b3c57db91351b9f811b 100644 (file)
@@ -1317,12 +1317,12 @@ void gpiochip_remove(struct gpio_chip *chip)
 
        /* FIXME: should the legacy sysfs handling be moved to gpio_device? */
        gpiochip_sysfs_unregister(gdev);
+       gpiochip_free_hogs(chip);
        /* Numb the device, cancelling all outstanding operations */
        gdev->chip = NULL;
        gpiochip_irqchip_remove(chip);
        acpi_gpiochip_remove(chip);
        gpiochip_remove_pin_ranges(chip);
-       gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
        /*
         * We accept no more calls into the driver from this point, so
index 9ada56c16a589d01e43162f656c0a25c8d926284..4c851fde1e82231d04366b1916da170d0b24cb0e 100644 (file)
@@ -840,6 +840,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
                                else if (type == CGS_UCODE_ID_SMU_SK)
                                        strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin");
                                break;
+                       case CHIP_POLARIS12:
+                               strcpy(fw_name, "amdgpu/polaris12_smc.bin");
+                               break;
                        default:
                                DRM_ERROR("SMC firmware not supported\n");
                                return -EINVAL;
index 60bd4afe45c8c550b48e4484bf4d42f279f161c5..fe3bb94fe58df1fed0df7160c47932f358a513e8 100644 (file)
@@ -73,6 +73,7 @@ static const char *amdgpu_asic_name[] = {
        "STONEY",
        "POLARIS10",
        "POLARIS11",
+       "POLARIS12",
        "LAST",
 };
 
@@ -1277,6 +1278,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
        case CHIP_FIJI:
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
        case CHIP_CARRIZO:
        case CHIP_STONEY:
                if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY)
index 8cb937b2bfcc7fac0e3308aaa5cdc70cd53021c2..2534adaebe30f2d11a27fbaa121ff23cf6fce561 100644 (file)
@@ -418,6 +418,13 @@ static const struct pci_device_id pciidlist[] = {
        {0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
        {0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
        {0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
+       /* Polaris12 */
+       {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+       {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+       {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+       {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+       {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+       {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
 
        {0, 0, 0}
 };
index fc592c2b0e166825100c1908691f02ac2f49a642..95a568df8551e589701b9cb2d1be6c04d97bf14a 100644 (file)
@@ -98,6 +98,7 @@ static int amdgpu_pp_early_init(void *handle)
        switch (adev->asic_type) {
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
        case CHIP_TONGA:
        case CHIP_FIJI:
        case CHIP_TOPAZ:
index a81dfaeeb8c0713e61b66046cf35fb8f89f86161..1d564beb0fde67541eab9be4ee76a39eb89197e1 100644 (file)
@@ -65,6 +65,7 @@
 #define FIRMWARE_STONEY                "amdgpu/stoney_uvd.bin"
 #define FIRMWARE_POLARIS10     "amdgpu/polaris10_uvd.bin"
 #define FIRMWARE_POLARIS11     "amdgpu/polaris11_uvd.bin"
+#define FIRMWARE_POLARIS12     "amdgpu/polaris12_uvd.bin"
 
 /**
  * amdgpu_uvd_cs_ctx - Command submission parser context
@@ -98,6 +99,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI);
 MODULE_FIRMWARE(FIRMWARE_STONEY);
 MODULE_FIRMWARE(FIRMWARE_POLARIS10);
 MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
 
 static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
 
@@ -149,6 +151,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
        case CHIP_POLARIS11:
                fw_name = FIRMWARE_POLARIS11;
                break;
+       case CHIP_POLARIS12:
+               fw_name = FIRMWARE_POLARIS12;
+               break;
        default:
                return -EINVAL;
        }
index 69b66b9e7f57e4ffaab3f83d6c17fb3a7161df34..8fec802d3908c05459c1e0ca2737cd19450ce9a4 100644 (file)
@@ -52,6 +52,7 @@
 #define FIRMWARE_STONEY                "amdgpu/stoney_vce.bin"
 #define FIRMWARE_POLARIS10     "amdgpu/polaris10_vce.bin"
 #define FIRMWARE_POLARIS11         "amdgpu/polaris11_vce.bin"
+#define FIRMWARE_POLARIS12         "amdgpu/polaris12_vce.bin"
 
 #ifdef CONFIG_DRM_AMDGPU_CIK
 MODULE_FIRMWARE(FIRMWARE_BONAIRE);
@@ -66,6 +67,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI);
 MODULE_FIRMWARE(FIRMWARE_STONEY);
 MODULE_FIRMWARE(FIRMWARE_POLARIS10);
 MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
 
 static void amdgpu_vce_idle_work_handler(struct work_struct *work);
 
@@ -121,6 +123,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
        case CHIP_POLARIS11:
                fw_name = FIRMWARE_POLARIS11;
                break;
+       case CHIP_POLARIS12:
+               fw_name = FIRMWARE_POLARIS12;
+               break;
 
        default:
                return -EINVAL;
index b3d62b909f4372db1e569308e29a436de873d0c9..2006abbbfb6216d34c3fb3e18573e17f37561f18 100644 (file)
@@ -167,6 +167,7 @@ static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev)
                                                 (const u32)ARRAY_SIZE(stoney_golden_settings_a11));
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                amdgpu_program_register_sequence(adev,
                                                 polaris11_golden_settings_a11,
                                                 (const u32)ARRAY_SIZE(polaris11_golden_settings_a11));
@@ -608,6 +609,7 @@ static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev)
                num_crtc = 6;
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                num_crtc = 5;
                break;
        default:
@@ -1589,6 +1591,7 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev)
                adev->mode_info.audio.num_pins = 8;
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                adev->mode_info.audio.num_pins = 6;
                break;
        default:
@@ -2388,7 +2391,8 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc)
        int pll;
 
        if ((adev->asic_type == CHIP_POLARIS10) ||
-           (adev->asic_type == CHIP_POLARIS11)) {
+           (adev->asic_type == CHIP_POLARIS11) ||
+           (adev->asic_type == CHIP_POLARIS12)) {
                struct amdgpu_encoder *amdgpu_encoder =
                        to_amdgpu_encoder(amdgpu_crtc->encoder);
                struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
@@ -2822,7 +2826,8 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
 
        if ((adev->asic_type == CHIP_POLARIS10) ||
-           (adev->asic_type == CHIP_POLARIS11)) {
+           (adev->asic_type == CHIP_POLARIS11) ||
+           (adev->asic_type == CHIP_POLARIS12)) {
                struct amdgpu_encoder *amdgpu_encoder =
                        to_amdgpu_encoder(amdgpu_crtc->encoder);
                int encoder_mode =
@@ -2992,6 +2997,7 @@ static int dce_v11_0_early_init(void *handle)
                adev->mode_info.num_dig = 6;
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                adev->mode_info.num_hpd = 5;
                adev->mode_info.num_dig = 5;
                break;
@@ -3101,7 +3107,8 @@ static int dce_v11_0_hw_init(void *handle)
        amdgpu_atombios_crtc_powergate_init(adev);
        amdgpu_atombios_encoder_init_dig(adev);
        if ((adev->asic_type == CHIP_POLARIS10) ||
-           (adev->asic_type == CHIP_POLARIS11)) {
+           (adev->asic_type == CHIP_POLARIS11) ||
+           (adev->asic_type == CHIP_POLARIS12)) {
                amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk,
                                                   DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS);
                amdgpu_atombios_crtc_set_dce_clock(adev, 0,
index d0ec00986f3826c32957ab432c677c53c24091c2..373374164bd59edc0970e3f73a77ca31b17652e7 100644 (file)
@@ -139,6 +139,13 @@ MODULE_FIRMWARE("amdgpu/polaris10_mec.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin");
 
+MODULE_FIRMWARE("amdgpu/polaris12_ce.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_me.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin");
+
 static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] =
 {
        {mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0},
@@ -689,6 +696,7 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
                                                 (const u32)ARRAY_SIZE(tonga_golden_common_all));
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                amdgpu_program_register_sequence(adev,
                                                 golden_settings_polaris11_a11,
                                                 (const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -903,6 +911,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        case CHIP_POLARIS10:
                chip_name = "polaris10";
                break;
+       case CHIP_POLARIS12:
+               chip_name = "polaris12";
+               break;
        case CHIP_STONEY:
                chip_name = "stoney";
                break;
@@ -1768,6 +1779,7 @@ static int gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
                gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN;
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                ret = amdgpu_atombios_get_gfx_info(adev);
                if (ret)
                        return ret;
@@ -2682,6 +2694,7 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
 
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
                                PIPE_CONFIG(ADDR_SURF_P4_16x16) |
                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
@@ -3503,6 +3516,7 @@ gfx_v8_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
                *rconf1 |= 0x0;
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
                          SE_XSEL(1) | SE_YSEL(1);
                *rconf1 |= 0x0;
@@ -4021,7 +4035,8 @@ static void gfx_v8_0_init_pg(struct amdgpu_device *adev)
                        cz_enable_cp_power_gating(adev, true);
                else
                        cz_enable_cp_power_gating(adev, false);
-       } else if (adev->asic_type == CHIP_POLARIS11) {
+       } else if ((adev->asic_type == CHIP_POLARIS11) ||
+                  (adev->asic_type == CHIP_POLARIS12)) {
                gfx_v8_0_init_csb(adev);
                gfx_v8_0_init_save_restore_list(adev);
                gfx_v8_0_enable_save_restore_machine(adev);
@@ -4095,7 +4110,8 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
                 RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
        WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
        if (adev->asic_type == CHIP_POLARIS11 ||
-           adev->asic_type == CHIP_POLARIS10) {
+           adev->asic_type == CHIP_POLARIS10 ||
+           adev->asic_type == CHIP_POLARIS12) {
                tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D);
                tmp &= ~0x3;
                WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp);
@@ -4283,6 +4299,7 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev)
                amdgpu_ring_write(ring, 0x0000002A);
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                amdgpu_ring_write(ring, 0x16000012);
                amdgpu_ring_write(ring, 0x00000000);
                break;
@@ -4664,7 +4681,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
                            (adev->asic_type == CHIP_FIJI) ||
                            (adev->asic_type == CHIP_STONEY) ||
                            (adev->asic_type == CHIP_POLARIS11) ||
-                           (adev->asic_type == CHIP_POLARIS10)) {
+                           (adev->asic_type == CHIP_POLARIS10) ||
+                           (adev->asic_type == CHIP_POLARIS12)) {
                                WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
                                       AMDGPU_DOORBELL_KIQ << 2);
                                WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
@@ -4700,7 +4718,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
                mqd->cp_hqd_persistent_state = tmp;
                if (adev->asic_type == CHIP_STONEY ||
                        adev->asic_type == CHIP_POLARIS11 ||
-                       adev->asic_type == CHIP_POLARIS10) {
+                       adev->asic_type == CHIP_POLARIS10 ||
+                       adev->asic_type == CHIP_POLARIS12) {
                        tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL);
                        tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1);
                        WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp);
@@ -5279,7 +5298,8 @@ static int gfx_v8_0_late_init(void *handle)
 static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev,
                                                       bool enable)
 {
-       if (adev->asic_type == CHIP_POLARIS11)
+       if ((adev->asic_type == CHIP_POLARIS11) ||
+           (adev->asic_type == CHIP_POLARIS12))
                /* Send msg to SMU via Powerplay */
                amdgpu_set_powergating_state(adev,
                                             AMD_IP_BLOCK_TYPE_SMC,
@@ -5353,6 +5373,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
                        gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false);
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable)
                        gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true);
                else
index 0daac3a5be79572e65a2fff812453c2bd541940c..476bc9f1954b9daee41d154a94b17ee0896e59ed 100644 (file)
@@ -46,6 +46,7 @@ static int gmc_v8_0_wait_for_idle(void *handle);
 MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
 MODULE_FIRMWARE("amdgpu/polaris11_mc.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_mc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mc.bin");
 
 static const u32 golden_settings_tonga_a11[] =
 {
@@ -130,6 +131,7 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
                                                 (const u32)ARRAY_SIZE(golden_settings_tonga_a11));
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                amdgpu_program_register_sequence(adev,
                                                 golden_settings_polaris11_a11,
                                                 (const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -225,6 +227,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev)
        case CHIP_POLARIS10:
                chip_name = "polaris10";
                break;
+       case CHIP_POLARIS12:
+               chip_name = "polaris12";
+               break;
        case CHIP_FIJI:
        case CHIP_CARRIZO:
        case CHIP_STONEY:
index 1170a64a3184f6788c58cf1f6038bacaf45c4e62..034ace79ed492951d1ed06b9dc1543419b1948bf 100644 (file)
@@ -60,6 +60,8 @@ MODULE_FIRMWARE("amdgpu/polaris10_sdma.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin");
 MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin");
 MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin");
 
 
 static const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
@@ -206,6 +208,7 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev)
                                                 (const u32)ARRAY_SIZE(golden_settings_tonga_a11));
                break;
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                amdgpu_program_register_sequence(adev,
                                                 golden_settings_polaris11_a11,
                                                 (const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -278,6 +281,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
        case CHIP_POLARIS10:
                chip_name = "polaris10";
                break;
+       case CHIP_POLARIS12:
+               chip_name = "polaris12";
+               break;
        case CHIP_CARRIZO:
                chip_name = "carrizo";
                break;
index 6c65a1a2de798b5630d6b356065a32fe578608c5..10bedfac27b8118dae6735a65ecebcbdd4109d2b 100644 (file)
@@ -56,7 +56,6 @@
 #define BIOS_SCRATCH_4                                    0x5cd
 
 MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
 MODULE_FIRMWARE("radeon/pitcairn_smc.bin");
 MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin");
 MODULE_FIRMWARE("radeon/verde_smc.bin");
@@ -3488,19 +3487,6 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
                    (adev->pdev->device == 0x6817) ||
                    (adev->pdev->device == 0x6806))
                        max_mclk = 120000;
-       } else if (adev->asic_type == CHIP_VERDE) {
-               if ((adev->pdev->revision == 0x81) ||
-                   (adev->pdev->revision == 0x83) ||
-                   (adev->pdev->revision == 0x87) ||
-                   (adev->pdev->device == 0x6820) ||
-                   (adev->pdev->device == 0x6821) ||
-                   (adev->pdev->device == 0x6822) ||
-                   (adev->pdev->device == 0x6823) ||
-                   (adev->pdev->device == 0x682A) ||
-                   (adev->pdev->device == 0x682B)) {
-                       max_sclk = 75000;
-                       max_mclk = 80000;
-               }
        } else if (adev->asic_type == CHIP_OLAND) {
                if ((adev->pdev->revision == 0xC7) ||
                    (adev->pdev->revision == 0x80) ||
@@ -7687,49 +7673,49 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev)
                chip_name = "tahiti";
                break;
        case CHIP_PITCAIRN:
-               if ((adev->pdev->revision == 0x81) ||
-                   (adev->pdev->device == 0x6810) ||
-                   (adev->pdev->device == 0x6811) ||
-                   (adev->pdev->device == 0x6816) ||
-                   (adev->pdev->device == 0x6817) ||
-                   (adev->pdev->device == 0x6806))
+               if ((adev->pdev->revision == 0x81) &&
+                   ((adev->pdev->device == 0x6810) ||
+                   (adev->pdev->device == 0x6811)))
                        chip_name = "pitcairn_k";
                else
                        chip_name = "pitcairn";
                break;
        case CHIP_VERDE:
-               if ((adev->pdev->revision == 0x81) ||
-                   (adev->pdev->revision == 0x83) ||
-                   (adev->pdev->revision == 0x87) ||
-                   (adev->pdev->device == 0x6820) ||
-                   (adev->pdev->device == 0x6821) ||
-                   (adev->pdev->device == 0x6822) ||
-                   (adev->pdev->device == 0x6823) ||
-                   (adev->pdev->device == 0x682A) ||
-                   (adev->pdev->device == 0x682B))
+               if (((adev->pdev->device == 0x6820) &&
+                       ((adev->pdev->revision == 0x81) ||
+                       (adev->pdev->revision == 0x83))) ||
+                   ((adev->pdev->device == 0x6821) &&
+                       ((adev->pdev->revision == 0x83) ||
+                       (adev->pdev->revision == 0x87))) ||
+                   ((adev->pdev->revision == 0x87) &&
+                       ((adev->pdev->device == 0x6823) ||
+                       (adev->pdev->device == 0x682b))))
                        chip_name = "verde_k";
                else
                        chip_name = "verde";
                break;
        case CHIP_OLAND:
-               if ((adev->pdev->revision == 0xC7) ||
-                   (adev->pdev->revision == 0x80) ||
-                   (adev->pdev->revision == 0x81) ||
-                   (adev->pdev->revision == 0x83) ||
-                   (adev->pdev->revision == 0x87) ||
-                   (adev->pdev->device == 0x6604) ||
-                   (adev->pdev->device == 0x6605))
+               if (((adev->pdev->revision == 0x81) &&
+                       ((adev->pdev->device == 0x6600) ||
+                       (adev->pdev->device == 0x6604) ||
+                       (adev->pdev->device == 0x6605) ||
+                       (adev->pdev->device == 0x6610))) ||
+                   ((adev->pdev->revision == 0x83) &&
+                       (adev->pdev->device == 0x6610)))
                        chip_name = "oland_k";
                else
                        chip_name = "oland";
                break;
        case CHIP_HAINAN:
-               if ((adev->pdev->revision == 0x81) ||
-                   (adev->pdev->revision == 0x83) ||
-                   (adev->pdev->revision == 0xC3) ||
-                   (adev->pdev->device == 0x6664) ||
-                   (adev->pdev->device == 0x6665) ||
-                   (adev->pdev->device == 0x6667))
+               if (((adev->pdev->revision == 0x81) &&
+                       (adev->pdev->device == 0x6660)) ||
+                   ((adev->pdev->revision == 0x83) &&
+                       ((adev->pdev->device == 0x6660) ||
+                       (adev->pdev->device == 0x6663) ||
+                       (adev->pdev->device == 0x6665) ||
+                       (adev->pdev->device == 0x6667))) ||
+                   ((adev->pdev->revision == 0xc3) &&
+                       (adev->pdev->device == 0x6665)))
                        chip_name = "hainan_k";
                else
                        chip_name = "hainan";
index a79e283590fbe7fc9b627a097ccec81b99d1a66c..6de6becce74567d962eb498dcd33cbd1aedc62c6 100644 (file)
@@ -791,15 +791,10 @@ static int uvd_v5_0_set_clockgating_state(void *handle,
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
-       static int curstate = -1;
 
        if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
                return 0;
 
-       if (curstate == state)
-               return 0;
-
-       curstate = state;
        if (enable) {
                /* wait for STATUS to clear */
                if (uvd_v5_0_wait_for_idle(handle))
index 6b3293a1c7b8b92d9d47d780de7c883a0beac195..5fb0b7f5c065121218ea4befe1a9da8def2e3035 100644 (file)
@@ -320,11 +320,12 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
 {
        u32 tmp;
 
-       /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
+       /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */
        if ((adev->asic_type == CHIP_FIJI) ||
            (adev->asic_type == CHIP_STONEY) ||
            (adev->asic_type == CHIP_POLARIS10) ||
-           (adev->asic_type == CHIP_POLARIS11))
+           (adev->asic_type == CHIP_POLARIS11) ||
+           (adev->asic_type == CHIP_POLARIS12))
                return AMDGPU_VCE_HARVEST_VCE1;
 
        /* Tonga and CZ are dual or single pipe */
index bf088d6d9bf1f96430d7afda1ec3fbeae6e82768..c2ac54f1134179457db3823eb64161817ee8f5b3 100644 (file)
@@ -88,6 +88,7 @@ MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
 MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
 MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_smc.bin");
 
 /*
  * Indirect registers accessor
@@ -312,6 +313,7 @@ static void vi_init_golden_registers(struct amdgpu_device *adev)
                break;
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
        default:
                break;
        }
@@ -671,6 +673,7 @@ static int vi_read_register(struct amdgpu_device *adev, u32 se_num,
        case CHIP_TONGA:
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
        case CHIP_CARRIZO:
        case CHIP_STONEY:
                asic_register_table = cz_allowed_read_registers;
@@ -994,6 +997,11 @@ static int vi_common_early_init(void *handle)
                adev->pg_flags = 0;
                adev->external_rev_id = adev->rev_id + 0x50;
                break;
+       case CHIP_POLARIS12:
+               adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
+               adev->pg_flags = 0;
+               adev->external_rev_id = adev->rev_id + 0x64;
+               break;
        case CHIP_CARRIZO:
                adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
                        AMD_CG_SUPPORT_GFX_MGCG |
@@ -1346,6 +1354,7 @@ static int vi_common_set_clockgating_state(void *handle,
        case CHIP_TONGA:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                vi_common_set_clockgating_state_by_smu(adev, state);
        default:
                break;
@@ -1429,6 +1438,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                break;
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
                amdgpu_ip_block_add(adev, &vi_common_ip_block);
                amdgpu_ip_block_add(adev, &gmc_v8_1_ip_block);
                amdgpu_ip_block_add(adev, &tonga_ih_ip_block);
index c02469ada9f131f417e2a4fdb1d0c6b1fac4eafa..85f358764bbc8f2475e0bbf36df5013312354cab 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __AMD_SHARED_H__
 #define __AMD_SHARED_H__
 
-#define AMD_MAX_USEC_TIMEOUT           100000  /* 100 ms */
+#define AMD_MAX_USEC_TIMEOUT           200000  /* 200 ms */
 
 /*
  * Supported ASIC types
@@ -46,6 +46,7 @@ enum amd_asic_type {
        CHIP_STONEY,
        CHIP_POLARIS10,
        CHIP_POLARIS11,
+       CHIP_POLARIS12,
        CHIP_LAST,
 };
 
index dc6700aee18f624266a47d773abfb20bea573e03..b03606405a53399ea1a6755fecc637fa9bc09b23 100644 (file)
@@ -95,6 +95,7 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
                        break;
                case CHIP_POLARIS11:
                case CHIP_POLARIS10:
+               case CHIP_POLARIS12:
                        polaris_set_asic_special_caps(hwmgr);
                        hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK);
                        break;
@@ -745,7 +746,7 @@ int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr)
        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
                                PHM_PlatformCaps_TablelessHardwareInterface);
 
-       if (hwmgr->chip_id == CHIP_POLARIS11)
+       if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12))
                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
                                        PHM_PlatformCaps_SPLLShutdownSupport);
        return 0;
index 26477f0f09dcc7045db5626abb7a9da8b4a2b3cc..6cd1287a7a8fda1cfe38482cd47899223496b2fd 100644 (file)
@@ -521,7 +521,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
                                PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
                                result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10);
                                PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
-                       } else if (hwmgr->chip_id == CHIP_POLARIS11) {
+                       } else if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) {
                                result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11);
                                PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
                                result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11);
index e5812aa456f3b1440e525f0592d299672db14759..6e618aa20719d27f56b05db5ed2a76b7b7829c97 100644 (file)
@@ -65,6 +65,7 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
                        break;
                case CHIP_POLARIS11:
                case CHIP_POLARIS10:
+               case CHIP_POLARIS12:
                        polaris10_smum_init(smumgr);
                        break;
                default:
index 583f47f27b36de20a7ec1e273ce02559aa3fdae0..34f757bcabae8d88382f18392467e67f4e0f6100 100644 (file)
@@ -1259,8 +1259,10 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        if (!nonblock) {
                ret = drm_atomic_helper_wait_for_fences(dev, state, true);
-               if (ret)
+               if (ret) {
+                       drm_atomic_helper_cleanup_planes(dev, state);
                        return ret;
+               }
        }
 
        /*
index 4942ca090b46fdfa1cf4b6193f3d66095804e02e..7890e30eb584570d5d87d857131db4065a8b3849 100644 (file)
@@ -51,6 +51,9 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
        struct drm_crtc_state *crtc_state;
        struct drm_rect clip = { 0, };
 
+       if (!state->crtc)
+               return 0;
+
        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
        if (IS_ERR(crtc_state))
                return PTR_ERR(crtc_state);
index d836b2274531f83fcd49ea86d649ca49fb405489..f7c87017222048eff2bd17be8eb4f6c83f52b4a7 100644 (file)
  * - TV Panel encoding via ENCT
  */
 
+/* HHI Registers */
+#define HHI_VDAC_CNTL0         0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1         0x2F8 /* 0xbe offset in data sheet */
+#define HHI_HDMI_PHY_CNTL0     0x3a0 /* 0xe8 offset in data sheet */
+
 struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
        .mode_tag = MESON_VENC_MODE_CVBS_PAL,
        .hso_begin = 3,
@@ -242,6 +247,20 @@ void meson_venc_disable_vsync(struct meson_drm *priv)
 
 void meson_venc_init(struct meson_drm *priv)
 {
+       /* Disable CVBS VDAC */
+       regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
+       regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
+
+       /* Power Down Dacs */
+       writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
+
+       /* Disable HDMI PHY */
+       regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
+
+       /* Disable HDMI */
+       writel_bits_relaxed(0x3, 0,
+                           priv->io_base + _REG(VPU_HDMI_SETTING));
+
        /* Disable all encoders */
        writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
        writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
index c809c085fd78abd61f15f3c9d2a19f14ff173d00..a2bcc70a03efaaac6ee32058f747e57161222b23 100644 (file)
@@ -167,7 +167,7 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder)
 
        /* Disable CVBS VDAC */
        regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
-       regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
+       regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
 }
 
 static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder)
index a18126150e1136ea380dcdddc89aabe293d7fcbb..14ff87686a36ffb2580353bde1f0126964c2f8dc 100644 (file)
@@ -213,7 +213,14 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 void adreno_flush(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
-       uint32_t wptr = get_wptr(gpu->rb);
+       uint32_t wptr;
+
+       /*
+        * Mask wptr value that we calculate to fit in the HW range. This is
+        * to account for the possibility that the last command fit exactly into
+        * the ringbuffer and rb->next hasn't wrapped to zero yet
+        */
+       wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1);
 
        /* ensure writes to ringbuffer have hit system memory: */
        mb();
index 166e84e4f0d48f80eacb992c3ccc8964af89b28d..489676568a10d15ac959093e6a09ee3f133abe45 100644 (file)
@@ -106,7 +106,8 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                        pagefault_disable();
                }
 
-               if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+               if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
+                       !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
                        DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
                        ret = -EINVAL;
                        goto out_unlock;
@@ -290,7 +291,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
 {
        uint32_t i, last_offset = 0;
        uint32_t *ptr;
-       int ret;
+       int ret = 0;
 
        if (offset % 4) {
                DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
@@ -318,12 +319,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
 
                ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
                if (ret)
-                       return -EFAULT;
+                       goto out;
 
                if (submit_reloc.submit_offset % 4) {
                        DRM_ERROR("non-aligned reloc offset: %u\n",
                                        submit_reloc.submit_offset);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
 
                /* offset in dwords: */
@@ -332,12 +334,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
                if ((off >= (obj->base.size / 4)) ||
                                (off < last_offset)) {
                        DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
 
                ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid);
                if (ret)
-                       return ret;
+                       goto out;
 
                if (valid)
                        continue;
@@ -354,9 +357,10 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
                last_offset = off;
        }
 
+out:
        msm_gem_put_vaddr_locked(&obj->base);
 
-       return 0;
+       return ret;
 }
 
 static void submit_cleanup(struct msm_gem_submit *submit)
index f326cf6a32e64473461e0b7859101f1a404c0318..67b34e069abf383d4c533ab7d348fd5d576ad525 100644 (file)
@@ -23,7 +23,8 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size)
        struct msm_ringbuffer *ring;
        int ret;
 
-       size = ALIGN(size, 4);   /* size should be dword aligned */
+       if (WARN_ON(!is_power_of_2(size)))
+               return ERR_PTR(-EINVAL);
 
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
        if (!ring) {
index ad4d7b8b832271a8e28a1b59dc496fa19049ed34..e8a38d29685547a69fb1d657e833cd9cf5637cff 100644 (file)
@@ -50,7 +50,6 @@ MODULE_FIRMWARE("radeon/tahiti_ce.bin");
 MODULE_FIRMWARE("radeon/tahiti_mc.bin");
 MODULE_FIRMWARE("radeon/tahiti_rlc.bin");
 MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
 
 MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
@@ -1657,9 +1656,6 @@ static int si_init_microcode(struct radeon_device *rdev)
        switch (rdev->family) {
        case CHIP_TAHITI:
                chip_name = "TAHITI";
-               /* XXX: figure out which Tahitis need the new ucode */
-               if (0)
-                       new_smc = true;
                new_chip_name = "tahiti";
                pfp_req_size = SI_PFP_UCODE_SIZE * 4;
                me_req_size = SI_PM4_UCODE_SIZE * 4;
@@ -1671,12 +1667,9 @@ static int si_init_microcode(struct radeon_device *rdev)
                break;
        case CHIP_PITCAIRN:
                chip_name = "PITCAIRN";
-               if ((rdev->pdev->revision == 0x81) ||
-                   (rdev->pdev->device == 0x6810) ||
-                   (rdev->pdev->device == 0x6811) ||
-                   (rdev->pdev->device == 0x6816) ||
-                   (rdev->pdev->device == 0x6817) ||
-                   (rdev->pdev->device == 0x6806))
+               if ((rdev->pdev->revision == 0x81) &&
+                   ((rdev->pdev->device == 0x6810) ||
+                    (rdev->pdev->device == 0x6811)))
                        new_smc = true;
                new_chip_name = "pitcairn";
                pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1689,15 +1682,15 @@ static int si_init_microcode(struct radeon_device *rdev)
                break;
        case CHIP_VERDE:
                chip_name = "VERDE";
-               if ((rdev->pdev->revision == 0x81) ||
-                   (rdev->pdev->revision == 0x83) ||
-                   (rdev->pdev->revision == 0x87) ||
-                   (rdev->pdev->device == 0x6820) ||
-                   (rdev->pdev->device == 0x6821) ||
-                   (rdev->pdev->device == 0x6822) ||
-                   (rdev->pdev->device == 0x6823) ||
-                   (rdev->pdev->device == 0x682A) ||
-                   (rdev->pdev->device == 0x682B))
+               if (((rdev->pdev->device == 0x6820) &&
+                    ((rdev->pdev->revision == 0x81) ||
+                     (rdev->pdev->revision == 0x83))) ||
+                   ((rdev->pdev->device == 0x6821) &&
+                    ((rdev->pdev->revision == 0x83) ||
+                     (rdev->pdev->revision == 0x87))) ||
+                   ((rdev->pdev->revision == 0x87) &&
+                    ((rdev->pdev->device == 0x6823) ||
+                     (rdev->pdev->device == 0x682b))))
                        new_smc = true;
                new_chip_name = "verde";
                pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1710,13 +1703,13 @@ static int si_init_microcode(struct radeon_device *rdev)
                break;
        case CHIP_OLAND:
                chip_name = "OLAND";
-               if ((rdev->pdev->revision == 0xC7) ||
-                   (rdev->pdev->revision == 0x80) ||
-                   (rdev->pdev->revision == 0x81) ||
-                   (rdev->pdev->revision == 0x83) ||
-                   (rdev->pdev->revision == 0x87) ||
-                   (rdev->pdev->device == 0x6604) ||
-                   (rdev->pdev->device == 0x6605))
+               if (((rdev->pdev->revision == 0x81) &&
+                    ((rdev->pdev->device == 0x6600) ||
+                     (rdev->pdev->device == 0x6604) ||
+                     (rdev->pdev->device == 0x6605) ||
+                     (rdev->pdev->device == 0x6610))) ||
+                   ((rdev->pdev->revision == 0x83) &&
+                    (rdev->pdev->device == 0x6610)))
                        new_smc = true;
                new_chip_name = "oland";
                pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1728,12 +1721,15 @@ static int si_init_microcode(struct radeon_device *rdev)
                break;
        case CHIP_HAINAN:
                chip_name = "HAINAN";
-               if ((rdev->pdev->revision == 0x81) ||
-                   (rdev->pdev->revision == 0x83) ||
-                   (rdev->pdev->revision == 0xC3) ||
-                   (rdev->pdev->device == 0x6664) ||
-                   (rdev->pdev->device == 0x6665) ||
-                   (rdev->pdev->device == 0x6667))
+               if (((rdev->pdev->revision == 0x81) &&
+                    (rdev->pdev->device == 0x6660)) ||
+                   ((rdev->pdev->revision == 0x83) &&
+                    ((rdev->pdev->device == 0x6660) ||
+                     (rdev->pdev->device == 0x6663) ||
+                     (rdev->pdev->device == 0x6665) ||
+                     (rdev->pdev->device == 0x6667))) ||
+                   ((rdev->pdev->revision == 0xc3) &&
+                    (rdev->pdev->device == 0x6665)))
                        new_smc = true;
                new_chip_name = "hainan";
                pfp_req_size = SI_PFP_UCODE_SIZE * 4;
index 8b5e697f2549ee3f81dff2cb8cc8a05e7543c856..13ba73fd9b68849bd34d27207eb282eb6ff62793 100644 (file)
@@ -3008,19 +3008,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                    (rdev->pdev->device == 0x6817) ||
                    (rdev->pdev->device == 0x6806))
                        max_mclk = 120000;
-       } else if (rdev->family == CHIP_VERDE) {
-               if ((rdev->pdev->revision == 0x81) ||
-                   (rdev->pdev->revision == 0x83) ||
-                   (rdev->pdev->revision == 0x87) ||
-                   (rdev->pdev->device == 0x6820) ||
-                   (rdev->pdev->device == 0x6821) ||
-                   (rdev->pdev->device == 0x6822) ||
-                   (rdev->pdev->device == 0x6823) ||
-                   (rdev->pdev->device == 0x682A) ||
-                   (rdev->pdev->device == 0x682B)) {
-                       max_sclk = 75000;
-                       max_mclk = 80000;
-               }
        } else if (rdev->family == CHIP_OLAND) {
                if ((rdev->pdev->revision == 0xC7) ||
                    (rdev->pdev->revision == 0x80) ||
index 725dffad5640cddf43d6aea4616cd90a035c40bc..6dfdb145f3bbb694c2750e30807640999404e91e 100644 (file)
@@ -856,7 +856,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct tilcdc_drm_private *priv = dev->dev_private;
-       uint32_t stat;
+       uint32_t stat, reg;
 
        stat = tilcdc_read_irqstatus(dev);
        tilcdc_clear_irqstatus(dev, stat);
@@ -921,17 +921,26 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
                dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
                                    __func__, stat);
                tilcdc_crtc->frame_intact = false;
-               if (tilcdc_crtc->sync_lost_count++ >
-                   SYNC_LOST_COUNT_LIMIT) {
-                       dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
-                       queue_work(system_wq, &tilcdc_crtc->recover_work);
-                       if (priv->rev == 1)
+               if (priv->rev == 1) {
+                       reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG);
+                       if (reg & LCDC_RASTER_ENABLE) {
                                tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
-                                            LCDC_V1_SYNC_LOST_INT_ENA);
-                       else
+                                            LCDC_RASTER_ENABLE);
+                               tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
+                                          LCDC_RASTER_ENABLE);
+                       }
+               } else {
+                       if (tilcdc_crtc->sync_lost_count++ >
+                           SYNC_LOST_COUNT_LIMIT) {
+                               dev_err(dev->dev,
+                                       "%s(0x%08x): Sync lost flood detected, recovering",
+                                       __func__, stat);
+                               queue_work(system_wq,
+                                          &tilcdc_crtc->recover_work);
                                tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
                                             LCDC_SYNC_LOST);
-                       tilcdc_crtc->sync_lost_count = 0;
+                               tilcdc_crtc->sync_lost_count = 0;
+                       }
                }
        }
 
index cff060b56da9d6cb8cb138657cf4efca7debef61..ea36b557d5eea87b27171937fe9bc05f680b15a8 100644 (file)
@@ -2496,6 +2496,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
 #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
index 1b764d1745f3daa693a17ee706c302ff31ae0f0e..1689568b597d4e5bb8824ccbe679f627525bf2a4 100644 (file)
@@ -39,6 +39,9 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
                return rdesc;
 
+       if (*rsize < 4)
+               return rdesc;
+
        for (i = 0; i < *rsize - 4; i++)
                if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
                        rdesc[i] = 0x19;
index 54bd22dc14110c308744f28f01a7ab4cff79ff95..f46f2c5117fae76a1c87105363e5c8db4c8673a3 100644 (file)
 #define USB_VENDOR_ID_PETALYNX         0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
 
+#define USB_VENDOR_ID_PETZL            0x2122
+#define USB_DEVICE_ID_PETZL_HEADLAMP   0x1234
+
 #define USB_VENDOR_ID_PHILIPS          0x0471
 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
 
index 78fb32a7b103446136000c8ee9ac64cf7fba7054..ea3c3546cef7f81f0f1c82b996c3ed5ab9fb26ed 100644 (file)
@@ -426,6 +426,15 @@ static int i2c_hid_hwreset(struct i2c_client *client)
        if (ret)
                goto out_unlock;
 
+       /*
+        * The HID over I2C specification states that if a DEVICE needs time
+        * after the PWR_ON request, it should utilise CLOCK stretching.
+        * However, it has been observered that the Windows driver provides a
+        * 1ms sleep between the PWR_ON and RESET requests and that some devices
+        * rely on this.
+        */
+       usleep_range(1000, 5000);
+
        i2c_hid_dbg(ihid, "resetting...\n");
 
        ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
index 5fb4c6d9209b753a12dcddb4c441ff00c3e8746a..be34547cdb681e9f2d34f05404067e1c4fdf5643 100644 (file)
@@ -157,6 +157,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        }
 
        init_completion(&open_info->waitevent);
+       open_info->waiting_channel = newchannel;
 
        open_msg = (struct vmbus_channel_open_channel *)open_info->msg;
        open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL;
@@ -181,7 +182,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
        ret = vmbus_post_msg(open_msg,
-                              sizeof(struct vmbus_channel_open_channel));
+                            sizeof(struct vmbus_channel_open_channel), true);
 
        if (ret != 0) {
                err = ret;
@@ -194,6 +195,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        list_del(&open_info->msglistentry);
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
+       if (newchannel->rescind) {
+               err = -ENODEV;
+               goto error_free_gpadl;
+       }
+
        if (open_info->response.open_result.status) {
                err = -EAGAIN;
                goto error_free_gpadl;
@@ -233,7 +239,7 @@ int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id,
        conn_msg.guest_endpoint_id = *shv_guest_servie_id;
        conn_msg.host_service_id = *shv_host_servie_id;
 
-       return vmbus_post_msg(&conn_msg, sizeof(conn_msg));
+       return vmbus_post_msg(&conn_msg, sizeof(conn_msg), true);
 }
 EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request);
 
@@ -405,6 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
                return ret;
 
        init_completion(&msginfo->waitevent);
+       msginfo->waiting_channel = channel;
 
        gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
        gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
@@ -419,7 +426,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
        ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
-                              sizeof(*msginfo));
+                            sizeof(*msginfo), true);
        if (ret != 0)
                goto cleanup;
 
@@ -433,14 +440,19 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
                gpadl_body->gpadl = next_gpadl_handle;
 
                ret = vmbus_post_msg(gpadl_body,
-                                    submsginfo->msgsize -
-                                    sizeof(*submsginfo));
+                                    submsginfo->msgsize - sizeof(*submsginfo),
+                                    true);
                if (ret != 0)
                        goto cleanup;
 
        }
        wait_for_completion(&msginfo->waitevent);
 
+       if (channel->rescind) {
+               ret = -ENODEV;
+               goto cleanup;
+       }
+
        /* At this point, we received the gpadl created msg */
        *gpadl_handle = gpadlmsg->gpadl;
 
@@ -474,6 +486,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
                return -ENOMEM;
 
        init_completion(&info->waitevent);
+       info->waiting_channel = channel;
 
        msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
 
@@ -485,14 +498,19 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
        list_add_tail(&info->msglistentry,
                      &vmbus_connection.chn_msg_list);
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
-       ret = vmbus_post_msg(msg,
-                              sizeof(struct vmbus_channel_gpadl_teardown));
+       ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown),
+                            true);
 
        if (ret)
                goto post_msg_err;
 
        wait_for_completion(&info->waitevent);
 
+       if (channel->rescind) {
+               ret = -ENODEV;
+               goto post_msg_err;
+       }
+
 post_msg_err:
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&info->msglistentry);
@@ -557,7 +575,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
        msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
        msg->child_relid = channel->offermsg.child_relid;
 
-       ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
+       ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel),
+                            true);
 
        if (ret) {
                pr_err("Close failed: close post msg return is %d\n", ret);
index 26b419203f16a6eee9f34f22659a3d09230c2aa0..49d77be90ca4562dba160a257ab1b05585f99269 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/hyperv.h>
+#include <asm/mshyperv.h>
 
 #include "hyperv_vmbus.h"
 
@@ -147,6 +148,29 @@ static const struct {
        { HV_RDV_GUID   },
 };
 
+/*
+ * The rescinded channel may be blocked waiting for a response from the host;
+ * take care of that.
+ */
+static void vmbus_rescind_cleanup(struct vmbus_channel *channel)
+{
+       struct vmbus_channel_msginfo *msginfo;
+       unsigned long flags;
+
+
+       spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+       list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+                               msglistentry) {
+
+               if (msginfo->waiting_channel == channel) {
+                       complete(&msginfo->waitevent);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
 static bool is_unsupported_vmbus_devs(const uuid_le *guid)
 {
        int i;
@@ -321,7 +345,8 @@ static void vmbus_release_relid(u32 relid)
        memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
        msg.child_relid = relid;
        msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
-       vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+       vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released),
+                      true);
 }
 
 void hv_event_tasklet_disable(struct vmbus_channel *channel)
@@ -728,7 +753,8 @@ void vmbus_initiate_unload(bool crash)
        init_completion(&vmbus_connection.unload_event);
        memset(&hdr, 0, sizeof(struct vmbus_channel_message_header));
        hdr.msgtype = CHANNELMSG_UNLOAD;
-       vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
+       vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header),
+                      !crash);
 
        /*
         * vmbus_initiate_unload() is also called on crash and the crash can be
@@ -823,6 +849,8 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
        channel->rescind = true;
        spin_unlock_irqrestore(&channel->lock, flags);
 
+       vmbus_rescind_cleanup(channel);
+
        if (channel->device_obj) {
                if (channel->chn_rescind_callback) {
                        channel->chn_rescind_callback(channel);
@@ -1116,8 +1144,8 @@ int vmbus_request_offers(void)
        msg->msgtype = CHANNELMSG_REQUESTOFFERS;
 
 
-       ret = vmbus_post_msg(msg,
-                              sizeof(struct vmbus_channel_message_header));
+       ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_message_header),
+                            true);
        if (ret != 0) {
                pr_err("Unable to request offers - %d\n", ret);
 
index 6ce8b874e833dbd7f0b630f97d9bd4e6790e6831..307a5a8937f68a579d96d1ab7a7c9cba06c32cb4 100644 (file)
@@ -111,7 +111,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
        ret = vmbus_post_msg(msg,
-                              sizeof(struct vmbus_channel_initiate_contact));
+                            sizeof(struct vmbus_channel_initiate_contact),
+                            true);
        if (ret != 0) {
                spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
                list_del(&msginfo->msglistentry);
@@ -220,11 +221,8 @@ int vmbus_connect(void)
                goto cleanup;
 
        vmbus_proto_version = version;
-       pr_info("Hyper-V Host Build:%d-%d.%d-%d-%d.%d; Vmbus version:%d.%d\n",
-                   host_info_eax, host_info_ebx >> 16,
-                   host_info_ebx & 0xFFFF, host_info_ecx,
-                   host_info_edx >> 24, host_info_edx & 0xFFFFFF,
-                   version >> 16, version & 0xFFFF);
+       pr_info("Vmbus version:%d.%d\n",
+               version >> 16, version & 0xFFFF);
 
        kfree(msginfo);
        return 0;
@@ -435,7 +433,7 @@ void vmbus_on_event(unsigned long data)
 /*
  * vmbus_post_msg - Send a msg on the vmbus's message connection
  */
-int vmbus_post_msg(void *buffer, size_t buflen)
+int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
 {
        union hv_connection_id conn_id;
        int ret = 0;
@@ -450,7 +448,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
         * insufficient resources. Retry the operation a couple of
         * times before giving up.
         */
-       while (retries < 20) {
+       while (retries < 100) {
                ret = hv_post_message(conn_id, 1, buffer, buflen);
 
                switch (ret) {
@@ -473,8 +471,14 @@ int vmbus_post_msg(void *buffer, size_t buflen)
                }
 
                retries++;
-               udelay(usec);
-               if (usec < 2048)
+               if (can_sleep && usec > 1000)
+                       msleep(usec / 1000);
+               else if (usec < MAX_UDELAY_MS * 1000)
+                       udelay(usec);
+               else
+                       mdelay(usec / 1000);
+
+               if (usec < 256000)
                        usec *= 2;
        }
        return ret;
index b44b32f21e61db00a2db56db81c4e4a1a04053db..60594fa3250d5fcf3e5e60d6ffd91b9c4c47172a 100644 (file)
 /* The one and only */
 struct hv_context hv_context = {
        .synic_initialized      = false,
-       .hypercall_page         = NULL,
 };
 
 #define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
 #define HV_MAX_MAX_DELTA_TICKS 0xffffffff
 #define HV_MIN_DELTA_TICKS 1
 
-/*
- * query_hypervisor_info - Get version info of the windows hypervisor
- */
-unsigned int host_info_eax;
-unsigned int host_info_ebx;
-unsigned int host_info_ecx;
-unsigned int host_info_edx;
-
-static int query_hypervisor_info(void)
-{
-       unsigned int eax;
-       unsigned int ebx;
-       unsigned int ecx;
-       unsigned int edx;
-       unsigned int max_leaf;
-       unsigned int op;
-
-       /*
-       * Its assumed that this is called after confirming that Viridian
-       * is present. Query id and revision.
-       */
-       eax = 0;
-       ebx = 0;
-       ecx = 0;
-       edx = 0;
-       op = HVCPUID_VENDOR_MAXFUNCTION;
-       cpuid(op, &eax, &ebx, &ecx, &edx);
-
-       max_leaf = eax;
-
-       if (max_leaf >= HVCPUID_VERSION) {
-               eax = 0;
-               ebx = 0;
-               ecx = 0;
-               edx = 0;
-               op = HVCPUID_VERSION;
-               cpuid(op, &eax, &ebx, &ecx, &edx);
-               host_info_eax = eax;
-               host_info_ebx = ebx;
-               host_info_ecx = ecx;
-               host_info_edx = edx;
-       }
-       return max_leaf;
-}
-
-/*
- * hv_do_hypercall- Invoke the specified hypercall
- */
-u64 hv_do_hypercall(u64 control, void *input, void *output)
-{
-       u64 input_address = (input) ? virt_to_phys(input) : 0;
-       u64 output_address = (output) ? virt_to_phys(output) : 0;
-       void *hypercall_page = hv_context.hypercall_page;
-#ifdef CONFIG_X86_64
-       u64 hv_status = 0;
-
-       if (!hypercall_page)
-               return (u64)ULLONG_MAX;
-
-       __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
-       __asm__ __volatile__("call *%3" : "=a" (hv_status) :
-                            "c" (control), "d" (input_address),
-                            "m" (hypercall_page));
-
-       return hv_status;
-
-#else
-
-       u32 control_hi = control >> 32;
-       u32 control_lo = control & 0xFFFFFFFF;
-       u32 hv_status_hi = 1;
-       u32 hv_status_lo = 1;
-       u32 input_address_hi = input_address >> 32;
-       u32 input_address_lo = input_address & 0xFFFFFFFF;
-       u32 output_address_hi = output_address >> 32;
-       u32 output_address_lo = output_address & 0xFFFFFFFF;
-
-       if (!hypercall_page)
-               return (u64)ULLONG_MAX;
-
-       __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
-                             "=a"(hv_status_lo) : "d" (control_hi),
-                             "a" (control_lo), "b" (input_address_hi),
-                             "c" (input_address_lo), "D"(output_address_hi),
-                             "S"(output_address_lo), "m" (hypercall_page));
-
-       return hv_status_lo | ((u64)hv_status_hi << 32);
-#endif /* !x86_64 */
-}
-EXPORT_SYMBOL_GPL(hv_do_hypercall);
-
-#ifdef CONFIG_X86_64
-static u64 read_hv_clock_tsc(struct clocksource *arg)
-{
-       u64 current_tick;
-       struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page;
-
-       if (tsc_pg->tsc_sequence != 0) {
-               /*
-                * Use the tsc page to compute the value.
-                */
-
-               while (1) {
-                       u64 tmp;
-                       u32 sequence = tsc_pg->tsc_sequence;
-                       u64 cur_tsc;
-                       u64 scale = tsc_pg->tsc_scale;
-                       s64 offset = tsc_pg->tsc_offset;
-
-                       rdtscll(cur_tsc);
-                       /* current_tick = ((cur_tsc *scale) >> 64) + offset */
-                       asm("mulq %3"
-                               : "=d" (current_tick), "=a" (tmp)
-                               : "a" (cur_tsc), "r" (scale));
-
-                       current_tick += offset;
-                       if (tsc_pg->tsc_sequence == sequence)
-                               return current_tick;
-
-                       if (tsc_pg->tsc_sequence != 0)
-                               continue;
-                       /*
-                        * Fallback using MSR method.
-                        */
-                       break;
-               }
-       }
-       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
-       return current_tick;
-}
-
-static struct clocksource hyperv_cs_tsc = {
-               .name           = "hyperv_clocksource_tsc_page",
-               .rating         = 425,
-               .read           = read_hv_clock_tsc,
-               .mask           = CLOCKSOURCE_MASK(64),
-               .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-#endif
-
-
 /*
  * hv_init - Main initialization routine.
  *
@@ -191,9 +49,6 @@ static struct clocksource hyperv_cs_tsc = {
  */
 int hv_init(void)
 {
-       int max_leaf;
-       union hv_x64_msr_hypercall_contents hypercall_msr;
-       void *virtaddr = NULL;
 
        memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
        memset(hv_context.synic_message_page, 0,
@@ -209,68 +64,10 @@ int hv_init(void)
        memset(hv_context.clk_evt, 0,
               sizeof(void *) * NR_CPUS);
 
-       max_leaf = query_hypervisor_info();
-
-       /*
-        * Write our OS ID.
-        */
-       hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
-       wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
-
-       /* See if the hypercall page is already set */
-       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-
-       virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
-
-       if (!virtaddr)
-               goto cleanup;
-
-       hypercall_msr.enable = 1;
-
-       hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
-       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-
-       /* Confirm that hypercall page did get setup. */
-       hypercall_msr.as_uint64 = 0;
-       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-
-       if (!hypercall_msr.enable)
-               goto cleanup;
-
-       hv_context.hypercall_page = virtaddr;
-
-#ifdef CONFIG_X86_64
-       if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
-               union hv_x64_msr_hypercall_contents tsc_msr;
-               void *va_tsc;
-
-               va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
-               if (!va_tsc)
-                       goto cleanup;
-               hv_context.tsc_page = va_tsc;
+       if (!hv_is_hypercall_page_setup())
+               return -ENOTSUPP;
 
-               rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
-
-               tsc_msr.enable = 1;
-               tsc_msr.guest_physical_address = vmalloc_to_pfn(va_tsc);
-
-               wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
-               clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
-       }
-#endif
        return 0;
-
-cleanup:
-       if (virtaddr) {
-               if (hypercall_msr.enable) {
-                       hypercall_msr.as_uint64 = 0;
-                       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               }
-
-               vfree(virtaddr);
-       }
-
-       return -ENOTSUPP;
 }
 
 /*
@@ -280,40 +77,7 @@ int hv_init(void)
  */
 void hv_cleanup(bool crash)
 {
-       union hv_x64_msr_hypercall_contents hypercall_msr;
-
-       /* Reset our OS id */
-       wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
 
-       if (hv_context.hypercall_page) {
-               hypercall_msr.as_uint64 = 0;
-               wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               if (!crash)
-                       vfree(hv_context.hypercall_page);
-               hv_context.hypercall_page = NULL;
-       }
-
-#ifdef CONFIG_X86_64
-       /*
-        * Cleanup the TSC page based CS.
-        */
-       if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
-               /*
-                * Crash can happen in an interrupt context and unregistering
-                * a clocksource is impossible and redundant in this case.
-                */
-               if (!oops_in_progress) {
-                       clocksource_change_rating(&hyperv_cs_tsc, 10);
-                       clocksource_unregister(&hyperv_cs_tsc);
-               }
-
-               hypercall_msr.as_uint64 = 0;
-               wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
-               if (!crash)
-                       vfree(hv_context.tsc_page);
-               hv_context.tsc_page = NULL;
-       }
-#endif
 }
 
 /*
@@ -354,16 +118,16 @@ static int hv_ce_set_next_event(unsigned long delta,
 
        WARN_ON(!clockevent_state_oneshot(evt));
 
-       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+       hv_get_current_tick(current_tick);
        current_tick += delta;
-       wrmsrl(HV_X64_MSR_STIMER0_COUNT, current_tick);
+       hv_init_timer(HV_X64_MSR_STIMER0_COUNT, current_tick);
        return 0;
 }
 
 static int hv_ce_shutdown(struct clock_event_device *evt)
 {
-       wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0);
-       wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0);
+       hv_init_timer(HV_X64_MSR_STIMER0_COUNT, 0);
+       hv_init_timer_config(HV_X64_MSR_STIMER0_CONFIG, 0);
 
        return 0;
 }
@@ -375,7 +139,7 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt)
        timer_cfg.enable = 1;
        timer_cfg.auto_enable = 1;
        timer_cfg.sintx = VMBUS_MESSAGE_SINT;
-       wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+       hv_init_timer_config(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
 
        return 0;
 }
@@ -411,7 +175,7 @@ int hv_synic_alloc(void)
                goto err;
        }
 
-       for_each_online_cpu(cpu) {
+       for_each_present_cpu(cpu) {
                hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
                if (hv_context.event_dpc[cpu] == NULL) {
                        pr_err("Unable to allocate event dpc\n");
@@ -457,6 +221,8 @@ int hv_synic_alloc(void)
                        pr_err("Unable to allocate post msg page\n");
                        goto err;
                }
+
+               INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
        }
 
        return 0;
@@ -482,7 +248,7 @@ void hv_synic_free(void)
        int cpu;
 
        kfree(hv_context.hv_numa_map);
-       for_each_online_cpu(cpu)
+       for_each_present_cpu(cpu)
                hv_synic_free_cpu(cpu);
 }
 
@@ -493,54 +259,47 @@ void hv_synic_free(void)
  * retrieve the initialized message and event pages.  Otherwise, we create and
  * initialize the message and event pages.
  */
-void hv_synic_init(void *arg)
+int hv_synic_init(unsigned int cpu)
 {
-       u64 version;
        union hv_synic_simp simp;
        union hv_synic_siefp siefp;
        union hv_synic_sint shared_sint;
        union hv_synic_scontrol sctrl;
        u64 vp_index;
 
-       int cpu = smp_processor_id();
-
-       if (!hv_context.hypercall_page)
-               return;
-
-       /* Check the version */
-       rdmsrl(HV_X64_MSR_SVERSION, version);
-
        /* Setup the Synic's message page */
-       rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+       hv_get_simp(simp.as_uint64);
        simp.simp_enabled = 1;
        simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
                >> PAGE_SHIFT;
 
-       wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+       hv_set_simp(simp.as_uint64);
 
        /* Setup the Synic's event page */
-       rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+       hv_get_siefp(siefp.as_uint64);
        siefp.siefp_enabled = 1;
        siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
                >> PAGE_SHIFT;
 
-       wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+       hv_set_siefp(siefp.as_uint64);
 
        /* Setup the shared SINT. */
-       rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+       hv_get_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT,
+                           shared_sint.as_uint64);
 
        shared_sint.as_uint64 = 0;
        shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR;
        shared_sint.masked = false;
        shared_sint.auto_eoi = true;
 
-       wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+       hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT,
+                           shared_sint.as_uint64);
 
        /* Enable the global synic bit */
-       rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+       hv_get_synic_state(sctrl.as_uint64);
        sctrl.enable = 1;
 
-       wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+       hv_set_synic_state(sctrl.as_uint64);
 
        hv_context.synic_initialized = true;
 
@@ -549,11 +308,9 @@ void hv_synic_init(void *arg)
         * of cpuid and Linux' notion of cpuid.
         * This array will be indexed using Linux cpuid.
         */
-       rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
+       hv_get_vp_index(vp_index);
        hv_context.vp_index[cpu] = (u32)vp_index;
 
-       INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
-
        /*
         * Register the per-cpu clockevent source.
         */
@@ -562,7 +319,7 @@ void hv_synic_init(void *arg)
                                                HV_TIMER_FREQUENCY,
                                                HV_MIN_DELTA_TICKS,
                                                HV_MAX_MAX_DELTA_TICKS);
-       return;
+       return 0;
 }
 
 /*
@@ -582,16 +339,46 @@ void hv_synic_clockevents_cleanup(void)
 /*
  * hv_synic_cleanup - Cleanup routine for hv_synic_init().
  */
-void hv_synic_cleanup(void *arg)
+int hv_synic_cleanup(unsigned int cpu)
 {
        union hv_synic_sint shared_sint;
        union hv_synic_simp simp;
        union hv_synic_siefp siefp;
        union hv_synic_scontrol sctrl;
-       int cpu = smp_processor_id();
+       struct vmbus_channel *channel, *sc;
+       bool channel_found = false;
+       unsigned long flags;
 
        if (!hv_context.synic_initialized)
-               return;
+               return -EFAULT;
+
+       /*
+        * Search for channels which are bound to the CPU we're about to
+        * cleanup. In case we find one and vmbus is still connected we need to
+        * fail, this will effectively prevent CPU offlining. There is no way
+        * we can re-bind channels to different CPUs for now.
+        */
+       mutex_lock(&vmbus_connection.channel_mutex);
+       list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
+               if (channel->target_cpu == cpu) {
+                       channel_found = true;
+                       break;
+               }
+               spin_lock_irqsave(&channel->lock, flags);
+               list_for_each_entry(sc, &channel->sc_list, sc_list) {
+                       if (sc->target_cpu == cpu) {
+                               channel_found = true;
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(&channel->lock, flags);
+               if (channel_found)
+                       break;
+       }
+       mutex_unlock(&vmbus_connection.channel_mutex);
+
+       if (channel_found && vmbus_connection.conn_state == CONNECTED)
+               return -EBUSY;
 
        /* Turn off clockevent device */
        if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE) {
@@ -599,28 +386,32 @@ void hv_synic_cleanup(void *arg)
                hv_ce_shutdown(hv_context.clk_evt[cpu]);
        }
 
-       rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+       hv_get_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT,
+                           shared_sint.as_uint64);
 
        shared_sint.masked = 1;
 
        /* Need to correctly cleanup in the case of SMP!!! */
        /* Disable the interrupt */
-       wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+       hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT,
+                           shared_sint.as_uint64);
 
-       rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+       hv_get_simp(simp.as_uint64);
        simp.simp_enabled = 0;
        simp.base_simp_gpa = 0;
 
-       wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+       hv_set_simp(simp.as_uint64);
 
-       rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+       hv_get_siefp(siefp.as_uint64);
        siefp.siefp_enabled = 0;
        siefp.base_siefp_gpa = 0;
 
-       wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+       hv_set_siefp(siefp.as_uint64);
 
        /* Disable the global synic bit */
-       rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+       hv_get_synic_state(sctrl.as_uint64);
        sctrl.enable = 0;
-       wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+       hv_set_synic_state(sctrl.as_uint64);
+
+       return 0;
 }
index 8b2ba98831ec52a5ed60b4a06097db48e781daf9..e47d8c9db03a7a4bdb472b8bbbb2ccdd8ef6561c 100644 (file)
@@ -61,6 +61,7 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
 static const char fcopy_devname[] = "vmbus/hv_fcopy";
 static u8 *recv_buffer;
 static struct hvutil_transport *hvt;
+static struct completion release_event;
 /*
  * This state maintains the version number registered by the daemon.
  */
@@ -317,6 +318,7 @@ static void fcopy_on_reset(void)
 
        if (cancel_delayed_work_sync(&fcopy_timeout_work))
                fcopy_respond_to_host(HV_E_FAIL);
+       complete(&release_event);
 }
 
 int hv_fcopy_init(struct hv_util_service *srv)
@@ -324,6 +326,7 @@ int hv_fcopy_init(struct hv_util_service *srv)
        recv_buffer = srv->recv_buffer;
        fcopy_transaction.recv_channel = srv->channel;
 
+       init_completion(&release_event);
        /*
         * When this driver loads, the user level daemon that
         * processes the host requests may not yet be running.
@@ -345,4 +348,5 @@ void hv_fcopy_deinit(void)
        fcopy_transaction.state = HVUTIL_DEVICE_DYING;
        cancel_delayed_work_sync(&fcopy_timeout_work);
        hvutil_transport_destroy(hvt);
+       wait_for_completion(&release_event);
 }
index 5e1fdc8d32ab0c03d25bfcf7d3fbadbcedc6f2eb..3abfc5983c97c87f6457111a937d4f330ba185e1 100644 (file)
@@ -88,6 +88,7 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
 static const char kvp_devname[] = "vmbus/hv_kvp";
 static u8 *recv_buffer;
 static struct hvutil_transport *hvt;
+static struct completion release_event;
 /*
  * Register the kernel component with the user-level daemon.
  * As part of this registration, pass the LIC version number.
@@ -716,6 +717,7 @@ static void kvp_on_reset(void)
        if (cancel_delayed_work_sync(&kvp_timeout_work))
                kvp_respond_to_host(NULL, HV_E_FAIL);
        kvp_transaction.state = HVUTIL_DEVICE_INIT;
+       complete(&release_event);
 }
 
 int
@@ -724,6 +726,7 @@ hv_kvp_init(struct hv_util_service *srv)
        recv_buffer = srv->recv_buffer;
        kvp_transaction.recv_channel = srv->channel;
 
+       init_completion(&release_event);
        /*
         * When this driver loads, the user level daemon that
         * processes the host requests may not yet be running.
@@ -747,4 +750,5 @@ void hv_kvp_deinit(void)
        cancel_delayed_work_sync(&kvp_timeout_work);
        cancel_work_sync(&kvp_sendkey_work);
        hvutil_transport_destroy(hvt);
+       wait_for_completion(&release_event);
 }
index eee238cc60bd09da1e260863f5d0532a893cbd7d..4e543dbb731a26efe44491f543272b1b6bfd6319 100644 (file)
@@ -69,6 +69,7 @@ static int dm_reg_value;
 static const char vss_devname[] = "vmbus/hv_vss";
 static __u8 *recv_buffer;
 static struct hvutil_transport *hvt;
+static struct completion release_event;
 
 static void vss_timeout_func(struct work_struct *dummy);
 static void vss_handle_request(struct work_struct *dummy);
@@ -345,11 +346,13 @@ static void vss_on_reset(void)
        if (cancel_delayed_work_sync(&vss_timeout_work))
                vss_respond_to_host(HV_E_FAIL);
        vss_transaction.state = HVUTIL_DEVICE_INIT;
+       complete(&release_event);
 }
 
 int
 hv_vss_init(struct hv_util_service *srv)
 {
+       init_completion(&release_event);
        if (vmbus_proto_version < VERSION_WIN8_1) {
                pr_warn("Integration service 'Backup (volume snapshot)'"
                        " not supported on this host version.\n");
@@ -382,4 +385,5 @@ void hv_vss_deinit(void)
        cancel_delayed_work_sync(&vss_timeout_work);
        cancel_work_sync(&vss_handle_request_work);
        hvutil_transport_destroy(hvt);
+       wait_for_completion(&release_event);
 }
index e7707747f56df05208fc2a0607007206c224290e..7c90e3334a88a80bbd19211c2627fb2466e30c22 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sysctl.h>
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
+#include <asm/mshyperv.h>
 
 #include "hyperv_vmbus.h"
 
@@ -199,7 +200,7 @@ static void hv_set_host_time(struct work_struct *work)
                 */
                u64 current_tick;
 
-               rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+               hv_get_current_tick(current_tick);
                newtime += (current_tick - wrk->ref_time);
        }
        host_tns = (newtime - WLTIMEDELTA) * 100;
index 0675b395ce5c47f284dec3c86b02133086e86cf9..2463ef93c1f6c9584aadb8fd41c3a0a199eb15d2 100644 (file)
  */
 #define HV_UTIL_NEGO_TIMEOUT 55
 
-/*
- * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
- * is set by CPUID(HVCPUID_VERSION_FEATURES).
- */
-enum hv_cpuid_function {
-       HVCPUID_VERSION_FEATURES                = 0x00000001,
-       HVCPUID_VENDOR_MAXFUNCTION              = 0x40000000,
-       HVCPUID_INTERFACE                       = 0x40000001,
-
-       /*
-        * The remaining functions depend on the value of
-        * HVCPUID_INTERFACE
-        */
-       HVCPUID_VERSION                 = 0x40000002,
-       HVCPUID_FEATURES                        = 0x40000003,
-       HVCPUID_ENLIGHTENMENT_INFO      = 0x40000004,
-       HVCPUID_IMPLEMENTATION_LIMITS           = 0x40000005,
-};
-
-#define  HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE   0x400
 
-#define HV_X64_MSR_CRASH_P0   0x40000100
-#define HV_X64_MSR_CRASH_P1   0x40000101
-#define HV_X64_MSR_CRASH_P2   0x40000102
-#define HV_X64_MSR_CRASH_P3   0x40000103
-#define HV_X64_MSR_CRASH_P4   0x40000104
-#define HV_X64_MSR_CRASH_CTL  0x40000105
 
-#define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63)
 
-/* Define version of the synthetic interrupt controller. */
-#define HV_SYNIC_VERSION               (1)
-
-#define HV_ANY_VP                      (0xFFFFFFFF)
-
-/* Define synthetic interrupt controller flag constants. */
-#define HV_EVENT_FLAGS_COUNT           (256 * 8)
 #define HV_EVENT_FLAGS_BYTE_COUNT      (256)
 #define HV_EVENT_FLAGS_DWORD_COUNT     (256 / sizeof(u32))
 
-/* Define invalid partition identifier. */
-#define HV_PARTITION_ID_INVALID                ((u64)0x0)
-
-/* Define port type. */
-enum hv_port_type {
-       HVPORT_MSG      = 1,
-       HVPORT_EVENT            = 2,
-       HVPORT_MONITOR  = 3
-};
-
-/* Define port information structure. */
-struct hv_port_info {
-       enum hv_port_type port_type;
-       u32 padding;
-       union {
-               struct {
-                       u32 target_sint;
-                       u32 target_vp;
-                       u64 rsvdz;
-               } message_port_info;
-               struct {
-                       u32 target_sint;
-                       u32 target_vp;
-                       u16 base_flag_number;
-                       u16 flag_count;
-                       u32 rsvdz;
-               } event_port_info;
-               struct {
-                       u64 monitor_address;
-                       u64 rsvdz;
-               } monitor_port_info;
-       };
-};
-
-struct hv_connection_info {
-       enum hv_port_type port_type;
-       u32 padding;
-       union {
-               struct {
-                       u64 rsvdz;
-               } message_connection_info;
-               struct {
-                       u64 rsvdz;
-               } event_connection_info;
-               struct {
-                       u64 monitor_address;
-               } monitor_connection_info;
-       };
-};
-
 /*
  * Timer configuration register.
  */
@@ -146,8 +62,6 @@ union hv_timer_config {
        };
 };
 
-/* Define the number of message buffers associated with each port. */
-#define HV_PORT_MESSAGE_BUFFER_COUNT   (16)
 
 /* Define the synthetic interrupt controller event flags format. */
 union hv_synic_event_flags {
@@ -155,11 +69,6 @@ union hv_synic_event_flags {
        u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
 };
 
-/* Define the synthetic interrupt flags page layout. */
-struct hv_synic_event_flags_page {
-       union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT];
-};
-
 /* Define SynIC control register. */
 union hv_synic_scontrol {
        u64 as_uint64;
@@ -261,6 +170,8 @@ struct hv_monitor_page {
        u8 rsvdz4[1984];
 };
 
+#define HV_HYPERCALL_PARAM_ALIGN       sizeof(u64)
+
 /* Definition of the hv_post_message hypercall input structure. */
 struct hv_input_post_message {
        union hv_connection_id connectionid;
@@ -270,56 +181,6 @@ struct hv_input_post_message {
        u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
 };
 
-/*
- * Versioning definitions used for guests reporting themselves to the
- * hypervisor, and visa versa.
- */
-
-/* Version info reported by guest OS's */
-enum hv_guest_os_vendor {
-       HVGUESTOS_VENDOR_MICROSOFT      = 0x0001
-};
-
-enum hv_guest_os_microsoft_ids {
-       HVGUESTOS_MICROSOFT_UNDEFINED   = 0x00,
-       HVGUESTOS_MICROSOFT_MSDOS               = 0x01,
-       HVGUESTOS_MICROSOFT_WINDOWS3X   = 0x02,
-       HVGUESTOS_MICROSOFT_WINDOWS9X   = 0x03,
-       HVGUESTOS_MICROSOFT_WINDOWSNT   = 0x04,
-       HVGUESTOS_MICROSOFT_WINDOWSCE   = 0x05
-};
-
-/*
- * Declare the MSR used to identify the guest OS.
- */
-#define HV_X64_MSR_GUEST_OS_ID 0x40000000
-
-union hv_x64_msr_guest_os_id_contents {
-       u64 as_uint64;
-       struct {
-               u64 build_number:16;
-               u64 service_version:8; /* Service Pack, etc. */
-               u64 minor_version:8;
-               u64 major_version:8;
-               u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
-               u64 vendor_id:16; /* enum hv_guest_os_vendor */
-       };
-};
-
-/*
- * Declare the MSR used to setup pages used to communicate with the hypervisor.
- */
-#define HV_X64_MSR_HYPERCALL   0x40000001
-
-union hv_x64_msr_hypercall_contents {
-       u64 as_uint64;
-       struct {
-               u64 enable:1;
-               u64 reserved:11;
-               u64 guest_physical_address:52;
-       };
-};
-
 
 enum {
        VMBUS_MESSAGE_CONNECTION_ID     = 1,
@@ -331,105 +192,12 @@ enum {
        VMBUS_MESSAGE_SINT              = 2,
 };
 
-/* #defines */
-
-#define HV_PRESENT_BIT                 0x80000000
-
-/*
- * The guest OS needs to register the guest ID with the hypervisor.
- * The guest ID is a 64 bit entity and the structure of this ID is
- * specified in the Hyper-V specification:
- *
- * http://msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
- *
- * While the current guideline does not specify how Linux guest ID(s)
- * need to be generated, our plan is to publish the guidelines for
- * Linux and other guest operating systems that currently are hosted
- * on Hyper-V. The implementation here conforms to this yet
- * unpublished guidelines.
- *
- *
- * Bit(s)
- * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
- * 62:56 - Os Type; Linux is 0x100
- * 55:48 - Distro specific identification
- * 47:16 - Linux kernel version number
- * 15:0  - Distro specific identification
- *
- *
- */
-
-#define HV_LINUX_VENDOR_ID             0x8100
-
-/*
- * Generate the guest ID based on the guideline described above.
- */
-
-static inline  __u64 generate_guest_id(__u8 d_info1, __u32 kernel_version,
-                                       __u16 d_info2)
-{
-       __u64 guest_id = 0;
-
-       guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
-       guest_id |= (((__u64)(d_info1)) << 48);
-       guest_id |= (((__u64)(kernel_version)) << 16);
-       guest_id |= ((__u64)(d_info2));
-
-       return guest_id;
-}
-
-
-#define HV_CPU_POWER_MANAGEMENT                (1 << 0)
-#define HV_RECOMMENDATIONS_MAX         4
-
-#define HV_X64_MAX                     5
-#define HV_CAPS_MAX                    8
-
-
-#define HV_HYPERCALL_PARAM_ALIGN       sizeof(u64)
-
-
-/* Service definitions */
-
-#define HV_SERVICE_PARENT_PORT                         (0)
-#define HV_SERVICE_PARENT_CONNECTION                   (0)
-
-#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS            (0)
-#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER  (1)
-#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE    (2)
-#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED        (3)
-
-#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID          (1)
-#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID         (2)
-#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID       (3)
-#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID      (4)
-#define HV_SERVICE_MAX_MESSAGE_ID                              (4)
-
-#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
-#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
-
-/* #define VMBUS_REVISION_NUMBER       6 */
-
-/* Our local vmbus's port and connection id. Anything >0 is fine */
-/* #define VMBUS_PORT_ID               11 */
-
-/* 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 */
-static const uuid_le VMBUS_SERVICE_ID = {
-       .b = {
-               0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c,
-               0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4
-       },
-};
-
-
-
 struct hv_context {
        /* We only support running on top of Hyper-V
        * So at this point this really can only contain the Hyper-V ID
        */
        u64 guestid;
 
-       void *hypercall_page;
        void *tsc_page;
 
        bool synic_initialized;
@@ -475,14 +243,6 @@ struct hv_context {
 
 extern struct hv_context hv_context;
 
-struct ms_hyperv_tsc_page {
-       volatile u32 tsc_sequence;
-       u32 reserved1;
-       volatile u64 tsc_scale;
-       volatile s64 tsc_offset;
-       u64 reserved2[509];
-};
-
 struct hv_ring_buffer_debug_info {
        u32 current_interrupt_mask;
        u32 current_read_index;
@@ -505,20 +265,12 @@ extern int hv_synic_alloc(void);
 
 extern void hv_synic_free(void);
 
-extern void hv_synic_init(void *irqarg);
+extern int hv_synic_init(unsigned int cpu);
 
-extern void hv_synic_cleanup(void *arg);
+extern int hv_synic_cleanup(unsigned int cpu);
 
 extern void hv_synic_clockevents_cleanup(void);
 
-/*
- * Host version information.
- */
-extern unsigned int host_info_eax;
-extern unsigned int host_info_ebx;
-extern unsigned int host_info_ecx;
-extern unsigned int host_info_edx;
-
 /* Interface */
 
 
@@ -625,41 +377,6 @@ struct vmbus_channel_message_table_entry {
 extern struct vmbus_channel_message_table_entry
        channel_message_table[CHANNELMSG_COUNT];
 
-/* Free the message slot and signal end-of-message if required */
-static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
-{
-       /*
-        * On crash we're reading some other CPU's message page and we need
-        * to be careful: this other CPU may already had cleared the header
-        * and the host may already had delivered some other message there.
-        * In case we blindly write msg->header.message_type we're going
-        * to lose it. We can still lose a message of the same type but
-        * we count on the fact that there can only be one
-        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
-        * on crash.
-        */
-       if (cmpxchg(&msg->header.message_type, old_msg_type,
-                   HVMSG_NONE) != old_msg_type)
-               return;
-
-       /*
-        * Make sure the write to MessageType (ie set to
-        * HVMSG_NONE) happens before we read the
-        * MessagePending and EOMing. Otherwise, the EOMing
-        * will not deliver any more messages since there is
-        * no empty slot
-        */
-       mb();
-
-       if (msg->header.message_flags.msg_pending) {
-               /*
-                * This will cause message queue rescan to
-                * possibly deliver another msg from the
-                * hypervisor
-                */
-               wrmsrl(HV_X64_MSR_EOM, 0);
-       }
-}
 
 /* General vmbus interface */
 
@@ -670,10 +387,6 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
 int vmbus_device_register(struct hv_device *child_device_obj);
 void vmbus_device_unregister(struct hv_device *device_obj);
 
-/* static void */
-/* VmbusChildDeviceDestroy( */
-/* struct hv_device *); */
-
 struct vmbus_channel *relid2channel(u32 relid);
 
 void vmbus_free_channels(void);
@@ -683,7 +396,7 @@ void vmbus_free_channels(void);
 int vmbus_connect(void);
 void vmbus_disconnect(void);
 
-int vmbus_post_msg(void *buffer, size_t buflen);
+int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep);
 
 void vmbus_on_event(unsigned long data);
 void vmbus_on_msg_dpc(unsigned long data);
index cd49cb17eb7fb385ddbf507ef14b2ea2be090159..2cd40298685862bb8ad9b87a6cc57cd21888c64a 100644 (file)
@@ -298,6 +298,9 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
        unsigned long flags = 0;
        struct hv_ring_buffer_info *outring_info = &channel->outbound;
 
+       if (channel->rescind)
+               return -ENODEV;
+
        for (i = 0; i < kv_count; i++)
                totalbytes_towrite += kv_list[i].iov_len;
 
@@ -350,6 +353,10 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
                spin_unlock_irqrestore(&outring_info->ring_lock, flags);
 
        hv_signal_on_write(old_write, channel, kick_q);
+
+       if (channel->rescind)
+               return -ENODEV;
+
        return 0;
 }
 
index 230c62e7f567521fc442154a448f1fd457f7f48a..8e81346114d41b9d17f0959a7e202352291fbb01 100644 (file)
@@ -54,31 +54,7 @@ static struct acpi_device  *hv_acpi_dev;
 
 static struct completion probe_event;
 
-
-static void hyperv_report_panic(struct pt_regs *regs)
-{
-       static bool panic_reported;
-
-       /*
-        * We prefer to report panic on 'die' chain as we have proper
-        * registers to report, but if we miss it (e.g. on BUG()) we need
-        * to report it on 'panic'.
-        */
-       if (panic_reported)
-               return;
-       panic_reported = true;
-
-       wrmsrl(HV_X64_MSR_CRASH_P0, regs->ip);
-       wrmsrl(HV_X64_MSR_CRASH_P1, regs->ax);
-       wrmsrl(HV_X64_MSR_CRASH_P2, regs->bx);
-       wrmsrl(HV_X64_MSR_CRASH_P3, regs->cx);
-       wrmsrl(HV_X64_MSR_CRASH_P4, regs->dx);
-
-       /*
-        * Let Hyper-V know there is crash data available
-        */
-       wrmsrl(HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
-}
+static int hyperv_cpuhp_online;
 
 static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
                              void *args)
@@ -997,14 +973,16 @@ static int vmbus_bus_init(void)
         * Initialize the per-cpu interrupt state and
         * connect to the host.
         */
-       on_each_cpu(hv_synic_init, NULL, 1);
+       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv:online",
+                               hv_synic_init, hv_synic_cleanup);
+       if (ret < 0)
+               goto err_alloc;
+       hyperv_cpuhp_online = ret;
+
        ret = vmbus_connect();
        if (ret)
                goto err_connect;
 
-       if (vmbus_proto_version > VERSION_WIN7)
-               cpu_hotplug_disable();
-
        /*
         * Only register if the crash MSRs are available
         */
@@ -1019,7 +997,7 @@ static int vmbus_bus_init(void)
        return 0;
 
 err_connect:
-       on_each_cpu(hv_synic_cleanup, NULL, 1);
+       cpuhp_remove_state(hyperv_cpuhp_online);
 err_alloc:
        hv_synic_free();
        hv_remove_vmbus_irq();
@@ -1478,12 +1456,12 @@ static struct acpi_driver vmbus_acpi_driver = {
 
 static void hv_kexec_handler(void)
 {
-       int cpu;
-
        hv_synic_clockevents_cleanup();
        vmbus_initiate_unload(false);
-       for_each_online_cpu(cpu)
-               smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
+       vmbus_connection.conn_state = DISCONNECTED;
+       /* Make sure conn_state is set as hv_synic_cleanup checks for it */
+       mb();
+       cpuhp_remove_state(hyperv_cpuhp_online);
        hv_cleanup(false);
 };
 
@@ -1495,7 +1473,8 @@ static void hv_crash_handler(struct pt_regs *regs)
         * doing the cleanup for current CPU only. This should be sufficient
         * for kdump.
         */
-       hv_synic_cleanup(NULL);
+       vmbus_connection.conn_state = DISCONNECTED;
+       hv_synic_cleanup(smp_processor_id());
        hv_cleanup(true);
 };
 
@@ -1559,12 +1538,10 @@ static void __exit vmbus_exit(void)
        hv_cleanup(false);
        for_each_online_cpu(cpu) {
                tasklet_kill(hv_context.event_dpc[cpu]);
-               smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
        }
+       cpuhp_remove_state(hyperv_cpuhp_online);
        hv_synic_free();
        acpi_bus_unregister_driver(&vmbus_acpi_driver);
-       if (vmbus_proto_version > VERSION_WIN7)
-               cpu_hotplug_enable();
 }
 
 
index e4c55c5f998884f24b216861a2bc5c624b2376c8..93fc26f01bab61e59379681598d64320b7625651 100644 (file)
@@ -356,7 +356,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return;
 
-       stm_disable(drvdata->csdev, NULL);
+       coresight_disable(drvdata->csdev);
 }
 
 static phys_addr_t
index c2268cdf38e82348ae883c99d1f140a7fc2d0ecc..e34d82e79b988a781010cad1e0f283617dfb8471 100644 (file)
@@ -585,10 +585,29 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
                 u8 command, int size, union i2c_smbus_data *data)
 {
        struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+       unsigned short piix4_smba = adapdata->smba;
+       int retries = MAX_TIMEOUT;
+       int smbslvcnt;
        u8 smba_en_lo;
        u8 port;
        int retval;
 
+       /* Request the SMBUS semaphore, avoid conflicts with the IMC */
+       smbslvcnt  = inb_p(SMBSLVCNT);
+       do {
+               outb_p(smbslvcnt | 0x10, SMBSLVCNT);
+
+               /* Check the semaphore status */
+               smbslvcnt  = inb_p(SMBSLVCNT);
+               if (smbslvcnt & 0x10)
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (--retries);
+       /* SMBus is still owned by the IMC, we give up */
+       if (!retries)
+               return -EBUSY;
+
        mutex_lock(&piix4_mutex_sb800);
 
        outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
@@ -606,6 +625,9 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
 
        mutex_unlock(&piix4_mutex_sb800);
 
+       /* Release the semaphore */
+       outb_p(smbslvcnt | 0x20, SMBSLVCNT);
+
        return retval;
 }
 
index cf9e396d7702c6c769e2106a6938f90c6ddbb7a9..583e95042a21d86fe235d2e9784a1f6a6723205b 100644 (file)
@@ -931,7 +931,10 @@ static int i2c_device_probe(struct device *dev)
        if (!client->irq) {
                int irq = -ENOENT;
 
-               if (dev->of_node) {
+               if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
+                       dev_dbg(dev, "Using Host Notify IRQ\n");
+                       irq = i2c_smbus_host_notify_to_irq(client);
+               } else if (dev->of_node) {
                        irq = of_irq_get_byname(dev->of_node, "irq");
                        if (irq == -EINVAL || irq == -ENODATA)
                                irq = of_irq_get(dev->of_node, 0);
@@ -940,14 +943,7 @@ static int i2c_device_probe(struct device *dev)
                }
                if (irq == -EPROBE_DEFER)
                        return irq;
-               /*
-                * ACPI and OF did not find any useful IRQ, try to see
-                * if Host Notify can be used.
-                */
-               if (irq < 0) {
-                       dev_dbg(dev, "Using Host Notify IRQ\n");
-                       irq = i2c_smbus_host_notify_to_irq(client);
-               }
+
                if (irq < 0)
                        irq = 0;
 
@@ -1708,7 +1704,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
 
        if (i2c_check_addr_validity(addr, info.flags)) {
                dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
-                       info.addr, node->full_name);
+                       addr, node->full_name);
                return ERR_PTR(-EINVAL);
        }
 
@@ -1716,6 +1712,9 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
        info.of_node = of_node_get(node);
        info.archdata = &dev_ad;
 
+       if (of_property_read_bool(node, "host-notify"))
+               info.flags |= I2C_CLIENT_HOST_NOTIFY;
+
        if (of_get_property(node, "wakeup-source", NULL))
                info.flags |= I2C_CLIENT_WAKE;
 
@@ -3633,7 +3632,7 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
        int ret;
 
        if (!client || !slave_cb) {
-               WARN(1, "insufficent data\n");
+               WARN(1, "insufficient data\n");
                return -EINVAL;
        }
 
index 66f323fd39826ebe9a738d55724ee2e124b45419..6f638bbc922db4fd366e1e3dcdd11c8655215622 100644 (file)
@@ -331,7 +331,7 @@ static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
                unsigned long arg)
 {
        struct i2c_smbus_ioctl_data data_arg;
-       union i2c_smbus_data temp;
+       union i2c_smbus_data temp = {};
        int datasize, res;
 
        if (copy_from_user(&data_arg,
index f3135ae22df429c743c771c40c29d049869091f5..abd18f31b24f68e27c28f1120e52aa96b9347887 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/init.h>
index 6d949965867190458abaa653636ed4ab6702a4aa..c7d5b2b643d10798eb7da917f16888a2cff2bc3b 100644 (file)
@@ -1377,6 +1377,12 @@ static int xpad_init_input(struct usb_xpad *xpad)
        input_dev->name = xpad->name;
        input_dev->phys = xpad->phys;
        usb_to_input_id(xpad->udev, &input_dev->id);
+
+       if (xpad->xtype == XTYPE_XBOX360W) {
+               /* x360w controllers and the receiver have different ids */
+               input_dev->id.product = 0x02a1;
+       }
+
        input_dev->dev.parent = &xpad->intf->dev;
 
        input_set_drvdata(input_dev, xpad);
index a8b0a2eec344e863bd292251095a4e84f3a0b98b..7fed92fb8cc137c28e9e54a08d5bea4f1233ba08 100644 (file)
@@ -136,7 +136,6 @@ static const struct i2c_device_id adxl34x_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, adxl34x_id);
 
-#ifdef CONFIG_OF
 static const struct of_device_id adxl34x_of_id[] = {
        /*
         * The ADXL346 is backward-compatible with the ADXL345. Differences are
@@ -153,13 +152,12 @@ static const struct of_device_id adxl34x_of_id[] = {
 };
 
 MODULE_DEVICE_TABLE(of, adxl34x_of_id);
-#endif
 
 static struct i2c_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .pm = &adxl34x_i2c_pm,
-               .of_match_table = of_match_ptr(adxl34x_of_id),
+               .of_match_table = adxl34x_of_id,
        },
        .probe    = adxl34x_i2c_probe,
        .remove   = adxl34x_i2c_remove,
index cde6f4bd8ea2e3f0f70fbccf3f684e5cd079ec04..6d279aa27cb9a10d70a2e732fe9599297883cbc0 100644 (file)
@@ -114,7 +114,7 @@ enum SS4_PACKET_ID {
                                 (_b[1] & 0x7F)         \
                                )
 
-#define SS4_TS_Y_V2(_b)                (s8)(                           \
+#define SS4_TS_Y_V2(_b)                -(s8)(                          \
                                 ((_b[3] & 0x01) << 7) |        \
                                 (_b[2] & 0x7F)         \
                                )
index aa7c5da608005cfb471279b484bcc46f39fe3c82..cb2bf203f4cabac152d8fedd13fe9ec55826f136 100644 (file)
@@ -29,7 +29,7 @@
  * after soft reset, we should wait for 1 ms
  * before the device becomes operational
  */
-#define SOFT_RESET_DELAY_MS    3
+#define SOFT_RESET_DELAY_US    3000
 /* and after hard reset, we should wait for max 500ms */
 #define HARD_RESET_DELAY_MS    500
 
@@ -311,7 +311,7 @@ static int synaptics_i2c_reset_config(struct i2c_client *client)
        if (ret) {
                dev_err(&client->dev, "Unable to reset device\n");
        } else {
-               msleep(SOFT_RESET_DELAY_MS);
+               usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100);
                ret = synaptics_i2c_config(client);
                if (ret)
                        dev_err(&client->dev, "Unable to config device\n");
index 30cc627a4f4531ff93014ea94bf9835b0b37e8bc..8993983e3fe4892b748ff5d77c1597880c63e2c9 100644 (file)
@@ -41,7 +41,8 @@ config RMI4_SMB
 
 config RMI4_F03
         bool "RMI4 Function 03 (PS2 Guest)"
-        depends on RMI4_CORE && SERIO
+       depends on RMI4_CORE
+       depends on SERIO=y || RMI4_CORE=SERIO
         help
           Say Y here if you want to add support for RMI4 function 03.
 
index 77551f52220275c0589419ced9f7037cc11062b0..a7618776705ab929e42d4c3e870b4911f1a30d9c 100644 (file)
@@ -211,6 +211,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
                },
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
+               },
+       },
        { }
 };
 
index 02aec284decac37b1a93b16b609007c077db7f98..3e6003d32e565c748a43730574b9424eeb294d33 100644 (file)
@@ -914,9 +914,9 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
 
                case QUEUE_HEADER_NORMAL:
                        report_count = ts->buf[FW_HDR_COUNT];
-                       if (report_count > 3) {
+                       if (report_count == 0 || report_count > 3) {
                                dev_err(&client->dev,
-                                       "too large report count: %*ph\n",
+                                       "bad report count: %*ph\n",
                                        HEADER_SIZE, ts->buf);
                                break;
                        }
index e38936d05df18fa20564c0ed7e8093e3b377fd81..2a514036a83dc0da07c0966b7fe247c18356bbbf 100644 (file)
@@ -212,6 +212,7 @@ extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
                                int is_new);
 struct md_cluster_info;
 
+/* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
 enum mddev_flags {
        MD_ARRAY_FIRST_USE,     /* First use of array, needs initialization */
        MD_CLOSING,             /* If set, we are closing the array, do not open
@@ -702,4 +703,11 @@ static inline int mddev_is_clustered(struct mddev *mddev)
 {
        return mddev->cluster_info && mddev->bitmap_info.nodes > 1;
 }
+
+/* clear unsupported mddev_flags */
+static inline void mddev_clear_unsupported_flags(struct mddev *mddev,
+       unsigned long unsupported_flags)
+{
+       mddev->flags &= ~unsupported_flags;
+}
 #endif /* _MD_MD_H */
index a162fedeb51a48ce31d18fbca5a51a0fe9204bf4..848365d474f3a3bca26168ac3619f2c52edd7618 100644 (file)
 #include "raid0.h"
 #include "raid5.h"
 
+#define UNSUPPORTED_MDDEV_FLAGS                \
+       ((1L << MD_HAS_JOURNAL) |       \
+        (1L << MD_JOURNAL_CLEAN) |     \
+        (1L << MD_FAILFAST_SUPPORTED))
+
 static int raid0_congested(struct mddev *mddev, int bits)
 {
        struct r0conf *conf = mddev->private;
@@ -539,8 +544,7 @@ static void *raid0_takeover_raid45(struct mddev *mddev)
        mddev->delta_disks = -1;
        /* make sure it will be not marked as dirty */
        mddev->recovery_cp = MaxSector;
-       clear_bit(MD_HAS_JOURNAL, &mddev->flags);
-       clear_bit(MD_JOURNAL_CLEAN, &mddev->flags);
+       mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
 
        create_strip_zones(mddev, &priv_conf);
 
@@ -583,7 +587,7 @@ static void *raid0_takeover_raid10(struct mddev *mddev)
        mddev->degraded = 0;
        /* make sure it will be not marked as dirty */
        mddev->recovery_cp = MaxSector;
-       clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+       mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
 
        create_strip_zones(mddev, &priv_conf);
        return priv_conf;
@@ -626,7 +630,7 @@ static void *raid0_takeover_raid1(struct mddev *mddev)
        mddev->raid_disks = 1;
        /* make sure it will be not marked as dirty */
        mddev->recovery_cp = MaxSector;
-       clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+       mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
 
        create_strip_zones(mddev, &priv_conf);
        return priv_conf;
index a1f3fbed91009c5aa3253109d82db8eed38a2720..7b0f647bcccb513b6650136cddd51bc0ebec796a 100644 (file)
 #include "raid1.h"
 #include "bitmap.h"
 
+#define UNSUPPORTED_MDDEV_FLAGS                \
+       ((1L << MD_HAS_JOURNAL) |       \
+        (1L << MD_JOURNAL_CLEAN))
+
 /*
  * Number of guaranteed r1bios in case of extreme VM load:
  */
@@ -1066,17 +1070,107 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
        kfree(plug);
 }
 
-static void raid1_make_request(struct mddev *mddev, struct bio * bio)
+static void raid1_read_request(struct mddev *mddev, struct bio *bio,
+                                struct r1bio *r1_bio)
 {
        struct r1conf *conf = mddev->private;
        struct raid1_info *mirror;
-       struct r1bio *r1_bio;
        struct bio *read_bio;
+       struct bitmap *bitmap = mddev->bitmap;
+       const int op = bio_op(bio);
+       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       int sectors_handled;
+       int max_sectors;
+       int rdisk;
+
+       wait_barrier(conf, bio);
+
+read_again:
+       rdisk = read_balance(conf, r1_bio, &max_sectors);
+
+       if (rdisk < 0) {
+               /* couldn't find anywhere to read from */
+               raid_end_bio_io(r1_bio);
+               return;
+       }
+       mirror = conf->mirrors + rdisk;
+
+       if (test_bit(WriteMostly, &mirror->rdev->flags) &&
+           bitmap) {
+               /*
+                * Reading from a write-mostly device must take care not to
+                * over-take any writes that are 'behind'
+                */
+               raid1_log(mddev, "wait behind writes");
+               wait_event(bitmap->behind_wait,
+                          atomic_read(&bitmap->behind_writes) == 0);
+       }
+       r1_bio->read_disk = rdisk;
+       r1_bio->start_next_window = 0;
+
+       read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+       bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector,
+                max_sectors);
+
+       r1_bio->bios[rdisk] = read_bio;
+
+       read_bio->bi_iter.bi_sector = r1_bio->sector +
+               mirror->rdev->data_offset;
+       read_bio->bi_bdev = mirror->rdev->bdev;
+       read_bio->bi_end_io = raid1_end_read_request;
+       bio_set_op_attrs(read_bio, op, do_sync);
+       if (test_bit(FailFast, &mirror->rdev->flags) &&
+           test_bit(R1BIO_FailFast, &r1_bio->state))
+               read_bio->bi_opf |= MD_FAILFAST;
+       read_bio->bi_private = r1_bio;
+
+       if (mddev->gendisk)
+               trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
+                                     read_bio, disk_devt(mddev->gendisk),
+                                     r1_bio->sector);
+
+       if (max_sectors < r1_bio->sectors) {
+               /*
+                * could not read all from this device, so we will need another
+                * r1_bio.
+                */
+               sectors_handled = (r1_bio->sector + max_sectors
+                                  - bio->bi_iter.bi_sector);
+               r1_bio->sectors = max_sectors;
+               spin_lock_irq(&conf->device_lock);
+               if (bio->bi_phys_segments == 0)
+                       bio->bi_phys_segments = 2;
+               else
+                       bio->bi_phys_segments++;
+               spin_unlock_irq(&conf->device_lock);
+
+               /*
+                * Cannot call generic_make_request directly as that will be
+                * queued in __make_request and subsequent mempool_alloc might
+                * block waiting for it.  So hand bio over to raid1d.
+                */
+               reschedule_retry(r1_bio);
+
+               r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+               r1_bio->master_bio = bio;
+               r1_bio->sectors = bio_sectors(bio) - sectors_handled;
+               r1_bio->state = 0;
+               r1_bio->mddev = mddev;
+               r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
+               goto read_again;
+       } else
+               generic_make_request(read_bio);
+}
+
+static void raid1_write_request(struct mddev *mddev, struct bio *bio,
+                               struct r1bio *r1_bio)
+{
+       struct r1conf *conf = mddev->private;
        int i, disks;
-       struct bitmap *bitmap;
+       struct bitmap *bitmap = mddev->bitmap;
        unsigned long flags;
        const int op = bio_op(bio);
-       const int rw = bio_data_dir(bio);
        const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
        const unsigned long do_flush_fua = (bio->bi_opf &
                                                (REQ_PREFLUSH | REQ_FUA));
@@ -1096,15 +1190,15 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
 
        md_write_start(mddev, bio); /* wait on superblock update early */
 
-       if (bio_data_dir(bio) == WRITE &&
-           ((bio_end_sector(bio) > mddev->suspend_lo &&
+       if ((bio_end_sector(bio) > mddev->suspend_lo &&
            bio->bi_iter.bi_sector < mddev->suspend_hi) ||
            (mddev_is_clustered(mddev) &&
             md_cluster_ops->area_resyncing(mddev, WRITE,
-                    bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
-               /* As the suspend_* range is controlled by
-                * userspace, we want an interruptible
-                * wait.
+                    bio->bi_iter.bi_sector, bio_end_sector(bio)))) {
+
+               /*
+                * As the suspend_* range is controlled by userspace, we want
+                * an interruptible wait.
                 */
                DEFINE_WAIT(w);
                for (;;) {
@@ -1115,128 +1209,15 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
                            bio->bi_iter.bi_sector >= mddev->suspend_hi ||
                            (mddev_is_clustered(mddev) &&
                             !md_cluster_ops->area_resyncing(mddev, WRITE,
-                                    bio->bi_iter.bi_sector, bio_end_sector(bio))))
+                                    bio->bi_iter.bi_sector,
+                                    bio_end_sector(bio))))
                                break;
                        schedule();
                }
                finish_wait(&conf->wait_barrier, &w);
        }
-
        start_next_window = wait_barrier(conf, bio);
 
-       bitmap = mddev->bitmap;
-
-       /*
-        * make_request() can abort the operation when read-ahead is being
-        * used and no empty request is available.
-        *
-        */
-       r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
-
-       r1_bio->master_bio = bio;
-       r1_bio->sectors = bio_sectors(bio);
-       r1_bio->state = 0;
-       r1_bio->mddev = mddev;
-       r1_bio->sector = bio->bi_iter.bi_sector;
-
-       /* We might need to issue multiple reads to different
-        * devices if there are bad blocks around, so we keep
-        * track of the number of reads in bio->bi_phys_segments.
-        * If this is 0, there is only one r1_bio and no locking
-        * will be needed when requests complete.  If it is
-        * non-zero, then it is the number of not-completed requests.
-        */
-       bio->bi_phys_segments = 0;
-       bio_clear_flag(bio, BIO_SEG_VALID);
-
-       if (rw == READ) {
-               /*
-                * read balancing logic:
-                */
-               int rdisk;
-
-read_again:
-               rdisk = read_balance(conf, r1_bio, &max_sectors);
-
-               if (rdisk < 0) {
-                       /* couldn't find anywhere to read from */
-                       raid_end_bio_io(r1_bio);
-                       return;
-               }
-               mirror = conf->mirrors + rdisk;
-
-               if (test_bit(WriteMostly, &mirror->rdev->flags) &&
-                   bitmap) {
-                       /* Reading from a write-mostly device must
-                        * take care not to over-take any writes
-                        * that are 'behind'
-                        */
-                       raid1_log(mddev, "wait behind writes");
-                       wait_event(bitmap->behind_wait,
-                                  atomic_read(&bitmap->behind_writes) == 0);
-               }
-               r1_bio->read_disk = rdisk;
-               r1_bio->start_next_window = 0;
-
-               read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector,
-                        max_sectors);
-
-               r1_bio->bios[rdisk] = read_bio;
-
-               read_bio->bi_iter.bi_sector = r1_bio->sector +
-                       mirror->rdev->data_offset;
-               read_bio->bi_bdev = mirror->rdev->bdev;
-               read_bio->bi_end_io = raid1_end_read_request;
-               bio_set_op_attrs(read_bio, op, do_sync);
-               if (test_bit(FailFast, &mirror->rdev->flags) &&
-                   test_bit(R1BIO_FailFast, &r1_bio->state))
-                       read_bio->bi_opf |= MD_FAILFAST;
-               read_bio->bi_private = r1_bio;
-
-               if (mddev->gendisk)
-                       trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
-                                             read_bio, disk_devt(mddev->gendisk),
-                                             r1_bio->sector);
-
-               if (max_sectors < r1_bio->sectors) {
-                       /* could not read all from this device, so we will
-                        * need another r1_bio.
-                        */
-
-                       sectors_handled = (r1_bio->sector + max_sectors
-                                          - bio->bi_iter.bi_sector);
-                       r1_bio->sectors = max_sectors;
-                       spin_lock_irq(&conf->device_lock);
-                       if (bio->bi_phys_segments == 0)
-                               bio->bi_phys_segments = 2;
-                       else
-                               bio->bi_phys_segments++;
-                       spin_unlock_irq(&conf->device_lock);
-                       /* Cannot call generic_make_request directly
-                        * as that will be queued in __make_request
-                        * and subsequent mempool_alloc might block waiting
-                        * for it.  So hand bio over to raid1d.
-                        */
-                       reschedule_retry(r1_bio);
-
-                       r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
-
-                       r1_bio->master_bio = bio;
-                       r1_bio->sectors = bio_sectors(bio) - sectors_handled;
-                       r1_bio->state = 0;
-                       r1_bio->mddev = mddev;
-                       r1_bio->sector = bio->bi_iter.bi_sector +
-                               sectors_handled;
-                       goto read_again;
-               } else
-                       generic_make_request(read_bio);
-               return;
-       }
-
-       /*
-        * WRITE:
-        */
        if (conf->pending_count >= max_queued_requests) {
                md_wakeup_thread(mddev->thread);
                raid1_log(mddev, "wait queued");
@@ -1280,8 +1261,7 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
                        int bad_sectors;
                        int is_bad;
 
-                       is_bad = is_badblock(rdev, r1_bio->sector,
-                                            max_sectors,
+                       is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
                                             &first_bad, &bad_sectors);
                        if (is_bad < 0) {
                                /* mustn't write here until the bad block is
@@ -1370,7 +1350,8 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
                        continue;
 
                mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors);
+               bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector,
+                        max_sectors);
 
                if (first_clone) {
                        /* do behind I/O ?
@@ -1464,6 +1445,40 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
        wake_up(&conf->wait_barrier);
 }
 
+static void raid1_make_request(struct mddev *mddev, struct bio *bio)
+{
+       struct r1conf *conf = mddev->private;
+       struct r1bio *r1_bio;
+
+       /*
+        * make_request() can abort the operation when read-ahead is being
+        * used and no empty request is available.
+        *
+        */
+       r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+       r1_bio->master_bio = bio;
+       r1_bio->sectors = bio_sectors(bio);
+       r1_bio->state = 0;
+       r1_bio->mddev = mddev;
+       r1_bio->sector = bio->bi_iter.bi_sector;
+
+       /*
+        * We might need to issue multiple reads to different devices if there
+        * are bad blocks around, so we keep track of the number of reads in
+        * bio->bi_phys_segments.  If this is 0, there is only one r1_bio and
+        * no locking will be needed when requests complete.  If it is
+        * non-zero, then it is the number of not-completed requests.
+        */
+       bio->bi_phys_segments = 0;
+       bio_clear_flag(bio, BIO_SEG_VALID);
+
+       if (bio_data_dir(bio) == READ)
+               raid1_read_request(mddev, bio, r1_bio);
+       else
+               raid1_write_request(mddev, bio, r1_bio);
+}
+
 static void raid1_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct r1conf *conf = mddev->private;
@@ -3246,8 +3261,8 @@ static void *raid1_takeover(struct mddev *mddev)
                if (!IS_ERR(conf)) {
                        /* Array must appear to be quiesced */
                        conf->array_frozen = 1;
-                       clear_bit(MD_HAS_JOURNAL, &mddev->flags);
-                       clear_bit(MD_JOURNAL_CLEAN, &mddev->flags);
+                       mddev_clear_unsupported_flags(mddev,
+                               UNSUPPORTED_MDDEV_FLAGS);
                }
                return conf;
        }
index ab5e86209322fc0d0ed3e2db18a468c6f5054f13..1920756828dfb3fd512e2cb5705f329f10324698 100644 (file)
@@ -1087,23 +1087,122 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
        kfree(plug);
 }
 
-static void __make_request(struct mddev *mddev, struct bio *bio)
+static void raid10_read_request(struct mddev *mddev, struct bio *bio,
+                               struct r10bio *r10_bio)
 {
        struct r10conf *conf = mddev->private;
-       struct r10bio *r10_bio;
        struct bio *read_bio;
+       const int op = bio_op(bio);
+       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       int sectors_handled;
+       int max_sectors;
+       sector_t sectors;
+       struct md_rdev *rdev;
+       int slot;
+
+       /*
+        * Register the new request and wait if the reconstruction
+        * thread has put up a bar for new requests.
+        * Continue immediately if no resync is active currently.
+        */
+       wait_barrier(conf);
+
+       sectors = bio_sectors(bio);
+       while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+           bio->bi_iter.bi_sector < conf->reshape_progress &&
+           bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
+               /*
+                * IO spans the reshape position.  Need to wait for reshape to
+                * pass
+                */
+               raid10_log(conf->mddev, "wait reshape");
+               allow_barrier(conf);
+               wait_event(conf->wait_barrier,
+                          conf->reshape_progress <= bio->bi_iter.bi_sector ||
+                          conf->reshape_progress >= bio->bi_iter.bi_sector +
+                          sectors);
+               wait_barrier(conf);
+       }
+
+read_again:
+       rdev = read_balance(conf, r10_bio, &max_sectors);
+       if (!rdev) {
+               raid_end_bio_io(r10_bio);
+               return;
+       }
+       slot = r10_bio->read_slot;
+
+       read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+       bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector,
+                max_sectors);
+
+       r10_bio->devs[slot].bio = read_bio;
+       r10_bio->devs[slot].rdev = rdev;
+
+       read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
+               choose_data_offset(r10_bio, rdev);
+       read_bio->bi_bdev = rdev->bdev;
+       read_bio->bi_end_io = raid10_end_read_request;
+       bio_set_op_attrs(read_bio, op, do_sync);
+       if (test_bit(FailFast, &rdev->flags) &&
+           test_bit(R10BIO_FailFast, &r10_bio->state))
+               read_bio->bi_opf |= MD_FAILFAST;
+       read_bio->bi_private = r10_bio;
+
+       if (mddev->gendisk)
+               trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
+                                     read_bio, disk_devt(mddev->gendisk),
+                                     r10_bio->sector);
+       if (max_sectors < r10_bio->sectors) {
+               /*
+                * Could not read all from this device, so we will need another
+                * r10_bio.
+                */
+               sectors_handled = (r10_bio->sector + max_sectors
+                                  - bio->bi_iter.bi_sector);
+               r10_bio->sectors = max_sectors;
+               spin_lock_irq(&conf->device_lock);
+               if (bio->bi_phys_segments == 0)
+                       bio->bi_phys_segments = 2;
+               else
+                       bio->bi_phys_segments++;
+               spin_unlock_irq(&conf->device_lock);
+               /*
+                * Cannot call generic_make_request directly as that will be
+                * queued in __generic_make_request and subsequent
+                * mempool_alloc might block waiting for it.  so hand bio over
+                * to raid10d.
+                */
+               reschedule_retry(r10_bio);
+
+               r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+               r10_bio->master_bio = bio;
+               r10_bio->sectors = bio_sectors(bio) - sectors_handled;
+               r10_bio->state = 0;
+               r10_bio->mddev = mddev;
+               r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
+               goto read_again;
+       } else
+               generic_make_request(read_bio);
+       return;
+}
+
+static void raid10_write_request(struct mddev *mddev, struct bio *bio,
+                                struct r10bio *r10_bio)
+{
+       struct r10conf *conf = mddev->private;
        int i;
        const int op = bio_op(bio);
-       const int rw = bio_data_dir(bio);
        const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
        const unsigned long do_fua = (bio->bi_opf & REQ_FUA);
        unsigned long flags;
        struct md_rdev *blocked_rdev;
        struct blk_plug_cb *cb;
        struct raid10_plug_cb *plug = NULL;
+       sector_t sectors;
        int sectors_handled;
        int max_sectors;
-       int sectors;
 
        md_write_start(mddev, bio);
 
@@ -1118,8 +1217,9 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
        while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
            bio->bi_iter.bi_sector < conf->reshape_progress &&
            bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
-               /* IO spans the reshape position.  Need to wait for
-                * reshape to pass
+               /*
+                * IO spans the reshape position.  Need to wait for reshape to
+                * pass
                 */
                raid10_log(conf->mddev, "wait reshape");
                allow_barrier(conf);
@@ -1129,8 +1229,8 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
                           sectors);
                wait_barrier(conf);
        }
+
        if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-           bio_data_dir(bio) == WRITE &&
            (mddev->reshape_backwards
             ? (bio->bi_iter.bi_sector < conf->reshape_safe &&
                bio->bi_iter.bi_sector + sectors > conf->reshape_progress)
@@ -1148,98 +1248,6 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
                conf->reshape_safe = mddev->reshape_position;
        }
 
-       r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
-
-       r10_bio->master_bio = bio;
-       r10_bio->sectors = sectors;
-
-       r10_bio->mddev = mddev;
-       r10_bio->sector = bio->bi_iter.bi_sector;
-       r10_bio->state = 0;
-
-       /* We might need to issue multiple reads to different
-        * devices if there are bad blocks around, so we keep
-        * track of the number of reads in bio->bi_phys_segments.
-        * If this is 0, there is only one r10_bio and no locking
-        * will be needed when the request completes.  If it is
-        * non-zero, then it is the number of not-completed requests.
-        */
-       bio->bi_phys_segments = 0;
-       bio_clear_flag(bio, BIO_SEG_VALID);
-
-       if (rw == READ) {
-               /*
-                * read balancing logic:
-                */
-               struct md_rdev *rdev;
-               int slot;
-
-read_again:
-               rdev = read_balance(conf, r10_bio, &max_sectors);
-               if (!rdev) {
-                       raid_end_bio_io(r10_bio);
-                       return;
-               }
-               slot = r10_bio->read_slot;
-
-               read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector,
-                        max_sectors);
-
-               r10_bio->devs[slot].bio = read_bio;
-               r10_bio->devs[slot].rdev = rdev;
-
-               read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
-                       choose_data_offset(r10_bio, rdev);
-               read_bio->bi_bdev = rdev->bdev;
-               read_bio->bi_end_io = raid10_end_read_request;
-               bio_set_op_attrs(read_bio, op, do_sync);
-               if (test_bit(FailFast, &rdev->flags) &&
-                   test_bit(R10BIO_FailFast, &r10_bio->state))
-                       read_bio->bi_opf |= MD_FAILFAST;
-               read_bio->bi_private = r10_bio;
-
-               if (mddev->gendisk)
-                       trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
-                                             read_bio, disk_devt(mddev->gendisk),
-                                             r10_bio->sector);
-               if (max_sectors < r10_bio->sectors) {
-                       /* Could not read all from this device, so we will
-                        * need another r10_bio.
-                        */
-                       sectors_handled = (r10_bio->sector + max_sectors
-                                          - bio->bi_iter.bi_sector);
-                       r10_bio->sectors = max_sectors;
-                       spin_lock_irq(&conf->device_lock);
-                       if (bio->bi_phys_segments == 0)
-                               bio->bi_phys_segments = 2;
-                       else
-                               bio->bi_phys_segments++;
-                       spin_unlock_irq(&conf->device_lock);
-                       /* Cannot call generic_make_request directly
-                        * as that will be queued in __generic_make_request
-                        * and subsequent mempool_alloc might block
-                        * waiting for it.  so hand bio over to raid10d.
-                        */
-                       reschedule_retry(r10_bio);
-
-                       r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
-
-                       r10_bio->master_bio = bio;
-                       r10_bio->sectors = bio_sectors(bio) - sectors_handled;
-                       r10_bio->state = 0;
-                       r10_bio->mddev = mddev;
-                       r10_bio->sector = bio->bi_iter.bi_sector +
-                               sectors_handled;
-                       goto read_again;
-               } else
-                       generic_make_request(read_bio);
-               return;
-       }
-
-       /*
-        * WRITE:
-        */
        if (conf->pending_count >= max_queued_requests) {
                md_wakeup_thread(mddev->thread);
                raid10_log(mddev, "wait queued");
@@ -1300,8 +1308,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
                        int bad_sectors;
                        int is_bad;
 
-                       is_bad = is_badblock(rdev, dev_sector,
-                                            max_sectors,
+                       is_bad = is_badblock(rdev, dev_sector, max_sectors,
                                             &first_bad, &bad_sectors);
                        if (is_bad < 0) {
                                /* Mustn't write here until the bad block
@@ -1405,8 +1412,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
                        r10_bio->devs[i].bio = mbio;
 
                        mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+
-                                          choose_data_offset(r10_bio,
-                                                             rdev));
+                                          choose_data_offset(r10_bio, rdev));
                        mbio->bi_bdev = rdev->bdev;
                        mbio->bi_end_io = raid10_end_write_request;
                        bio_set_op_attrs(mbio, op, do_sync | do_fua);
@@ -1457,8 +1463,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
                        r10_bio->devs[i].repl_bio = mbio;
 
                        mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr +
-                                          choose_data_offset(
-                                                  r10_bio, rdev));
+                                          choose_data_offset(r10_bio, rdev));
                        mbio->bi_bdev = rdev->bdev;
                        mbio->bi_end_io = raid10_end_write_request;
                        bio_set_op_attrs(mbio, op, do_sync | do_fua);
@@ -1503,6 +1508,36 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
        one_write_done(r10_bio);
 }
 
+static void __make_request(struct mddev *mddev, struct bio *bio)
+{
+       struct r10conf *conf = mddev->private;
+       struct r10bio *r10_bio;
+
+       r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+       r10_bio->master_bio = bio;
+       r10_bio->sectors = bio_sectors(bio);
+
+       r10_bio->mddev = mddev;
+       r10_bio->sector = bio->bi_iter.bi_sector;
+       r10_bio->state = 0;
+
+       /*
+        * We might need to issue multiple reads to different devices if there
+        * are bad blocks around, so we keep track of the number of reads in
+        * bio->bi_phys_segments.  If this is 0, there is only one r10_bio and
+        * no locking will be needed when the request completes.  If it is
+        * non-zero, then it is the number of not-completed requests.
+        */
+       bio->bi_phys_segments = 0;
+       bio_clear_flag(bio, BIO_SEG_VALID);
+
+       if (bio_data_dir(bio) == READ)
+               raid10_read_request(mddev, bio, r10_bio);
+       else
+               raid10_write_request(mddev, bio, r10_bio);
+}
+
 static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 {
        struct r10conf *conf = mddev->private;
index d7bfb6fc8aef8808b143c024f823bab4e6bf640b..0e8ed2c327b07fd849c1720d7b272dd860b949b9 100644 (file)
@@ -1682,8 +1682,7 @@ r5l_recovery_replay_one_stripe(struct r5conf *conf,
 
 static struct stripe_head *
 r5c_recovery_alloc_stripe(struct r5conf *conf,
-                         sector_t stripe_sect,
-                         sector_t log_start)
+                         sector_t stripe_sect)
 {
        struct stripe_head *sh;
 
@@ -1692,7 +1691,6 @@ r5c_recovery_alloc_stripe(struct r5conf *conf,
                return NULL;  /* no more stripe available */
 
        r5l_recovery_reset_stripe(sh);
-       sh->log_start = log_start;
 
        return sh;
 }
@@ -1862,7 +1860,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
                                                stripe_sect);
 
                if (!sh) {
-                       sh = r5c_recovery_alloc_stripe(conf, stripe_sect, ctx->pos);
+                       sh = r5c_recovery_alloc_stripe(conf, stripe_sect);
                        /*
                         * cannot get stripe from raid5_get_active_stripe
                         * try replay some stripes
@@ -1871,7 +1869,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
                                r5c_recovery_replay_stripes(
                                        cached_stripe_list, ctx);
                                sh = r5c_recovery_alloc_stripe(
-                                       conf, stripe_sect, ctx->pos);
+                                       conf, stripe_sect);
                        }
                        if (!sh) {
                                pr_debug("md/raid:%s: Increasing stripe cache size to %d to recovery data on journal.\n",
@@ -1879,8 +1877,8 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
                                        conf->min_nr_stripes * 2);
                                raid5_set_cache_size(mddev,
                                                     conf->min_nr_stripes * 2);
-                               sh = r5c_recovery_alloc_stripe(
-                                       conf, stripe_sect, ctx->pos);
+                               sh = r5c_recovery_alloc_stripe(conf,
+                                                              stripe_sect);
                        }
                        if (!sh) {
                                pr_err("md/raid:%s: Cannot get enough stripes due to memory pressure. Recovery failed.\n",
@@ -1894,7 +1892,6 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
                        if (!test_bit(STRIPE_R5C_CACHING, &sh->state) &&
                            test_bit(R5_Wantwrite, &sh->dev[sh->pd_idx].flags)) {
                                r5l_recovery_replay_one_stripe(conf, sh, ctx);
-                               sh->log_start = ctx->pos;
                                list_move_tail(&sh->lru, cached_stripe_list);
                        }
                        r5l_recovery_load_data(log, sh, ctx, payload,
@@ -1933,8 +1930,6 @@ static void r5c_recovery_load_one_stripe(struct r5l_log *log,
                        set_bit(R5_UPTODATE, &dev->flags);
                }
        }
-       list_add_tail(&sh->r5c, &log->stripe_in_journal_list);
-       atomic_inc(&log->stripe_in_journal_count);
 }
 
 /*
@@ -2070,6 +2065,7 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
        struct stripe_head *sh, *next;
        struct mddev *mddev = log->rdev->mddev;
        struct page *page;
+       sector_t next_checkpoint = MaxSector;
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
@@ -2078,6 +2074,8 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
                return -ENOMEM;
        }
 
+       WARN_ON(list_empty(&ctx->cached_list));
+
        list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
                struct r5l_meta_block *mb;
                int i;
@@ -2123,12 +2121,15 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
                sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page,
                             REQ_OP_WRITE, REQ_FUA, false);
                sh->log_start = ctx->pos;
+               list_add_tail(&sh->r5c, &log->stripe_in_journal_list);
+               atomic_inc(&log->stripe_in_journal_count);
                ctx->pos = write_pos;
                ctx->seq += 1;
-
+               next_checkpoint = sh->log_start;
                list_del_init(&sh->lru);
                raid5_release_stripe(sh);
        }
+       log->next_checkpoint = next_checkpoint;
        __free_page(page);
        return 0;
 }
@@ -2139,7 +2140,6 @@ static int r5l_recovery_log(struct r5l_log *log)
        struct r5l_recovery_ctx ctx;
        int ret;
        sector_t pos;
-       struct stripe_head *sh;
 
        ctx.pos = log->last_checkpoint;
        ctx.seq = log->last_cp_seq;
@@ -2164,16 +2164,13 @@ static int r5l_recovery_log(struct r5l_log *log)
                log->next_checkpoint = ctx.pos;
                r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
                ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
-       } else {
-               sh = list_last_entry(&ctx.cached_list, struct stripe_head, lru);
-               log->next_checkpoint = sh->log_start;
        }
 
        if ((ctx.data_only_stripes == 0) && (ctx.data_parity_stripes == 0))
                pr_debug("md/raid:%s: starting from clean shutdown\n",
                         mdname(mddev));
        else {
-               pr_debug("md/raid:%s: recoverying %d data-only stripes and %d data-parity stripes\n",
+               pr_debug("md/raid:%s: recovering %d data-only stripes and %d data-parity stripes\n",
                         mdname(mddev), ctx.data_only_stripes,
                         ctx.data_parity_stripes);
 
@@ -2418,9 +2415,6 @@ void r5c_finish_stripe_write_out(struct r5conf *conf,
        if (do_wakeup)
                wake_up(&conf->wait_for_overlap);
 
-       if (conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH)
-               return;
-
        spin_lock_irq(&conf->log->stripe_in_journal_lock);
        list_del_init(&sh->r5c);
        spin_unlock_irq(&conf->log->stripe_in_journal_lock);
@@ -2639,14 +2633,16 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
        spin_lock_init(&log->stripe_in_journal_lock);
        atomic_set(&log->stripe_in_journal_count, 0);
 
+       rcu_assign_pointer(conf->log, log);
+
        if (r5l_load_log(log))
                goto error;
 
-       rcu_assign_pointer(conf->log, log);
        set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
        return 0;
 
 error:
+       rcu_assign_pointer(conf->log, NULL);
        md_unregister_thread(&log->reclaim_thread);
 reclaim_thread:
        mempool_destroy(log->meta_pool);
index 06d7279bdd048e66369961194bc1d21567a08446..36c13e4be9c9e5d0cedacb59910e7b4482eb6ddd 100644 (file)
@@ -62,6 +62,8 @@
 #include "raid0.h"
 #include "bitmap.h"
 
+#define UNSUPPORTED_MDDEV_FLAGS        (1L << MD_FAILFAST_SUPPORTED)
+
 #define cpu_to_group(cpu) cpu_to_node(cpu)
 #define ANY_GROUP NUMA_NO_NODE
 
@@ -7829,8 +7831,9 @@ static void *raid5_takeover_raid1(struct mddev *mddev)
        mddev->new_chunk_sectors = chunksect;
 
        ret = setup_conf(mddev);
-       if (!IS_ERR_VALUE(ret))
-               clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+       if (!IS_ERR(ret))
+               mddev_clear_unsupported_flags(mddev,
+                       UNSUPPORTED_MDDEV_FLAGS);
        return ret;
 }
 
index a579a0f258402c0096bc8bdb562d4e1b501fe3fb..22c1aeeb64215d855613422b7a075c2e8a5458bb 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/ti-aemif.h>
 
 #define TA_SHIFT       2
 #define RHOLD_SHIFT    4
@@ -335,6 +336,8 @@ static int aemif_probe(struct platform_device *pdev)
        struct device_node *np = dev->of_node;
        struct device_node *child_np;
        struct aemif_device *aemif;
+       struct aemif_platform_data *pdata;
+       struct of_dev_auxdata *dev_lookup;
 
        if (np == NULL)
                return 0;
@@ -343,6 +346,9 @@ static int aemif_probe(struct platform_device *pdev)
        if (!aemif)
                return -ENOMEM;
 
+       pdata = dev_get_platdata(&pdev->dev);
+       dev_lookup = pdata ? pdata->dev_lookup : NULL;
+
        platform_set_drvdata(pdev, aemif);
 
        aemif->clk = devm_clk_get(dev, NULL);
@@ -390,7 +396,7 @@ static int aemif_probe(struct platform_device *pdev)
         * parameters are set.
         */
        for_each_available_child_of_node(np, child_np) {
-               ret = of_platform_populate(child_np, NULL, NULL, dev);
+               ret = of_platform_populate(child_np, NULL, dev_lookup, dev);
                if (ret < 0)
                        goto error;
        }
index c4e41c26649e9c096675b7d6bdab82e8cc4ce30a..de58762097c4b285baa4f686c87bee856efd63e3 100644 (file)
@@ -100,4 +100,14 @@ config EEPROM_DIGSY_MTC_CFG
 
          If unsure, say N.
 
+config EEPROM_IDT_89HPESX
+       tristate "IDT 89HPESx PCIe-swtiches EEPROM / CSR support"
+       depends on I2C && SYSFS
+       help
+         Enable this driver to get read/write access to EEPROM / CSRs
+         over IDT PCIe-swtich i2c-slave interface.
+
+         This driver can also be built as a module. If so, the module
+         will be called idt_89hpesx.
+
 endmenu
index fc1e81d292673b14732e9268b7cb9cdca9d921fb..90a52624ddeb0c093a7f66e6b8a2b2c6b10e4f55 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_EEPROM_MAX6875)    += max6875.o
 obj-$(CONFIG_EEPROM_93CX6)     += eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)    += eeprom_93xx46.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
+obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
new file mode 100644 (file)
index 0000000..25d47d0
--- /dev/null
@@ -0,0 +1,1587 @@
+/*
+ *   This file is provided under a GPLv2 license.  When using or
+ *   redistributing this file, you may do so under that license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms and conditions of the GNU General Public License,
+ *   version 2, as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but WITHOUT
+ *   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ *   more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, it can be found <http://www.gnu.org/licenses/>.
+ *
+ *   The full GNU General Public License is included in this distribution in
+ *   the file called "COPYING".
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * IDT PCIe-switch NTB Linux driver
+ *
+ * Contact Information:
+ * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru>
+ */
+/*
+ *           NOTE of the IDT 89HPESx SMBus-slave interface driver
+ *    This driver primarily is developed to have an access to EEPROM device of
+ * IDT PCIe-switches. IDT provides a simple SMBus interface to perform IO-
+ * operations from/to EEPROM, which is located at private (so called Master)
+ * SMBus of switches. Using that interface this the driver creates a simple
+ * binary sysfs-file in the device directory:
+ * /sys/bus/i2c/devices/<bus>-<devaddr>/eeprom
+ * In case if read-only flag is specified in the dts-node of device desription,
+ * User-space applications won't be able to write to the EEPROM sysfs-node.
+ *    Additionally IDT 89HPESx SMBus interface has an ability to write/read
+ * data of device CSRs. This driver exposes debugf-file to perform simple IO
+ * operations using that ability for just basic debug purpose. Particularly
+ * next file is created in the specific debugfs-directory:
+ * /sys/kernel/debug/idt_csr/
+ * Format of the debugfs-node is:
+ * $ cat /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>;
+ * <CSR address>:<CSR value>
+ * So reading the content of the file gives current CSR address and it value.
+ * If User-space application wishes to change current CSR address,
+ * it can just write a proper value to the sysfs-file:
+ * $ echo "<CSR address>" > /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>
+ * If it wants to change the CSR value as well, the format of the write
+ * operation is:
+ * $ echo "<CSR address>:<CSR value>" > \
+ *        /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>;
+ * CSR address and value can be any of hexadecimal, decimal or octal format.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/debugfs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+
+#define IDT_NAME               "89hpesx"
+#define IDT_89HPESX_DESC       "IDT 89HPESx SMBus-slave interface driver"
+#define IDT_89HPESX_VER                "1.0"
+
+MODULE_DESCRIPTION(IDT_89HPESX_DESC);
+MODULE_VERSION(IDT_89HPESX_VER);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("T-platforms");
+
+/*
+ * csr_dbgdir - CSR read/write operations Debugfs directory
+ */
+static struct dentry *csr_dbgdir;
+
+/*
+ * struct idt_89hpesx_dev - IDT 89HPESx device data structure
+ * @eesize:    Size of EEPROM in bytes (calculated from "idt,eecompatible")
+ * @eero:      EEPROM Read-only flag
+ * @eeaddr:    EEPROM custom address
+ *
+ * @inieecmd:  Initial cmd value for EEPROM read/write operations
+ * @inicsrcmd: Initial cmd value for CSR read/write operations
+ * @iniccode:  Initialial command code value for IO-operations
+ *
+ * @csr:       CSR address to perform read operation
+ *
+ * @smb_write: SMBus write method
+ * @smb_read:  SMBus read method
+ * @smb_mtx:   SMBus mutex
+ *
+ * @client:    i2c client used to perform IO operations
+ *
+ * @ee_file:   EEPROM read/write sysfs-file
+ * @csr_file:  CSR read/write debugfs-node
+ */
+struct idt_smb_seq;
+struct idt_89hpesx_dev {
+       u32 eesize;
+       bool eero;
+       u8 eeaddr;
+
+       u8 inieecmd;
+       u8 inicsrcmd;
+       u8 iniccode;
+
+       u16 csr;
+
+       int (*smb_write)(struct idt_89hpesx_dev *, const struct idt_smb_seq *);
+       int (*smb_read)(struct idt_89hpesx_dev *, struct idt_smb_seq *);
+       struct mutex smb_mtx;
+
+       struct i2c_client *client;
+
+       struct bin_attribute *ee_file;
+       struct dentry *csr_dir;
+       struct dentry *csr_file;
+};
+
+/*
+ * struct idt_smb_seq - sequence of data to be read/written from/to IDT 89HPESx
+ * @ccode:     SMBus command code
+ * @bytecnt:   Byte count of operation
+ * @data:      Data to by written
+ */
+struct idt_smb_seq {
+       u8 ccode;
+       u8 bytecnt;
+       u8 *data;
+};
+
+/*
+ * struct idt_eeprom_seq - sequence of data to be read/written from/to EEPROM
+ * @cmd:       Transaction CMD
+ * @eeaddr:    EEPROM custom address
+ * @memaddr:   Internal memory address of EEPROM
+ * @data:      Data to be written at the memory address
+ */
+struct idt_eeprom_seq {
+       u8 cmd;
+       u8 eeaddr;
+       u16 memaddr;
+       u8 data;
+} __packed;
+
+/*
+ * struct idt_csr_seq - sequence of data to be read/written from/to CSR
+ * @cmd:       Transaction CMD
+ * @csraddr:   Internal IDT device CSR address
+ * @data:      Data to be read/written from/to the CSR address
+ */
+struct idt_csr_seq {
+       u8 cmd;
+       u16 csraddr;
+       u32 data;
+} __packed;
+
+/*
+ * SMBus command code macros
+ * @CCODE_END:         Indicates the end of transaction
+ * @CCODE_START:       Indicates the start of transaction
+ * @CCODE_CSR:         CSR read/write transaction
+ * @CCODE_EEPROM:      EEPROM read/write transaction
+ * @CCODE_BYTE:                Supplied data has BYTE length
+ * @CCODE_WORD:                Supplied data has WORD length
+ * @CCODE_BLOCK:       Supplied data has variable length passed in bytecnt
+ *                     byte right following CCODE byte
+ */
+#define CCODE_END      ((u8)0x01)
+#define CCODE_START    ((u8)0x02)
+#define CCODE_CSR      ((u8)0x00)
+#define CCODE_EEPROM   ((u8)0x04)
+#define CCODE_BYTE     ((u8)0x00)
+#define CCODE_WORD     ((u8)0x20)
+#define CCODE_BLOCK    ((u8)0x40)
+#define CCODE_PEC      ((u8)0x80)
+
+/*
+ * EEPROM command macros
+ * @EEPROM_OP_WRITE:   EEPROM write operation
+ * @EEPROM_OP_READ:    EEPROM read operation
+ * @EEPROM_USA:                Use specified address of EEPROM
+ * @EEPROM_NAERR:      EEPROM device is not ready to respond
+ * @EEPROM_LAERR:      EEPROM arbitration loss error
+ * @EEPROM_MSS:                EEPROM misplace start & stop bits error
+ * @EEPROM_WR_CNT:     Bytes count to perform write operation
+ * @EEPROM_WRRD_CNT:   Bytes count to write before reading
+ * @EEPROM_RD_CNT:     Bytes count to perform read operation
+ * @EEPROM_DEF_SIZE:   Fall back size of EEPROM
+ * @EEPROM_DEF_ADDR:   Defatul EEPROM address
+ * @EEPROM_TOUT:       Timeout before retry read operation if eeprom is busy
+ */
+#define EEPROM_OP_WRITE        ((u8)0x00)
+#define EEPROM_OP_READ ((u8)0x01)
+#define EEPROM_USA     ((u8)0x02)
+#define EEPROM_NAERR   ((u8)0x08)
+#define EEPROM_LAERR    ((u8)0x10)
+#define EEPROM_MSS     ((u8)0x20)
+#define EEPROM_WR_CNT  ((u8)5)
+#define EEPROM_WRRD_CNT        ((u8)4)
+#define EEPROM_RD_CNT  ((u8)5)
+#define EEPROM_DEF_SIZE        ((u16)4096)
+#define EEPROM_DEF_ADDR        ((u8)0x50)
+#define EEPROM_TOUT    (100)
+
+/*
+ * CSR command macros
+ * @CSR_DWE:           Enable all four bytes of the operation
+ * @CSR_OP_WRITE:      CSR write operation
+ * @CSR_OP_READ:       CSR read operation
+ * @CSR_RERR:          Read operation error
+ * @CSR_WERR:          Write operation error
+ * @CSR_WR_CNT:                Bytes count to perform write operation
+ * @CSR_WRRD_CNT:      Bytes count to write before reading
+ * @CSR_RD_CNT:                Bytes count to perform read operation
+ * @CSR_MAX:           Maximum CSR address
+ * @CSR_DEF:           Default CSR address
+ * @CSR_REAL_ADDR:     CSR real unshifted address
+ */
+#define CSR_DWE                        ((u8)0x0F)
+#define CSR_OP_WRITE           ((u8)0x00)
+#define CSR_OP_READ            ((u8)0x10)
+#define CSR_RERR               ((u8)0x40)
+#define CSR_WERR               ((u8)0x80)
+#define CSR_WR_CNT             ((u8)7)
+#define CSR_WRRD_CNT           ((u8)3)
+#define CSR_RD_CNT             ((u8)7)
+#define CSR_MAX                        ((u32)0x3FFFF)
+#define CSR_DEF                        ((u16)0x0000)
+#define CSR_REAL_ADDR(val)     ((unsigned int)val << 2)
+
+/*
+ * IDT 89HPESx basic register
+ * @IDT_VIDDID_CSR:    PCIe VID and DID of IDT 89HPESx
+ * @IDT_VID_MASK:      Mask of VID
+ */
+#define IDT_VIDDID_CSR ((u32)0x0000)
+#define IDT_VID_MASK   ((u32)0xFFFF)
+
+/*
+ * IDT 89HPESx can send NACK when new command is sent before previous one
+ * fininshed execution. In this case driver retries operation
+ * certain times.
+ * @RETRY_CNT:         Number of retries before giving up and fail
+ * @idt_smb_safe:      Generate a retry loop on corresponding SMBus method
+ */
+#define RETRY_CNT (128)
+#define idt_smb_safe(ops, args...) ({ \
+       int __retry = RETRY_CNT; \
+       s32 __sts; \
+       do { \
+               __sts = i2c_smbus_ ## ops ## _data(args); \
+       } while (__retry-- && __sts < 0); \
+       __sts; \
+})
+
+/*===========================================================================
+ *                         i2c bus level IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_smb_write_byte() - SMBus write method when I2C_SMBUS_BYTE_DATA operation
+ *                        is only available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Sequence of data to be written
+ */
+static int idt_smb_write_byte(struct idt_89hpesx_dev *pdev,
+                             const struct idt_smb_seq *seq)
+{
+       s32 sts;
+       u8 ccode;
+       int idx;
+
+       /* Loop over the supplied data sending byte one-by-one */
+       for (idx = 0; idx < seq->bytecnt; idx++) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_BYTE;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+               if (idx == seq->bytecnt - 1)
+                       ccode |= CCODE_END;
+
+               /* Send data to the device */
+               sts = idt_smb_safe(write_byte, pdev->client, ccode,
+                       seq->data[idx]);
+               if (sts != 0)
+                       return (int)sts;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_smb_read_byte() - SMBus read method when I2C_SMBUS_BYTE_DATA operation
+ *                        is only available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Buffer to read data to
+ */
+static int idt_smb_read_byte(struct idt_89hpesx_dev *pdev,
+                            struct idt_smb_seq *seq)
+{
+       s32 sts;
+       u8 ccode;
+       int idx;
+
+       /* Loop over the supplied buffer receiving byte one-by-one */
+       for (idx = 0; idx < seq->bytecnt; idx++) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_BYTE;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+               if (idx == seq->bytecnt - 1)
+                       ccode |= CCODE_END;
+
+               /* Read data from the device */
+               sts = idt_smb_safe(read_byte, pdev->client, ccode);
+               if (sts < 0)
+                       return (int)sts;
+
+               seq->data[idx] = (u8)sts;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_smb_write_word() - SMBus write method when I2C_SMBUS_BYTE_DATA and
+ *                        I2C_FUNC_SMBUS_WORD_DATA operations are available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Sequence of data to be written
+ */
+static int idt_smb_write_word(struct idt_89hpesx_dev *pdev,
+                             const struct idt_smb_seq *seq)
+{
+       s32 sts;
+       u8 ccode;
+       int idx, evencnt;
+
+       /* Calculate the even count of data to send */
+       evencnt = seq->bytecnt - (seq->bytecnt % 2);
+
+       /* Loop over the supplied data sending two bytes at a time */
+       for (idx = 0; idx < evencnt; idx += 2) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_WORD;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+               if (idx == evencnt - 2)
+                       ccode |= CCODE_END;
+
+               /* Send word data to the device */
+               sts = idt_smb_safe(write_word, pdev->client, ccode,
+                       *(u16 *)&seq->data[idx]);
+               if (sts != 0)
+                       return (int)sts;
+       }
+
+       /* If there is odd number of bytes then send just one last byte */
+       if (seq->bytecnt != evencnt) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_BYTE | CCODE_END;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+
+               /* Send byte data to the device */
+               sts = idt_smb_safe(write_byte, pdev->client, ccode,
+                       seq->data[idx]);
+               if (sts != 0)
+                       return (int)sts;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_smb_read_word() - SMBus read method when I2C_SMBUS_BYTE_DATA and
+ *                       I2C_FUNC_SMBUS_WORD_DATA operations are available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Buffer to read data to
+ */
+static int idt_smb_read_word(struct idt_89hpesx_dev *pdev,
+                            struct idt_smb_seq *seq)
+{
+       s32 sts;
+       u8 ccode;
+       int idx, evencnt;
+
+       /* Calculate the even count of data to send */
+       evencnt = seq->bytecnt - (seq->bytecnt % 2);
+
+       /* Loop over the supplied data reading two bytes at a time */
+       for (idx = 0; idx < evencnt; idx += 2) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_WORD;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+               if (idx == evencnt - 2)
+                       ccode |= CCODE_END;
+
+               /* Read word data from the device */
+               sts = idt_smb_safe(read_word, pdev->client, ccode);
+               if (sts < 0)
+                       return (int)sts;
+
+               *(u16 *)&seq->data[idx] = (u16)sts;
+       }
+
+       /* If there is odd number of bytes then receive just one last byte */
+       if (seq->bytecnt != evencnt) {
+               /* Collect the command code byte */
+               ccode = seq->ccode | CCODE_BYTE | CCODE_END;
+               if (idx == 0)
+                       ccode |= CCODE_START;
+
+               /* Read last data byte from the device */
+               sts = idt_smb_safe(read_byte, pdev->client, ccode);
+               if (sts < 0)
+                       return (int)sts;
+
+               seq->data[idx] = (u8)sts;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_smb_write_block() - SMBus write method when I2C_SMBUS_BLOCK_DATA
+ *                         operation is available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Sequence of data to be written
+ */
+static int idt_smb_write_block(struct idt_89hpesx_dev *pdev,
+                              const struct idt_smb_seq *seq)
+{
+       u8 ccode;
+
+       /* Return error if too much data passed to send */
+       if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+               return -EINVAL;
+
+       /* Collect the command code byte */
+       ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+       /* Send block of data to the device */
+       return idt_smb_safe(write_block, pdev->client, ccode, seq->bytecnt,
+               seq->data);
+}
+
+/*
+ * idt_smb_read_block() - SMBus read method when I2C_SMBUS_BLOCK_DATA
+ *                        operation is available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Buffer to read data to
+ */
+static int idt_smb_read_block(struct idt_89hpesx_dev *pdev,
+                             struct idt_smb_seq *seq)
+{
+       s32 sts;
+       u8 ccode;
+
+       /* Return error if too much data passed to send */
+       if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+               return -EINVAL;
+
+       /* Collect the command code byte */
+       ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+       /* Read block of data from the device */
+       sts = idt_smb_safe(read_block, pdev->client, ccode, seq->data);
+       if (sts != seq->bytecnt)
+               return (sts < 0 ? sts : -ENODATA);
+
+       return 0;
+}
+
+/*
+ * idt_smb_write_i2c_block() - SMBus write method when I2C_SMBUS_I2C_BLOCK_DATA
+ *                             operation is available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Sequence of data to be written
+ *
+ * NOTE It's usual SMBus write block operation, except the actual data length is
+ * sent as first byte of data
+ */
+static int idt_smb_write_i2c_block(struct idt_89hpesx_dev *pdev,
+                                  const struct idt_smb_seq *seq)
+{
+       u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1];
+
+       /* Return error if too much data passed to send */
+       if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+               return -EINVAL;
+
+       /* Collect the data to send. Length byte must be added prior the data */
+       buf[0] = seq->bytecnt;
+       memcpy(&buf[1], seq->data, seq->bytecnt);
+
+       /* Collect the command code byte */
+       ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+       /* Send length and block of data to the device */
+       return idt_smb_safe(write_i2c_block, pdev->client, ccode,
+               seq->bytecnt + 1, buf);
+}
+
+/*
+ * idt_smb_read_i2c_block() - SMBus read method when I2C_SMBUS_I2C_BLOCK_DATA
+ *                            operation is available
+ * @pdev:      Pointer to the driver data
+ * @seq:       Buffer to read data to
+ *
+ * NOTE It's usual SMBus read block operation, except the actual data length is
+ * retrieved as first byte of data
+ */
+static int idt_smb_read_i2c_block(struct idt_89hpesx_dev *pdev,
+                                 struct idt_smb_seq *seq)
+{
+       u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1];
+       s32 sts;
+
+       /* Return error if too much data passed to send */
+       if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+               return -EINVAL;
+
+       /* Collect the command code byte */
+       ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+       /* Read length and block of data from the device */
+       sts = idt_smb_safe(read_i2c_block, pdev->client, ccode,
+               seq->bytecnt + 1, buf);
+       if (sts != seq->bytecnt + 1)
+               return (sts < 0 ? sts : -ENODATA);
+       if (buf[0] != seq->bytecnt)
+               return -ENODATA;
+
+       /* Copy retrieved data to the output data buffer */
+       memcpy(seq->data, &buf[1], seq->bytecnt);
+
+       return 0;
+}
+
+/*===========================================================================
+ *                          EEPROM IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_eeprom_read_byte() - read just one byte from EEPROM
+ * @pdev:      Pointer to the driver data
+ * @memaddr:   Start EEPROM memory address
+ * @data:      Data to be written to EEPROM
+ */
+static int idt_eeprom_read_byte(struct idt_89hpesx_dev *pdev, u16 memaddr,
+                               u8 *data)
+{
+       struct device *dev = &pdev->client->dev;
+       struct idt_eeprom_seq eeseq;
+       struct idt_smb_seq smbseq;
+       int ret, retry;
+
+       /* Initialize SMBus sequence fields */
+       smbseq.ccode = pdev->iniccode | CCODE_EEPROM;
+       smbseq.data = (u8 *)&eeseq;
+
+       /*
+        * Sometimes EEPROM may respond with NACK if it's busy with previous
+        * operation, so we need to perform a few attempts of read cycle
+        */
+       retry = RETRY_CNT;
+       do {
+               /* Send EEPROM memory address to read data from */
+               smbseq.bytecnt = EEPROM_WRRD_CNT;
+               eeseq.cmd = pdev->inieecmd | EEPROM_OP_READ;
+               eeseq.eeaddr = pdev->eeaddr;
+               eeseq.memaddr = cpu_to_le16(memaddr);
+               ret = pdev->smb_write(pdev, &smbseq);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to init eeprom addr 0x%02hhx",
+                               memaddr);
+                       break;
+               }
+
+               /* Perform read operation */
+               smbseq.bytecnt = EEPROM_RD_CNT;
+               ret = pdev->smb_read(pdev, &smbseq);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to read eeprom data 0x%02hhx",
+                               memaddr);
+                       break;
+               }
+
+               /* Restart read operation if the device is busy */
+               if (retry && (eeseq.cmd & EEPROM_NAERR)) {
+                       dev_dbg(dev, "EEPROM busy, retry reading after %d ms",
+                               EEPROM_TOUT);
+                       msleep(EEPROM_TOUT);
+                       continue;
+               }
+
+               /* Check whether IDT successfully read data from EEPROM */
+               if (eeseq.cmd & (EEPROM_NAERR | EEPROM_LAERR | EEPROM_MSS)) {
+                       dev_err(dev,
+                               "Communication with eeprom failed, cmd 0x%hhx",
+                               eeseq.cmd);
+                       ret = -EREMOTEIO;
+                       break;
+               }
+
+               /* Save retrieved data and exit the loop */
+               *data = eeseq.data;
+               break;
+       } while (retry--);
+
+       /* Return the status of operation */
+       return ret;
+}
+
+/*
+ * idt_eeprom_write() - EEPROM write operation
+ * @pdev:      Pointer to the driver data
+ * @memaddr:   Start EEPROM memory address
+ * @len:       Length of data to be written
+ * @data:      Data to be written to EEPROM
+ */
+static int idt_eeprom_write(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len,
+                           const u8 *data)
+{
+       struct device *dev = &pdev->client->dev;
+       struct idt_eeprom_seq eeseq;
+       struct idt_smb_seq smbseq;
+       int ret;
+       u16 idx;
+
+       /* Initialize SMBus sequence fields */
+       smbseq.ccode = pdev->iniccode | CCODE_EEPROM;
+       smbseq.data = (u8 *)&eeseq;
+
+       /* Send data byte-by-byte, checking if it is successfully written */
+       for (idx = 0; idx < len; idx++, memaddr++) {
+               /* Lock IDT SMBus device */
+               mutex_lock(&pdev->smb_mtx);
+
+               /* Perform write operation */
+               smbseq.bytecnt = EEPROM_WR_CNT;
+               eeseq.cmd = pdev->inieecmd | EEPROM_OP_WRITE;
+               eeseq.eeaddr = pdev->eeaddr;
+               eeseq.memaddr = cpu_to_le16(memaddr);
+               eeseq.data = data[idx];
+               ret = pdev->smb_write(pdev, &smbseq);
+               if (ret != 0) {
+                       dev_err(dev,
+                               "Failed to write 0x%04hx:0x%02hhx to eeprom",
+                               memaddr, data[idx]);
+                       goto err_mutex_unlock;
+               }
+
+               /*
+                * Check whether the data is successfully written by reading
+                * from the same EEPROM memory address.
+                */
+               eeseq.data = ~data[idx];
+               ret = idt_eeprom_read_byte(pdev, memaddr, &eeseq.data);
+               if (ret != 0)
+                       goto err_mutex_unlock;
+
+               /* Check whether the read byte is the same as written one */
+               if (eeseq.data != data[idx]) {
+                       dev_err(dev, "Values don't match 0x%02hhx != 0x%02hhx",
+                               eeseq.data, data[idx]);
+                       ret = -EREMOTEIO;
+                       goto err_mutex_unlock;
+               }
+
+               /* Unlock IDT SMBus device */
+err_mutex_unlock:
+               mutex_unlock(&pdev->smb_mtx);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_eeprom_read() - EEPROM read operation
+ * @pdev:      Pointer to the driver data
+ * @memaddr:   Start EEPROM memory address
+ * @len:       Length of data to read
+ * @buf:       Buffer to read data to
+ */
+static int idt_eeprom_read(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len,
+                          u8 *buf)
+{
+       int ret;
+       u16 idx;
+
+       /* Read data byte-by-byte, retrying if it wasn't successful */
+       for (idx = 0; idx < len; idx++, memaddr++) {
+               /* Lock IDT SMBus device */
+               mutex_lock(&pdev->smb_mtx);
+
+               /* Just read the byte to the buffer */
+               ret = idt_eeprom_read_byte(pdev, memaddr, &buf[idx]);
+
+               /* Unlock IDT SMBus device */
+               mutex_unlock(&pdev->smb_mtx);
+
+               /* Return error if read operation failed */
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*===========================================================================
+ *                          CSR IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_csr_write() - CSR write operation
+ * @pdev:      Pointer to the driver data
+ * @csraddr:   CSR address (with no two LS bits)
+ * @data:      Data to be written to CSR
+ */
+static int idt_csr_write(struct idt_89hpesx_dev *pdev, u16 csraddr,
+                        const u32 data)
+{
+       struct device *dev = &pdev->client->dev;
+       struct idt_csr_seq csrseq;
+       struct idt_smb_seq smbseq;
+       int ret;
+
+       /* Initialize SMBus sequence fields */
+       smbseq.ccode = pdev->iniccode | CCODE_CSR;
+       smbseq.data = (u8 *)&csrseq;
+
+       /* Lock IDT SMBus device */
+       mutex_lock(&pdev->smb_mtx);
+
+       /* Perform write operation */
+       smbseq.bytecnt = CSR_WR_CNT;
+       csrseq.cmd = pdev->inicsrcmd | CSR_OP_WRITE;
+       csrseq.csraddr = cpu_to_le16(csraddr);
+       csrseq.data = cpu_to_le32(data);
+       ret = pdev->smb_write(pdev, &smbseq);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write 0x%04x: 0x%04x to csr",
+                       CSR_REAL_ADDR(csraddr), data);
+               goto err_mutex_unlock;
+       }
+
+       /* Send CSR address to read data from */
+       smbseq.bytecnt = CSR_WRRD_CNT;
+       csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ;
+       ret = pdev->smb_write(pdev, &smbseq);
+       if (ret != 0) {
+               dev_err(dev, "Failed to init csr address 0x%04x",
+                       CSR_REAL_ADDR(csraddr));
+               goto err_mutex_unlock;
+       }
+
+       /* Perform read operation */
+       smbseq.bytecnt = CSR_RD_CNT;
+       ret = pdev->smb_read(pdev, &smbseq);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read csr 0x%04x",
+                       CSR_REAL_ADDR(csraddr));
+               goto err_mutex_unlock;
+       }
+
+       /* Check whether IDT successfully retrieved CSR data */
+       if (csrseq.cmd & (CSR_RERR | CSR_WERR)) {
+               dev_err(dev, "IDT failed to perform CSR r/w");
+               ret = -EREMOTEIO;
+               goto err_mutex_unlock;
+       }
+
+       /* Unlock IDT SMBus device */
+err_mutex_unlock:
+       mutex_unlock(&pdev->smb_mtx);
+
+       return ret;
+}
+
+/*
+ * idt_csr_read() - CSR read operation
+ * @pdev:      Pointer to the driver data
+ * @csraddr:   CSR address (with no two LS bits)
+ * @data:      Data to be written to CSR
+ */
+static int idt_csr_read(struct idt_89hpesx_dev *pdev, u16 csraddr, u32 *data)
+{
+       struct device *dev = &pdev->client->dev;
+       struct idt_csr_seq csrseq;
+       struct idt_smb_seq smbseq;
+       int ret;
+
+       /* Initialize SMBus sequence fields */
+       smbseq.ccode = pdev->iniccode | CCODE_CSR;
+       smbseq.data = (u8 *)&csrseq;
+
+       /* Lock IDT SMBus device */
+       mutex_lock(&pdev->smb_mtx);
+
+       /* Send CSR register address before reading it */
+       smbseq.bytecnt = CSR_WRRD_CNT;
+       csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ;
+       csrseq.csraddr = cpu_to_le16(csraddr);
+       ret = pdev->smb_write(pdev, &smbseq);
+       if (ret != 0) {
+               dev_err(dev, "Failed to init csr address 0x%04x",
+                       CSR_REAL_ADDR(csraddr));
+               goto err_mutex_unlock;
+       }
+
+       /* Perform read operation */
+       smbseq.bytecnt = CSR_RD_CNT;
+       ret = pdev->smb_read(pdev, &smbseq);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read csr 0x%04hx",
+                       CSR_REAL_ADDR(csraddr));
+               goto err_mutex_unlock;
+       }
+
+       /* Check whether IDT successfully retrieved CSR data */
+       if (csrseq.cmd & (CSR_RERR | CSR_WERR)) {
+               dev_err(dev, "IDT failed to perform CSR r/w");
+               ret = -EREMOTEIO;
+               goto err_mutex_unlock;
+       }
+
+       /* Save data retrieved from IDT */
+       *data = le32_to_cpu(csrseq.data);
+
+       /* Unlock IDT SMBus device */
+err_mutex_unlock:
+       mutex_unlock(&pdev->smb_mtx);
+
+       return ret;
+}
+
+/*===========================================================================
+ *                          Sysfs/debugfs-nodes IO-operations
+ *===========================================================================
+ */
+
+/*
+ * eeprom_write() - EEPROM sysfs-node write callback
+ * @filep:     Pointer to the file system node
+ * @kobj:      Pointer to the kernel object related to the sysfs-node
+ * @attr:      Attributes of the file
+ * @buf:       Buffer to write data to
+ * @off:       Offset at which data should be written to
+ * @count:     Number of bytes to write
+ */
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+                           struct bin_attribute *attr,
+                           char *buf, loff_t off, size_t count)
+{
+       struct idt_89hpesx_dev *pdev;
+       int ret;
+
+       /* Retrieve driver data */
+       pdev = dev_get_drvdata(kobj_to_dev(kobj));
+
+       /* Perform EEPROM write operation */
+       ret = idt_eeprom_write(pdev, (u16)off, (u16)count, (u8 *)buf);
+       return (ret != 0 ? ret : count);
+}
+
+/*
+ * eeprom_read() - EEPROM sysfs-node read callback
+ * @filep:     Pointer to the file system node
+ * @kobj:      Pointer to the kernel object related to the sysfs-node
+ * @attr:      Attributes of the file
+ * @buf:       Buffer to write data to
+ * @off:       Offset at which data should be written to
+ * @count:     Number of bytes to write
+ */
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+                          struct bin_attribute *attr,
+                          char *buf, loff_t off, size_t count)
+{
+       struct idt_89hpesx_dev *pdev;
+       int ret;
+
+       /* Retrieve driver data */
+       pdev = dev_get_drvdata(kobj_to_dev(kobj));
+
+       /* Perform EEPROM read operation */
+       ret = idt_eeprom_read(pdev, (u16)off, (u16)count, (u8 *)buf);
+       return (ret != 0 ? ret : count);
+}
+
+/*
+ * idt_dbgfs_csr_write() - CSR debugfs-node write callback
+ * @filep:     Pointer to the file system file descriptor
+ * @buf:       Buffer to read data from
+ * @count:     Size of the buffer
+ * @offp:      Offset within the file
+ *
+ * It accepts either "0x<reg addr>:0x<value>" for saving register address
+ * and writing value to specified DWORD register or "0x<reg addr>" for
+ * just saving register address in order to perform next read operation.
+ *
+ * WARNING No spaces are allowed. Incoming string must be strictly formated as:
+ * "<reg addr>:<value>". Register address must be aligned within 4 bytes
+ * (one DWORD).
+ */
+static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf,
+                                  size_t count, loff_t *offp)
+{
+       struct idt_89hpesx_dev *pdev = filep->private_data;
+       char *colon_ch, *csraddr_str, *csrval_str;
+       int ret, csraddr_len, csrval_len;
+       u32 csraddr, csrval;
+       char *buf;
+
+       /* Copy data from User-space */
+       buf = kmalloc(count + 1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = simple_write_to_buffer(buf, count, offp, ubuf, count);
+       if (ret < 0)
+               goto free_buf;
+       buf[count] = 0;
+
+       /* Find position of colon in the buffer */
+       colon_ch = strnchr(buf, count, ':');
+
+       /*
+        * If there is colon passed then new CSR value should be parsed as
+        * well, so allocate buffer for CSR address substring.
+        * If no colon is found, then string must have just one number with
+        * no new CSR value
+        */
+       if (colon_ch != NULL) {
+               csraddr_len = colon_ch - buf;
+               csraddr_str =
+                       kmalloc(sizeof(char)*(csraddr_len + 1), GFP_KERNEL);
+               if (csraddr_str == NULL)
+                       return -ENOMEM;
+               /* Copy the register address to the substring buffer */
+               strncpy(csraddr_str, buf, csraddr_len);
+               csraddr_str[csraddr_len] = '\0';
+               /* Register value must follow the colon */
+               csrval_str = colon_ch + 1;
+               csrval_len = strnlen(csrval_str, count - csraddr_len);
+       } else /* if (str_colon == NULL) */ {
+               csraddr_str = (char *)buf; /* Just to shut warning up */
+               csraddr_len = strnlen(csraddr_str, count);
+               csrval_str = NULL;
+               csrval_len = 0;
+       }
+
+       /* Convert CSR address to u32 value */
+       ret = kstrtou32(csraddr_str, 0, &csraddr);
+       if (ret != 0)
+               goto free_csraddr_str;
+
+       /* Check whether passed register address is valid */
+       if (csraddr > CSR_MAX || !IS_ALIGNED(csraddr, SZ_4)) {
+               ret = -EINVAL;
+               goto free_csraddr_str;
+       }
+
+       /* Shift register address to the right so to have u16 address */
+       pdev->csr = (csraddr >> 2);
+
+       /* Parse new CSR value and send it to IDT, if colon has been found */
+       if (colon_ch != NULL) {
+               ret = kstrtou32(csrval_str, 0, &csrval);
+               if (ret != 0)
+                       goto free_csraddr_str;
+
+               ret = idt_csr_write(pdev, pdev->csr, csrval);
+               if (ret != 0)
+                       goto free_csraddr_str;
+       }
+
+       /* Free memory only if colon has been found */
+free_csraddr_str:
+       if (colon_ch != NULL)
+               kfree(csraddr_str);
+
+       /* Free buffer allocated for data retrieved from User-space */
+free_buf:
+       kfree(buf);
+
+       return (ret != 0 ? ret : count);
+}
+
+/*
+ * idt_dbgfs_csr_read() - CSR debugfs-node read callback
+ * @filep:     Pointer to the file system file descriptor
+ * @buf:       Buffer to write data to
+ * @count:     Size of the buffer
+ * @offp:      Offset within the file
+ *
+ * It just prints the pair "0x<reg addr>:0x<value>" to passed buffer.
+ */
+#define CSRBUF_SIZE    ((size_t)32)
+static ssize_t idt_dbgfs_csr_read(struct file *filep, char __user *ubuf,
+                                 size_t count, loff_t *offp)
+{
+       struct idt_89hpesx_dev *pdev = filep->private_data;
+       u32 csraddr, csrval;
+       char buf[CSRBUF_SIZE];
+       int ret, size;
+
+       /* Perform CSR read operation */
+       ret = idt_csr_read(pdev, pdev->csr, &csrval);
+       if (ret != 0)
+               return ret;
+
+       /* Shift register address to the left so to have real address */
+       csraddr = ((u32)pdev->csr << 2);
+
+       /* Print the "0x<reg addr>:0x<value>" to buffer */
+       size = snprintf(buf, CSRBUF_SIZE, "0x%05x:0x%08x\n",
+               (unsigned int)csraddr, (unsigned int)csrval);
+
+       /* Copy data to User-space */
+       return simple_read_from_buffer(ubuf, count, offp, buf, size);
+}
+
+/*
+ * eeprom_attribute - EEPROM sysfs-node attributes
+ *
+ * NOTE Size will be changed in compliance with OF node. EEPROM attribute will
+ * be read-only as well if the corresponding flag is specified in OF node.
+ */
+static BIN_ATTR_RW(eeprom, EEPROM_DEF_SIZE);
+
+/*
+ * csr_dbgfs_ops - CSR debugfs-node read/write operations
+ */
+static const struct file_operations csr_dbgfs_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .write = idt_dbgfs_csr_write,
+       .read = idt_dbgfs_csr_read
+};
+
+/*===========================================================================
+ *                       Driver init/deinit methods
+ *===========================================================================
+ */
+
+/*
+ * idt_set_defval() - disable EEPROM access by default
+ * @pdev:      Pointer to the driver data
+ */
+static void idt_set_defval(struct idt_89hpesx_dev *pdev)
+{
+       /* If OF info is missing then use next values */
+       pdev->eesize = 0;
+       pdev->eero = true;
+       pdev->inieecmd = 0;
+       pdev->eeaddr = 0;
+}
+
+#ifdef CONFIG_OF
+static const struct i2c_device_id ee_ids[];
+/*
+ * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs
+ */
+static const struct i2c_device_id *idt_ee_match_id(struct device_node *node)
+{
+       const struct i2c_device_id *id = ee_ids;
+       char devname[I2C_NAME_SIZE];
+
+       /* Retrieve the device name without manufacturer name */
+       if (of_modalias_node(node, devname, sizeof(devname)))
+               return NULL;
+
+       /* Search through the device name */
+        while (id->name[0]) {
+                if (strcmp(devname, id->name) == 0)
+                        return id;
+                id++;
+        }
+        return NULL;
+}
+
+/*
+ * idt_get_ofdata() - get IDT i2c-device parameters from device tree
+ * @pdev:      Pointer to the driver data
+ */
+static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
+{
+       const struct device_node *node = pdev->client->dev.of_node;
+       struct device *dev = &pdev->client->dev;
+
+       /* Read dts node parameters */
+       if (node) {
+               const struct i2c_device_id *ee_id = NULL;
+               struct device_node *child;
+               const __be32 *addr_be;
+               int len;
+
+               /* Walk through all child nodes looking for compatible one */
+               for_each_available_child_of_node(node, child) {
+                       ee_id = idt_ee_match_id(child);
+                       if (IS_ERR_OR_NULL(ee_id)) {
+                               dev_warn(dev, "Skip unsupported child node %s",
+                                       child->full_name);
+                               continue;
+                       } else
+                               break;
+               }
+
+               /* If there is no child EEPROM device, then set zero size */
+               if (!ee_id) {
+                       idt_set_defval(pdev);
+                       return;
+               }
+
+               /* Retrieve EEPROM size */
+               pdev->eesize = (u32)ee_id->driver_data;
+
+               /* Get custom EEPROM address from 'reg' attribute */
+               addr_be = of_get_property(child, "reg", &len);
+               if (!addr_be || (len < sizeof(*addr_be))) {
+                       dev_warn(dev, "No reg on %s, use default address %d",
+                               child->full_name, EEPROM_DEF_ADDR);
+                       pdev->inieecmd = 0;
+                       pdev->eeaddr = EEPROM_DEF_ADDR << 1;
+               } else {
+                       pdev->inieecmd = EEPROM_USA;
+                       pdev->eeaddr = be32_to_cpup(addr_be) << 1;
+               }
+
+               /* Check EEPROM 'read-only' flag */
+               if (of_get_property(child, "read-only", NULL))
+                       pdev->eero = true;
+               else /* if (!of_get_property(node, "read-only", NULL)) */
+                       pdev->eero = false;
+
+               dev_dbg(dev, "EEPROM of %u bytes found by %hhu",
+                       pdev->eesize, pdev->eeaddr);
+       } else {
+               dev_warn(dev, "No dts node, EEPROM access disabled");
+               idt_set_defval(pdev);
+       }
+}
+#else
+static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
+{
+       struct device *dev = &pdev->client->dev;
+
+       dev_warn(dev, "OF table is unsupported, EEPROM access disabled");
+
+       /* Nothing we can do, just set the default values */
+       idt_set_defval(pdev);
+}
+#endif /* CONFIG_OF */
+
+/*
+ * idt_create_pdev() - create and init data structure of the driver
+ * @client:    i2c client of IDT PCIe-switch device
+ */
+static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client)
+{
+       struct idt_89hpesx_dev *pdev;
+
+       /* Allocate memory for driver data */
+       pdev = devm_kmalloc(&client->dev, sizeof(struct idt_89hpesx_dev),
+               GFP_KERNEL);
+       if (pdev == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       /* Initialize basic fields of the data */
+       pdev->client = client;
+       i2c_set_clientdata(client, pdev);
+
+       /* Read OF nodes information */
+       idt_get_ofdata(pdev);
+
+       /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */
+       pdev->inicsrcmd = CSR_DWE;
+       pdev->csr = CSR_DEF;
+
+       /* Enable Packet Error Checking if it's supported by adapter */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) {
+               pdev->iniccode = CCODE_PEC;
+               client->flags |= I2C_CLIENT_PEC;
+       } else /* PEC is unsupported */ {
+               pdev->iniccode = 0;
+       }
+
+       return pdev;
+}
+
+/*
+ * idt_free_pdev() - free data structure of the driver
+ * @pdev:      Pointer to the driver data
+ */
+static void idt_free_pdev(struct idt_89hpesx_dev *pdev)
+{
+       /* Clear driver data from device private field */
+       i2c_set_clientdata(pdev->client, NULL);
+
+       /* Just free memory allocated for data */
+       devm_kfree(&pdev->client->dev, pdev);
+}
+
+/*
+ * idt_set_smbus_ops() - set supported SMBus operations
+ * @pdev:      Pointer to the driver data
+ * Return status of smbus check operations
+ */
+static int idt_set_smbus_ops(struct idt_89hpesx_dev *pdev)
+{
+       struct i2c_adapter *adapter = pdev->client->adapter;
+       struct device *dev = &pdev->client->dev;
+
+       /* Check i2c adapter read functionality */
+       if (i2c_check_functionality(adapter,
+                                   I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
+               pdev->smb_read = idt_smb_read_block;
+               dev_dbg(dev, "SMBus block-read op chosen");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+               pdev->smb_read = idt_smb_read_i2c_block;
+               dev_dbg(dev, "SMBus i2c-block-read op chosen");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_READ_WORD_DATA) &&
+                  i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+               pdev->smb_read = idt_smb_read_word;
+               dev_warn(dev, "Use slow word/byte SMBus read ops");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+               pdev->smb_read = idt_smb_read_byte;
+               dev_warn(dev, "Use slow byte SMBus read op");
+       } else /* no supported smbus read operations */ {
+               dev_err(dev, "No supported SMBus read op");
+               return -EPFNOSUPPORT;
+       }
+
+       /* Check i2c adapter write functionality */
+       if (i2c_check_functionality(adapter,
+                                   I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) {
+               pdev->smb_write = idt_smb_write_block;
+               dev_dbg(dev, "SMBus block-write op chosen");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+               pdev->smb_write = idt_smb_write_i2c_block;
+               dev_dbg(dev, "SMBus i2c-block-write op chosen");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_WRITE_WORD_DATA) &&
+                  i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+               pdev->smb_write = idt_smb_write_word;
+               dev_warn(dev, "Use slow word/byte SMBus write op");
+       } else if (i2c_check_functionality(adapter,
+                                          I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+               pdev->smb_write = idt_smb_write_byte;
+               dev_warn(dev, "Use slow byte SMBus write op");
+       } else /* no supported smbus write operations */ {
+               dev_err(dev, "No supported SMBus write op");
+               return -EPFNOSUPPORT;
+       }
+
+       /* Initialize IDT SMBus slave interface mutex */
+       mutex_init(&pdev->smb_mtx);
+
+       return 0;
+}
+
+/*
+ * idt_check_dev() - check whether it's really IDT 89HPESx device
+ * @pdev:      Pointer to the driver data
+ * Return status of i2c adapter check operation
+ */
+static int idt_check_dev(struct idt_89hpesx_dev *pdev)
+{
+       struct device *dev = &pdev->client->dev;
+       u32 viddid;
+       int ret;
+
+       /* Read VID and DID directly from IDT memory space */
+       ret = idt_csr_read(pdev, IDT_VIDDID_CSR, &viddid);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read VID/DID");
+               return ret;
+       }
+
+       /* Check whether it's IDT device */
+       if ((viddid & IDT_VID_MASK) != PCI_VENDOR_ID_IDT) {
+               dev_err(dev, "Got unsupported VID/DID: 0x%08x", viddid);
+               return -ENODEV;
+       }
+
+       dev_info(dev, "Found IDT 89HPES device VID:0x%04x, DID:0x%04x",
+               (viddid & IDT_VID_MASK), (viddid >> 16));
+
+       return 0;
+}
+
+/*
+ * idt_create_sysfs_files() - create sysfs attribute files
+ * @pdev:      Pointer to the driver data
+ * Return status of operation
+ */
+static int idt_create_sysfs_files(struct idt_89hpesx_dev *pdev)
+{
+       struct device *dev = &pdev->client->dev;
+       int ret;
+
+       /* Don't do anything if EEPROM isn't accessible */
+       if (pdev->eesize == 0) {
+               dev_dbg(dev, "Skip creating sysfs-files");
+               return 0;
+       }
+
+       /* Allocate memory for attribute file */
+       pdev->ee_file = devm_kmalloc(dev, sizeof(*pdev->ee_file), GFP_KERNEL);
+       if (!pdev->ee_file)
+               return -ENOMEM;
+
+       /* Copy the declared EEPROM attr structure to change some of fields */
+       memcpy(pdev->ee_file, &bin_attr_eeprom, sizeof(*pdev->ee_file));
+
+       /* In case of read-only EEPROM get rid of write ability */
+       if (pdev->eero) {
+               pdev->ee_file->attr.mode &= ~0200;
+               pdev->ee_file->write = NULL;
+       }
+       /* Create EEPROM sysfs file */
+       pdev->ee_file->size = pdev->eesize;
+       ret = sysfs_create_bin_file(&dev->kobj, pdev->ee_file);
+       if (ret != 0) {
+               kfree(pdev->ee_file);
+               dev_err(dev, "Failed to create EEPROM sysfs-node");
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_remove_sysfs_files() - remove sysfs attribute files
+ * @pdev:      Pointer to the driver data
+ */
+static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev)
+{
+       struct device *dev = &pdev->client->dev;
+
+       /* Don't do anything if EEPROM wasn't accessible */
+       if (pdev->eesize == 0)
+               return;
+
+       /* Remove EEPROM sysfs file */
+       sysfs_remove_bin_file(&dev->kobj, pdev->ee_file);
+
+       /* Free memory allocated for bin_attribute structure */
+       kfree(pdev->ee_file);
+}
+
+/*
+ * idt_create_dbgfs_files() - create debugfs files
+ * @pdev:      Pointer to the driver data
+ */
+#define CSRNAME_LEN    ((size_t)32)
+static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev)
+{
+       struct i2c_client *cli = pdev->client;
+       char fname[CSRNAME_LEN];
+
+       /* Create Debugfs directory for CSR file */
+       snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr);
+       pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir);
+
+       /* Create Debugfs file for CSR read/write operations */
+       pdev->csr_file = debugfs_create_file(cli->name, 0600,
+               pdev->csr_dir, pdev, &csr_dbgfs_ops);
+}
+
+/*
+ * idt_remove_dbgfs_files() - remove debugfs files
+ * @pdev:      Pointer to the driver data
+ */
+static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev)
+{
+       /* Remove CSR directory and it sysfs-node */
+       debugfs_remove_recursive(pdev->csr_dir);
+}
+
+/*
+ * idt_probe() - IDT 89HPESx driver probe() callback method
+ */
+static int idt_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct idt_89hpesx_dev *pdev;
+       int ret;
+
+       /* Create driver data */
+       pdev = idt_create_pdev(client);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       /* Set SMBus operations */
+       ret = idt_set_smbus_ops(pdev);
+       if (ret != 0)
+               goto err_free_pdev;
+
+       /* Check whether it is truly IDT 89HPESx device */
+       ret = idt_check_dev(pdev);
+       if (ret != 0)
+               goto err_free_pdev;
+
+       /* Create sysfs files */
+       ret = idt_create_sysfs_files(pdev);
+       if (ret != 0)
+               goto err_free_pdev;
+
+       /* Create debugfs files */
+       idt_create_dbgfs_files(pdev);
+
+       return 0;
+
+err_free_pdev:
+       idt_free_pdev(pdev);
+
+       return ret;
+}
+
+/*
+ * idt_remove() - IDT 89HPESx driver remove() callback method
+ */
+static int idt_remove(struct i2c_client *client)
+{
+       struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client);
+
+       /* Remove debugfs files first */
+       idt_remove_dbgfs_files(pdev);
+
+       /* Remove sysfs files */
+       idt_remove_sysfs_files(pdev);
+
+       /* Discard driver data structure */
+       idt_free_pdev(pdev);
+
+       return 0;
+}
+
+/*
+ * ee_ids - array of supported EEPROMs
+ */
+static const struct i2c_device_id ee_ids[] = {
+       { "24c32",  4096},
+       { "24c64",  8192},
+       { "24c128", 16384},
+       { "24c256", 32768},
+       { "24c512", 65536},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ee_ids);
+
+/*
+ * idt_ids - supported IDT 89HPESx devices
+ */
+static const struct i2c_device_id idt_ids[] = {
+       { "89hpes8nt2", 0 },
+       { "89hpes12nt3", 0 },
+
+       { "89hpes24nt6ag2", 0 },
+       { "89hpes32nt8ag2", 0 },
+       { "89hpes32nt8bg2", 0 },
+       { "89hpes12nt12g2", 0 },
+       { "89hpes16nt16g2", 0 },
+       { "89hpes24nt24g2", 0 },
+       { "89hpes32nt24ag2", 0 },
+       { "89hpes32nt24bg2", 0 },
+
+       { "89hpes12n3", 0 },
+       { "89hpes12n3a", 0 },
+       { "89hpes24n3", 0 },
+       { "89hpes24n3a", 0 },
+
+       { "89hpes32h8", 0 },
+       { "89hpes32h8g2", 0 },
+       { "89hpes48h12", 0 },
+       { "89hpes48h12g2", 0 },
+       { "89hpes48h12ag2", 0 },
+       { "89hpes16h16", 0 },
+       { "89hpes22h16", 0 },
+       { "89hpes22h16g2", 0 },
+       { "89hpes34h16", 0 },
+       { "89hpes34h16g2", 0 },
+       { "89hpes64h16", 0 },
+       { "89hpes64h16g2", 0 },
+       { "89hpes64h16ag2", 0 },
+
+       /* { "89hpes3t3", 0 }, // No SMBus-slave iface */
+       { "89hpes12t3g2", 0 },
+       { "89hpes24t3g2", 0 },
+       /* { "89hpes4t4", 0 }, // No SMBus-slave iface */
+       { "89hpes16t4", 0 },
+       { "89hpes4t4g2", 0 },
+       { "89hpes10t4g2", 0 },
+       { "89hpes16t4g2", 0 },
+       { "89hpes16t4ag2", 0 },
+       { "89hpes5t5", 0 },
+       { "89hpes6t5", 0 },
+       { "89hpes8t5", 0 },
+       { "89hpes8t5a", 0 },
+       { "89hpes24t6", 0 },
+       { "89hpes6t6g2", 0 },
+       { "89hpes24t6g2", 0 },
+       { "89hpes16t7", 0 },
+       { "89hpes32t8", 0 },
+       { "89hpes32t8g2", 0 },
+       { "89hpes48t12", 0 },
+       { "89hpes48t12g2", 0 },
+       { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, idt_ids);
+
+/*
+ * idt_driver - IDT 89HPESx driver structure
+ */
+static struct i2c_driver idt_driver = {
+       .driver = {
+               .name = IDT_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = idt_probe,
+       .remove = idt_remove,
+       .id_table = idt_ids,
+};
+
+/*
+ * idt_init() - IDT 89HPESx driver init() callback method
+ */
+static int __init idt_init(void)
+{
+       /* Create Debugfs directory first */
+       if (debugfs_initialized())
+               csr_dbgdir = debugfs_create_dir("idt_csr", NULL);
+
+       /* Add new i2c-device driver */
+       return i2c_add_driver(&idt_driver);
+}
+module_init(idt_init);
+
+/*
+ * idt_exit() - IDT 89HPESx driver exit() callback method
+ */
+static void __exit idt_exit(void)
+{
+       /* Discard debugfs directory and all files if any */
+       debugfs_remove_recursive(csr_dbgdir);
+
+       /* Unregister i2c-device driver */
+       i2c_del_driver(&idt_driver);
+}
+module_exit(idt_exit);
index 6c1f49a85023e6abd80804ab71c27d57c1ccd5e0..4fd21e86ad56ea33f7d303dc108ac1888e4ac3fd 100644 (file)
@@ -1336,7 +1336,6 @@ static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
 static struct pci_error_handlers genwqe_err_handler = {
        .error_detected = genwqe_err_error_detected,
        .mmio_enabled   = genwqe_err_result_none,
-       .link_reset     = genwqe_err_result_none,
        .slot_reset     = genwqe_err_slot_reset,
        .resume         = genwqe_err_resume,
 };
index 91edd0b55e5ce99e955708d7c5425515fd7740bd..bb3bb8ef5f4401d13e5e6b35e8797cb48dc8f081 100644 (file)
@@ -80,12 +80,17 @@ void lkdtm_OVERFLOW(void)
        (void) recursive_loop(recur_count);
 }
 
+static noinline void __lkdtm_CORRUPT_STACK(void *stack)
+{
+       memset(stack, 'a', 64);
+}
+
 noinline void lkdtm_CORRUPT_STACK(void)
 {
        /* Use default char array length that triggers stack protection. */
        char data[8];
+       __lkdtm_CORRUPT_STACK(&data);
 
-       memset((void *)data, 'a', 64);
        pr_info("Corrupted stack with '%16s'...\n", data);
 }
 
index 18e05ca7584f9723ba12bf26a0aaf145b5903896..3600c9993a9830504d0cc5bcd61c4b8f19376762 100644 (file)
@@ -152,6 +152,9 @@ static void mei_mkhi_fix(struct mei_cl_device *cldev)
 {
        int ret;
 
+       if (!cldev->bus->hbm_f_os_supported)
+               return;
+
        ret = mei_cldev_enable(cldev);
        if (ret)
                return;
index b0395601c6ae83340f62cd801531632134b85a7a..da1c0703910a4d1d7def39156df2f73ef30b0902 100644 (file)
@@ -404,7 +404,7 @@ static void __mei_io_list_flush(struct mei_cl_cb *list,
  * @list:  An instance of our list structure
  * @cl: host client
  */
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
 {
        __mei_io_list_flush(list, cl, false);
 }
@@ -756,7 +756,7 @@ static void mei_cl_wake_all(struct mei_cl *cl)
  *
  * @cl: host client
  */
-void mei_cl_set_disconnected(struct mei_cl *cl)
+static void mei_cl_set_disconnected(struct mei_cl *cl)
 {
        struct mei_device *dev = cl->dev;
 
index f2545af9be7be47ff29f225814d01719108be3fc..ab92a542661b3805024e2e499cc0558aafe5c86b 100644 (file)
@@ -93,7 +93,6 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
 {
        INIT_LIST_HEAD(&list->list);
 }
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
 
 /*
  * MEI Host Client Functions
@@ -209,7 +208,6 @@ static inline u8 mei_cl_host_addr(const struct mei_cl *cl)
 }
 
 int mei_cl_disconnect(struct mei_cl *cl);
-void mei_cl_set_disconnected(struct mei_cl *cl);
 int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
                          struct mei_cl_cb *cmpl_list);
 int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
index c6c051b52f55faf1b5896164a4e5e3e251f86899..c6217a4993ad4da05094978e50cc3f1acb1b1fd5 100644 (file)
@@ -180,6 +180,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
                                 dev->hbm_f_ev_supported);
                pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
                                 dev->hbm_f_fa_supported);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n",
+                                dev->hbm_f_os_supported);
        }
 
        pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",
index dd7f15a65eeddbdf53bd2b6c094bfa98be969caf..25b4a1ba522df87fa60f0c8a9555607aa76df6d6 100644 (file)
@@ -989,6 +989,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
        /* Fixed Address Client Support */
        if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
                dev->hbm_f_fa_supported = 1;
+
+       /* OS ver message Support */
+       if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)
+               dev->hbm_f_os_supported = 1;
 }
 
 /**
index 9daf3f9aed2508e08070cb3ef96a53fc43f8d5f9..e1e4d47d4d7d21f5d62a7b514b2886277f9ae9bb 100644 (file)
 #define HBM_MINOR_VERSION_FA               0
 #define HBM_MAJOR_VERSION_FA               2
 
+/*
+ * MEI version with OS ver message support
+ */
+#define HBM_MINOR_VERSION_OS               0
+#define HBM_MAJOR_VERSION_OS               2
+
 /* Host bus message command opcode */
 #define MEI_HBM_CMD_OP_MSK                  0x7f
 /* Host bus message command RESPONSE */
index 699693cd8c59ddde7cd109c550d92f955b0f4c0e..8dadb98662a9e61da14ed8d95268bc9b4ec23d2b 100644 (file)
@@ -406,6 +406,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @hbm_f_ev_supported  : hbm feature event notification
  * @hbm_f_fa_supported  : hbm feature fixed address client
  * @hbm_f_ie_supported  : hbm feature immediate reply to enum request
+ * @hbm_f_os_supported  : hbm feature support OS ver message
  *
  * @me_clients_rwsem: rw lock over me_clients list
  * @me_clients  : list of FW clients
@@ -487,6 +488,7 @@ struct mei_device {
        unsigned int hbm_f_ev_supported:1;
        unsigned int hbm_f_fa_supported:1;
        unsigned int hbm_f_ie_supported:1;
+       unsigned int hbm_f_os_supported:1;
 
        struct rw_semaphore me_clients_rwsem;
        struct list_head me_clients;
index 88e45234d527518e0d449d598c5f04a5be5538a1..fed992e2c2583907711a056ed54bc87a0888d532 100644 (file)
@@ -292,7 +292,6 @@ static int vop_virtio_add_device(struct vop_vdev *vdev,
        if (ret) {
                dev_err(vop_dev(vdev), "%s %d err %d\n",
                        __func__, __LINE__, ret);
-               kfree(vdev);
                return ret;
        }
 
index b33ab8ce47ab7c3d9732f8e39b85bbc93c81d770..07ec2a8a93439e72071cc3bdceceefa0843cdf63 100644 (file)
@@ -249,8 +249,10 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
 
                        block->label = devm_kstrdup(sram->dev,
                                                    label, GFP_KERNEL);
-                       if (!block->label)
+                       if (!block->label) {
+                               ret = -ENOMEM;
                                goto err_chunks;
+                       }
 
                        dev_dbg(sram->dev, "found %sblock '%s' 0x%x-0x%x\n",
                                block->export ? "exported " : "", block->label,
index b8c293373eccd8293ab50fea6a4ce25b1745076b..a306de4318d7d2301fdcb8f34c7045e884278ad4 100644 (file)
@@ -190,7 +190,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
  */
 static int ipddp_create(struct ipddp_route *new_rt)
 {
-        struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
+        struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL);
 
         if (rt == NULL)
                 return -ENOMEM;
index 9ec33b51a0edad879701bef79d6c8f250d778b91..2ce7ae97ac9148d39137eff66954dfc3b4cf239b 100644 (file)
@@ -393,7 +393,7 @@ static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
        if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
                return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);
        else
-               return mdiobus_read(priv->master_mii_bus, addr, regnum);
+               return mdiobus_read_nested(priv->master_mii_bus, addr, regnum);
 }
 
 static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
@@ -407,7 +407,7 @@ static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
        if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
                bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);
        else
-               mdiobus_write(priv->master_mii_bus, addr, regnum, val);
+               mdiobus_write_nested(priv->master_mii_bus, addr, regnum, val);
 
        return 0;
 }
@@ -982,6 +982,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
        const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
        struct device_node *dn = pdev->dev.of_node;
        struct b53_platform_data *pdata;
+       struct dsa_switch_ops *ops;
        struct bcm_sf2_priv *priv;
        struct b53_device *dev;
        struct dsa_switch *ds;
@@ -995,6 +996,10 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       ops = devm_kzalloc(&pdev->dev, sizeof(*ops), GFP_KERNEL);
+       if (!ops)
+               return -ENOMEM;
+
        dev = b53_switch_alloc(&pdev->dev, &bcm_sf2_io_ops, priv);
        if (!dev)
                return -ENOMEM;
@@ -1014,6 +1019,8 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
        ds = dev->ds;
 
        /* Override the parts that are non-standard wrt. normal b53 devices */
+       memcpy(ops, ds->ops, sizeof(*ops));
+       ds->ops = ops;
        ds->ops->get_tag_protocol = bcm_sf2_sw_get_tag_protocol;
        ds->ops->setup = bcm_sf2_sw_setup;
        ds->ops->get_phy_flags = bcm_sf2_sw_get_phy_flags;
index 155190db682d29a6a97b2267550954fb4eba639d..9943629fcbf9ae14a9683e0b2eb0da459f83c0c6 100644 (file)
@@ -539,6 +539,7 @@ static irqreturn_t xgbe_isr(int irq, void *data)
                }
        }
 
+isr_done:
        /* If there is not a separate AN irq, handle it here */
        if (pdata->dev_irq == pdata->an_irq)
                pdata->phy_if.an_isr(irq, pdata);
@@ -551,7 +552,6 @@ static irqreturn_t xgbe_isr(int irq, void *data)
        if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq))
                pdata->i2c_if.i2c_isr(irq, pdata);
 
-isr_done:
        return IRQ_HANDLED;
 }
 
index 185e9e047aa9adda61ac602caea5f59c3efe2d7e..ae42de4fdddf6b77d2c2cf1606795e139d4b472b 100644 (file)
@@ -8720,11 +8720,14 @@ static void tg3_free_consistent(struct tg3 *tp)
        tg3_mem_rx_release(tp);
        tg3_mem_tx_release(tp);
 
+       /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
+       tg3_full_lock(tp, 0);
        if (tp->hw_stats) {
                dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
                                  tp->hw_stats, tp->stats_mapping);
                tp->hw_stats = NULL;
        }
+       tg3_full_unlock(tp);
 }
 
 /*
index 225e9a4877d7b16e058cfa7c0dac9ccb5434bb5b..ec010ced6c99626c610609efc7933f7d54ae2619 100644 (file)
@@ -275,8 +275,7 @@ static int be_dev_mac_add(struct be_adapter *adapter, u8 *mac)
 
        /* Check if mac has already been added as part of uc-list */
        for (i = 0; i < adapter->uc_macs; i++) {
-               if (ether_addr_equal((u8 *)&adapter->uc_list[i * ETH_ALEN],
-                                    mac)) {
+               if (ether_addr_equal(adapter->uc_list[i].mac, mac)) {
                        /* mac already added, skip addition */
                        adapter->pmac_id[0] = adapter->pmac_id[i + 1];
                        return 0;
@@ -1655,14 +1654,12 @@ static void be_clear_mc_list(struct be_adapter *adapter)
 
 static int be_uc_mac_add(struct be_adapter *adapter, int uc_idx)
 {
-       if (ether_addr_equal((u8 *)&adapter->uc_list[uc_idx * ETH_ALEN],
-                            adapter->dev_mac)) {
+       if (ether_addr_equal(adapter->uc_list[uc_idx].mac, adapter->dev_mac)) {
                adapter->pmac_id[uc_idx + 1] = adapter->pmac_id[0];
                return 0;
        }
 
-       return be_cmd_pmac_add(adapter,
-                              (u8 *)&adapter->uc_list[uc_idx * ETH_ALEN],
+       return be_cmd_pmac_add(adapter, adapter->uc_list[uc_idx].mac,
                               adapter->if_handle,
                               &adapter->pmac_id[uc_idx + 1], 0);
 }
@@ -1698,9 +1695,8 @@ static void be_set_uc_list(struct be_adapter *adapter)
        }
 
        if (adapter->update_uc_list) {
-               i = 1; /* First slot is claimed by the Primary MAC */
-
                /* cache the uc-list in adapter array */
+               i = 0;
                netdev_for_each_uc_addr(ha, netdev) {
                        ether_addr_copy(adapter->uc_list[i].mac, ha->addr);
                        i++;
index a761001308dcc190d8c9bad57dad40f09dc49caa..1515abaa5ac9cab53ef4aab0ee05104c5bd2a61f 100644 (file)
@@ -3962,8 +3962,8 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
                                     PAGE_SIZE,
                                     DMA_FROM_DEVICE,
                                     DMA_ATTR_SKIP_CPU_SYNC);
-               __page_frag_drain(buffer_info->page, 0,
-                                 buffer_info->pagecnt_bias);
+               __page_frag_cache_drain(buffer_info->page,
+                                       buffer_info->pagecnt_bias);
 
                buffer_info->page = NULL;
        }
@@ -6991,7 +6991,7 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
                dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
                                     PAGE_SIZE, DMA_FROM_DEVICE,
                                     DMA_ATTR_SKIP_CPU_SYNC);
-               __page_frag_drain(page, 0, rx_buffer->pagecnt_bias);
+               __page_frag_cache_drain(page, rx_buffer->pagecnt_bias);
        }
 
        /* clear contents of rx_buffer */
index edbe200ac2fa4a11ad30bb8f08d8f7e3cb910708..4910d9af19335d4b97d39760c163b41eecc26242 100644 (file)
@@ -2277,7 +2277,7 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
 
        if (priv->tx_ring_num[TX_XDP] &&
            !mlx4_en_check_xdp_mtu(dev, new_mtu))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        dev->mtu = new_mtu;
 
index 1236b27b149386ab61f1c25ab26c84d43d561ab9..2b7dd315020cd9e1a21b28643621122695cd06dd 100644 (file)
@@ -3675,14 +3675,8 @@ static void mlx5e_nic_init(struct mlx5_core_dev *mdev,
 
 static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
 {
-       struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5_eswitch *esw = mdev->priv.eswitch;
-
        mlx5e_vxlan_cleanup(priv);
 
-       if (MLX5_CAP_GEN(mdev, vport_group_manager))
-               mlx5_eswitch_unregister_vport_rep(esw, 0);
-
        if (priv->xdp_prog)
                bpf_prog_put(priv->xdp_prog);
 }
@@ -3807,9 +3801,14 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
 
 static void mlx5e_nic_disable(struct mlx5e_priv *priv)
 {
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
+
        queue_work(priv->wq, &priv->set_rx_mode_work);
+       if (MLX5_CAP_GEN(mdev, vport_group_manager))
+               mlx5_eswitch_unregister_vport_rep(esw, 0);
        mlx5e_disable_async_events(priv);
-       mlx5_lag_remove(priv->mdev);
+       mlx5_lag_remove(mdev);
 }
 
 static const struct mlx5e_profile mlx5e_nic_profile = {
index 1fffe48a93cc35d55d03eba9ba352590924548d2..cbfac06b7ffd1d5140226ccb87331db57d4880d8 100644 (file)
@@ -109,7 +109,6 @@ static bool mlx5e_am_on_top(struct mlx5e_rx_am *am)
        switch (am->tune_state) {
        case MLX5E_AM_PARKING_ON_TOP:
        case MLX5E_AM_PARKING_TIRED:
-               WARN_ONCE(true, "mlx5e_am_on_top: PARKING\n");
                return true;
        case MLX5E_AM_GOING_RIGHT:
                return (am->steps_left > 1) && (am->steps_right == 1);
@@ -123,7 +122,6 @@ static void mlx5e_am_turn(struct mlx5e_rx_am *am)
        switch (am->tune_state) {
        case MLX5E_AM_PARKING_ON_TOP:
        case MLX5E_AM_PARKING_TIRED:
-               WARN_ONCE(true, "mlx5e_am_turn: PARKING\n");
                break;
        case MLX5E_AM_GOING_RIGHT:
                am->tune_state = MLX5E_AM_GOING_LEFT;
@@ -144,7 +142,6 @@ static int mlx5e_am_step(struct mlx5e_rx_am *am)
        switch (am->tune_state) {
        case MLX5E_AM_PARKING_ON_TOP:
        case MLX5E_AM_PARKING_TIRED:
-               WARN_ONCE(true, "mlx5e_am_step: PARKING\n");
                break;
        case MLX5E_AM_GOING_RIGHT:
                if (am->profile_ix == (MLX5E_PARAMS_AM_NUM_PROFILES - 1))
@@ -282,10 +279,8 @@ static void mlx5e_am_calc_stats(struct mlx5e_rx_am_sample *start,
        u32 delta_us = ktime_us_delta(end->time, start->time);
        unsigned int npkts = end->pkt_ctr - start->pkt_ctr;
 
-       if (!delta_us) {
-               WARN_ONCE(true, "mlx5e_am_calc_stats: delta_us=0\n");
+       if (!delta_us)
                return;
-       }
 
        curr_stats->ppms =            (npkts * USEC_PER_MSEC) / delta_us;
        curr_stats->epms = (MLX5E_AM_NEVENTS * USEC_PER_MSEC) / delta_us;
index f8829b5171560ed2f51cd05b8c82d2a076ce8cbb..118cea5e5489e69f7496f6772b7f189d66b3ac10 100644 (file)
@@ -161,15 +161,21 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv,
        }
 }
 
+/* we get here also when setting rule to the FW failed, etc. It means that the
+ * flow rule itself might not exist, but some offloading related to the actions
+ * should be cleaned.
+ */
 static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
                              struct mlx5e_tc_flow *flow)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5_fc *counter = NULL;
 
-       counter = mlx5_flow_rule_counter(flow->rule);
-
-       mlx5_del_flow_rules(flow->rule);
+       if (!IS_ERR(flow->rule)) {
+               counter = mlx5_flow_rule_counter(flow->rule);
+               mlx5_del_flow_rules(flow->rule);
+               mlx5_fc_destroy(priv->mdev, counter);
+       }
 
        if (esw && esw->mode == SRIOV_OFFLOADS) {
                mlx5_eswitch_del_vlan_action(esw, flow->attr);
@@ -177,8 +183,6 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
                        mlx5e_detach_encap(priv, flow);
        }
 
-       mlx5_fc_destroy(priv->mdev, counter);
-
        if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
                mlx5_destroy_flow_table(priv->fs.tc.t);
                priv->fs.tc.t = NULL;
@@ -225,6 +229,11 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
        void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
                                       outer_headers);
 
+       struct flow_dissector_key_control *enc_control =
+               skb_flow_dissector_target(f->dissector,
+                                         FLOW_DISSECTOR_KEY_ENC_CONTROL,
+                                         f->key);
+
        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
                struct flow_dissector_key_ports *key =
                        skb_flow_dissector_target(f->dissector,
@@ -237,28 +246,34 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
 
                /* Full udp dst port must be given */
                if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst)))
-                       return -EOPNOTSUPP;
-
-               /* udp src port isn't supported */
-               if (memchr_inv(&mask->src, 0, sizeof(mask->src)))
-                       return -EOPNOTSUPP;
+                       goto vxlan_match_offload_err;
 
                if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->dst)) &&
                    MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
                        parse_vxlan_attr(spec, f);
-               else
+               else {
+                       netdev_warn(priv->netdev,
+                                   "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst));
                        return -EOPNOTSUPP;
+               }
 
                MLX5_SET(fte_match_set_lyr_2_4, headers_c,
                         udp_dport, ntohs(mask->dst));
                MLX5_SET(fte_match_set_lyr_2_4, headers_v,
                         udp_dport, ntohs(key->dst));
 
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                        udp_sport, ntohs(mask->src));
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                        udp_sport, ntohs(key->src));
        } else { /* udp dst port must be given */
-                       return -EOPNOTSUPP;
+vxlan_match_offload_err:
+               netdev_warn(priv->netdev,
+                           "IP tunnel decap offload supported only for vxlan, must set UDP dport\n");
+               return -EOPNOTSUPP;
        }
 
-       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+       if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
                struct flow_dissector_key_ipv4_addrs *key =
                        skb_flow_dissector_target(f->dissector,
                                                  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
@@ -280,10 +295,10 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
                MLX5_SET(fte_match_set_lyr_2_4, headers_v,
                         dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
                         ntohl(key->dst));
-       }
 
-       MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
-       MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
+               MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
+       }
 
        /* Enforce DMAC when offloading incoming tunneled flows.
         * Flow counters require a match on the DMAC.
@@ -346,6 +361,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                        if (parse_tunnel_attr(priv, spec, f))
                                return -EOPNOTSUPP;
                        break;
+               case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
+                       netdev_warn(priv->netdev,
+                                   "IPv6 tunnel decap offload isn't supported\n");
                default:
                        return -EOPNOTSUPP;
                }
@@ -375,6 +393,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                        MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
                        MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
                                 key->flags & FLOW_DIS_IS_FRAGMENT);
+
+                       /* the HW doesn't need L3 inline to match on frag=no */
+                       if (key->flags & FLOW_DIS_IS_FRAGMENT)
+                               *min_inline = MLX5_INLINE_MODE_IP;
                }
        }
 
@@ -647,17 +669,14 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
 
 #if IS_ENABLED(CONFIG_INET)
        rt = ip_route_output_key(dev_net(mirred_dev), fl4);
-       if (IS_ERR(rt)) {
-               pr_warn("%s: no route to %pI4\n", __func__, &fl4->daddr);
-               return -EOPNOTSUPP;
-       }
+       if (IS_ERR(rt))
+               return PTR_ERR(rt);
 #else
        return -EOPNOTSUPP;
 #endif
 
        if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) {
-               pr_warn("%s: Can't offload the flow, netdevices aren't on the same HW e-switch\n",
-                       __func__);
+               pr_warn("%s: can't offload, devices not on same HW e-switch\n", __func__);
                ip_rt_put(rt);
                return -EOPNOTSUPP;
        }
@@ -718,12 +737,12 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
                                          struct net_device **out_dev)
 {
        int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
+       struct neighbour *n = NULL;
        struct flowi4 fl4 = {};
-       struct neighbour *n;
        char *encap_header;
        int encap_size;
-       __be32 saddr;
-       int ttl;
+       __be32 saddr = 0;
+       int ttl = 0;
        int err;
 
        encap_header = kzalloc(max_encap_size, GFP_KERNEL);
@@ -750,7 +769,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
        e->out_dev = *out_dev;
 
        if (!(n->nud_state & NUD_VALID)) {
-               err = -ENOTSUPP;
+               pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr);
+               err = -EOPNOTSUPP;
                goto out;
        }
 
@@ -772,6 +792,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
        err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
                               encap_size, encap_header, &e->encap_id);
 out:
+       if (err && n)
+               neigh_release(n);
        kfree(encap_header);
        return err;
 }
@@ -792,9 +814,17 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
        int tunnel_type;
        int err;
 
-       /* udp dst port must be given */
+       /* udp dst port must be set */
        if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst)))
+               goto vxlan_encap_offload_err;
+
+       /* setting udp src port isn't supported */
+       if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) {
+vxlan_encap_offload_err:
+               netdev_warn(priv->netdev,
+                           "must set udp dst port and not set udp src port\n");
                return -EOPNOTSUPP;
+       }
 
        if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->tp_dst)) &&
            MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) {
@@ -802,6 +832,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
                info.tun_id = tunnel_id_to_key32(key->tun_id);
                tunnel_type = MLX5_HEADER_TYPE_VXLAN;
        } else {
+               netdev_warn(priv->netdev,
+                           "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst));
                return -EOPNOTSUPP;
        }
 
@@ -809,6 +841,9 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
        case AF_INET:
                info.daddr = key->u.ipv4.dst;
                break;
+       case AF_INET6:
+               netdev_warn(priv->netdev,
+                           "IPv6 tunnel encap offload isn't supported\n");
        default:
                return -EOPNOTSUPP;
        }
@@ -986,7 +1021,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
 
        if (IS_ERR(flow->rule)) {
                err = PTR_ERR(flow->rule);
-               goto err_free;
+               goto err_del_rule;
        }
 
        err = rhashtable_insert_fast(&tc->ht, &flow->node,
@@ -997,7 +1032,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
        goto out;
 
 err_del_rule:
-       mlx5_del_flow_rules(flow->rule);
+       mlx5e_tc_del_flow(priv, flow);
 
 err_free:
        kfree(flow);
index 6547f22e6b9b919010eada133093654348dff671..d01e9f21d4691ea497aa7ea0666c83e330c078bb 100644 (file)
@@ -1195,7 +1195,8 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 {
        int err = 0;
 
-       mlx5_drain_health_wq(dev);
+       if (cleanup)
+               mlx5_drain_health_wq(dev);
 
        mutex_lock(&dev->intf_state_mutex);
        if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) {
@@ -1359,9 +1360,10 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
 
        mlx5_enter_error_state(dev);
        mlx5_unload_one(dev, priv, false);
-       /* In case of kernel call save the pci state */
+       /* In case of kernel call save the pci state and drain the health wq */
        if (state) {
                pci_save_state(pdev);
+               mlx5_drain_health_wq(dev);
                mlx5_pci_disable_device(dev);
        }
 
index 44389c90056a0f197a97f5d36478ec597f266004..8f1623bf2134700498198a98cb6aca9dddd2a6cd 100644 (file)
@@ -696,7 +696,7 @@ enum rtl_tx_desc_bit_1 {
 enum rtl_rx_desc_bit {
        /* Rx private */
        PID1            = (1 << 18), /* Protocol ID bit 1/2 */
-       PID0            = (1 << 17), /* Protocol ID bit 2/2 */
+       PID0            = (1 << 17), /* Protocol ID bit 0/2 */
 
 #define RxProtoUDP     (PID1)
 #define RxProtoTCP     (PID0)
index 00fafabab1d08ed505130ceab5306255c9910087..f729a6b43958cc82a1b2d38293cb50baf767f39a 100644 (file)
@@ -574,6 +574,7 @@ static struct sh_eth_cpu_data r8a7740_data = {
        .rpadir_value   = 2 << 16,
        .no_trimd       = 1,
        .no_ade         = 1,
+       .hw_crc         = 1,
        .tsu            = 1,
        .select_mii     = 1,
        .shift_rd0      = 1,
@@ -802,7 +803,7 @@ static struct sh_eth_cpu_data sh7734_data = {
 
        .ecsr_value     = ECSR_ICD | ECSR_MPD,
        .ecsipr_value   = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
-       .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+       .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
        .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
@@ -832,7 +833,7 @@ static struct sh_eth_cpu_data sh7763_data = {
 
        .ecsr_value     = ECSR_ICD | ECSR_MPD,
        .ecsipr_value   = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
-       .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+       .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
        .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
index 39eb7a65bb9f6a6137ffe13c4c2e776720311db1..a276a32d57f24374444ec06c02b3707fec8fae0a 100644 (file)
@@ -3319,8 +3319,16 @@ int stmmac_dvr_probe(struct device *device,
                ndev->max_mtu = JUMBO_LEN;
        else
                ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
-       if (priv->plat->maxmtu < ndev->max_mtu)
+       /* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu
+        * as well as plat->maxmtu < ndev->min_mtu which is a invalid range.
+        */
+       if ((priv->plat->maxmtu < ndev->max_mtu) &&
+           (priv->plat->maxmtu >= ndev->min_mtu))
                ndev->max_mtu = priv->plat->maxmtu;
+       else if (priv->plat->maxmtu < ndev->min_mtu)
+               netdev_warn(priv->dev,
+                           "%s: warning: maxmtu having invalid value (%d)\n",
+                           __func__, priv->plat->maxmtu);
 
        if (flow_ctrl)
                priv->flow_ctrl = FLOW_AUTO;    /* RX/TX pause on */
index a2831773431a6c19d185b2e82e50897aaf7ef7d8..3da4737620cb3fbf50e16c2cf61de3dbfd3e2355 100644 (file)
@@ -89,6 +89,9 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
 
        /* Set default value for unicast filter entries */
        plat->unicast_filter_entries = 1;
+
+       /* Set the maxmtu to a default of JUMBO_LEN */
+       plat->maxmtu = JUMBO_LEN;
 }
 
 static int quark_default_data(struct plat_stmmacenet_data *plat,
@@ -126,6 +129,9 @@ static int quark_default_data(struct plat_stmmacenet_data *plat,
        /* Set default value for unicast filter entries */
        plat->unicast_filter_entries = 1;
 
+       /* Set the maxmtu to a default of JUMBO_LEN */
+       plat->maxmtu = JUMBO_LEN;
+
        return 0;
 }
 
index d361835b315dd6b9ed542a48515e85c8024192d3..8dbd59baa34d5ed9eda97396f38b5ab38e96416a 100644 (file)
@@ -279,6 +279,7 @@ config MARVELL_PHY
 
 config MESON_GXL_PHY
        tristate "Amlogic Meson GXL Internal PHY"
+       depends on ARCH_MESON || COMPILE_TEST
        ---help---
          Currently has a driver for the Amlogic Meson GXL Internal PHY
 
index 1b639242f9e23170e69f7b7669ba82d8d4263fb5..e84ae084e259c90649277532f64e563e1091bf28 100644 (file)
@@ -29,6 +29,7 @@
 #define MII_DP83867_MICR       0x12
 #define MII_DP83867_ISR                0x13
 #define DP83867_CTRL           0x1f
+#define DP83867_CFG3           0x1e
 
 /* Extended Registers */
 #define DP83867_RGMIICTL       0x0032
@@ -98,6 +99,8 @@ static int dp83867_config_intr(struct phy_device *phydev)
                micr_status |=
                        (MII_DP83867_MICR_AN_ERR_INT_EN |
                        MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+                       MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
+                       MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
                        MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
                        MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
 
@@ -214,6 +217,13 @@ static int dp83867_config_init(struct phy_device *phydev)
                }
        }
 
+       /* Enable Interrupt output INT_OE in CFG3 register */
+       if (phy_interrupt_is_valid(phydev)) {
+               val = phy_read(phydev, DP83867_CFG3);
+               val |= BIT(7);
+               phy_write(phydev, DP83867_CFG3, val);
+       }
+
        return 0;
 }
 
index e269262471a44fdcbfc9ef3c5833bf3ceb78624e..0b78210c0fa74e88b2ef5e27d4a7e6c78e9fa45c 100644 (file)
@@ -1192,7 +1192,8 @@ static int marvell_read_status(struct phy_device *phydev)
        int err;
 
        /* Check the fiber mode first */
-       if (phydev->supported & SUPPORTED_FIBRE) {
+       if (phydev->supported & SUPPORTED_FIBRE &&
+           phydev->interface != PHY_INTERFACE_MODE_SGMII) {
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
                if (err < 0)
                        goto error;
index 25f93a98863b79be76ac72b814d5dd4ff75c89a9..48da6e93c3f783e07f61ae24151e3114ac8dc1ae 100644 (file)
@@ -1065,6 +1065,15 @@ void phy_state_machine(struct work_struct *work)
                        if (old_link != phydev->link)
                                phydev->state = PHY_CHANGELINK;
                }
+               /*
+                * Failsafe: check that nobody set phydev->link=0 between two
+                * poll cycles, otherwise we won't leave RUNNING state as long
+                * as link remains down.
+                */
+               if (!phydev->link && phydev->state == PHY_RUNNING) {
+                       phydev->state = PHY_CHANGELINK;
+                       phydev_err(phydev, "no link in PHY_RUNNING\n");
+               }
                break;
        case PHY_CHANGELINK:
                err = phy_read_status(phydev);
index 7dc61228c55b8af26f0623fa4cfb9dd512cd97ac..be418563cb18c6132cb29d4201b831072749d43b 100644 (file)
@@ -3576,39 +3576,87 @@ static bool delay_autosuspend(struct r8152 *tp)
                return false;
 }
 
-static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+static int rtl8152_rumtime_suspend(struct r8152 *tp)
 {
-       struct r8152 *tp = usb_get_intfdata(intf);
        struct net_device *netdev = tp->netdev;
        int ret = 0;
 
-       mutex_lock(&tp->control);
+       if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
+               u32 rcr = 0;
 
-       if (PMSG_IS_AUTO(message)) {
-               if (netif_running(netdev) && delay_autosuspend(tp)) {
+               if (delay_autosuspend(tp)) {
                        ret = -EBUSY;
                        goto out1;
                }
 
-               set_bit(SELECTIVE_SUSPEND, &tp->flags);
-       } else {
-               netif_device_detach(netdev);
+               if (netif_carrier_ok(netdev)) {
+                       u32 ocp_data;
+
+                       rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+                       ocp_data = rcr & ~RCR_ACPT_ALL;
+                       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+                       rxdy_gated_en(tp, true);
+                       ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA,
+                                                PLA_OOB_CTRL);
+                       if (!(ocp_data & RXFIFO_EMPTY)) {
+                               rxdy_gated_en(tp, false);
+                               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+                               ret = -EBUSY;
+                               goto out1;
+                       }
+               }
+
+               clear_bit(WORK_ENABLE, &tp->flags);
+               usb_kill_urb(tp->intr_urb);
+
+               tp->rtl_ops.autosuspend_en(tp, true);
+
+               if (netif_carrier_ok(netdev)) {
+                       napi_disable(&tp->napi);
+                       rtl_stop_rx(tp);
+                       rxdy_gated_en(tp, false);
+                       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+                       napi_enable(&tp->napi);
+               }
        }
 
+       set_bit(SELECTIVE_SUSPEND, &tp->flags);
+
+out1:
+       return ret;
+}
+
+static int rtl8152_system_suspend(struct r8152 *tp)
+{
+       struct net_device *netdev = tp->netdev;
+       int ret = 0;
+
+       netif_device_detach(netdev);
+
        if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
                clear_bit(WORK_ENABLE, &tp->flags);
                usb_kill_urb(tp->intr_urb);
                napi_disable(&tp->napi);
-               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
-                       rtl_stop_rx(tp);
-                       tp->rtl_ops.autosuspend_en(tp, true);
-               } else {
-                       cancel_delayed_work_sync(&tp->schedule);
-                       tp->rtl_ops.down(tp);
-               }
+               cancel_delayed_work_sync(&tp->schedule);
+               tp->rtl_ops.down(tp);
                napi_enable(&tp->napi);
        }
-out1:
+
+       return ret;
+}
+
+static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+       int ret;
+
+       mutex_lock(&tp->control);
+
+       if (PMSG_IS_AUTO(message))
+               ret = rtl8152_rumtime_suspend(tp);
+       else
+               ret = rtl8152_system_suspend(tp);
+
        mutex_unlock(&tp->control);
 
        return ret;
index 23dfb0eac0981704f2770bc3abe9bb32a80e3fc9..454f907d419a7f87cc0ae1813f40c054726be7e8 100644 (file)
@@ -263,7 +263,9 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
                .flowi4_iif = LOOPBACK_IFINDEX,
                .flowi4_tos = RT_TOS(ip4h->tos),
                .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF,
+               .flowi4_proto = ip4h->protocol,
                .daddr = ip4h->daddr,
+               .saddr = ip4h->saddr,
        };
        struct net *net = dev_net(vrf_dev);
        struct rtable *rt;
@@ -1250,6 +1252,8 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
                return -EINVAL;
 
        vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]);
+       if (vrf->tb_id == RT_TABLE_UNSPEC)
+               return -EINVAL;
 
        dev->priv_flags |= IFF_L3MDEV_MASTER;
 
index bc7397d709d3ac5ff85b9a1057e43a93500587fc..08bc7822f8209d0a9136357edb18683092c86c18 100644 (file)
@@ -16,7 +16,7 @@
 /********************************************************************/
 int orinoco_mic_init(struct orinoco_private *priv)
 {
-       priv->tx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+       priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
                                              CRYPTO_ALG_ASYNC);
        if (IS_ERR(priv->tx_tfm_mic)) {
                printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
@@ -25,7 +25,7 @@ int orinoco_mic_init(struct orinoco_private *priv)
                return -ENOMEM;
        }
 
-       priv->rx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+       priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
                                              CRYPTO_ALG_ASYNC);
        if (IS_ERR(priv->rx_tfm_mic)) {
                printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
@@ -40,17 +40,16 @@ int orinoco_mic_init(struct orinoco_private *priv)
 void orinoco_mic_free(struct orinoco_private *priv)
 {
        if (priv->tx_tfm_mic)
-               crypto_free_ahash(priv->tx_tfm_mic);
+               crypto_free_shash(priv->tx_tfm_mic);
        if (priv->rx_tfm_mic)
-               crypto_free_ahash(priv->rx_tfm_mic);
+               crypto_free_shash(priv->rx_tfm_mic);
 }
 
-int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
                u8 *da, u8 *sa, u8 priority,
                u8 *data, size_t data_len, u8 *mic)
 {
-       AHASH_REQUEST_ON_STACK(req, tfm_michael);
-       struct scatterlist sg[2];
+       SHASH_DESC_ON_STACK(desc, tfm_michael);
        u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
        int err;
 
@@ -67,18 +66,27 @@ int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
        hdr[ETH_ALEN * 2 + 2] = 0;
        hdr[ETH_ALEN * 2 + 3] = 0;
 
-       /* Use scatter gather to MIC header and data in one go */
-       sg_init_table(sg, 2);
-       sg_set_buf(&sg[0], hdr, sizeof(hdr));
-       sg_set_buf(&sg[1], data, data_len);
+       desc->tfm = tfm_michael;
+       desc->flags = 0;
 
-       if (crypto_ahash_setkey(tfm_michael, key, MIC_KEYLEN))
-               return -1;
+       err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
+       if (err)
+               return err;
+
+       err = crypto_shash_init(desc);
+       if (err)
+               return err;
+
+       err = crypto_shash_update(desc, hdr, sizeof(hdr));
+       if (err)
+               return err;
+
+       err = crypto_shash_update(desc, data, data_len);
+       if (err)
+               return err;
+
+       err = crypto_shash_final(desc, mic);
+       shash_desc_zero(desc);
 
-       ahash_request_set_tfm(req, tfm_michael);
-       ahash_request_set_callback(req, 0, NULL, NULL);
-       ahash_request_set_crypt(req, sg, mic, data_len + sizeof(hdr));
-       err = crypto_ahash_digest(req);
-       ahash_request_zero(req);
        return err;
 }
index ce731d05cc98cd2d0b6415f66868d3ad517b4753..e8724e8892194bb3e732078b3561ab031071a061 100644 (file)
@@ -6,6 +6,7 @@
 #define _ORINOCO_MIC_H_
 
 #include <linux/types.h>
+#include <crypto/hash.h>
 
 #define MICHAEL_MIC_LEN 8
 
@@ -15,7 +16,7 @@ struct crypto_ahash;
 
 int orinoco_mic_init(struct orinoco_private *priv);
 void orinoco_mic_free(struct orinoco_private *priv);
-int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
                u8 *da, u8 *sa, u8 priority,
                u8 *data, size_t data_len, u8 *mic);
 
index 2f0c84b1c440cd1160bdebc3cabcb13be110a73e..5fa1c3e3713f835387353ba781cbb24ce95df6dc 100644 (file)
@@ -152,8 +152,8 @@ struct orinoco_private {
        u8 *wpa_ie;
        int wpa_ie_len;
 
-       struct crypto_ahash *rx_tfm_mic;
-       struct crypto_ahash *tx_tfm_mic;
+       struct crypto_shash *rx_tfm_mic;
+       struct crypto_shash *tx_tfm_mic;
 
        unsigned int wpa_enabled:1;
        unsigned int tkip_cm_active:1;
index 0a508649903d73fe4b9a643a5e7e43577abc22c9..49015b05f3d1a048ee6e3ac00426ea76cd5bab44 100644 (file)
@@ -1063,6 +1063,7 @@ int rtl_usb_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
        rtlpriv = hw->priv;
+       rtlpriv->hw = hw;
        rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
                                    GFP_KERNEL);
        if (!rtlpriv->usb_data)
index 2fc86dc7a8df3e487c8222fa84310e7832c9c0a8..8a3c3e32a704b3e359a78ed06e95c6e977f322bc 100644 (file)
@@ -1106,12 +1106,7 @@ int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap)
        if (ret)
                return ret;
 
-       /* Checking for ctrl->tagset is a trick to avoid sleeping on module
-        * load, since we only need the quirk on reset_controller. Notice
-        * that the HGST device needs this delay only in firmware activation
-        * procedure; unfortunately we have no (easy) way to verify this.
-        */
-       if ((ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) && ctrl->tagset)
+       if (ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY)
                msleep(NVME_QUIRK_DELAY_AMOUNT);
 
        return nvme_wait_ready(ctrl, cap, false);
index aa0bc60810a74ff93cf05b294b2a9d4968ecf397..fcc9dcfdf67517d1352bef388a50d2dbf6c9a129 100644 (file)
@@ -1654,13 +1654,12 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
                struct nvme_fc_fcp_op *op)
 {
        struct nvmefc_fcp_req *freq = &op->fcp_req;
-       u32 map_len = nvme_map_len(rq);
        enum dma_data_direction dir;
        int ret;
 
        freq->sg_cnt = 0;
 
-       if (!map_len)
+       if (!blk_rq_payload_bytes(rq))
                return 0;
 
        freq->sg_table.sgl = freq->first_sgl;
@@ -1854,7 +1853,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (ret)
                return ret;
 
-       data_len = nvme_map_len(rq);
+       data_len = blk_rq_payload_bytes(rq);
        if (data_len)
                io_dir = ((rq_data_dir(rq) == WRITE) ?
                                        NVMEFC_FCP_WRITE : NVMEFC_FCP_READ);
index 6377e14586dc5c837749049cf3dafc7b210a3026..aead6d08ed2c83b4f67e9087b0ca446247b57d18 100644 (file)
@@ -225,14 +225,6 @@ static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector)
        return (sector >> (ns->lba_shift - 9));
 }
 
-static inline unsigned nvme_map_len(struct request *rq)
-{
-       if (req_op(rq) == REQ_OP_DISCARD)
-               return sizeof(struct nvme_dsm_range);
-       else
-               return blk_rq_bytes(rq);
-}
-
 static inline void nvme_cleanup_cmd(struct request *req)
 {
        if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
index 19beeb7b2ac26a5bf0f81bf4e8b995bf29dba195..3faefabf339c98d221373437e411512543d29263 100644 (file)
@@ -306,11 +306,11 @@ static __le64 **iod_list(struct request *req)
        return (__le64 **)(iod->sg + blk_rq_nr_phys_segments(req));
 }
 
-static int nvme_init_iod(struct request *rq, unsigned size,
-               struct nvme_dev *dev)
+static int nvme_init_iod(struct request *rq, struct nvme_dev *dev)
 {
        struct nvme_iod *iod = blk_mq_rq_to_pdu(rq);
        int nseg = blk_rq_nr_phys_segments(rq);
+       unsigned int size = blk_rq_payload_bytes(rq);
 
        if (nseg > NVME_INT_PAGES || size > NVME_INT_BYTES(dev)) {
                iod->sg = kmalloc(nvme_iod_alloc_size(dev, size, nseg), GFP_ATOMIC);
@@ -420,12 +420,11 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
 }
 #endif
 
-static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req,
-               int total_len)
+static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
 {
        struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
        struct dma_pool *pool;
-       int length = total_len;
+       int length = blk_rq_payload_bytes(req);
        struct scatterlist *sg = iod->sg;
        int dma_len = sg_dma_len(sg);
        u64 dma_addr = sg_dma_address(sg);
@@ -501,7 +500,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req,
 }
 
 static int nvme_map_data(struct nvme_dev *dev, struct request *req,
-               unsigned size, struct nvme_command *cmnd)
+               struct nvme_command *cmnd)
 {
        struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
        struct request_queue *q = req->q;
@@ -519,7 +518,7 @@ static int nvme_map_data(struct nvme_dev *dev, struct request *req,
                                DMA_ATTR_NO_WARN))
                goto out;
 
-       if (!nvme_setup_prps(dev, req, size))
+       if (!nvme_setup_prps(dev, req))
                goto out_unmap;
 
        ret = BLK_MQ_RQ_QUEUE_ERROR;
@@ -580,7 +579,6 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct nvme_dev *dev = nvmeq->dev;
        struct request *req = bd->rq;
        struct nvme_command cmnd;
-       unsigned map_len;
        int ret = BLK_MQ_RQ_QUEUE_OK;
 
        /*
@@ -600,13 +598,12 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (ret != BLK_MQ_RQ_QUEUE_OK)
                return ret;
 
-       map_len = nvme_map_len(req);
-       ret = nvme_init_iod(req, map_len, dev);
+       ret = nvme_init_iod(req, dev);
        if (ret != BLK_MQ_RQ_QUEUE_OK)
                goto out_free_cmd;
 
        if (blk_rq_nr_phys_segments(req))
-               ret = nvme_map_data(dev, req, map_len, &cmnd);
+               ret = nvme_map_data(dev, req, &cmnd);
 
        if (ret != BLK_MQ_RQ_QUEUE_OK)
                goto out_cleanup_iod;
index f587af345889eb1b32a1f4f87dbe0c9a3a30ae42..557f29b1f1bb23e4e5cded156db21b4f981b585a 100644 (file)
@@ -981,8 +981,7 @@ static int nvme_rdma_map_sg_fr(struct nvme_rdma_queue *queue,
 }
 
 static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
-               struct request *rq, unsigned int map_len,
-               struct nvme_command *c)
+               struct request *rq, struct nvme_command *c)
 {
        struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
        struct nvme_rdma_device *dev = queue->device;
@@ -1014,9 +1013,9 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
        }
 
        if (count == 1) {
-               if (rq_data_dir(rq) == WRITE &&
-                   map_len <= nvme_rdma_inline_data_size(queue) &&
-                   nvme_rdma_queue_idx(queue))
+               if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) &&
+                   blk_rq_payload_bytes(rq) <=
+                               nvme_rdma_inline_data_size(queue))
                        return nvme_rdma_map_sg_inline(queue, req, c);
 
                if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
@@ -1422,7 +1421,7 @@ static inline bool nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
                struct request *rq)
 {
        if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
-               struct nvme_command *cmd = (struct nvme_command *)rq->cmd;
+               struct nvme_command *cmd = nvme_req(rq)->cmd;
 
                if (rq->cmd_type != REQ_TYPE_DRV_PRIV ||
                    cmd->common.opcode != nvme_fabrics_command ||
@@ -1444,7 +1443,6 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct nvme_command *c = sqe->data;
        bool flush = false;
        struct ib_device *dev;
-       unsigned int map_len;
        int ret;
 
        WARN_ON_ONCE(rq->tag < 0);
@@ -1462,8 +1460,7 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
        blk_mq_start_request(rq);
 
-       map_len = nvme_map_len(rq);
-       ret = nvme_rdma_map_data(queue, rq, map_len, c);
+       ret = nvme_rdma_map_data(queue, rq, c);
        if (ret < 0) {
                dev_err(queue->ctrl->ctrl.device,
                             "Failed to map data (%d)\n", ret);
index 9a507e77eced18cc433792f651761dd137b75d62..90b05c72186c4f9e9c37a812ec469a738d253e95 100644 (file)
@@ -396,9 +396,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
                        goto unwind_vring_allocations;
        }
 
-       /* track the rvdevs list reference */
-       kref_get(&rvdev->refcount);
-
        list_add_tail(&rvdev->node, &rproc->rvdevs);
 
        rproc_add_subdev(rproc, &rvdev->subdev,
@@ -889,13 +886,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
        /*
         * Create a copy of the resource table. When a virtio device starts
         * and calls vring_new_virtqueue() the address of the allocated vring
-        * will be stored in the table_ptr. Before the device is started,
-        * table_ptr will be copied into device memory.
+        * will be stored in the cached_table. Before the device is started,
+        * cached_table will be copied into device memory.
         */
-       rproc->table_ptr = kmemdup(table, tablesz, GFP_KERNEL);
-       if (!rproc->table_ptr)
+       rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
+       if (!rproc->cached_table)
                goto clean_up;
 
+       rproc->table_ptr = rproc->cached_table;
+
        /* reset max_notifyid */
        rproc->max_notifyid = -1;
 
@@ -914,16 +913,18 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
        }
 
        /*
-        * The starting device has been given the rproc->table_ptr as the
+        * The starting device has been given the rproc->cached_table as the
         * resource table. The address of the vring along with the other
-        * allocated resources (carveouts etc) is stored in table_ptr.
+        * allocated resources (carveouts etc) is stored in cached_table.
         * In order to pass this information to the remote device we must copy
         * this information to device memory. We also update the table_ptr so
         * that any subsequent changes will be applied to the loaded version.
         */
        loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
-       if (loaded_table)
-               memcpy(loaded_table, rproc->table_ptr, tablesz);
+       if (loaded_table) {
+               memcpy(loaded_table, rproc->cached_table, tablesz);
+               rproc->table_ptr = loaded_table;
+       }
 
        /* power up the remote processor */
        ret = rproc->ops->start(rproc);
@@ -951,7 +952,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 clean_up_resources:
        rproc_resource_cleanup(rproc);
 clean_up:
-       kfree(rproc->table_ptr);
+       kfree(rproc->cached_table);
+       rproc->cached_table = NULL;
        rproc->table_ptr = NULL;
 
        rproc_disable_iommu(rproc);
@@ -1185,7 +1187,8 @@ void rproc_shutdown(struct rproc *rproc)
        rproc_disable_iommu(rproc);
 
        /* Free the copy of the resource table */
-       kfree(rproc->table_ptr);
+       kfree(rproc->cached_table);
+       rproc->cached_table = NULL;
        rproc->table_ptr = NULL;
 
        /* if in crash state, unlock crash handler */
index a79cb5a9e5f22963ed56214421abc099c5949c37..1cfb775e8e82b8b391108c700abba57f92867066 100644 (file)
@@ -453,8 +453,8 @@ int rpmsg_register_device(struct rpmsg_device *rpdev)
        struct device *dev = &rpdev->dev;
        int ret;
 
-       dev_set_name(&rpdev->dev, "%s:%s",
-                    dev_name(dev->parent), rpdev->id.name);
+       dev_set_name(&rpdev->dev, "%s.%s.%d.%d", dev_name(dev->parent),
+                    rpdev->id.name, rpdev->src, rpdev->dst);
 
        rpdev->dev.bus = &rpmsg_bus;
        rpdev->dev.release = rpmsg_release_device;
index d9e15210b110efcd3147d5a02f0e06c0673d4ad3..5caf5f3ff642282ee13776e9df9ca9a18f494536 100644 (file)
@@ -64,9 +64,9 @@ int           max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS;
 u32    bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
 u32    *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
 
-#define BFAD_FW_FILE_CB                "cbfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT                "ctfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT2       "ct2fw-3.2.3.0.bin"
+#define BFAD_FW_FILE_CB                "cbfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT                "ctfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT2       "ct2fw-3.2.5.1.bin"
 
 static u32 *bfad_load_fwimg(struct pci_dev *pdev);
 static void bfad_free_fwimg(void);
index f9e862093a25935e601c45b4854035e98e035f03..cfcfff48e8e16e3fb2b66c0d491c0d612a8cdd38 100644 (file)
@@ -58,7 +58,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.2.25.0"
+#define BFAD_DRIVER_VERSION    "3.2.25.1"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
index 9ddc9200e0a48b00632bbc441c492679786ec570..9e4b7709043e0c49620755cafce2f80b3e99df89 100644 (file)
@@ -248,6 +248,7 @@ struct fnic {
        struct completion *remove_wait; /* device remove thread blocks */
 
        atomic_t in_flight;             /* io counter */
+       bool internal_reset_inprogress;
        u32 _reserved;                  /* fill hole */
        unsigned long state_flags;      /* protected by host lock */
        enum fnic_state state;
index 2544a37ece0afdc19742d01954487f87dd4c3c5c..adb3d5871e743442e04014cd2f86eae15ab27912 100644 (file)
@@ -2581,6 +2581,19 @@ int fnic_host_reset(struct scsi_cmnd *sc)
        unsigned long wait_host_tmo;
        struct Scsi_Host *shost = sc->device->host;
        struct fc_lport *lp = shost_priv(shost);
+       struct fnic *fnic = lport_priv(lp);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fnic->fnic_lock, flags);
+       if (fnic->internal_reset_inprogress == 0) {
+               fnic->internal_reset_inprogress = 1;
+       } else {
+               spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+               FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+                       "host reset in progress skipping another host reset\n");
+               return SUCCESS;
+       }
+       spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
        /*
         * If fnic_reset is successful, wait for fabric login to complete
@@ -2601,6 +2614,9 @@ int fnic_host_reset(struct scsi_cmnd *sc)
                }
        }
 
+       spin_lock_irqsave(&fnic->fnic_lock, flags);
+       fnic->internal_reset_inprogress = 0;
+       spin_unlock_irqrestore(&fnic->fnic_lock, flags);
        return ret;
 }
 
index 3d3768aaab4f2bb79ccbaf40f1f569114e4f9b30..8fb5c54c7dd3752084cf1063078422b34e65624c 100644 (file)
@@ -3585,7 +3585,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
                               1, 1);
        if (rc) {
                pr_err("srp_transfer_data() failed: %d\n", rc);
-               return -EAGAIN;
+               return -EIO;
        }
        /*
         * We now tell TCM to add this WRITE CDB directly into the TCM storage
index 23ca8a274586746e19204f291a844e6cbc43a07f..21331453db7bd29a0c2bc8cac430b8c8bb60b9c2 100644 (file)
@@ -1,6 +1,6 @@
 config QEDI
        tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support"
-       depends on PCI && SCSI
+       depends on PCI && SCSI && UIO
        depends on QED
        select SCSI_ISCSI_ATTRS
        select QED_LL2
index c35b6de4ca643297d1908341421c865c2cb93e84..e9e1e141af9cd287bcca730d05a7a62d58fb644a 100644 (file)
@@ -1018,7 +1018,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb)
        count = blk_rq_map_sg(req->q, req, sdb->table.sgl);
        BUG_ON(count > sdb->table.nents);
        sdb->table.nents = count;
-       sdb->length = blk_rq_bytes(req);
+       sdb->length = blk_rq_payload_bytes(req);
        return BLKPREP_OK;
 }
 
@@ -2893,7 +2893,7 @@ scsi_internal_device_block(struct scsi_device *sdev)
         * request queue. 
         */
        if (q->mq_ops) {
-               blk_mq_stop_hw_queues(q);
+               blk_mq_quiesce_queue(q);
        } else {
                spin_lock_irqsave(q->queue_lock, flags);
                blk_stop_queue(q);
index b1933041da39d414f9c6e127052ba8cbaa25e65e..1fbb1ecf49f2ec8639e30457e2ec3aee68015bb4 100644 (file)
@@ -836,7 +836,6 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
        struct bio *bio = rq->bio;
        sector_t sector = blk_rq_pos(rq);
        unsigned int nr_sectors = blk_rq_sectors(rq);
-       unsigned int nr_bytes = blk_rq_bytes(rq);
        int ret;
 
        if (sdkp->device->no_write_same)
@@ -869,21 +868,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
 
        cmd->transfersize = sdp->sector_size;
        cmd->allowed = SD_MAX_RETRIES;
-
-       /*
-        * For WRITE_SAME the data transferred in the DATA IN buffer is
-        * different from the amount of data actually written to the target.
-        *
-        * We set up __data_len to the amount of data transferred from the
-        * DATA IN buffer so that blk_rq_map_sg set up the proper S/G list
-        * to transfer a single sector of data first, but then reset it to
-        * the amount of data to be written right after so that the I/O path
-        * knows how much to actually write.
-        */
-       rq->__data_len = sdp->sector_size;
-       ret = scsi_init_io(cmd);
-       rq->__data_len = nr_bytes;
-       return ret;
+       return scsi_init_io(cmd);
 }
 
 static int sd_setup_flush_cmnd(struct scsi_cmnd *cmd)
index 396b32dca07464dddbf575a37fd13ad1e3f92579..7cf70aaec0ba32ce9c506a84f21fb9be39bf9e64 100644 (file)
@@ -591,6 +591,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!pool) {
                SNIC_HOST_ERR(shost, "dflt sgl pool creation failed\n");
 
+               ret = -ENOMEM;
                goto err_free_res;
        }
 
@@ -601,6 +602,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!pool) {
                SNIC_HOST_ERR(shost, "max sgl pool creation failed\n");
 
+               ret = -ENOMEM;
                goto err_free_dflt_sgl_pool;
        }
 
@@ -611,6 +613,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!pool) {
                SNIC_HOST_ERR(shost, "snic tmreq info pool creation failed.\n");
 
+               ret = -ENOMEM;
                goto err_free_max_sgl_pool;
        }
 
index 7dfefd66df93874b1359824890b4b760275ff2c6..1cadc9eefa21a47e783160b874dbd2ce02f8f05f 100644 (file)
@@ -1693,6 +1693,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
        case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
+       case TCM_TOO_MANY_TARGET_DESCS:
+       case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
+       case TCM_TOO_MANY_SEGMENT_DESCS:
+       case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -2808,6 +2812,26 @@ static const struct sense_info sense_info_table[] = {
                .key = ILLEGAL_REQUEST,
                .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
        },
+       [TCM_TOO_MANY_TARGET_DESCS] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x26,
+               .ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
+       },
+       [TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x26,
+               .ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
+       },
+       [TCM_TOO_MANY_SEGMENT_DESCS] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x26,
+               .ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
+       },
+       [TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x26,
+               .ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
+       },
        [TCM_PARAMETER_LIST_LENGTH_ERROR] = {
                .key = ILLEGAL_REQUEST,
                .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
index 37d5caebffa6b593025a28b703a54a71e7d940d3..d828b3b5000bf421826b9823efcbac8d6b2d58a3 100644 (file)
@@ -53,18 +53,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
        return 0;
 }
 
-static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
-                                       bool src)
+static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+                                       struct se_device **found_dev)
 {
        struct se_device *se_dev;
-       unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
+       unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
        int rc;
 
-       if (src)
-               dev_wwn = &xop->dst_tid_wwn[0];
-       else
-               dev_wwn = &xop->src_tid_wwn[0];
-
        mutex_lock(&g_device_mutex);
        list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
 
@@ -78,15 +73,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
                if (rc != 0)
                        continue;
 
-               if (src) {
-                       xop->dst_dev = se_dev;
-                       pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
-                               " se_dev\n", xop->dst_dev);
-               } else {
-                       xop->src_dev = se_dev;
-                       pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
-                               " se_dev\n", xop->src_dev);
-               }
+               *found_dev = se_dev;
+               pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
 
                rc = target_depend_item(&se_dev->dev_group.cg_item);
                if (rc != 0) {
@@ -110,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
 }
 
 static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
-                               unsigned char *p, bool src)
+                               unsigned char *p, unsigned short cscd_index)
 {
        unsigned char *desc = p;
        unsigned short ript;
@@ -155,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
                return -EINVAL;
        }
 
-       if (src) {
+       if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
+               pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
+                        "dest\n", cscd_index);
+               return 0;
+       }
+
+       if (cscd_index == xop->stdi) {
                memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
                /*
                 * Determine if the source designator matches the local device
@@ -167,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
                        pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
                                        " received xop\n", xop->src_dev);
                }
-       } else {
+       }
+
+       if (cscd_index == xop->dtdi) {
                memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
                /*
-                * Determine if the destination designator matches the local device
+                * Determine if the destination designator matches the local
+                * device. If @cscd_index corresponds to both source (stdi) and
+                * destination (dtdi), or dtdi comes after stdi, then
+                * XCOL_DEST_RECV_OP wins.
                 */
                if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
                                XCOPY_NAA_IEEE_REGEX_LEN)) {
@@ -190,20 +189,23 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
 {
        struct se_device *local_dev = se_cmd->se_dev;
        unsigned char *desc = p;
-       int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
+       int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
+       unsigned short cscd_index = 0;
        unsigned short start = 0;
-       bool src = true;
 
        *sense_ret = TCM_INVALID_PARAMETER_LIST;
 
        if (offset != 0) {
                pr_err("XCOPY target descriptor list length is not"
                        " multiple of %d\n", XCOPY_TARGET_DESC_LEN);
+               *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
                return -EINVAL;
        }
-       if (tdll > 64) {
+       if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
                pr_err("XCOPY target descriptor supports a maximum"
                        " two src/dest descriptors, tdll: %hu too large..\n", tdll);
+               /* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
+               *sense_ret = TCM_TOO_MANY_TARGET_DESCS;
                return -EINVAL;
        }
        /*
@@ -215,37 +217,43 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
 
        while (start < tdll) {
                /*
-                * Check target descriptor identification with 0xE4 type with
-                * use VPD 0x83 WWPN matching ..
+                * Check target descriptor identification with 0xE4 type, and
+                * compare the current index with the CSCD descriptor IDs in
+                * the segment descriptor. Use VPD 0x83 WWPN matching ..
                 */
                switch (desc[0]) {
                case 0xe4:
                        rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
-                                                       &desc[0], src);
+                                                       &desc[0], cscd_index);
                        if (rc != 0)
                                goto out;
-                       /*
-                        * Assume target descriptors are in source -> destination order..
-                        */
-                       if (src)
-                               src = false;
-                       else
-                               src = true;
                        start += XCOPY_TARGET_DESC_LEN;
                        desc += XCOPY_TARGET_DESC_LEN;
-                       ret++;
+                       cscd_index++;
                        break;
                default:
                        pr_err("XCOPY unsupported descriptor type code:"
                                        " 0x%02x\n", desc[0]);
+                       *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
                        goto out;
                }
        }
 
-       if (xop->op_origin == XCOL_SOURCE_RECV_OP)
-               rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
-       else
-               rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
+       switch (xop->op_origin) {
+       case XCOL_SOURCE_RECV_OP:
+               rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
+                                               &xop->dst_dev);
+               break;
+       case XCOL_DEST_RECV_OP:
+               rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
+                                               &xop->src_dev);
+               break;
+       default:
+               pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
+                       "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
+               rc = -EINVAL;
+               break;
+       }
        /*
         * If a matching IEEE NAA 0x83 descriptor for the requested device
         * is not located on this node, return COPY_ABORTED with ASQ/ASQC
@@ -262,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
        pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
                 xop->dst_dev, &xop->dst_tid_wwn[0]);
 
-       return ret;
+       return cscd_index;
 
 out:
        return -EINVAL;
@@ -284,6 +292,14 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
 
        xop->stdi = get_unaligned_be16(&desc[4]);
        xop->dtdi = get_unaligned_be16(&desc[6]);
+
+       if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
+           xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
+               pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
+                       XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
+               return -EINVAL;
+       }
+
        pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
                desc_len, xop->stdi, xop->dtdi, dc);
 
@@ -306,15 +322,25 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
 
 static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
                                struct xcopy_op *xop, unsigned char *p,
-                               unsigned int sdll)
+                               unsigned int sdll, sense_reason_t *sense_ret)
 {
        unsigned char *desc = p;
        unsigned int start = 0;
        int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
 
+       *sense_ret = TCM_INVALID_PARAMETER_LIST;
+
        if (offset != 0) {
                pr_err("XCOPY segment descriptor list length is not"
                        " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
+               *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
+               return -EINVAL;
+       }
+       if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
+               pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
+                       " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
+               /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
+               *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
                return -EINVAL;
        }
 
@@ -335,6 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
                default:
                        pr_err("XCOPY unsupported segment descriptor"
                                "type: 0x%02x\n", desc[0]);
+                       *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
                        goto out;
                }
        }
@@ -861,6 +888,16 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
                return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
 
+       if (se_cmd->data_length == 0) {
+               target_complete_cmd(se_cmd, SAM_STAT_GOOD);
+               return TCM_NO_SENSE;
+       }
+       if (se_cmd->data_length < XCOPY_HDR_LEN) {
+               pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
+                               se_cmd->data_length, XCOPY_HDR_LEN);
+               return TCM_PARAMETER_LIST_LENGTH_ERROR;
+       }
+
        xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
        if (!xop) {
                pr_err("Unable to allocate xcopy_op\n");
@@ -883,6 +920,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
         */
        tdll = get_unaligned_be16(&p[2]);
        sdll = get_unaligned_be32(&p[8]);
+       if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
+               pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
+                      tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
+               ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
+               goto out;
+       }
 
        inline_dl = get_unaligned_be32(&p[12]);
        if (inline_dl != 0) {
@@ -890,10 +933,32 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
                goto out;
        }
 
+       if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
+               pr_err("XCOPY parameter truncation: data length %u too small "
+                       "for tdll: %hu sdll: %u inline_dl: %u\n",
+                       se_cmd->data_length, tdll, sdll, inline_dl);
+               ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
+               goto out;
+       }
+
        pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
                " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
                tdll, sdll, inline_dl);
 
+       /*
+        * skip over the target descriptors until segment descriptors
+        * have been passed - CSCD ids are needed to determine src and dest.
+        */
+       seg_desc = &p[16] + tdll;
+
+       rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
+                                                   sdll, &ret);
+       if (rc <= 0)
+               goto out;
+
+       pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
+                               rc * XCOPY_SEGMENT_DESC_LEN);
+
        rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
        if (rc <= 0)
                goto out;
@@ -911,18 +976,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
 
        pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
                                rc * XCOPY_TARGET_DESC_LEN);
-       seg_desc = &p[16];
-       seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
-
-       rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
-       if (rc <= 0) {
-               xcopy_pt_undepend_remotedev(xop);
-               goto out;
-       }
        transport_kunmap_data_sg(se_cmd);
 
-       pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
-                               rc * XCOPY_SEGMENT_DESC_LEN);
        INIT_WORK(&xop->xop_work, target_xcopy_do_work);
        queue_work(xcopy_wq, &xop->xop_work);
        return TCM_NO_SENSE;
index 4d3d4dd060f28366ebd069abb603472ae0275d5b..7c0b105cbe1b486062c40d97280059a286f59bf8 100644 (file)
@@ -1,10 +1,17 @@
 #include <target/target_core_base.h>
 
+#define XCOPY_HDR_LEN                  16
 #define XCOPY_TARGET_DESC_LEN          32
 #define XCOPY_SEGMENT_DESC_LEN         28
 #define XCOPY_NAA_IEEE_REGEX_LEN       16
 #define XCOPY_MAX_SECTORS              1024
 
+/*
+ * SPC4r37 6.4.6.1
+ * Table 150 â€” CSCD descriptor ID values
+ */
+#define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX        0x07FF
+
 enum xcopy_origin_list {
        XCOL_SOURCE_RECV_OP = 0x01,
        XCOL_DEST_RECV_OP = 0x02,
index 61569a765d9ee17213052db6f0d3a1c41d4d9293..76e03a7de9cc3d790a230948f599ef2db4b93249 100644 (file)
@@ -675,7 +675,7 @@ static struct console univ8250_console = {
        .device         = uart_console_device,
        .setup          = univ8250_console_setup,
        .match          = univ8250_console_match,
-       .flags          = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV,
+       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
        .index          = -1,
        .data           = &serial8250_reg,
 };
index aa0166b6d450dcadc85b89d3939c7ae3dd4f0cbc..116436b7fa52a96c740e025d7b5c613e1d365fa8 100644 (file)
@@ -5642,17 +5642,15 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
 static void serial8250_io_resume(struct pci_dev *dev)
 {
        struct serial_private *priv = pci_get_drvdata(dev);
-       const struct pciserial_board *board;
+       struct serial_private *new;
 
        if (!priv)
                return;
 
-       board = priv->board;
-       kfree(priv);
-       priv = pciserial_init_ports(dev, board);
-
-       if (!IS_ERR(priv)) {
-               pci_set_drvdata(dev, priv);
+       new = pciserial_init_ports(dev, priv->board);
+       if (!IS_ERR(new)) {
+               pci_set_drvdata(dev, new);
+               kfree(priv);
        }
 }
 
index fe4399b41df6cea4904edcee4749bb67532f7e18..c13fec451d03db3bfc382d77ea3b1fdf7b3d04e1 100644 (file)
@@ -1413,7 +1413,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
         * Enable previously disabled RX interrupts.
         */
        if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
-               serial8250_clear_fifos(p);
+               serial8250_clear_and_reinit_fifos(p);
 
                p->ier |= UART_IER_RLSI | UART_IER_RDI;
                serial_port_out(&p->port, UART_IER, p->ier);
index 168b10cad47b5437c2152313fcad026e2747300a..fabbe76203bb76a541775792828d3a8662c78348 100644 (file)
@@ -481,6 +481,14 @@ static void atmel_stop_tx(struct uart_port *port)
                /* disable PDC transmit */
                atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
        }
+
+       /*
+        * Disable the transmitter.
+        * This is mandatory when DMA is used, otherwise the DMA buffer
+        * is fully transmitted.
+        */
+       atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+
        /* Disable interrupts */
        atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
 
@@ -513,6 +521,9 @@ static void atmel_start_tx(struct uart_port *port)
 
        /* Enable interrupts */
        atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+       /* re-enable the transmitter */
+       atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
 }
 
 /*
@@ -798,6 +809,11 @@ static void atmel_complete_tx_dma(void *arg)
         */
        if (!uart_circ_empty(xmit))
                atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
+       else if ((port->rs485.flags & SER_RS485_ENABLED) &&
+                !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+               /* DMA done, stop TX, start RX for RS485 */
+               atmel_start_rx(port);
+       }
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -900,12 +916,6 @@ static void atmel_tx_dma(struct uart_port *port)
                desc->callback = atmel_complete_tx_dma;
                desc->callback_param = atmel_port;
                atmel_port->cookie_tx = dmaengine_submit(desc);
-
-       } else {
-               if (port->rs485.flags & SER_RS485_ENABLED) {
-                       /* DMA done, stop TX, start RX for RS485 */
-                       atmel_start_rx(port);
-               }
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
index 52bbd27e93ae7a83af92489b6d27fe0309437afe..701c085bb19b8e03f67316133fa5a4be7e0b05fe 100644 (file)
@@ -946,8 +946,8 @@ static const struct input_device_id sysrq_ids[] = {
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
                                INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { BIT_MASK(KEY_LEFTALT) },
+               .evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_LEFTALT)] = BIT_MASK(KEY_LEFTALT) },
        },
        { },
 };
index 25f522b09dd9746938168e6f675464db9f2e6740..e32029a31ca4d2ed5856c18e6e10b4b40de1132a 100644 (file)
@@ -913,17 +913,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
        spin_lock_irqsave(&xhci->lock, flags);
 
        ep->stop_cmds_pending--;
-       if (xhci->xhc_state & XHCI_STATE_REMOVING) {
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return;
-       }
-       if (xhci->xhc_state & XHCI_STATE_DYING) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                               "Stop EP timer ran, but another timer marked "
-                               "xHCI as DYING, exiting.");
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return;
-       }
        if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
                                "Stop EP timer ran, but no command pending, "
index 0c8deb9ed42def112efc8ad1aaf95526315c164f..9a0ec116654acd27740d497c76ba1a6bb6ab6dd9 100644 (file)
@@ -1534,19 +1534,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_urb_free_priv(urb_priv);
                return ret;
        }
-       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
-                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                               "Ep 0x%x: URB %p to be canceled on "
-                               "non-responsive xHCI host.",
-                               urb->ep->desc.bEndpointAddress, urb);
-               /* Let the stop endpoint command watchdog timer (which set this
-                * state) finish cleaning up the endpoint TD lists.  We must
-                * have caught it in the middle of dropping a lock and giving
-                * back an URB.
-                */
-               goto done;
-       }
 
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
index 4fef50e5c8c1295364aca0a28ba9cf8da005ac21..dd70c88419d20798b738c3da2df009887fdfec7f 100644 (file)
@@ -114,6 +114,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused)
        unsigned                i;
 
        seq_printf(s, "MUSB (M)HDRC Register Dump\n");
+       pm_runtime_get_sync(musb->controller);
 
        for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
                switch (musb_regmap[i].size) {
@@ -132,6 +133,8 @@ static int musb_regdump_show(struct seq_file *s, void *unused)
                }
        }
 
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return 0;
 }
 
@@ -145,7 +148,10 @@ static int musb_test_mode_show(struct seq_file *s, void *unused)
        struct musb             *musb = s->private;
        unsigned                test;
 
+       pm_runtime_get_sync(musb->controller);
        test = musb_readb(musb->mregs, MUSB_TESTMODE);
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
 
        if (test & MUSB_TEST_FORCE_HOST)
                seq_printf(s, "force host\n");
@@ -194,11 +200,12 @@ static ssize_t musb_test_mode_write(struct file *file,
        u8                      test;
        char                    buf[18];
 
+       pm_runtime_get_sync(musb->controller);
        test = musb_readb(musb->mregs, MUSB_TESTMODE);
        if (test) {
                dev_err(musb->controller, "Error: test mode is already set. "
                        "Please do USB Bus Reset to start a new test.\n");
-               return count;
+               goto ret;
        }
 
        memset(buf, 0x00, sizeof(buf));
@@ -234,6 +241,9 @@ static ssize_t musb_test_mode_write(struct file *file,
 
        musb_writeb(musb->mregs, MUSB_TESTMODE, test);
 
+ret:
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return count;
 }
 
@@ -254,8 +264,13 @@ static int musb_softconnect_show(struct seq_file *s, void *unused)
        switch (musb->xceiv->otg->state) {
        case OTG_STATE_A_HOST:
        case OTG_STATE_A_WAIT_BCON:
+               pm_runtime_get_sync(musb->controller);
+
                reg = musb_readb(musb->mregs, MUSB_DEVCTL);
                connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
+
+               pm_runtime_mark_last_busy(musb->controller);
+               pm_runtime_put_autosuspend(musb->controller);
                break;
        default:
                connect = -1;
@@ -284,6 +299,7 @@ static ssize_t musb_softconnect_write(struct file *file,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
+       pm_runtime_get_sync(musb->controller);
        if (!strncmp(buf, "0", 1)) {
                switch (musb->xceiv->otg->state) {
                case OTG_STATE_A_HOST:
@@ -314,6 +330,8 @@ static ssize_t musb_softconnect_write(struct file *file,
                }
        }
 
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return count;
 }
 
index 2597b83a8ae254d0eff28b2d2d124ff51c196248..95aa5233726cf86166ae5aad2ea88c446e894d13 100644 (file)
@@ -95,6 +95,7 @@ struct ch341_private {
        unsigned baud_rate; /* set baud rate */
        u8 line_control; /* set line control value RTS/DTR */
        u8 line_status; /* active status of modem control inputs */
+       u8 lcr;
 };
 
 static void ch341_set_termios(struct tty_struct *tty,
@@ -112,6 +113,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
        r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                            value, index, NULL, 0, DEFAULT_TIMEOUT);
+       if (r < 0)
+               dev_err(&dev->dev, "failed to send control message: %d\n", r);
 
        return r;
 }
@@ -129,11 +132,24 @@ static int ch341_control_in(struct usb_device *dev,
        r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                            value, index, buf, bufsize, DEFAULT_TIMEOUT);
-       return r;
+       if (r < bufsize) {
+               if (r >= 0) {
+                       dev_err(&dev->dev,
+                               "short control message received (%d < %u)\n",
+                               r, bufsize);
+                       r = -EIO;
+               }
+
+               dev_err(&dev->dev, "failed to receive control message: %d\n",
+                       r);
+               return r;
+       }
+
+       return 0;
 }
 
-static int ch341_init_set_baudrate(struct usb_device *dev,
-                                  struct ch341_private *priv, unsigned ctrl)
+static int ch341_set_baudrate_lcr(struct usb_device *dev,
+                                 struct ch341_private *priv, u8 lcr)
 {
        short a;
        int r;
@@ -156,9 +172,19 @@ static int ch341_init_set_baudrate(struct usb_device *dev,
        factor = 0x10000 - factor;
        a = (factor & 0xff00) | divisor;
 
-       /* 0x9c is "enable SFR_UART Control register and timer" */
-       r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT,
-                             0x9c | (ctrl << 8), a | 0x80);
+       /*
+        * CH341A buffers data until a full endpoint-size packet (32 bytes)
+        * has been received unless bit 7 is set.
+        */
+       a |= BIT(7);
+
+       r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a);
+       if (r)
+               return r;
+
+       r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, lcr);
+       if (r)
+               return r;
 
        return r;
 }
@@ -170,9 +196,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
 
 static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
 {
+       const unsigned int size = 2;
        char *buffer;
        int r;
-       const unsigned size = 8;
        unsigned long flags;
 
        buffer = kmalloc(size, GFP_KERNEL);
@@ -183,14 +209,9 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
        if (r < 0)
                goto out;
 
-       /* setup the private status if available */
-       if (r == 2) {
-               r = 0;
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
-               spin_unlock_irqrestore(&priv->lock, flags);
-       } else
-               r = -EPROTO;
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
+       spin_unlock_irqrestore(&priv->lock, flags);
 
 out:   kfree(buffer);
        return r;
@@ -200,9 +221,9 @@ out:        kfree(buffer);
 
 static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 {
+       const unsigned int size = 2;
        char *buffer;
        int r;
-       const unsigned size = 8;
 
        buffer = kmalloc(size, GFP_KERNEL);
        if (!buffer)
@@ -232,7 +253,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
        if (r < 0)
                goto out;
 
-       r = ch341_init_set_baudrate(dev, priv, 0);
+       r = ch341_set_baudrate_lcr(dev, priv, priv->lcr);
        if (r < 0)
                goto out;
 
@@ -258,7 +279,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
 
        spin_lock_init(&priv->lock);
        priv->baud_rate = DEFAULT_BAUD_RATE;
-       priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
 
        r = ch341_configure(port->serial->dev, priv);
        if (r < 0)
@@ -320,7 +340,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        r = ch341_configure(serial->dev, priv);
        if (r)
-               goto out;
+               return r;
 
        if (tty)
                ch341_set_termios(tty, port, NULL);
@@ -330,12 +350,19 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (r) {
                dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
                        __func__, r);
-               goto out;
+               return r;
        }
 
        r = usb_serial_generic_open(tty, port);
+       if (r)
+               goto err_kill_interrupt_urb;
+
+       return 0;
+
+err_kill_interrupt_urb:
+       usb_kill_urb(port->interrupt_in_urb);
 
-out:   return r;
+       return r;
 }
 
 /* Old_termios contains the original termios settings and
@@ -356,7 +383,6 @@ static void ch341_set_termios(struct tty_struct *tty,
 
        baud_rate = tty_get_baud_rate(tty);
 
-       priv->baud_rate = baud_rate;
        ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
 
        switch (C_CSIZE(tty)) {
@@ -386,22 +412,25 @@ static void ch341_set_termios(struct tty_struct *tty,
                ctrl |= CH341_LCR_STOP_BITS_2;
 
        if (baud_rate) {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
+               priv->baud_rate = baud_rate;
+
+               r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl);
                if (r < 0 && old_termios) {
                        priv->baud_rate = tty_termios_baud_rate(old_termios);
                        tty_termios_copy_hw(&tty->termios, old_termios);
+               } else if (r == 0) {
+                       priv->lcr = ctrl;
                }
-       } else {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       ch341_set_handshake(port->serial->dev, priv->line_control);
+       spin_lock_irqsave(&priv->lock, flags);
+       if (C_BAUD(tty) == B0)
+               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+       else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
+       ch341_set_handshake(port->serial->dev, priv->line_control);
 }
 
 static void ch341_break_ctl(struct tty_struct *tty, int break_state)
@@ -576,14 +605,23 @@ static int ch341_tiocmget(struct tty_struct *tty)
 
 static int ch341_reset_resume(struct usb_serial *serial)
 {
-       struct ch341_private *priv;
-
-       priv = usb_get_serial_port_data(serial->port[0]);
+       struct usb_serial_port *port = serial->port[0];
+       struct ch341_private *priv = usb_get_serial_port_data(port);
+       int ret;
 
        /* reconfigure ch341 serial port after bus-reset */
        ch341_configure(serial->dev, priv);
 
-       return 0;
+       if (tty_port_initialized(&port->port)) {
+               ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+               if (ret) {
+                       dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return usb_serial_generic_resume(serial);
 }
 
 static struct usb_serial_driver ch341_device = {
index 0ee190fc1bf8ce7154a4a4eac7023a377aa03365..6cb45757818fae2222383358b4d38d7c87b2dbf4 100644 (file)
@@ -192,10 +192,11 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
                             status_buf, KLSI_STATUSBUF_LEN,
                             10000
                             );
-       if (rc < 0)
-               dev_err(&port->dev, "Reading line status failed (error = %d)\n",
-                       rc);
-       else {
+       if (rc != KLSI_STATUSBUF_LEN) {
+               dev_err(&port->dev, "reading line status failed: %d\n", rc);
+               if (rc >= 0)
+                       rc = -EIO;
+       } else {
                status = get_unaligned_le16(status_buf);
 
                dev_info(&port->serial->dev->dev, "read status %x %x\n",
index 79451f7ef1b76301cc881379ad28ce12e4b4dc33..062c205f00469faf1f7226e152f61d920d71f27b 100644 (file)
@@ -216,7 +216,6 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
        struct scatterlist sg[4], sg_dst;
        void *dst_buf;
        size_t dst_size;
-       const u8 bzero[16] = { 0 };
        u8 iv[crypto_skcipher_ivsize(tfm_cbc)];
        size_t zero_padding;
 
@@ -261,7 +260,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
        sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
        sg_set_buf(&sg[2], b, blen);
        /* 0 if well behaved :) */
-       sg_set_buf(&sg[3], bzero, zero_padding);
+       sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
        sg_init_one(&sg_dst, dst_buf, dst_size);
 
        skcipher_request_set_tfm(req, tfm_cbc);
index 9266271a787a70b61325d1e92ae9a8d710465f0c..b3cc33fa6d26a69f44dc013b7bee55f6bd7682ab 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/uaccess.h>
 #include <linux/vfio.h>
 #include <linux/workqueue.h>
-#include <linux/pid_namespace.h>
 #include <linux/mdev.h>
 #include <linux/notifier.h>
 
@@ -495,8 +494,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
                                  unsigned long *pfn_base, bool do_accounting)
 {
        unsigned long limit;
-       bool lock_cap = ns_capable(task_active_pid_ns(dma->task)->user_ns,
-                                  CAP_IPC_LOCK);
+       bool lock_cap = has_capability(dma->task, CAP_IPC_LOCK);
        struct mm_struct *mm;
        int ret;
        bool rsvd;
index 6b5ee896af6318e9b50c384fcf3e062d24d89c47..7cc51223db1cbe8e905307850b7bd42b6c739279 100644 (file)
@@ -464,7 +464,7 @@ static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
        vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
        pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
 
-       *pci_base = (dma_addr_t)vme_base + pci_offset;
+       *pci_base = (dma_addr_t)*vme_base + pci_offset;
        *size = (unsigned long long)((vme_bound - *vme_base) + granularity);
 
        *enabled = 0;
index 4ab67e8cb776ac18fd12bfec2fa7816800f3f5fa..873b4ca82ccbcde4c108a2592fbd7f46b88273a0 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1085,7 +1085,8 @@ static void aio_complete(struct kiocb *kiocb, long res, long res2)
                 * Tell lockdep we inherited freeze protection from submission
                 * thread.
                 */
-               __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+               if (S_ISREG(file_inode(file)->i_mode))
+                       __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
                file_end_write(file);
        }
 
@@ -1525,7 +1526,8 @@ static ssize_t aio_write(struct kiocb *req, struct iocb *iocb, bool vectored,
                 * by telling it the lock got released so that it doesn't
                 * complain about held lock when we return to userspace.
                 */
-               __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+               if (S_ISREG(file_inode(file)->i_mode))
+                       __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
        }
        kfree(iovec);
        return ret;
index 29a02daf08a97896c600e88317e646dbf3ab3c9b..422370293cfd8cfc9b0f527f73498ce7c28244be 100644 (file)
@@ -2298,6 +2298,7 @@ static int elf_core_dump(struct coredump_params *cprm)
                                goto end_coredump;
                }
        }
+       dump_truncate(cprm);
 
        if (!elf_core_write_extra_data(cprm))
                goto end_coredump;
index 63d197724519b30d8392546f9a8ba9855feaf5aa..ff0b0be92d6122402f02c039eed8e4599fdce4df 100644 (file)
@@ -273,6 +273,8 @@ static void run_ordered_work(struct __btrfs_workqueue *wq)
        unsigned long flags;
 
        while (1) {
+               void *wtag;
+
                spin_lock_irqsave(lock, flags);
                if (list_empty(list))
                        break;
@@ -299,11 +301,13 @@ static void run_ordered_work(struct __btrfs_workqueue *wq)
                spin_unlock_irqrestore(lock, flags);
 
                /*
-                * we don't want to call the ordered free functions
-                * with the lock held though
+                * We don't want to call the ordered free functions with the
+                * lock held though. Save the work as tag for the trace event,
+                * because the callback could free the structure.
                 */
+               wtag = work;
                work->ordered_free(work);
-               trace_btrfs_all_work_done(work);
+               trace_btrfs_all_work_done(wq->fs_info, wtag);
        }
        spin_unlock_irqrestore(lock, flags);
 }
@@ -311,6 +315,7 @@ static void run_ordered_work(struct __btrfs_workqueue *wq)
 static void normal_work_helper(struct btrfs_work *work)
 {
        struct __btrfs_workqueue *wq;
+       void *wtag;
        int need_order = 0;
 
        /*
@@ -324,6 +329,8 @@ static void normal_work_helper(struct btrfs_work *work)
        if (work->ordered_func)
                need_order = 1;
        wq = work->wq;
+       /* Safe for tracepoints in case work gets freed by the callback */
+       wtag = work;
 
        trace_btrfs_work_sched(work);
        thresh_exec_hook(wq);
@@ -333,7 +340,7 @@ static void normal_work_helper(struct btrfs_work *work)
                run_ordered_work(wq);
        }
        if (!need_order)
-               trace_btrfs_all_work_done(work);
+               trace_btrfs_all_work_done(wq->fs_info, wtag);
 }
 
 void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t uniq_func,
index e97302f437a16db24db7d2aa6ae202cde3309fb6..dcd2e798767e57a80e7f50ff791a675e394a62c0 100644 (file)
@@ -2522,11 +2522,11 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                if (ref && ref->seq &&
                    btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
                        spin_unlock(&locked_ref->lock);
-                       btrfs_delayed_ref_unlock(locked_ref);
                        spin_lock(&delayed_refs->lock);
                        locked_ref->processing = 0;
                        delayed_refs->num_heads_ready++;
                        spin_unlock(&delayed_refs->lock);
+                       btrfs_delayed_ref_unlock(locked_ref);
                        locked_ref = NULL;
                        cond_resched();
                        count++;
@@ -2572,7 +2572,10 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                                         */
                                        if (must_insert_reserved)
                                                locked_ref->must_insert_reserved = 1;
+                                       spin_lock(&delayed_refs->lock);
                                        locked_ref->processing = 0;
+                                       delayed_refs->num_heads_ready++;
+                                       spin_unlock(&delayed_refs->lock);
                                        btrfs_debug(fs_info,
                                                    "run_delayed_extent_op returned %d",
                                                    ret);
@@ -7384,7 +7387,8 @@ btrfs_lock_cluster(struct btrfs_block_group_cache *block_group,
 
                spin_unlock(&cluster->refill_lock);
 
-               down_read(&used_bg->data_rwsem);
+               /* We should only have one-level nested. */
+               down_read_nested(&used_bg->data_rwsem, SINGLE_DEPTH_NESTING);
 
                spin_lock(&cluster->refill_lock);
                if (used_bg == cluster->block_group)
index f2b281ad7af6b9db26b48c6d4f072a850c19d58a..4e024260ad713ffc583d8f2ffaeb7ba6a025014d 100644 (file)
@@ -7059,7 +7059,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
        write_unlock(&em_tree->lock);
 out:
 
-       trace_btrfs_get_extent(root, em);
+       trace_btrfs_get_extent(root, inode, em);
 
        btrfs_free_path(path);
        if (trans) {
@@ -7623,11 +7623,18 @@ static void adjust_dio_outstanding_extents(struct inode *inode,
         * within our reservation, otherwise we need to adjust our inode
         * counter appropriately.
         */
-       if (dio_data->outstanding_extents) {
+       if (dio_data->outstanding_extents >= num_extents) {
                dio_data->outstanding_extents -= num_extents;
        } else {
+               /*
+                * If dio write length has been split due to no large enough
+                * contiguous space, we need to compensate our inode counter
+                * appropriately.
+                */
+               u64 num_needed = num_extents - dio_data->outstanding_extents;
+
                spin_lock(&BTRFS_I(inode)->lock);
-               BTRFS_I(inode)->outstanding_extents += num_extents;
+               BTRFS_I(inode)->outstanding_extents += num_needed;
                spin_unlock(&BTRFS_I(inode)->lock);
        }
 }
index f10bf5213ed8a48b95a8cf3cf51dc3c2c81b8463..eeffff84f280958cfd117e860055d7b9fc683377 100644 (file)
@@ -37,6 +37,7 @@
  */
 #define LOG_INODE_ALL 0
 #define LOG_INODE_EXISTS 1
+#define LOG_OTHER_INODE 2
 
 /*
  * directory trouble cases
@@ -4641,7 +4642,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        if (S_ISDIR(inode->i_mode) ||
            (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                       &BTRFS_I(inode)->runtime_flags) &&
-            inode_only == LOG_INODE_EXISTS))
+            inode_only >= LOG_INODE_EXISTS))
                max_key.type = BTRFS_XATTR_ITEM_KEY;
        else
                max_key.type = (u8)-1;
@@ -4665,7 +4666,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       mutex_lock(&BTRFS_I(inode)->log_mutex);
+       if (inode_only == LOG_OTHER_INODE) {
+               inode_only = LOG_INODE_EXISTS;
+               mutex_lock_nested(&BTRFS_I(inode)->log_mutex,
+                                 SINGLE_DEPTH_NESTING);
+       } else {
+               mutex_lock(&BTRFS_I(inode)->log_mutex);
+       }
 
        /*
         * a brute force approach to making sure we get the most uptodate
@@ -4817,7 +4824,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                                 * unpin it.
                                 */
                                err = btrfs_log_inode(trans, root, other_inode,
-                                                     LOG_INODE_EXISTS,
+                                                     LOG_OTHER_INODE,
                                                      0, LLONG_MAX, ctx);
                                iput(other_inode);
                                if (err)
index 161342b73ce50256bd2cba63b0d1c5ece503f599..726f928238d0c86a931cd58613799e59cc35fdf8 100644 (file)
@@ -352,7 +352,5 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
 
 out:
        btrfs_free_path(path);
-       if (ret)
-               btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
-       return 0;
+       return ret;
 }
index 9cd0c0ea7cdbd5b683ab035927636f9f56b751d3..e4b066cd912ad9ea249c3c88f81026a68186095c 100644 (file)
@@ -502,9 +502,9 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
                dout(" head snapc %p has %d dirty pages\n",
                     snapc, ci->i_wrbuffer_ref_head);
                if (truncate_size)
-                       *truncate_size = capsnap->truncate_size;
+                       *truncate_size = ci->i_truncate_size;
                if (truncate_seq)
-                       *truncate_seq = capsnap->truncate_seq;
+                       *truncate_seq = ci->i_truncate_seq;
        }
        spin_unlock(&ci->i_ceph_lock);
        return snapc;
index 4f49253387a0a59d238a041b1ec8fc9fd7185c40..ec6b35e9f966bfae46e69dfcaffee2769d699bfd 100644 (file)
@@ -2106,6 +2106,11 @@ static int __do_request(struct ceph_mds_client *mdsc,
                        dout("do_request mdsmap err %d\n", err);
                        goto finish;
                }
+               if (mdsc->mdsmap->m_epoch == 0) {
+                       dout("do_request no mdsmap, waiting for map\n");
+                       list_add(&req->r_wait, &mdsc->waiting_for_map);
+                       goto finish;
+               }
                if (!(mdsc->fsc->mount_options->flags &
                      CEPH_MOUNT_OPT_MOUNTWAIT) &&
                    !ceph_mdsmap_is_cluster_available(mdsc->mdsmap)) {
index e525b6017cdf863fd811425fb603070be40420b2..ae6b05629ca174d714bbdb3db477bee8f0d8bff8 100644 (file)
@@ -833,3 +833,21 @@ int dump_align(struct coredump_params *cprm, int align)
        return mod ? dump_skip(cprm, align - mod) : 1;
 }
 EXPORT_SYMBOL(dump_align);
+
+/*
+ * Ensures that file size is big enough to contain the current file
+ * postion. This prevents gdb from complaining about a truncated file
+ * if the last "write" to the file was dump_skip.
+ */
+void dump_truncate(struct coredump_params *cprm)
+{
+       struct file *file = cprm->file;
+       loff_t offset;
+
+       if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+               offset = file->f_op->llseek(file, 0, SEEK_CUR);
+               if (i_size_read(file->f_mapping->host) < offset)
+                       do_truncate(file->f_path.dentry, offset, 0, file);
+       }
+}
+EXPORT_SYMBOL(dump_truncate);
index 5c74f60d0a5094dc0a27f27ae0acd41667414332..ddcddfeaa03bd942e83738d34c4abaed06fa2709 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -691,8 +691,8 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
                                      pgoff_t index, unsigned long pfn)
 {
        struct vm_area_struct *vma;
-       pte_t *ptep;
-       pte_t pte;
+       pte_t pte, *ptep = NULL;
+       pmd_t *pmdp = NULL;
        spinlock_t *ptl;
        bool changed;
 
@@ -707,21 +707,42 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 
                address = pgoff_address(index, vma);
                changed = false;
-               if (follow_pte(vma->vm_mm, address, &ptep, &ptl))
+               if (follow_pte_pmd(vma->vm_mm, address, &ptep, &pmdp, &ptl))
                        continue;
-               if (pfn != pte_pfn(*ptep))
-                       goto unlock;
-               if (!pte_dirty(*ptep) && !pte_write(*ptep))
-                       goto unlock;
 
-               flush_cache_page(vma, address, pfn);
-               pte = ptep_clear_flush(vma, address, ptep);
-               pte = pte_wrprotect(pte);
-               pte = pte_mkclean(pte);
-               set_pte_at(vma->vm_mm, address, ptep, pte);
-               changed = true;
-unlock:
-               pte_unmap_unlock(ptep, ptl);
+               if (pmdp) {
+#ifdef CONFIG_FS_DAX_PMD
+                       pmd_t pmd;
+
+                       if (pfn != pmd_pfn(*pmdp))
+                               goto unlock_pmd;
+                       if (!pmd_dirty(*pmdp) && !pmd_write(*pmdp))
+                               goto unlock_pmd;
+
+                       flush_cache_page(vma, address, pfn);
+                       pmd = pmdp_huge_clear_flush(vma, address, pmdp);
+                       pmd = pmd_wrprotect(pmd);
+                       pmd = pmd_mkclean(pmd);
+                       set_pmd_at(vma->vm_mm, address, pmdp, pmd);
+                       changed = true;
+unlock_pmd:
+                       spin_unlock(ptl);
+#endif
+               } else {
+                       if (pfn != pte_pfn(*ptep))
+                               goto unlock_pte;
+                       if (!pte_dirty(*ptep) && !pte_write(*ptep))
+                               goto unlock_pte;
+
+                       flush_cache_page(vma, address, pfn);
+                       pte = ptep_clear_flush(vma, address, ptep);
+                       pte = pte_wrprotect(pte);
+                       pte = pte_mkclean(pte);
+                       set_pte_at(vma->vm_mm, address, ptep, pte);
+                       changed = true;
+unlock_pte:
+                       pte_unmap_unlock(ptep, ptl);
+               }
 
                if (changed)
                        mmu_notifier_invalidate_page(vma->vm_mm, address);
index 769903dbc19df53199b4aca2e79607145e179c98..95d71eda81420a506c5a1f4a4f5283b31310d5e4 100644 (file)
@@ -1336,8 +1336,11 @@ int d_set_mounted(struct dentry *dentry)
        }
        spin_lock(&dentry->d_lock);
        if (!d_unlinked(dentry)) {
-               dentry->d_flags |= DCACHE_MOUNTED;
-               ret = 0;
+               ret = -EBUSY;
+               if (!d_mountpoint(dentry)) {
+                       dentry->d_flags |= DCACHE_MOUNTED;
+                       ret = 0;
+               }
        }
        spin_unlock(&dentry->d_lock);
 out:
index aeae8c06345155e35e6f9d1567d004c6d073ea66..c87bae4376b848f4204c06016eeb223f675dc7db 100644 (file)
@@ -906,6 +906,7 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio,
                        struct buffer_head *map_bh)
 {
        const unsigned blkbits = sdio->blkbits;
+       const unsigned i_blkbits = blkbits + sdio->blkfactor;
        int ret = 0;
 
        while (sdio->block_in_file < sdio->final_block_in_request) {
@@ -949,7 +950,7 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio,
                                        clean_bdev_aliases(
                                                map_bh->b_bdev,
                                                map_bh->b_blocknr,
-                                               map_bh->b_size >> blkbits);
+                                               map_bh->b_size >> i_blkbits);
                                }
 
                                if (!sdio->blkfactor)
index 0738f48293ccbfe0fd528ededfd6a4a08fe4251d..0d880245375890058602437d3c709bfedd3945b8 100644 (file)
@@ -713,8 +713,8 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
        }
        sector = SECTOR_FROM_BLOCK(blkstart);
 
-       if (sector & (bdev_zone_size(bdev) - 1) ||
-                               nr_sects != bdev_zone_size(bdev)) {
+       if (sector & (bdev_zone_sectors(bdev) - 1) ||
+           nr_sects != bdev_zone_sectors(bdev)) {
                f2fs_msg(sbi->sb, KERN_INFO,
                        "(%d) %s: Unaligned discard attempted (block %x + %x)",
                        devi, sbi->s_ndevs ? FDEV(devi).path: "",
index 702638e21c7621a4804a8c84fefc7635785ff42d..46fd30d8af7763c93244092b6673e3cc2ff5f05f 100644 (file)
@@ -1553,16 +1553,16 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
                return 0;
 
        if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
-                               SECTOR_TO_BLOCK(bdev_zone_size(bdev)))
+                               SECTOR_TO_BLOCK(bdev_zone_sectors(bdev)))
                return -EINVAL;
-       sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_size(bdev));
+       sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_sectors(bdev));
        if (sbi->log_blocks_per_blkz && sbi->log_blocks_per_blkz !=
                                __ilog2_u32(sbi->blocks_per_blkz))
                return -EINVAL;
        sbi->log_blocks_per_blkz = __ilog2_u32(sbi->blocks_per_blkz);
        FDEV(devi).nr_blkz = SECTOR_TO_BLOCK(nr_sectors) >>
                                        sbi->log_blocks_per_blkz;
-       if (nr_sectors & (bdev_zone_size(bdev) - 1))
+       if (nr_sectors & (bdev_zone_sectors(bdev) - 1))
                FDEV(devi).nr_blkz++;
 
        FDEV(devi).blkz_type = kmalloc(FDEV(devi).nr_blkz, GFP_KERNEL);
index e973cd51f12632eff2c17929c85d1e8b2e955730..28d6f35feed62855e26ede0073b3bcaf6b6564a9 100644 (file)
@@ -245,7 +245,8 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
        struct inode *root;
        struct qstr d_name = QSTR_INIT(name, strlen(name));
 
-       s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL);
+       s = sget_userns(fs_type, NULL, set_anon_super, MS_KERNMOUNT|MS_NOUSER,
+                       &init_user_ns, NULL);
        if (IS_ERR(s))
                return ERR_CAST(s);
 
index b5b1259e064f8d9661110ba1f1f73d1a0ff19d51..487ba30bb5c67a8f66bdaadb5b13e8240c937f7a 100644 (file)
@@ -742,26 +742,50 @@ static struct mountpoint *lookup_mountpoint(struct dentry *dentry)
        return NULL;
 }
 
-static struct mountpoint *new_mountpoint(struct dentry *dentry)
+static struct mountpoint *get_mountpoint(struct dentry *dentry)
 {
-       struct hlist_head *chain = mp_hash(dentry);
-       struct mountpoint *mp;
+       struct mountpoint *mp, *new = NULL;
        int ret;
 
-       mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
-       if (!mp)
+       if (d_mountpoint(dentry)) {
+mountpoint:
+               read_seqlock_excl(&mount_lock);
+               mp = lookup_mountpoint(dentry);
+               read_sequnlock_excl(&mount_lock);
+               if (mp)
+                       goto done;
+       }
+
+       if (!new)
+               new = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
+       if (!new)
                return ERR_PTR(-ENOMEM);
 
+
+       /* Exactly one processes may set d_mounted */
        ret = d_set_mounted(dentry);
-       if (ret) {
-               kfree(mp);
-               return ERR_PTR(ret);
-       }
 
-       mp->m_dentry = dentry;
-       mp->m_count = 1;
-       hlist_add_head(&mp->m_hash, chain);
-       INIT_HLIST_HEAD(&mp->m_list);
+       /* Someone else set d_mounted? */
+       if (ret == -EBUSY)
+               goto mountpoint;
+
+       /* The dentry is not available as a mountpoint? */
+       mp = ERR_PTR(ret);
+       if (ret)
+               goto done;
+
+       /* Add the new mountpoint to the hash table */
+       read_seqlock_excl(&mount_lock);
+       new->m_dentry = dentry;
+       new->m_count = 1;
+       hlist_add_head(&new->m_hash, mp_hash(dentry));
+       INIT_HLIST_HEAD(&new->m_list);
+       read_sequnlock_excl(&mount_lock);
+
+       mp = new;
+       new = NULL;
+done:
+       kfree(new);
        return mp;
 }
 
@@ -1595,11 +1619,11 @@ void __detach_mounts(struct dentry *dentry)
        struct mount *mnt;
 
        namespace_lock();
+       lock_mount_hash();
        mp = lookup_mountpoint(dentry);
        if (IS_ERR_OR_NULL(mp))
                goto out_unlock;
 
-       lock_mount_hash();
        event++;
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
@@ -1609,9 +1633,9 @@ void __detach_mounts(struct dentry *dentry)
                }
                else umount_tree(mnt, UMOUNT_CONNECTED);
        }
-       unlock_mount_hash();
        put_mountpoint(mp);
 out_unlock:
+       unlock_mount_hash();
        namespace_unlock();
 }
 
@@ -2038,9 +2062,7 @@ static struct mountpoint *lock_mount(struct path *path)
        namespace_lock();
        mnt = lookup_mnt(path);
        if (likely(!mnt)) {
-               struct mountpoint *mp = lookup_mountpoint(dentry);
-               if (!mp)
-                       mp = new_mountpoint(dentry);
+               struct mountpoint *mp = get_mountpoint(dentry);
                if (IS_ERR(mp)) {
                        namespace_unlock();
                        inode_unlock(dentry->d_inode);
@@ -2059,7 +2081,11 @@ static struct mountpoint *lock_mount(struct path *path)
 static void unlock_mount(struct mountpoint *where)
 {
        struct dentry *dentry = where->m_dentry;
+
+       read_seqlock_excl(&mount_lock);
        put_mountpoint(where);
+       read_sequnlock_excl(&mount_lock);
+
        namespace_unlock();
        inode_unlock(dentry->d_inode);
 }
@@ -3135,9 +3161,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        touch_mnt_namespace(current->nsproxy->mnt_ns);
        /* A moved mount should not expire automatically */
        list_del_init(&new_mnt->mnt_expire);
+       put_mountpoint(root_mp);
        unlock_mount_hash();
        chroot_fs_refs(&root, &new);
-       put_mountpoint(root_mp);
        error = 0;
 out4:
        unlock_mount(old_mp);
index 83d576f6a287b13939a7dd70622ae4d89b5031f8..77d1632e905d8b1ec249cf86c7ece183c38f2746 100644 (file)
@@ -3303,6 +3303,16 @@ static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
        mlog(ML_BASTS, "lockres %s, level %d => %d\n", lockres->l_name,
             lockres->l_level, new_level);
 
+       /*
+        * On DLM_LKF_VALBLK, fsdlm behaves differently with o2cb. It always
+        * expects DLM_LKF_VALBLK being set if the LKB has LVB, so that
+        * we can recover correctly from node failure. Otherwise, we may get
+        * invalid LVB in LKB, but without DLM_SBF_VALNOTVALID being set.
+        */
+       if (!ocfs2_is_o2cb_active() &&
+           lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
+               lvb = 1;
+
        if (lvb)
                dlm_flags |= DLM_LKF_VALBLK;
 
index 52c07346bea3f8960399184c0e6aead7545a25f2..820359096c7aa8df5b76e2a0c1404ce7f9d0337d 100644 (file)
@@ -48,6 +48,12 @@ static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
  */
 static struct ocfs2_stack_plugin *active_stack;
 
+inline int ocfs2_is_o2cb_active(void)
+{
+       return !strcmp(active_stack->sp_name, OCFS2_STACK_PLUGIN_O2CB);
+}
+EXPORT_SYMBOL_GPL(ocfs2_is_o2cb_active);
+
 static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name)
 {
        struct ocfs2_stack_plugin *p;
index f2dce10fae543c254dcb4e6628d357b60a3ac16c..e3036e1790e86da7b4e13dcb0b8c88e3f19b6d50 100644 (file)
@@ -298,6 +298,9 @@ void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_p
 int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
 void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);
 
+/* In ocfs2_downconvert_lock(), we need to know which stack we are using */
+int ocfs2_is_o2cb_active(void);
+
 extern struct kset *ocfs2_kset;
 
 #endif  /* STACKGLUE_H */
index 595522022aca04beeeabd3d2ed4e73992f268296..c9d48dc784953fa4af62f9af58dfbb56ed2faa70 100644 (file)
@@ -922,11 +922,10 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        int error;
 
        if (type == ACL_TYPE_ACCESS) {
-               error = posix_acl_equiv_mode(acl, &inode->i_mode);
-               if (error < 0)
-                       return 0;
-               if (error == 0)
-                       acl = NULL;
+               error = posix_acl_update_mode(inode,
+                               &inode->i_mode, &acl);
+               if (error)
+                       return error;
        }
 
        inode->i_ctime = current_time(inode);
index 55313d9948954bbe4bff5769e487eb78012776db..d4e37acd48217dcb1090a1ee68bb4ec4cb7226e5 100644 (file)
@@ -709,7 +709,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
        ctl_dir = container_of(head, struct ctl_dir, header);
 
        if (!dir_emit_dots(file, ctx))
-               return 0;
+               goto out;
 
        pos = 2;
 
@@ -719,6 +719,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
                        break;
                }
        }
+out:
        sysctl_head_finish(head);
        return 0;
 }
index 5050056a0b06445a93845987a52ec8356c499f80..9f06a211e1570549cb8df3cdba2de2d01a79f890 100644 (file)
@@ -95,10 +95,7 @@ unsigned int
 xfs_alloc_set_aside(
        struct xfs_mount        *mp)
 {
-       unsigned int            blocks;
-
-       blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE);
-       return blocks;
+       return mp->m_sb.sb_agcount * (XFS_ALLOC_AGFL_RESERVE + 4);
 }
 
 /*
@@ -365,35 +362,11 @@ xfs_alloc_fix_len(
                return;
        ASSERT(rlen >= args->minlen && rlen <= args->maxlen);
        ASSERT(rlen % args->prod == args->mod);
+       ASSERT(args->pag->pagf_freeblks + args->pag->pagf_flcount >=
+               rlen + args->minleft);
        args->len = rlen;
 }
 
-/*
- * Fix up length if there is too little space left in the a.g.
- * Return 1 if ok, 0 if too little, should give up.
- */
-STATIC int
-xfs_alloc_fix_minleft(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
-{
-       xfs_agf_t       *agf;           /* a.g. freelist header */
-       int             diff;           /* free space difference */
-
-       if (args->minleft == 0)
-               return 1;
-       agf = XFS_BUF_TO_AGF(args->agbp);
-       diff = be32_to_cpu(agf->agf_freeblks)
-               - args->len - args->minleft;
-       if (diff >= 0)
-               return 1;
-       args->len += diff;              /* shrink the allocated space */
-       /* casts to (int) catch length underflows */
-       if ((int)args->len >= (int)args->minlen)
-               return 1;
-       args->agbno = NULLAGBLOCK;
-       return 0;
-}
-
 /*
  * Update the two btrees, logically removing from freespace the extent
  * starting at rbno, rlen blocks.  The extent is contained within the
@@ -689,8 +662,6 @@ xfs_alloc_ag_vextent(
        xfs_alloc_arg_t *args)  /* argument structure for allocation */
 {
        int             error=0;
-       xfs_extlen_t    reservation;
-       xfs_extlen_t    oldmax;
 
        ASSERT(args->minlen > 0);
        ASSERT(args->maxlen > 0);
@@ -698,20 +669,6 @@ xfs_alloc_ag_vextent(
        ASSERT(args->mod < args->prod);
        ASSERT(args->alignment > 0);
 
-       /*
-        * Clamp maxlen to the amount of free space minus any reservations
-        * that have been made.
-        */
-       oldmax = args->maxlen;
-       reservation = xfs_ag_resv_needed(args->pag, args->resv);
-       if (args->maxlen > args->pag->pagf_freeblks - reservation)
-               args->maxlen = args->pag->pagf_freeblks - reservation;
-       if (args->maxlen == 0) {
-               args->agbno = NULLAGBLOCK;
-               args->maxlen = oldmax;
-               return 0;
-       }
-
        /*
         * Branch to correct routine based on the type.
         */
@@ -731,8 +688,6 @@ xfs_alloc_ag_vextent(
                /* NOTREACHED */
        }
 
-       args->maxlen = oldmax;
-
        if (error || args->agbno == NULLAGBLOCK)
                return error;
 
@@ -841,9 +796,6 @@ xfs_alloc_ag_vextent_exact(
        args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen)
                                                - args->agbno;
        xfs_alloc_fix_len(args);
-       if (!xfs_alloc_fix_minleft(args))
-               goto not_found;
-
        ASSERT(args->agbno + args->len <= tend);
 
        /*
@@ -1149,12 +1101,7 @@ xfs_alloc_ag_vextent_near(
                XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
                args->len = blen;
-               if (!xfs_alloc_fix_minleft(args)) {
-                       xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
-                       trace_xfs_alloc_near_nominleft(args);
-                       return 0;
-               }
-               blen = args->len;
+
                /*
                 * We are allocating starting at bnew for blen blocks.
                 */
@@ -1346,12 +1293,6 @@ xfs_alloc_ag_vextent_near(
         */
        args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
        xfs_alloc_fix_len(args);
-       if (!xfs_alloc_fix_minleft(args)) {
-               trace_xfs_alloc_near_nominleft(args);
-               xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);
-               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
-               return 0;
-       }
        rlen = args->len;
        (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment,
                                     args->datatype, ltbnoa, ltlena, &ltnew);
@@ -1553,8 +1494,6 @@ xfs_alloc_ag_vextent_size(
        }
        xfs_alloc_fix_len(args);
 
-       if (!xfs_alloc_fix_minleft(args))
-               goto out_nominleft;
        rlen = args->len;
        XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0);
        /*
@@ -2056,7 +1995,7 @@ xfs_alloc_space_available(
        int                     flags)
 {
        struct xfs_perag        *pag = args->pag;
-       xfs_extlen_t            longest;
+       xfs_extlen_t            alloc_len, longest;
        xfs_extlen_t            reservation; /* blocks that are still reserved */
        int                     available;
 
@@ -2066,17 +2005,28 @@ xfs_alloc_space_available(
        reservation = xfs_ag_resv_needed(pag, args->resv);
 
        /* do we have enough contiguous free space for the allocation? */
+       alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop;
        longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free,
                        reservation);
-       if ((args->minlen + args->alignment + args->minalignslop - 1) > longest)
+       if (longest < alloc_len)
                return false;
 
        /* do we have enough free space remaining for the allocation? */
        available = (int)(pag->pagf_freeblks + pag->pagf_flcount -
-                         reservation - min_free - args->total);
-       if (available < (int)args->minleft || available <= 0)
+                         reservation - min_free - args->minleft);
+       if (available < (int)max(args->total, alloc_len))
                return false;
 
+       /*
+        * Clamp maxlen to the amount of free space available for the actual
+        * extent allocation.
+        */
+       if (available < (int)args->maxlen && !(flags & XFS_ALLOC_FLAG_CHECK)) {
+               args->maxlen = available;
+               ASSERT(args->maxlen > 0);
+               ASSERT(args->maxlen >= args->minlen);
+       }
+
        return true;
 }
 
@@ -2122,7 +2072,8 @@ xfs_alloc_fix_freelist(
        }
 
        need = xfs_alloc_min_freelist(mp, pag);
-       if (!xfs_alloc_space_available(args, need, flags))
+       if (!xfs_alloc_space_available(args, need, flags |
+                       XFS_ALLOC_FLAG_CHECK))
                goto out_agbp_relse;
 
        /*
@@ -2638,12 +2589,10 @@ xfs_alloc_vextent(
        xfs_agblock_t   agsize; /* allocation group size */
        int             error;
        int             flags;  /* XFS_ALLOC_FLAG_... locking flags */
-       xfs_extlen_t    minleft;/* minimum left value, temp copy */
        xfs_mount_t     *mp;    /* mount structure pointer */
        xfs_agnumber_t  sagno;  /* starting allocation group number */
        xfs_alloctype_t type;   /* input allocation type */
        int             bump_rotor = 0;
-       int             no_min = 0;
        xfs_agnumber_t  rotorstep = xfs_rotorstep; /* inode32 agf stepper */
 
        mp = args->mp;
@@ -2672,7 +2621,6 @@ xfs_alloc_vextent(
                trace_xfs_alloc_vextent_badargs(args);
                return 0;
        }
-       minleft = args->minleft;
 
        switch (type) {
        case XFS_ALLOCTYPE_THIS_AG:
@@ -2683,9 +2631,7 @@ xfs_alloc_vextent(
                 */
                args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
                args->pag = xfs_perag_get(mp, args->agno);
-               args->minleft = 0;
                error = xfs_alloc_fix_freelist(args, 0);
-               args->minleft = minleft;
                if (error) {
                        trace_xfs_alloc_vextent_nofix(args);
                        goto error0;
@@ -2750,9 +2696,7 @@ xfs_alloc_vextent(
                 */
                for (;;) {
                        args->pag = xfs_perag_get(mp, args->agno);
-                       if (no_min) args->minleft = 0;
                        error = xfs_alloc_fix_freelist(args, flags);
-                       args->minleft = minleft;
                        if (error) {
                                trace_xfs_alloc_vextent_nofix(args);
                                goto error0;
@@ -2792,20 +2736,17 @@ xfs_alloc_vextent(
                         * or switch to non-trylock mode.
                         */
                        if (args->agno == sagno) {
-                               if (no_min == 1) {
+                               if (flags == 0) {
                                        args->agbno = NULLAGBLOCK;
                                        trace_xfs_alloc_vextent_allfailed(args);
                                        break;
                                }
-                               if (flags == 0) {
-                                       no_min = 1;
-                               } else {
-                                       flags = 0;
-                                       if (type == XFS_ALLOCTYPE_START_BNO) {
-                                               args->agbno = XFS_FSB_TO_AGBNO(mp,
-                                                       args->fsbno);
-                                               args->type = XFS_ALLOCTYPE_NEAR_BNO;
-                                       }
+
+                               flags = 0;
+                               if (type == XFS_ALLOCTYPE_START_BNO) {
+                                       args->agbno = XFS_FSB_TO_AGBNO(mp,
+                                               args->fsbno);
+                                       args->type = XFS_ALLOCTYPE_NEAR_BNO;
                                }
                        }
                        xfs_perag_put(args->pag);
index 7c404a6b0ae32292cf9a6eb39efd15026e8e76ed..1d0f48a501a3d6e9575b634ac022f30a91a2f309 100644 (file)
@@ -56,7 +56,7 @@ typedef unsigned int xfs_alloctype_t;
 #define        XFS_ALLOC_FLAG_FREEING  0x00000002  /* indicate caller is freeing extents*/
 #define        XFS_ALLOC_FLAG_NORMAP   0x00000004  /* don't modify the rmapbt */
 #define        XFS_ALLOC_FLAG_NOSHRINK 0x00000008  /* don't shrink the freelist */
-
+#define        XFS_ALLOC_FLAG_CHECK    0x00000010  /* test only, don't modify args */
 
 /*
  * Argument structure for xfs_alloc routines.
index 2760bc3b2536c46eedd63c66e127e953dab9ce55..44773c9eb957dd8f6c5904ef9d41c3de880d14be 100644 (file)
@@ -3812,7 +3812,6 @@ xfs_bmap_btalloc(
                args.fsbno = 0;
                args.type = XFS_ALLOCTYPE_FIRST_AG;
                args.total = ap->minlen;
-               args.minleft = 0;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
                ap->dfops->dop_low = true;
@@ -4344,8 +4343,6 @@ xfs_bmapi_allocate(
        if (error)
                return error;
 
-       if (bma->dfops->dop_low)
-               bma->minleft = 0;
        if (bma->cur)
                bma->cur->bc_private.b.firstblock = *bma->firstblock;
        if (bma->blkno == NULLFSBLOCK)
index d6330c297ca0a4858666403f513f43ce4e16d1a0..d9be241fc86fb39207e725d28bdcdccf943a393d 100644 (file)
@@ -502,12 +502,11 @@ xfs_bmbt_alloc_block(
        if (args.fsbno == NULLFSBLOCK && args.minleft) {
                /*
                 * Could not find an AG with enough free space to satisfy
-                * a full btree split.  Try again without minleft and if
+                * a full btree split.  Try again and if
                 * successful activate the lowspace algorithm.
                 */
                args.fsbno = 0;
                args.type = XFS_ALLOCTYPE_FIRST_AG;
-               args.minleft = 0;
                error = xfs_alloc_vextent(&args);
                if (error)
                        goto error0;
index 0f56fcd3a5d51517b93c391bb3d97a58f205a544..631e7c0e0a29ae51eba5f7e25d8dfc96dc93c61e 100644 (file)
@@ -1152,19 +1152,22 @@ xfs_vm_releasepage(
         * block_invalidatepage() can send pages that are still marked dirty
         * but otherwise have invalidated buffers.
         *
-        * We've historically freed buffers on the latter. Instead, quietly
-        * filter out all dirty pages to avoid spurious buffer state warnings.
-        * This can likely be removed once shrink_active_list() is fixed.
+        * We want to release the latter to avoid unnecessary buildup of the
+        * LRU, skip the former and warn if we've left any lingering
+        * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
+        * or unwritten buffers and warn if the page is not dirty. Otherwise
+        * try to release the buffers.
         */
-       if (PageDirty(page))
-               return 0;
-
        xfs_count_page_state(page, &delalloc, &unwritten);
 
-       if (WARN_ON_ONCE(delalloc))
+       if (delalloc) {
+               WARN_ON_ONCE(!PageDirty(page));
                return 0;
-       if (WARN_ON_ONCE(unwritten))
+       }
+       if (unwritten) {
+               WARN_ON_ONCE(!PageDirty(page));
                return 0;
+       }
 
        return try_to_free_buffers(page);
 }
index c39ac14ff54009ba33a4a7313612bd2afb95117c..b1469f0a91a6c04329cb2fff2dc6e9953485a071 100644 (file)
@@ -3317,12 +3317,8 @@ xfs_log_force(
        xfs_mount_t     *mp,
        uint            flags)
 {
-       int     error;
-
        trace_xfs_log_force(mp, 0, _RET_IP_);
-       error = _xfs_log_force(mp, flags, NULL);
-       if (error)
-               xfs_warn(mp, "%s: error %d returned.", __func__, error);
+       _xfs_log_force(mp, flags, NULL);
 }
 
 /*
@@ -3466,12 +3462,8 @@ xfs_log_force_lsn(
        xfs_lsn_t       lsn,
        uint            flags)
 {
-       int     error;
-
        trace_xfs_log_force(mp, lsn, _RET_IP_);
-       error = _xfs_log_force_lsn(mp, lsn, flags, NULL);
-       if (error)
-               xfs_warn(mp, "%s: error %d returned.", __func__, error);
+       _xfs_log_force_lsn(mp, lsn, flags, NULL);
 }
 
 /*
index 83695641bd5ec272551857c448cc9b4f354898b8..1ca8e8fd10789d0fff1aa0b21ede64b72075e094 100644 (file)
@@ -739,7 +739,7 @@ static inline bool blk_queue_is_zoned(struct request_queue *q)
        }
 }
 
-static inline unsigned int blk_queue_zone_size(struct request_queue *q)
+static inline unsigned int blk_queue_zone_sectors(struct request_queue *q)
 {
        return blk_queue_is_zoned(q) ? q->limits.chunk_sectors : 0;
 }
@@ -1000,6 +1000,19 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
        return blk_rq_cur_bytes(rq) >> 9;
 }
 
+/*
+ * Some commands like WRITE SAME have a payload or data transfer size which
+ * is different from the size of the request.  Any driver that supports such
+ * commands using the RQF_SPECIAL_PAYLOAD flag needs to use this helper to
+ * calculate the data transfer size.
+ */
+static inline unsigned int blk_rq_payload_bytes(struct request *rq)
+{
+       if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
+               return rq->special_vec.bv_len;
+       return blk_rq_bytes(rq);
+}
+
 static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
                                                     int op)
 {
@@ -1536,12 +1549,12 @@ static inline bool bdev_is_zoned(struct block_device *bdev)
        return false;
 }
 
-static inline unsigned int bdev_zone_size(struct block_device *bdev)
+static inline unsigned int bdev_zone_sectors(struct block_device *bdev)
 {
        struct request_queue *q = bdev_get_queue(bdev);
 
        if (q)
-               return blk_queue_zone_size(q);
+               return blk_queue_zone_sectors(q);
 
        return 0;
 }
index d016a121a8c46492bd6feea5b093dcea9bf27933..28ffa94aed6b85d10531e7dc11864f9ebc8701f4 100644 (file)
@@ -14,6 +14,7 @@ struct coredump_params;
 extern int dump_skip(struct coredump_params *cprm, size_t nr);
 extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
 extern int dump_align(struct coredump_params *cprm, int align);
+extern void dump_truncate(struct coredump_params *cprm);
 #ifdef CONFIG_COREDUMP
 extern void do_coredump(const siginfo_t *siginfo);
 #else
index a07a476178cd1b4c59295ba2c1ee420c1bbb696e..5b1af30ece55828e655b2bf02a149fd71354f3eb 100644 (file)
@@ -103,6 +103,7 @@ typedef     struct {
 
 #define EFI_PAGE_SHIFT         12
 #define EFI_PAGE_SIZE          (1UL << EFI_PAGE_SHIFT)
+#define EFI_PAGES_MAX          (U64_MAX >> EFI_PAGE_SHIFT)
 
 typedef struct {
        u32 type;
@@ -950,6 +951,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes,
 #endif
 extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 
+extern phys_addr_t __init efi_memmap_alloc(unsigned int num_entries);
 extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
 extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
 extern void __init efi_memmap_unmap(void);
index 4175dca4ac39dd7848e3abcda5eb163865ab2734..0fe0b6295ab58edfe6745467487fe19beba0d723 100644 (file)
@@ -38,9 +38,8 @@ struct vm_area_struct;
 #define ___GFP_ACCOUNT         0x100000u
 #define ___GFP_NOTRACK         0x200000u
 #define ___GFP_DIRECT_RECLAIM  0x400000u
-#define ___GFP_OTHER_NODE      0x800000u
-#define ___GFP_WRITE           0x1000000u
-#define ___GFP_KSWAPD_RECLAIM  0x2000000u
+#define ___GFP_WRITE           0x800000u
+#define ___GFP_KSWAPD_RECLAIM  0x1000000u
 /* If the above are modified, __GFP_BITS_SHIFT may need updating */
 
 /*
@@ -172,11 +171,6 @@ struct vm_area_struct;
  * __GFP_NOTRACK_FALSE_POSITIVE is an alias of __GFP_NOTRACK. It's a means of
  *   distinguishing in the source between false positives and allocations that
  *   cannot be supported (e.g. page tables).
- *
- * __GFP_OTHER_NODE is for allocations that are on a remote node but that
- *   should not be accounted for as a remote allocation in vmstat. A
- *   typical user would be khugepaged collapsing a huge page on a remote
- *   node.
  */
 #define __GFP_COLD     ((__force gfp_t)___GFP_COLD)
 #define __GFP_NOWARN   ((__force gfp_t)___GFP_NOWARN)
@@ -184,10 +178,9 @@ struct vm_area_struct;
 #define __GFP_ZERO     ((__force gfp_t)___GFP_ZERO)
 #define __GFP_NOTRACK  ((__force gfp_t)___GFP_NOTRACK)
 #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
-#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE)
 
 /* Room for N __GFP_FOO bits */
-#define __GFP_BITS_SHIFT 26
+#define __GFP_BITS_SHIFT 25
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /*
@@ -506,11 +499,10 @@ extern void free_hot_cold_page(struct page *page, bool cold);
 extern void free_hot_cold_page_list(struct list_head *list, bool cold);
 
 struct page_frag_cache;
-extern void __page_frag_drain(struct page *page, unsigned int order,
-                             unsigned int count);
-extern void *__alloc_page_frag(struct page_frag_cache *nc,
-                              unsigned int fragsz, gfp_t gfp_mask);
-extern void __free_page_frag(void *addr);
+extern void __page_frag_cache_drain(struct page *page, unsigned int count);
+extern void *page_frag_alloc(struct page_frag_cache *nc,
+                            unsigned int fragsz, gfp_t gfp_mask);
+extern void page_frag_free(void *addr);
 
 #define __free_page(page) __free_pages((page), 0)
 #define free_page(addr) free_pages((addr), 0)
index 42fe43fb0c80605f9553c746f04310f43914f683..7ea20bd7cdd1a091054c55d99d311ea58fb27de6 100644 (file)
@@ -627,6 +627,7 @@ struct vmbus_channel_msginfo {
 
        /* Synchronize the request/response if needed */
        struct completion  waitevent;
+       struct vmbus_channel *waiting_channel;
        union {
                struct vmbus_channel_version_supported version_supported;
                struct vmbus_channel_open_result open_result;
index b2109c522dec0726d6e6e390358a79be4bcdf891..4b45ec46161fd66d6e7fd32f53dd71b8ac1cab42 100644 (file)
@@ -665,6 +665,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter)
 #define I2C_CLIENT_TEN         0x10    /* we have a ten bit chip address */
                                        /* Must equal I2C_M_TEN below */
 #define I2C_CLIENT_SLAVE       0x20    /* we are the slave */
+#define I2C_CLIENT_HOST_NOTIFY 0x40    /* We want to use I2C host notify */
 #define I2C_CLIENT_WAKE                0x80    /* for board_info; true iff can wake */
 #define I2C_CLIENT_SCCB                0x9000  /* Use Omnivision SCCB protocol */
                                        /* Must match I2C_M_STOP|IGNORE_NAK */
index 089f70f83e97c9a1adf1087f10d095a02bd3e152..23da3af459fe7af7b5e5c2eabccbda350122e88b 100644 (file)
@@ -14,6 +14,7 @@ struct static_key_deferred {
 
 #ifdef HAVE_JUMP_LABEL
 extern void static_key_slow_dec_deferred(struct static_key_deferred *key);
+extern void static_key_deferred_flush(struct static_key_deferred *key);
 extern void
 jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl);
 
@@ -26,6 +27,10 @@ static inline void static_key_slow_dec_deferred(struct static_key_deferred *key)
        STATIC_KEY_CHECK_USE();
        static_key_slow_dec(&key->key);
 }
+static inline void static_key_deferred_flush(struct static_key_deferred *key)
+{
+       STATIC_KEY_CHECK_USE();
+}
 static inline void
 jump_label_rate_limit(struct static_key_deferred *key,
                unsigned long rl)
index 61d20c17f3b7e40ba706a49da463c2f9eabd7d93..254698856b8fc2723dae61e3dd20b6c8176129e7 100644 (file)
@@ -120,7 +120,7 @@ struct mem_cgroup_reclaim_iter {
  */
 struct mem_cgroup_per_node {
        struct lruvec           lruvec;
-       unsigned long           lru_size[NR_LRU_LISTS];
+       unsigned long           lru_zone_size[MAX_NR_ZONES][NR_LRU_LISTS];
 
        struct mem_cgroup_reclaim_iter  iter[DEF_PRIORITY + 1];
 
@@ -432,7 +432,7 @@ static inline bool mem_cgroup_online(struct mem_cgroup *memcg)
 int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
 
 void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
-               int nr_pages);
+               int zid, int nr_pages);
 
 unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
                                           int nid, unsigned int lru_mask);
@@ -441,9 +441,23 @@ static inline
 unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
        struct mem_cgroup_per_node *mz;
+       unsigned long nr_pages = 0;
+       int zid;
 
        mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
-       return mz->lru_size[lru];
+       for (zid = 0; zid < MAX_NR_ZONES; zid++)
+               nr_pages += mz->lru_zone_size[zid][lru];
+       return nr_pages;
+}
+
+static inline
+unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
+               enum lru_list lru, int zone_idx)
+{
+       struct mem_cgroup_per_node *mz;
+
+       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
+       return mz->lru_zone_size[zone_idx][lru];
 }
 
 void mem_cgroup_handle_over_high(void);
@@ -671,6 +685,12 @@ mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
        return 0;
 }
+static inline
+unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
+               enum lru_list lru, int zone_idx)
+{
+       return 0;
+}
 
 static inline unsigned long
 mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
index ed30d5d713e3400944e6247a7079ee4840a1ae94..0590263c462ceeb71124b3e5339ea68756bbdef2 100644 (file)
@@ -22,6 +22,7 @@
 /*#define ADB_MOUSE_MINOR      10      FIXME OBSOLETE */
 #define WATCHDOG_MINOR         130     /* Watchdog timer     */
 #define TEMP_MINOR             131     /* Temperature Sensor */
+#define APM_MINOR_DEV          134
 #define RTC_MINOR              135
 #define EFI_RTC_MINOR          136     /* EFI Time services */
 #define VHCI_MINOR             137
index fe6b4036664a9a7c82fe4a22be93288928eceac1..b84615b0f64c294eebb72095cc8dbc874b4ae22b 100644 (file)
@@ -1210,8 +1210,8 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
                        struct vm_area_struct *vma);
 void unmap_mapping_range(struct address_space *mapping,
                loff_t const holebegin, loff_t const holelen, int even_cows);
-int follow_pte(struct mm_struct *mm, unsigned long address, pte_t **ptepp,
-              spinlock_t **ptlp);
+int follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+                            pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp);
 int follow_pfn(struct vm_area_struct *vma, unsigned long address,
        unsigned long *pfn);
 int follow_phys(struct vm_area_struct *vma, unsigned long address,
index 71613e8a720f99b6870f1e3f8957d2761a6ac1a0..41d376e7116dccae22d9881312cfb660cd9fd58e 100644 (file)
@@ -39,7 +39,7 @@ static __always_inline void update_lru_size(struct lruvec *lruvec,
 {
        __update_lru_size(lruvec, lru, zid, nr_pages);
 #ifdef CONFIG_MEMCG
-       mem_cgroup_update_lru_size(lruvec, lru, nr_pages);
+       mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages);
 #endif
 }
 
index 994f7423a74bd622884c3b646f4123d28697b8ad..9bde9558b59672a866bd763039d326bde2af0f81 100644 (file)
@@ -2477,14 +2477,19 @@ static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
        return NAPI_GRO_CB(skb)->frag0_len < hlen;
 }
 
+static inline void skb_gro_frag0_invalidate(struct sk_buff *skb)
+{
+       NAPI_GRO_CB(skb)->frag0 = NULL;
+       NAPI_GRO_CB(skb)->frag0_len = 0;
+}
+
 static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
                                        unsigned int offset)
 {
        if (!pskb_may_pull(skb, hlen))
                return NULL;
 
-       NAPI_GRO_CB(skb)->frag0 = NULL;
-       NAPI_GRO_CB(skb)->frag0_len = 0;
+       skb_gro_frag0_invalidate(skb);
        return skb->data + offset;
 }
 
index 4741ecdb981743151b70afff63b10740dfaa4132..78ed8105e64d1ae0341104c8d129cfeba9402800 100644 (file)
@@ -1259,6 +1259,7 @@ extern void perf_event_disable(struct perf_event *event);
 extern void perf_event_disable_local(struct perf_event *event);
 extern void perf_event_disable_inatomic(struct perf_event *event);
 extern void perf_event_task_tick(void);
+extern int perf_event_account_interrupt(struct perf_event *event);
 #else /* !CONFIG_PERF_EVENTS: */
 static inline void *
 perf_aux_output_begin(struct perf_output_handle *handle,
diff --git a/include/linux/platform_data/ti-aemif.h b/include/linux/platform_data/ti-aemif.h
new file mode 100644 (file)
index 0000000..ac72e11
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * TI DaVinci AEMIF platform glue.
+ *
+ * Copyright (C) 2017 BayLibre SAS
+ *
+ * Author:
+ *   Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TI_DAVINCI_AEMIF_DATA_H__
+#define __TI_DAVINCI_AEMIF_DATA_H__
+
+#include <linux/of_platform.h>
+
+struct aemif_platform_data {
+       struct of_dev_auxdata *dev_lookup;
+};
+
+#endif /* __TI_DAVINCI_AEMIF_DATA_H__ */
index e2f3a3281d8fd29de861f4d46ccf7da54ce6eea8..8265d351c9f0e6bc7814fd59ca1efff531e4798f 100644 (file)
@@ -408,7 +408,8 @@ enum rproc_crash_type {
  * @crash_comp: completion used to sync crash handler and the rproc reload
  * @recovery_disabled: flag that state if recovery was disabled
  * @max_notifyid: largest allocated notify id.
- * @table_ptr: our copy of the resource table
+ * @table_ptr: pointer to the resource table in effect
+ * @cached_table: copy of the resource table
  * @has_iommu: flag to indicate if remote processor is behind an MMU
  */
 struct rproc {
@@ -440,6 +441,7 @@ struct rproc {
        bool recovery_disabled;
        int max_notifyid;
        struct resource_table *table_ptr;
+       struct resource_table *cached_table;
        bool has_iommu;
        bool auto_boot;
 };
index 4d1905245c7aa50df56acf0f77c77f3347c28c04..ad3ec9ec61f7b6de743b5d6de4225defcc18be99 100644 (file)
@@ -854,6 +854,16 @@ struct signal_struct {
 
 #define SIGNAL_UNKILLABLE      0x00000040 /* for init: ignore fatal signals */
 
+#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
+                         SIGNAL_STOP_CONTINUED)
+
+static inline void signal_set_stop_flags(struct signal_struct *sig,
+                                        unsigned int flags)
+{
+       WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
+       sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
+}
+
 /* If true, all threads except ->group_exit_task have pending SIGKILL */
 static inline int signal_group_exit(const struct signal_struct *sig)
 {
index b53c0cfd417e3bec1c5cfab76787901bafa5884c..a410715bbef8889d148a6b3f8dbd6afc4ae6f4d0 100644 (file)
@@ -2480,7 +2480,7 @@ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
 
 static inline void skb_free_frag(void *addr)
 {
-       __free_page_frag(addr);
+       page_frag_free(addr);
 }
 
 void *napi_alloc_frag(unsigned int fragsz);
index 084b12bad198232426c6beb27cd348d72797b344..4c536356681543d8749bc5013d619f6c5c7a5bd3 100644 (file)
@@ -226,7 +226,7 @@ static inline const char *__check_heap_object(const void *ptr,
  * (PAGE_SIZE*2).  Larger requests are passed to the page allocator.
  */
 #define KMALLOC_SHIFT_HIGH     (PAGE_SHIFT + 1)
-#define KMALLOC_SHIFT_MAX      (MAX_ORDER + PAGE_SHIFT)
+#define KMALLOC_SHIFT_MAX      (MAX_ORDER + PAGE_SHIFT - 1)
 #ifndef KMALLOC_SHIFT_LOW
 #define KMALLOC_SHIFT_LOW      3
 #endif
@@ -239,7 +239,7 @@ static inline const char *__check_heap_object(const void *ptr,
  * be allocated from the same page.
  */
 #define KMALLOC_SHIFT_HIGH     PAGE_SHIFT
-#define KMALLOC_SHIFT_MAX      30
+#define KMALLOC_SHIFT_MAX      (MAX_ORDER + PAGE_SHIFT - 1)
 #ifndef KMALLOC_SHIFT_LOW
 #define KMALLOC_SHIFT_LOW      3
 #endif
index 09f4be179ff304ed0c5e921c8b9bd6e33112c886..7f47b7098b1b9b9cfb6aacfca126826160eaaa8c 100644 (file)
@@ -150,8 +150,9 @@ enum {
        SWP_FILE        = (1 << 7),     /* set after swap_activate success */
        SWP_AREA_DISCARD = (1 << 8),    /* single-time swap area discards */
        SWP_PAGE_DISCARD = (1 << 9),    /* freed swap page-cluster discards */
+       SWP_STABLE_WRITES = (1 << 10),  /* no overwrite PG_writeback pages */
                                        /* add others here before... */
-       SWP_SCANNING    = (1 << 10),    /* refcount in scan_swap_map */
+       SWP_SCANNING    = (1 << 11),    /* refcount in scan_swap_map */
 };
 
 #define SWAP_CLUSTER_MAX 32UL
index bd36ce431e32cbb57a1ec4e97964b78774787a2e..bab0b1ad0613eb7de475b88546cecd7a52645e90 100644 (file)
@@ -8,23 +8,7 @@
 #ifndef _LINUX_TIMERFD_H
 #define _LINUX_TIMERFD_H
 
-/* For O_CLOEXEC and O_NONBLOCK */
-#include <linux/fcntl.h>
-
-/* For _IO helpers */
-#include <linux/ioctl.h>
-
-/*
- * CAREFUL: Check include/asm-generic/fcntl.h when defining
- * new flags, since they might collide with O_* ones. We want
- * to re-use O_* flags that couldn't possibly have a meaning
- * from eventfd, in order to leave a free define-space for
- * shared O_* flags.
- */
-#define TFD_TIMER_ABSTIME (1 << 0)
-#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
-#define TFD_CLOEXEC O_CLOEXEC
-#define TFD_NONBLOCK O_NONBLOCK
+#include <uapi/linux/timerfd.h>
 
 #define TFD_SHARED_FCNTL_FLAGS (TFD_CLOEXEC | TFD_NONBLOCK)
 /* Flags for timerfd_create.  */
@@ -32,6 +16,4 @@
 /* Flags for timerfd_settime.  */
 #define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)
 
-#define TFD_IOC_SET_TICKS      _IOW('T', 0, u64)
-
 #endif /* _LINUX_TIMERFD_H */
index 8c589176c2f86a7241a37de8eb86498cec0e0577..ec5e8bf6118e7b1d99be2a5d0293c9a9babe6b1e 100644 (file)
@@ -108,7 +108,6 @@ struct vme_dev {
 };
 
 struct vme_driver {
-       struct list_head node;
        const char *name;
        int (*match)(struct vme_dev *);
        int (*probe)(struct vme_dev *);
index 530c57bdefa06567c3bcaba9249845af1d4e535a..915c4357945c27992aa3b7561ab705dedff082ad 100644 (file)
@@ -36,10 +36,10 @@ struct hdmi_codec_daifmt {
                HDMI_AC97,
                HDMI_SPDIF,
        } fmt;
-       int bit_clk_inv:1;
-       int frame_clk_inv:1;
-       int bit_clk_master:1;
-       int frame_clk_master:1;
+       unsigned int bit_clk_inv:1;
+       unsigned int frame_clk_inv:1;
+       unsigned int bit_clk_master:1;
+       unsigned int frame_clk_master:1;
 };
 
 /*
index 2b502f6cc6d036be6e25c6834671be1cde2fd8da..b86168a21d56c7fff1d59dfacbef93049bde888e 100644 (file)
@@ -813,6 +813,7 @@ struct snd_soc_component {
        unsigned int suspended:1; /* is in suspend PM state */
 
        struct list_head list;
+       struct list_head card_aux_list; /* for auxiliary bound components */
        struct list_head card_list;
 
        struct snd_soc_dai_driver *dai_drv;
@@ -1152,6 +1153,7 @@ struct snd_soc_card {
         */
        struct snd_soc_aux_dev *aux_dev;
        int num_aux_devs;
+       struct list_head aux_comp_list;
 
        const struct snd_kcontrol_new *controls;
        int num_controls;
@@ -1547,6 +1549,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
        INIT_LIST_HEAD(&card->widgets);
        INIT_LIST_HEAD(&card->paths);
        INIT_LIST_HEAD(&card->dapm_list);
+       INIT_LIST_HEAD(&card->aux_comp_list);
        INIT_LIST_HEAD(&card->component_dev_list);
 }
 
index 29e6858bb1648b636dcce48072f9fe43e5a8a884..43edf82e54fffce7b3d8bfed8c832aebfc60c79b 100644 (file)
@@ -174,6 +174,10 @@ enum tcm_sense_reason_table {
        TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED  = R(0x16),
        TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED  = R(0x17),
        TCM_COPY_TARGET_DEVICE_NOT_REACHABLE    = R(0x18),
+       TCM_TOO_MANY_TARGET_DESCS               = R(0x19),
+       TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE   = R(0x1a),
+       TCM_TOO_MANY_SEGMENT_DESCS              = R(0x1b),
+       TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE  = R(0x1c),
 #undef R
 };
 
index c14bed4ab0977fc1d7d06b38051644f8e67e2349..88d18a8ceb59f9c6e3c5630a491cf6d3c91cf73c 100644 (file)
@@ -130,8 +130,8 @@ DECLARE_EVENT_CLASS(btrfs__inode,
                                BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, "
-                 "disk_i_size = %llu, last_trans = %llu, logged_trans = %llu",
+       TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%lu blocks=%llu "
+                 "disk_i_size=%llu last_trans=%llu logged_trans=%llu",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->generation,
                  (unsigned long)__entry->ino,
@@ -184,14 +184,16 @@ DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
 
 TRACE_EVENT_CONDITION(btrfs_get_extent,
 
-       TP_PROTO(struct btrfs_root *root, struct extent_map *map),
+       TP_PROTO(struct btrfs_root *root, struct inode *inode,
+                struct extent_map *map),
 
-       TP_ARGS(root, map),
+       TP_ARGS(root, inode, map),
 
        TP_CONDITION(map),
 
        TP_STRUCT__entry_btrfs(
                __field(        u64,  root_objectid     )
+               __field(        u64,  ino               )
                __field(        u64,  start             )
                __field(        u64,  len               )
                __field(        u64,  orig_start        )
@@ -204,7 +206,8 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
 
        TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
-               __entry->start          = map->start;
+               __entry->ino            = btrfs_ino(inode);
+               __entry->start          = map->start;
                __entry->len            = map->len;
                __entry->orig_start     = map->orig_start;
                __entry->block_start    = map->block_start;
@@ -214,11 +217,12 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
                __entry->compress_type  = map->compress_type;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu, "
-                 "orig_start = %llu, block_start = %llu(%s), "
-                 "block_len = %llu, flags = %s, refs = %u, "
-                 "compress_type = %u",
+       TP_printk_btrfs("root=%llu(%s) ino=%llu start=%llu len=%llu "
+                 "orig_start=%llu block_start=%llu(%s) "
+                 "block_len=%llu flags=%s refs=%u "
+                 "compress_type=%u",
                  show_root_type(__entry->root_objectid),
+                 (unsigned long long)__entry->ino,
                  (unsigned long long)__entry->start,
                  (unsigned long long)__entry->len,
                  (unsigned long long)__entry->orig_start,
@@ -259,6 +263,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
                __field(        int,  compress_type     )
                __field(        int,  refs              )
                __field(        u64,  root_objectid     )
+               __field(        u64,  truncated_len     )
        ),
 
        TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
@@ -273,18 +278,21 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
                __entry->refs           = atomic_read(&ordered->refs);
                __entry->root_objectid  =
                                BTRFS_I(inode)->root->root_key.objectid;
+               __entry->truncated_len  = ordered->truncated_len;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), ino = %llu, file_offset = %llu, "
-                 "start = %llu, len = %llu, disk_len = %llu, "
-                 "bytes_left = %llu, flags = %s, compress_type = %d, "
-                 "refs = %d",
+       TP_printk_btrfs("root=%llu(%s) ino=%llu file_offset=%llu "
+                 "start=%llu len=%llu disk_len=%llu "
+                 "truncated_len=%llu "
+                 "bytes_left=%llu flags=%s compress_type=%d "
+                 "refs=%d",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->ino,
                  (unsigned long long)__entry->file_offset,
                  (unsigned long long)__entry->start,
                  (unsigned long long)__entry->len,
                  (unsigned long long)__entry->disk_len,
+                 (unsigned long long)__entry->truncated_len,
                  (unsigned long long)__entry->bytes_left,
                  show_ordered_flags(__entry->flags),
                  __entry->compress_type, __entry->refs)
@@ -354,10 +362,10 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
                                 BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, "
-                 "nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, "
-                 "range_end = %llu, for_kupdate = %d, "
-                 "for_reclaim = %d, range_cyclic = %d, writeback_index = %lu",
+       TP_printk_btrfs("root=%llu(%s) ino=%lu page_index=%lu "
+                 "nr_to_write=%ld pages_skipped=%ld range_start=%llu "
+                 "range_end=%llu for_kupdate=%d "
+                 "for_reclaim=%d range_cyclic=%d writeback_index=%lu",
                  show_root_type(__entry->root_objectid),
                  (unsigned long)__entry->ino, __entry->index,
                  __entry->nr_to_write, __entry->pages_skipped,
@@ -400,8 +408,8 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
                         BTRFS_I(page->mapping->host)->root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, "
-                 "end = %llu, uptodate = %d",
+       TP_printk_btrfs("root=%llu(%s) ino=%lu page_index=%lu start=%llu "
+                 "end=%llu uptodate=%d",
                  show_root_type(__entry->root_objectid),
                  (unsigned long)__entry->ino, (unsigned long)__entry->index,
                  (unsigned long long)__entry->start,
@@ -433,7 +441,7 @@ TRACE_EVENT(btrfs_sync_file,
                                 BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d",
+       TP_printk_btrfs("root=%llu(%s) ino=%ld parent=%ld datasync=%d",
                  show_root_type(__entry->root_objectid),
                  (unsigned long)__entry->ino, (unsigned long)__entry->parent,
                  __entry->datasync)
@@ -484,9 +492,9 @@ TRACE_EVENT(btrfs_add_block_group,
                __entry->create         = create;
        ),
 
-       TP_printk("%pU: block_group offset = %llu, size = %llu, "
-                 "flags = %llu(%s), bytes_used = %llu, bytes_super = %llu, "
-                 "create = %d", __entry->fsid,
+       TP_printk("%pU: block_group offset=%llu size=%llu "
+                 "flags=%llu(%s) bytes_used=%llu bytes_super=%llu "
+                 "create=%d", __entry->fsid,
                  (unsigned long long)__entry->offset,
                  (unsigned long long)__entry->size,
                  (unsigned long long)__entry->flags,
@@ -535,9 +543,9 @@ DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
                __entry->seq            = ref->seq;
        ),
 
-       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
-                 "parent = %llu(%s), ref_root = %llu(%s), level = %d, "
-                 "type = %s, seq = %llu",
+       TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s "
+                 "parent=%llu(%s) ref_root=%llu(%s) level=%d "
+                 "type=%s seq=%llu",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes,
                  show_ref_action(__entry->action),
@@ -600,9 +608,9 @@ DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
                __entry->seq            = ref->seq;
        ),
 
-       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
-                 "parent = %llu(%s), ref_root = %llu(%s), owner = %llu, "
-                 "offset = %llu, type = %s, seq = %llu",
+       TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s "
+                 "parent=%llu(%s) ref_root=%llu(%s) owner=%llu "
+                 "offset=%llu type=%s seq=%llu",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes,
                  show_ref_action(__entry->action),
@@ -657,7 +665,7 @@ DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
                __entry->is_data        = head_ref->is_data;
        ),
 
-       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d",
+       TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s is_data=%d",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes,
                  show_ref_action(__entry->action),
@@ -721,8 +729,8 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
                __entry->root_objectid  = fs_info->chunk_root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), offset = %llu, size = %llu, "
-                 "num_stripes = %d, sub_stripes = %d, type = %s",
+       TP_printk_btrfs("root=%llu(%s) offset=%llu size=%llu "
+                 "num_stripes=%d sub_stripes=%d type=%s",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->offset,
                  (unsigned long long)__entry->size,
@@ -771,8 +779,8 @@ TRACE_EVENT(btrfs_cow_block,
                __entry->cow_level      = btrfs_header_level(cow);
        ),
 
-       TP_printk_btrfs("root = %llu(%s), refs = %d, orig_buf = %llu "
-                 "(orig_level = %d), cow_buf = %llu (cow_level = %d)",
+       TP_printk_btrfs("root=%llu(%s) refs=%d orig_buf=%llu "
+                 "(orig_level=%d) cow_buf=%llu (cow_level=%d)",
                  show_root_type(__entry->root_objectid),
                  __entry->refs,
                  (unsigned long long)__entry->buf_start,
@@ -836,7 +844,7 @@ TRACE_EVENT(btrfs_trigger_flush,
                __assign_str(reason, reason)
        ),
 
-       TP_printk("%pU: %s: flush = %d(%s), flags = %llu(%s), bytes = %llu",
+       TP_printk("%pU: %s: flush=%d(%s) flags=%llu(%s) bytes=%llu",
                  __entry->fsid, __get_str(reason), __entry->flush,
                  show_flush_action(__entry->flush),
                  (unsigned long long)__entry->flags,
@@ -879,8 +887,8 @@ TRACE_EVENT(btrfs_flush_space,
                __entry->ret            =       ret;
        ),
 
-       TP_printk("%pU: state = %d(%s), flags = %llu(%s), num_bytes = %llu, "
-                 "orig_bytes = %llu, ret = %d", __entry->fsid, __entry->state,
+       TP_printk("%pU: state=%d(%s) flags=%llu(%s) num_bytes=%llu "
+                 "orig_bytes=%llu ret=%d", __entry->fsid, __entry->state,
                  show_flush_state(__entry->state),
                  (unsigned long long)__entry->flags,
                  __print_flags((unsigned long)__entry->flags, "|",
@@ -905,7 +913,7 @@ DECLARE_EVENT_CLASS(btrfs__reserved_extent,
                __entry->len            = len;
        ),
 
-       TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu",
+       TP_printk_btrfs("root=%llu(%s) start=%llu len=%llu",
                  show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
                  (unsigned long long)__entry->start,
                  (unsigned long long)__entry->len)
@@ -944,7 +952,7 @@ TRACE_EVENT(find_free_extent,
                __entry->data           = data;
        ),
 
-       TP_printk_btrfs("root = %Lu(%s), len = %Lu, empty_size = %Lu, flags = %Lu(%s)",
+       TP_printk_btrfs("root=%Lu(%s) len=%Lu empty_size=%Lu flags=%Lu(%s)",
                  show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
                  __entry->num_bytes, __entry->empty_size, __entry->data,
                  __print_flags((unsigned long)__entry->data, "|",
@@ -973,8 +981,8 @@ DECLARE_EVENT_CLASS(btrfs__reserve_extent,
                __entry->len            = len;
        ),
 
-       TP_printk_btrfs("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), "
-                 "start = %Lu, len = %Lu",
+       TP_printk_btrfs("root=%Lu(%s) block_group=%Lu flags=%Lu(%s) "
+                 "start=%Lu len=%Lu",
                  show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
                  __entry->bg_objectid,
                  __entry->flags, __print_flags((unsigned long)__entry->flags,
@@ -1025,8 +1033,8 @@ TRACE_EVENT(btrfs_find_cluster,
                __entry->min_bytes      = min_bytes;
        ),
 
-       TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu,"
-                 " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid,
+       TP_printk_btrfs("block_group=%Lu flags=%Lu(%s) start=%Lu len=%Lu "
+                 "empty_size=%Lu min_bytes=%Lu", __entry->bg_objectid,
                  __entry->flags,
                  __print_flags((unsigned long)__entry->flags, "|",
                                BTRFS_GROUP_FLAGS), __entry->start,
@@ -1047,7 +1055,7 @@ TRACE_EVENT(btrfs_failed_cluster_setup,
                __entry->bg_objectid    = block_group->key.objectid;
        ),
 
-       TP_printk_btrfs("block_group = %Lu", __entry->bg_objectid)
+       TP_printk_btrfs("block_group=%Lu", __entry->bg_objectid)
 );
 
 TRACE_EVENT(btrfs_setup_cluster,
@@ -1075,8 +1083,8 @@ TRACE_EVENT(btrfs_setup_cluster,
                __entry->bitmap         = bitmap;
        ),
 
-       TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, "
-                 "size = %Lu, max_size = %Lu, bitmap = %d",
+       TP_printk_btrfs("block_group=%Lu flags=%Lu(%s) window_start=%Lu "
+                 "size=%Lu max_size=%Lu bitmap=%d",
                  __entry->bg_objectid,
                  __entry->flags,
                  __print_flags((unsigned long)__entry->flags, "|",
@@ -1103,7 +1111,7 @@ TRACE_EVENT(alloc_extent_state,
                __entry->ip     = IP
        ),
 
-       TP_printk("state=%p; mask = %s; caller = %pS", __entry->state,
+       TP_printk("state=%p mask=%s caller=%pS", __entry->state,
                  show_gfp_flags(__entry->mask), (void *)__entry->ip)
 );
 
@@ -1123,7 +1131,7 @@ TRACE_EVENT(free_extent_state,
                __entry->ip = IP
        ),
 
-       TP_printk(" state=%p; caller = %pS", __entry->state,
+       TP_printk("state=%p caller=%pS", __entry->state,
                  (void *)__entry->ip)
 );
 
@@ -1151,28 +1159,32 @@ DECLARE_EVENT_CLASS(btrfs__work,
                __entry->normal_work    = &work->normal_work;
        ),
 
-       TP_printk_btrfs("work=%p (normal_work=%p), wq=%p, func=%pf, ordered_func=%p,"
-                 " ordered_free=%p",
+       TP_printk_btrfs("work=%p (normal_work=%p) wq=%p func=%pf ordered_func=%p "
+                 "ordered_free=%p",
                  __entry->work, __entry->normal_work, __entry->wq,
                   __entry->func, __entry->ordered_func, __entry->ordered_free)
 );
 
-/* For situiations that the work is freed */
+/*
+ * For situiations when the work is freed, we pass fs_info and a tag that that
+ * matches address of the work structure so it can be paired with the
+ * scheduling event.
+ */
 DECLARE_EVENT_CLASS(btrfs__work__done,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
 
-       TP_ARGS(work),
+       TP_ARGS(fs_info, wtag),
 
        TP_STRUCT__entry_btrfs(
-               __field(        void *, work                    )
+               __field(        void *, wtag                    )
        ),
 
-       TP_fast_assign_btrfs(btrfs_work_owner(work),
-               __entry->work           = work;
+       TP_fast_assign_btrfs(fs_info,
+               __entry->wtag           = wtag;
        ),
 
-       TP_printk_btrfs("work->%p", __entry->work)
+       TP_printk_btrfs("work->%p", __entry->wtag)
 );
 
 DEFINE_EVENT(btrfs__work, btrfs_work_queued,
@@ -1191,9 +1203,9 @@ DEFINE_EVENT(btrfs__work, btrfs_work_sched,
 
 DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
 
-       TP_ARGS(work)
+       TP_ARGS(fs_info, wtag)
 );
 
 DEFINE_EVENT(btrfs__work, btrfs_ordered_sched,
@@ -1221,7 +1233,7 @@ DECLARE_EVENT_CLASS(btrfs__workqueue,
                __entry->high           = high;
        ),
 
-       TP_printk_btrfs("name=%s%s, wq=%p", __get_str(name),
+       TP_printk_btrfs("name=%s%s wq=%p", __get_str(name),
                  __print_flags(__entry->high, "",
                                {(WQ_HIGHPRI),  "-high"}),
                  __entry->wq)
@@ -1276,7 +1288,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_data_map,
                __entry->free_reserved  =       free_reserved;
        ),
 
-       TP_printk_btrfs("rootid=%llu, ino=%lu, free_reserved=%llu",
+       TP_printk_btrfs("rootid=%llu ino=%lu free_reserved=%llu",
                  __entry->rootid, __entry->ino, __entry->free_reserved)
 );
 
@@ -1323,7 +1335,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
                __entry->op             = op;
        ),
 
-       TP_printk_btrfs("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s",
+       TP_printk_btrfs("root=%llu ino=%lu start=%llu len=%llu reserved=%llu op=%s",
                  __entry->rootid, __entry->ino, __entry->start, __entry->len,
                  __entry->reserved,
                  __print_flags((unsigned long)__entry->op, "",
@@ -1361,7 +1373,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref,
                __entry->reserved       = reserved;
        ),
 
-       TP_printk_btrfs("root=%llu, reserved=%llu, op=free",
+       TP_printk_btrfs("root=%llu reserved=%llu op=free",
                  __entry->ref_root, __entry->reserved)
 );
 
@@ -1388,7 +1400,7 @@ DECLARE_EVENT_CLASS(btrfs_qgroup_extent,
                __entry->num_bytes      = rec->num_bytes;
        ),
 
-       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu",
+       TP_printk_btrfs("bytenr=%llu num_bytes=%llu",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes)
 );
@@ -1430,8 +1442,8 @@ TRACE_EVENT(btrfs_qgroup_account_extent,
                __entry->nr_new_roots   = nr_new_roots;
        ),
 
-       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, nr_old_roots = %llu, "
-                 "nr_new_roots = %llu",
+       TP_printk_btrfs("bytenr=%llu num_bytes=%llu nr_old_roots=%llu "
+                 "nr_new_roots=%llu",
                  __entry->bytenr,
                  __entry->num_bytes,
                  __entry->nr_old_roots,
@@ -1457,7 +1469,7 @@ TRACE_EVENT(qgroup_update_counters,
                __entry->cur_new_count  = cur_new_count;
        ),
 
-       TP_printk_btrfs("qgid = %llu, cur_old_count = %llu, cur_new_count = %llu",
+       TP_printk_btrfs("qgid=%llu cur_old_count=%llu cur_new_count=%llu",
                  __entry->qgid,
                  __entry->cur_old_count,
                  __entry->cur_new_count)
index 9e687ca9a307b1344889186e46dd5e62a85f614f..15bf875d0e4a666d91c959bd10b62318b62d61d5 100644 (file)
@@ -47,8 +47,7 @@
        {(unsigned long)__GFP_WRITE,            "__GFP_WRITE"},         \
        {(unsigned long)__GFP_RECLAIM,          "__GFP_RECLAIM"},       \
        {(unsigned long)__GFP_DIRECT_RECLAIM,   "__GFP_DIRECT_RECLAIM"},\
-       {(unsigned long)__GFP_KSWAPD_RECLAIM,   "__GFP_KSWAPD_RECLAIM"},\
-       {(unsigned long)__GFP_OTHER_NODE,       "__GFP_OTHER_NODE"}     \
+       {(unsigned long)__GFP_KSWAPD_RECLAIM,   "__GFP_KSWAPD_RECLAIM"}\
 
 #define show_gfp_flags(flags)                                          \
        (flags) ? __print_flags(flags, "|",                             \
index a8b93e68523941ca5615cbbe0da87f42d779db6d..f330ba4547cfd4c59da3d8f309e4ab76d8bd8b40 100644 (file)
@@ -414,6 +414,7 @@ header-y += telephony.h
 header-y += termios.h
 header-y += thermal.h
 header-y += time.h
+header-y += timerfd.h
 header-y += times.h
 header-y += timex.h
 header-y += tiocl.h
diff --git a/include/uapi/linux/timerfd.h b/include/uapi/linux/timerfd.h
new file mode 100644 (file)
index 0000000..6fcfaa8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  include/linux/timerfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _UAPI_LINUX_TIMERFD_H
+#define _UAPI_LINUX_TIMERFD_H
+
+#include <linux/types.h>
+
+/* For O_CLOEXEC and O_NONBLOCK */
+#include <linux/fcntl.h>
+
+/* For _IO helpers */
+#include <linux/ioctl.h>
+
+/*
+ * CAREFUL: Check include/asm-generic/fcntl.h when defining
+ * new flags, since they might collide with O_* ones. We want
+ * to re-use O_* flags that couldn't possibly have a meaning
+ * from eventfd, in order to leave a free define-space for
+ * shared O_* flags.
+ *
+ * Also make sure to update the masks in include/linux/timerfd.h
+ * when adding new flags.
+ */
+#define TFD_TIMER_ABSTIME (1 << 0)
+#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#define TFD_CLOEXEC O_CLOEXEC
+#define TFD_NONBLOCK O_NONBLOCK
+
+#define TFD_IOC_SET_TICKS      _IOW('T', 0, __u64)
+
+#endif /* _UAPI_LINUX_TIMERFD_H */
index 223b734abccdc3b7f3baae457261dd66862fcd1d..aca8881b9117b8880861af6764f073185e259db0 100644 (file)
@@ -1176,6 +1176,10 @@ config CGROUP_DEBUG
 
          Say N.
 
+config SOCK_CGROUP_DATA
+       bool
+       default n
+
 endif # CGROUPS
 
 config CHECKPOINT_RESTORE
@@ -1716,6 +1720,13 @@ config PERF_USE_VMALLOC
        help
          See tools/perf/design.txt for details
 
+config PC104
+       bool "PC/104 support"
+       help
+         Expose PC/104 form factor device drivers and options available for
+         selection and configuration. Enable this option if your target
+         machine has a PC/104 bus.
+
 menu "Kernel Performance Events And Counters"
 
 config PERF_EVENTS
index e08b948519223e62aca265284483ee7b1ef1420c..3ec5742b5640f5d265ea8f0d9b8f986cf25b8f1c 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
                }
 
                rcu_read_lock();
-               sem_lock(sma, sops, nsops);
+               locknum = sem_lock(sma, sops, nsops);
 
                if (!ipc_valid_object(&sma->sem_perm))
                        goto out_unlock_free;
index a2ac051c342f87b1372a7aeb33ba816327ee1a43..229a5d5df9770fc66774bf5defea359873946d01 100644 (file)
@@ -56,7 +56,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
            attr->value_size == 0 || attr->map_flags)
                return ERR_PTR(-EINVAL);
 
-       if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
+       if (attr->value_size > KMALLOC_MAX_SIZE)
                /* if value_size is bigger, the user space won't be able to
                 * access the elements.
                 */
index 34debc1a9641875382b6603820f3e85c4a18dffc..3f2bb58952d8dfa4a2e082f9e6f9d277e19f0577 100644 (file)
@@ -274,7 +274,7 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
                 */
                goto free_htab;
 
-       if (htab->map.value_size >= (1 << (KMALLOC_SHIFT_MAX - 1)) -
+       if (htab->map.value_size >= KMALLOC_MAX_SIZE -
            MAX_BPF_STACK - sizeof(struct htab_elem))
                /* if value_size is bigger, the user space won't be able to
                 * access the elements via bpf syscall. This check also makes
index a98e814f216f9c54f878bcfca32e4747be357c07..f97fe77ceb88aa39ff3bd01f497586f778c052a2 100644 (file)
@@ -318,6 +318,7 @@ bool has_capability(struct task_struct *t, int cap)
 {
        return has_ns_capability(t, &init_user_ns, cap);
 }
+EXPORT_SYMBOL(has_capability);
 
 /**
  * has_ns_capability_noaudit - Does a task have a capability (unaudited)
index ab15509fab8c0659c3f422036f5649718a9e4437..110b38a58493ee4ba4c19763d2678dae8815e1af 100644 (file)
@@ -2249,7 +2249,7 @@ static int  __perf_install_in_context(void *info)
        struct perf_event_context *ctx = event->ctx;
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        struct perf_event_context *task_ctx = cpuctx->task_ctx;
-       bool activate = true;
+       bool reprogram = true;
        int ret = 0;
 
        raw_spin_lock(&cpuctx->ctx.lock);
@@ -2257,27 +2257,26 @@ static int  __perf_install_in_context(void *info)
                raw_spin_lock(&ctx->lock);
                task_ctx = ctx;
 
-               /* If we're on the wrong CPU, try again */
-               if (task_cpu(ctx->task) != smp_processor_id()) {
-                       ret = -ESRCH;
-                       goto unlock;
-               }
+               reprogram = (ctx->task == current);
 
                /*
-                * If we're on the right CPU, see if the task we target is
-                * current, if not we don't have to activate the ctx, a future
-                * context switch will do that for us.
+                * If the task is running, it must be running on this CPU,
+                * otherwise we cannot reprogram things.
+                *
+                * If its not running, we don't care, ctx->lock will
+                * serialize against it becoming runnable.
                 */
-               if (ctx->task != current)
-                       activate = false;
-               else
-                       WARN_ON_ONCE(cpuctx->task_ctx && cpuctx->task_ctx != ctx);
+               if (task_curr(ctx->task) && !reprogram) {
+                       ret = -ESRCH;
+                       goto unlock;
+               }
 
+               WARN_ON_ONCE(reprogram && cpuctx->task_ctx && cpuctx->task_ctx != ctx);
        } else if (task_ctx) {
                raw_spin_lock(&task_ctx->lock);
        }
 
-       if (activate) {
+       if (reprogram) {
                ctx_sched_out(ctx, cpuctx, EVENT_TIME);
                add_event_to_ctx(event, ctx);
                ctx_resched(cpuctx, task_ctx);
@@ -2328,13 +2327,36 @@ perf_install_in_context(struct perf_event_context *ctx,
        /*
         * Installing events is tricky because we cannot rely on ctx->is_active
         * to be set in case this is the nr_events 0 -> 1 transition.
+        *
+        * Instead we use task_curr(), which tells us if the task is running.
+        * However, since we use task_curr() outside of rq::lock, we can race
+        * against the actual state. This means the result can be wrong.
+        *
+        * If we get a false positive, we retry, this is harmless.
+        *
+        * If we get a false negative, things are complicated. If we are after
+        * perf_event_context_sched_in() ctx::lock will serialize us, and the
+        * value must be correct. If we're before, it doesn't matter since
+        * perf_event_context_sched_in() will program the counter.
+        *
+        * However, this hinges on the remote context switch having observed
+        * our task->perf_event_ctxp[] store, such that it will in fact take
+        * ctx::lock in perf_event_context_sched_in().
+        *
+        * We do this by task_function_call(), if the IPI fails to hit the task
+        * we know any future context switch of task must see the
+        * perf_event_ctpx[] store.
         */
-again:
+
        /*
-        * Cannot use task_function_call() because we need to run on the task's
-        * CPU regardless of whether its current or not.
+        * This smp_mb() orders the task->perf_event_ctxp[] store with the
+        * task_cpu() load, such that if the IPI then does not find the task
+        * running, a future context switch of that task must observe the
+        * store.
         */
-       if (!cpu_function_call(task_cpu(task), __perf_install_in_context, event))
+       smp_mb();
+again:
+       if (!task_function_call(task, __perf_install_in_context, event))
                return;
 
        raw_spin_lock_irq(&ctx->lock);
@@ -2348,12 +2370,16 @@ perf_install_in_context(struct perf_event_context *ctx,
                raw_spin_unlock_irq(&ctx->lock);
                return;
        }
-       raw_spin_unlock_irq(&ctx->lock);
        /*
-        * Since !ctx->is_active doesn't mean anything, we must IPI
-        * unconditionally.
+        * If the task is not running, ctx->lock will avoid it becoming so,
+        * thus we can safely install the event.
         */
-       goto again;
+       if (task_curr(task)) {
+               raw_spin_unlock_irq(&ctx->lock);
+               goto again;
+       }
+       add_event_to_ctx(event, ctx);
+       raw_spin_unlock_irq(&ctx->lock);
 }
 
 /*
@@ -7034,25 +7060,12 @@ static void perf_log_itrace_start(struct perf_event *event)
        perf_output_end(&handle);
 }
 
-/*
- * Generic event overflow handling, sampling.
- */
-
-static int __perf_event_overflow(struct perf_event *event,
-                                  int throttle, struct perf_sample_data *data,
-                                  struct pt_regs *regs)
+static int
+__perf_event_account_interrupt(struct perf_event *event, int throttle)
 {
-       int events = atomic_read(&event->event_limit);
        struct hw_perf_event *hwc = &event->hw;
-       u64 seq;
        int ret = 0;
-
-       /*
-        * Non-sampling counters might still use the PMI to fold short
-        * hardware counters, ignore those.
-        */
-       if (unlikely(!is_sampling_event(event)))
-               return 0;
+       u64 seq;
 
        seq = __this_cpu_read(perf_throttled_seq);
        if (seq != hwc->interrupts_seq) {
@@ -7080,6 +7093,34 @@ static int __perf_event_overflow(struct perf_event *event,
                        perf_adjust_period(event, delta, hwc->last_period, true);
        }
 
+       return ret;
+}
+
+int perf_event_account_interrupt(struct perf_event *event)
+{
+       return __perf_event_account_interrupt(event, 1);
+}
+
+/*
+ * Generic event overflow handling, sampling.
+ */
+
+static int __perf_event_overflow(struct perf_event *event,
+                                  int throttle, struct perf_sample_data *data,
+                                  struct pt_regs *regs)
+{
+       int events = atomic_read(&event->event_limit);
+       int ret = 0;
+
+       /*
+        * Non-sampling counters might still use the PMI to fold short
+        * hardware counters, ignore those.
+        */
+       if (unlikely(!is_sampling_event(event)))
+               return 0;
+
+       ret = __perf_event_account_interrupt(event, throttle);
+
        /*
         * XXX event_limit might not quite work as expected on inherited
         * events
@@ -9503,6 +9544,37 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
        return 0;
 }
 
+/*
+ * Variation on perf_event_ctx_lock_nested(), except we take two context
+ * mutexes.
+ */
+static struct perf_event_context *
+__perf_event_ctx_lock_double(struct perf_event *group_leader,
+                            struct perf_event_context *ctx)
+{
+       struct perf_event_context *gctx;
+
+again:
+       rcu_read_lock();
+       gctx = READ_ONCE(group_leader->ctx);
+       if (!atomic_inc_not_zero(&gctx->refcount)) {
+               rcu_read_unlock();
+               goto again;
+       }
+       rcu_read_unlock();
+
+       mutex_lock_double(&gctx->mutex, &ctx->mutex);
+
+       if (group_leader->ctx != gctx) {
+               mutex_unlock(&ctx->mutex);
+               mutex_unlock(&gctx->mutex);
+               put_ctx(gctx);
+               goto again;
+       }
+
+       return gctx;
+}
+
 /**
  * sys_perf_event_open - open a performance event, associate it to a task/cpu
  *
@@ -9746,12 +9818,31 @@ SYSCALL_DEFINE5(perf_event_open,
        }
 
        if (move_group) {
-               gctx = group_leader->ctx;
-               mutex_lock_double(&gctx->mutex, &ctx->mutex);
+               gctx = __perf_event_ctx_lock_double(group_leader, ctx);
+
                if (gctx->task == TASK_TOMBSTONE) {
                        err = -ESRCH;
                        goto err_locked;
                }
+
+               /*
+                * Check if we raced against another sys_perf_event_open() call
+                * moving the software group underneath us.
+                */
+               if (!(group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
+                       /*
+                        * If someone moved the group out from under us, check
+                        * if this new event wound up on the same ctx, if so
+                        * its the regular !move_group case, otherwise fail.
+                        */
+                       if (gctx != ctx) {
+                               err = -EINVAL;
+                               goto err_locked;
+                       } else {
+                               perf_event_ctx_unlock(group_leader, gctx);
+                               move_group = 0;
+                       }
+               }
        } else {
                mutex_lock(&ctx->mutex);
        }
@@ -9853,7 +9944,7 @@ SYSCALL_DEFINE5(perf_event_open,
        perf_unpin_context(ctx);
 
        if (move_group)
-               mutex_unlock(&gctx->mutex);
+               perf_event_ctx_unlock(group_leader, gctx);
        mutex_unlock(&ctx->mutex);
 
        if (task) {
@@ -9879,7 +9970,7 @@ SYSCALL_DEFINE5(perf_event_open,
 
 err_locked:
        if (move_group)
-               mutex_unlock(&gctx->mutex);
+               perf_event_ctx_unlock(group_leader, gctx);
        mutex_unlock(&ctx->mutex);
 /* err_file: */
        fput(event_file);
index 93ad6c1fb9b6212e706eb3ae08f7b881192008ec..a9b8cf50059151c17f63d35cf4c622ae8b72f131 100644 (file)
@@ -182,6 +182,13 @@ void static_key_slow_dec_deferred(struct static_key_deferred *key)
 }
 EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
 
+void static_key_deferred_flush(struct static_key_deferred *key)
+{
+       STATIC_KEY_CHECK_USE();
+       flush_delayed_work(&key->work);
+}
+EXPORT_SYMBOL_GPL(static_key_deferred_flush);
+
 void jump_label_rate_limit(struct static_key_deferred *key,
                unsigned long rl)
 {
index b501e390bb34403c11d6ae09c31ea9fcb769ea8e..9ecedc28b928debb6a5988a5db8b76833133d9e4 100644 (file)
@@ -246,7 +246,9 @@ static void devm_memremap_pages_release(struct device *dev, void *data)
        /* pages are dead and unused, undo the arch mapping */
        align_start = res->start & ~(SECTION_SIZE - 1);
        align_size = ALIGN(resource_size(res), SECTION_SIZE);
+       mem_hotplug_begin();
        arch_remove_memory(align_start, align_size);
+       mem_hotplug_done();
        untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
        pgmap_radix_release(res);
        dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc,
@@ -358,7 +360,9 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
        if (error)
                goto err_pfn_remap;
 
+       mem_hotplug_begin();
        error = arch_add_memory(nid, align_start, align_size, true);
+       mem_hotplug_done();
        if (error)
                goto err_add_memory;
 
index df9e8e9e0be7714fa580b547492c940b11221008..eef2ce9686366a72e9dadaa9056bcda8295ae93d 100644 (file)
@@ -151,8 +151,12 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
 
 static void delayed_free_pidns(struct rcu_head *p)
 {
-       kmem_cache_free(pid_ns_cachep,
-                       container_of(p, struct pid_namespace, rcu));
+       struct pid_namespace *ns = container_of(p, struct pid_namespace, rcu);
+
+       dec_pid_namespaces(ns->ucounts);
+       put_user_ns(ns->user_ns);
+
+       kmem_cache_free(pid_ns_cachep, ns);
 }
 
 static void destroy_pid_namespace(struct pid_namespace *ns)
@@ -162,8 +166,6 @@ static void destroy_pid_namespace(struct pid_namespace *ns)
        ns_free_inum(&ns->ns);
        for (i = 0; i < PIDMAP_ENTRIES; i++)
                kfree(ns->pidmap[i].page);
-       dec_pid_namespaces(ns->ucounts);
-       put_user_ns(ns->user_ns);
        call_rcu(&ns->rcu, delayed_free_pidns);
 }
 
index ff046b73ff2d309ce00fbd3bd8949a8f6f5fd297..3603d93a19689be7188a004f2b999b27e0ebdf2f 100644 (file)
@@ -346,7 +346,7 @@ static bool task_participate_group_stop(struct task_struct *task)
         * fresh group stop.  Read comment in do_signal_stop() for details.
         */
        if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
-               sig->flags = SIGNAL_STOP_STOPPED;
+               signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
                return true;
        }
        return false;
@@ -843,7 +843,7 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force)
                         * will take ->siglock, notice SIGNAL_CLD_MASK, and
                         * notify its parent. See get_signal_to_deliver().
                         */
-                       signal->flags = why | SIGNAL_STOP_CONTINUED;
+                       signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
                        signal->group_stop_count = 0;
                        signal->group_exit_code = 0;
                }
index 2c115fdab39765f4ecbeaade9fa74008e711d08a..74e0388cc88d4d17b340d102ec8e053257d6ef55 100644 (file)
@@ -767,7 +767,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
        tick = expires;
 
        /* Skip reprogram of event if its not changed */
-       if (ts->tick_stopped && (expires == dev->next_event))
+       if (ts->tick_stopped && (expires == ts->next_tick))
                goto out;
 
        /*
@@ -787,6 +787,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
                trace_tick_stop(1, TICK_DEP_MASK_NONE);
        }
 
+       ts->next_tick = tick;
+
        /*
         * If the expiration time == KTIME_MAX, then we simply stop
         * the tick timer.
@@ -802,7 +804,10 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
        else
                tick_program_event(tick, 1);
 out:
-       /* Update the estimated sleep length */
+       /*
+        * Update the estimated sleep length until the next timer
+        * (not only the tick).
+        */
        ts->sleep_length = ktime_sub(dev->next_event, now);
        return tick;
 }
index bf38226e5c17c15e276c2e4e8c5f4fe423e071f3..075444e3d48e643549ba5c7fbcc3c792fb90e1db 100644 (file)
@@ -27,6 +27,7 @@ enum tick_nohz_mode {
  *                     timer is modified for nohz sleeps. This is necessary
  *                     to resume the tick timer operation in the timeline
  *                     when the CPU returns from nohz sleep.
+ * @next_tick:         Next tick to be fired when in dynticks mode.
  * @tick_stopped:      Indicator that the idle tick has been stopped
  * @idle_jiffies:      jiffies at the entry to idle for idle time accounting
  * @idle_calls:                Total number of idle calls
@@ -44,6 +45,7 @@ struct tick_sched {
        unsigned long                   check_clocks;
        enum tick_nohz_mode             nohz_mode;
        ktime_t                         last_tick;
+       ktime_t                         next_tick;
        int                             inidle;
        int                             tick_stopped;
        unsigned long                   idle_jiffies;
index b06848a104e6940e128e63a5d3c8c7fb39ffaf8b..eb9e9a7870fa7bdb0f373f858037c1026880c85f 100644 (file)
@@ -164,7 +164,7 @@ config DEBUG_INFO_REDUCED
 
 config DEBUG_INFO_SPLIT
        bool "Produce split debuginfo in .dwo files"
-       depends on DEBUG_INFO
+       depends on DEBUG_INFO && !FRV
        help
          Generate debug info into separate .dwo files. This significantly
          reduces the build directory size for builds with DEBUG_INFO,
index 25f57230380104f419257ea43c1cd3d2e31d7e65..e68604ae3cedf41ce98bc06de2142629fa115cbd 100644 (file)
@@ -730,43 +730,50 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
 }
 EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
 
+static inline void pipe_truncate(struct iov_iter *i)
+{
+       struct pipe_inode_info *pipe = i->pipe;
+       if (pipe->nrbufs) {
+               size_t off = i->iov_offset;
+               int idx = i->idx;
+               int nrbufs = (idx - pipe->curbuf) & (pipe->buffers - 1);
+               if (off) {
+                       pipe->bufs[idx].len = off - pipe->bufs[idx].offset;
+                       idx = next_idx(idx, pipe);
+                       nrbufs++;
+               }
+               while (pipe->nrbufs > nrbufs) {
+                       pipe_buf_release(pipe, &pipe->bufs[idx]);
+                       idx = next_idx(idx, pipe);
+                       pipe->nrbufs--;
+               }
+       }
+}
+
 static void pipe_advance(struct iov_iter *i, size_t size)
 {
        struct pipe_inode_info *pipe = i->pipe;
-       struct pipe_buffer *buf;
-       int idx = i->idx;
-       size_t off = i->iov_offset, orig_sz;
-       
        if (unlikely(i->count < size))
                size = i->count;
-       orig_sz = size;
-
        if (size) {
+               struct pipe_buffer *buf;
+               size_t off = i->iov_offset, left = size;
+               int idx = i->idx;
                if (off) /* make it relative to the beginning of buffer */
-                       size += off - pipe->bufs[idx].offset;
+                       left += off - pipe->bufs[idx].offset;
                while (1) {
                        buf = &pipe->bufs[idx];
-                       if (size <= buf->len)
+                       if (left <= buf->len)
                                break;
-                       size -= buf->len;
+                       left -= buf->len;
                        idx = next_idx(idx, pipe);
                }
-               buf->len = size;
                i->idx = idx;
-               off = i->iov_offset = buf->offset + size;
-       }
-       if (off)
-               idx = next_idx(idx, pipe);
-       if (pipe->nrbufs) {
-               int unused = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
-               /* [curbuf,unused) is in use.  Free [idx,unused) */
-               while (idx != unused) {
-                       pipe_buf_release(pipe, &pipe->bufs[idx]);
-                       idx = next_idx(idx, pipe);
-                       pipe->nrbufs--;
-               }
+               i->iov_offset = buf->offset + left;
        }
-       i->count -= orig_sz;
+       i->count -= size;
+       /* ... and discard everything past that point */
+       pipe_truncate(i);
 }
 
 void iov_iter_advance(struct iov_iter *i, size_t size)
@@ -826,6 +833,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction,
                        size_t count)
 {
        BUG_ON(direction != ITER_PIPE);
+       WARN_ON(pipe->nrbufs == pipe->buffers);
        i->type = direction;
        i->pipe = pipe;
        i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
index d0e4d1002059360e50254ae2c87dc8f7a87a2dff..b772a33ef640ab0d6770bb3d249a6fe6f16eeebc 100644 (file)
@@ -138,7 +138,7 @@ static int page_cache_tree_insert(struct address_space *mapping,
                                dax_radix_locked_entry(0, RADIX_DAX_EMPTY));
                        /* Wakeup waiters for exceptional entry lock */
                        dax_wake_mapping_entry_waiter(mapping, page->index, p,
-                                                     false);
+                                                     true);
                }
        }
        __radix_tree_replace(&mapping->page_tree, node, slot, page,
index 10eedbf14421f29675d18e80569bafc9efd60763..9a6bd6c8d55a6691047e516a46c2cf6b931b912d 100644 (file)
@@ -883,15 +883,17 @@ void huge_pmd_set_accessed(struct vm_fault *vmf, pmd_t orig_pmd)
 {
        pmd_t entry;
        unsigned long haddr;
+       bool write = vmf->flags & FAULT_FLAG_WRITE;
 
        vmf->ptl = pmd_lock(vmf->vma->vm_mm, vmf->pmd);
        if (unlikely(!pmd_same(*vmf->pmd, orig_pmd)))
                goto unlock;
 
        entry = pmd_mkyoung(orig_pmd);
+       if (write)
+               entry = pmd_mkdirty(entry);
        haddr = vmf->address & HPAGE_PMD_MASK;
-       if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry,
-                               vmf->flags & FAULT_FLAG_WRITE))
+       if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry, write))
                update_mmu_cache_pmd(vmf->vma, vmf->address, vmf->pmd);
 
 unlock:
@@ -919,8 +921,7 @@ static int do_huge_pmd_wp_page_fallback(struct vm_fault *vmf, pmd_t orig_pmd,
        }
 
        for (i = 0; i < HPAGE_PMD_NR; i++) {
-               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE |
-                                              __GFP_OTHER_NODE, vma,
+               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE, vma,
                                               vmf->address, page_to_nid(page));
                if (unlikely(!pages[i] ||
                             mem_cgroup_try_charge(pages[i], vma->vm_mm,
index 3edb759c5c7d15dfeacb4eb18e4a901602a0ee23..c7025c132670a4d8e3279d1ebb7730718fb6aa8a 100644 (file)
@@ -1773,23 +1773,32 @@ static int gather_surplus_pages(struct hstate *h, int delta)
 }
 
 /*
- * When releasing a hugetlb pool reservation, any surplus pages that were
- * allocated to satisfy the reservation must be explicitly freed if they were
- * never used.
- * Called with hugetlb_lock held.
+ * This routine has two main purposes:
+ * 1) Decrement the reservation count (resv_huge_pages) by the value passed
+ *    in unused_resv_pages.  This corresponds to the prior adjustments made
+ *    to the associated reservation map.
+ * 2) Free any unused surplus pages that may have been allocated to satisfy
+ *    the reservation.  As many as unused_resv_pages may be freed.
+ *
+ * Called with hugetlb_lock held.  However, the lock could be dropped (and
+ * reacquired) during calls to cond_resched_lock.  Whenever dropping the lock,
+ * we must make sure nobody else can claim pages we are in the process of
+ * freeing.  Do this by ensuring resv_huge_page always is greater than the
+ * number of huge pages we plan to free when dropping the lock.
  */
 static void return_unused_surplus_pages(struct hstate *h,
                                        unsigned long unused_resv_pages)
 {
        unsigned long nr_pages;
 
-       /* Uncommit the reservation */
-       h->resv_huge_pages -= unused_resv_pages;
-
        /* Cannot return gigantic pages currently */
        if (hstate_is_gigantic(h))
-               return;
+               goto out;
 
+       /*
+        * Part (or even all) of the reservation could have been backed
+        * by pre-allocated pages. Only free surplus pages.
+        */
        nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
 
        /*
@@ -1799,12 +1808,22 @@ static void return_unused_surplus_pages(struct hstate *h,
         * when the nodes with surplus pages have no free pages.
         * free_pool_huge_page() will balance the the freed pages across the
         * on-line nodes with memory and will handle the hstate accounting.
+        *
+        * Note that we decrement resv_huge_pages as we free the pages.  If
+        * we drop the lock, resv_huge_pages will still be sufficiently large
+        * to cover subsequent pages we may free.
         */
        while (nr_pages--) {
+               h->resv_huge_pages--;
+               unused_resv_pages--;
                if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
-                       break;
+                       goto out;
                cond_resched_lock(&hugetlb_lock);
        }
+
+out:
+       /* Fully uncommit the reservation */
+       h->resv_huge_pages -= unused_resv_pages;
 }
 
 
index e32389a970305eaf60b36da896e2226a8ce18a0d..77ae3239c3de17bfbf7ba29b56a5cb270611cfd8 100644 (file)
@@ -943,7 +943,7 @@ static void collapse_huge_page(struct mm_struct *mm,
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 
        /* Only allocate from the target node */
-       gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_OTHER_NODE | __GFP_THISNODE;
+       gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
 
        /*
         * Before allocating the hugepage, release the mmap_sem read lock.
@@ -1242,7 +1242,6 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
        struct vm_area_struct *vma;
        unsigned long addr;
        pmd_t *pmd, _pmd;
-       bool deposited = false;
 
        i_mmap_lock_write(mapping);
        vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
@@ -1267,26 +1266,10 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
                        spinlock_t *ptl = pmd_lock(vma->vm_mm, pmd);
                        /* assume page table is clear */
                        _pmd = pmdp_collapse_flush(vma, addr, pmd);
-                       /*
-                        * now deposit the pgtable for arch that need it
-                        * otherwise free it.
-                        */
-                       if (arch_needs_pgtable_deposit()) {
-                               /*
-                                * The deposit should be visibile only after
-                                * collapse is seen by others.
-                                */
-                               smp_wmb();
-                               pgtable_trans_huge_deposit(vma->vm_mm, pmd,
-                                                          pmd_pgtable(_pmd));
-                               deposited = true;
-                       }
                        spin_unlock(ptl);
                        up_write(&vma->vm_mm->mmap_sem);
-                       if (!deposited) {
-                               atomic_long_dec(&vma->vm_mm->nr_ptes);
-                               pte_free(vma->vm_mm, pmd_pgtable(_pmd));
-                       }
+                       atomic_long_dec(&vma->vm_mm->nr_ptes);
+                       pte_free(vma->vm_mm, pmd_pgtable(_pmd));
                }
        }
        i_mmap_unlock_write(mapping);
@@ -1326,8 +1309,7 @@ static void collapse_shmem(struct mm_struct *mm,
        VM_BUG_ON(start & (HPAGE_PMD_NR - 1));
 
        /* Only allocate from the target node */
-       gfp = alloc_hugepage_khugepaged_gfpmask() |
-               __GFP_OTHER_NODE | __GFP_THISNODE;
+       gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
 
        new_page = khugepaged_alloc_page(hpage, gfp, node);
        if (!new_page) {
index 4048897e7b01a6e5e82333c0852629eded927ff3..a63a8f8326647b92bdc63810c8a93be96047f748 100644 (file)
@@ -625,8 +625,8 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
 unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
                                           int nid, unsigned int lru_mask)
 {
+       struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);
        unsigned long nr = 0;
-       struct mem_cgroup_per_node *mz;
        enum lru_list lru;
 
        VM_BUG_ON((unsigned)nid >= nr_node_ids);
@@ -634,8 +634,7 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
        for_each_lru(lru) {
                if (!(BIT(lru) & lru_mask))
                        continue;
-               mz = mem_cgroup_nodeinfo(memcg, nid);
-               nr += mz->lru_size[lru];
+               nr += mem_cgroup_get_lru_size(lruvec, lru);
        }
        return nr;
 }
@@ -1002,6 +1001,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgd
  * mem_cgroup_update_lru_size - account for adding or removing an lru page
  * @lruvec: mem_cgroup per zone lru vector
  * @lru: index of lru list the page is sitting on
+ * @zid: zone id of the accounted pages
  * @nr_pages: positive when adding or negative when removing
  *
  * This function must be called under lru_lock, just before a page is added
@@ -1009,27 +1009,25 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgd
  * so as to allow it to check that lru_size 0 is consistent with list_empty).
  */
 void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
-                               int nr_pages)
+                               int zid, int nr_pages)
 {
        struct mem_cgroup_per_node *mz;
        unsigned long *lru_size;
        long size;
-       bool empty;
 
        if (mem_cgroup_disabled())
                return;
 
        mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
-       lru_size = mz->lru_size + lru;
-       empty = list_empty(lruvec->lists + lru);
+       lru_size = &mz->lru_zone_size[zid][lru];
 
        if (nr_pages < 0)
                *lru_size += nr_pages;
 
        size = *lru_size;
-       if (WARN_ONCE(size < 0 || empty != !size,
-               "%s(%p, %d, %d): lru_size %ld but %sempty\n",
-               __func__, lruvec, lru, nr_pages, size, empty ? "" : "not ")) {
+       if (WARN_ONCE(size < 0,
+               "%s(%p, %d, %d): lru_size %ld\n",
+               __func__, lruvec, lru, nr_pages, size)) {
                VM_BUG_ON(1);
                *lru_size = 0;
        }
index 9f2c15cdb32c6327c0d2e8992c5c269ba573f698..6bf2b471e30ca566a55160e4131bf7e7b9c3c4ea 100644 (file)
@@ -3772,8 +3772,8 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
 }
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-static int __follow_pte(struct mm_struct *mm, unsigned long address,
-               pte_t **ptepp, spinlock_t **ptlp)
+static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+               pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp)
 {
        pgd_t *pgd;
        pud_t *pud;
@@ -3790,11 +3790,20 @@ static int __follow_pte(struct mm_struct *mm, unsigned long address,
 
        pmd = pmd_offset(pud, address);
        VM_BUG_ON(pmd_trans_huge(*pmd));
-       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-               goto out;
 
-       /* We cannot handle huge page PFN maps. Luckily they don't exist. */
-       if (pmd_huge(*pmd))
+       if (pmd_huge(*pmd)) {
+               if (!pmdpp)
+                       goto out;
+
+               *ptlp = pmd_lock(mm, pmd);
+               if (pmd_huge(*pmd)) {
+                       *pmdpp = pmd;
+                       return 0;
+               }
+               spin_unlock(*ptlp);
+       }
+
+       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
                goto out;
 
        ptep = pte_offset_map_lock(mm, pmd, address, ptlp);
@@ -3810,16 +3819,30 @@ static int __follow_pte(struct mm_struct *mm, unsigned long address,
        return -EINVAL;
 }
 
-int follow_pte(struct mm_struct *mm, unsigned long address, pte_t **ptepp,
-              spinlock_t **ptlp)
+static inline int follow_pte(struct mm_struct *mm, unsigned long address,
+                            pte_t **ptepp, spinlock_t **ptlp)
+{
+       int res;
+
+       /* (void) is needed to make gcc happy */
+       (void) __cond_lock(*ptlp,
+                          !(res = __follow_pte_pmd(mm, address, ptepp, NULL,
+                                          ptlp)));
+       return res;
+}
+
+int follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+                            pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp)
 {
        int res;
 
        /* (void) is needed to make gcc happy */
        (void) __cond_lock(*ptlp,
-                          !(res = __follow_pte(mm, address, ptepp, ptlp)));
+                          !(res = __follow_pte_pmd(mm, address, ptepp, pmdpp,
+                                          ptlp)));
        return res;
 }
+EXPORT_SYMBOL(follow_pte_pmd);
 
 /**
  * follow_pfn - look up PFN at a user virtual address
index 2c6d5f64feca409e9fdca4b551a240882e421476..d604d2596b7bed41b9748ee3242571b771db4d5e 100644 (file)
@@ -1864,14 +1864,14 @@ int move_freepages(struct zone *zone,
 #endif
 
        for (page = start_page; page <= end_page;) {
-               /* Make sure we are not inadvertently changing nodes */
-               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
                if (!pfn_valid_within(page_to_pfn(page))) {
                        page++;
                        continue;
                }
 
+               /* Make sure we are not inadvertently changing nodes */
+               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+
                if (!PageBuddy(page)) {
                        page++;
                        continue;
@@ -2583,30 +2583,22 @@ int __isolate_free_page(struct page *page, unsigned int order)
  * Update NUMA hit/miss statistics
  *
  * Must be called with interrupts disabled.
- *
- * When __GFP_OTHER_NODE is set assume the node of the preferred
- * zone is the local node. This is useful for daemons who allocate
- * memory on behalf of other processes.
  */
-static inline void zone_statistics(struct zone *preferred_zone, struct zone *z,
-                                                               gfp_t flags)
+static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)
 {
 #ifdef CONFIG_NUMA
-       int local_nid = numa_node_id();
        enum zone_stat_item local_stat = NUMA_LOCAL;
 
-       if (unlikely(flags & __GFP_OTHER_NODE)) {
+       if (z->node != numa_node_id())
                local_stat = NUMA_OTHER;
-               local_nid = preferred_zone->node;
-       }
 
-       if (z->node == local_nid) {
+       if (z->node == preferred_zone->node)
                __inc_zone_state(z, NUMA_HIT);
-               __inc_zone_state(z, local_stat);
-       } else {
+       else {
                __inc_zone_state(z, NUMA_MISS);
                __inc_zone_state(preferred_zone, NUMA_FOREIGN);
        }
+       __inc_zone_state(z, local_stat);
 #endif
 }
 
@@ -2674,7 +2666,7 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
        }
 
        __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
-       zone_statistics(preferred_zone, zone, gfp_flags);
+       zone_statistics(preferred_zone, zone);
        local_irq_restore(flags);
 
        VM_BUG_ON_PAGE(bad_range(zone, page), page);
@@ -3904,8 +3896,8 @@ EXPORT_SYMBOL(free_pages);
  * drivers to provide a backing region of memory for use as either an
  * sk_buff->head, or to be used in the "frags" portion of skb_shared_info.
  */
-static struct page *__page_frag_refill(struct page_frag_cache *nc,
-                                      gfp_t gfp_mask)
+static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
+                                            gfp_t gfp_mask)
 {
        struct page *page = NULL;
        gfp_t gfp = gfp_mask;
@@ -3925,22 +3917,23 @@ static struct page *__page_frag_refill(struct page_frag_cache *nc,
        return page;
 }
 
-void __page_frag_drain(struct page *page, unsigned int order,
-                      unsigned int count)
+void __page_frag_cache_drain(struct page *page, unsigned int count)
 {
        VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
 
        if (page_ref_sub_and_test(page, count)) {
+               unsigned int order = compound_order(page);
+
                if (order == 0)
                        free_hot_cold_page(page, false);
                else
                        __free_pages_ok(page, order);
        }
 }
-EXPORT_SYMBOL(__page_frag_drain);
+EXPORT_SYMBOL(__page_frag_cache_drain);
 
-void *__alloc_page_frag(struct page_frag_cache *nc,
-                       unsigned int fragsz, gfp_t gfp_mask)
+void *page_frag_alloc(struct page_frag_cache *nc,
+                     unsigned int fragsz, gfp_t gfp_mask)
 {
        unsigned int size = PAGE_SIZE;
        struct page *page;
@@ -3948,7 +3941,7 @@ void *__alloc_page_frag(struct page_frag_cache *nc,
 
        if (unlikely(!nc->va)) {
 refill:
-               page = __page_frag_refill(nc, gfp_mask);
+               page = __page_frag_cache_refill(nc, gfp_mask);
                if (!page)
                        return NULL;
 
@@ -3991,19 +3984,19 @@ void *__alloc_page_frag(struct page_frag_cache *nc,
 
        return nc->va + offset;
 }
-EXPORT_SYMBOL(__alloc_page_frag);
+EXPORT_SYMBOL(page_frag_alloc);
 
 /*
  * Frees a page fragment allocated out of either a compound or order 0 page.
  */
-void __free_page_frag(void *addr)
+void page_frag_free(void *addr)
 {
        struct page *page = virt_to_head_page(addr);
 
        if (unlikely(put_page_testzero(page)))
                __free_pages_ok(page, compound_order(page));
 }
-EXPORT_SYMBOL(__free_page_frag);
+EXPORT_SYMBOL(page_frag_free);
 
 static void *make_alloc_exact(unsigned long addr, unsigned int order,
                size_t size)
index 29bc6c0dedd07020e9f433332f907620239343a5..4f2ec6bb46ebe949d2e19ff154faddc7e2526f02 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2457,7 +2457,6 @@ union freelist_init_state {
                unsigned int pos;
                unsigned int *list;
                unsigned int count;
-               unsigned int rand;
        };
        struct rnd_state rnd_state;
 };
@@ -2483,8 +2482,7 @@ static bool freelist_state_initialize(union freelist_init_state *state,
        } else {
                state->list = cachep->random_seq;
                state->count = count;
-               state->pos = 0;
-               state->rand = rand;
+               state->pos = rand % count;
                ret = true;
        }
        return ret;
@@ -2493,7 +2491,9 @@ static bool freelist_state_initialize(union freelist_init_state *state,
 /* Get the next entry on the list and randomize it using a random shift */
 static freelist_idx_t next_random_slot(union freelist_init_state *state)
 {
-       return (state->list[state->pos++] + state->rand) % state->count;
+       if (state->pos >= state->count)
+               state->pos = 0;
+       return state->list[state->pos++];
 }
 
 /* Swap two freelist entries */
index 1c6e0321205dd2d34abc7f39a0753c128eb7ae53..4761701d1721e63fb8334e3a63fcc11b9e5e6443 100644 (file)
@@ -943,11 +943,25 @@ bool reuse_swap_page(struct page *page, int *total_mapcount)
        count = page_trans_huge_mapcount(page, total_mapcount);
        if (count <= 1 && PageSwapCache(page)) {
                count += page_swapcount(page);
-               if (count == 1 && !PageWriteback(page)) {
+               if (count != 1)
+                       goto out;
+               if (!PageWriteback(page)) {
                        delete_from_swap_cache(page);
                        SetPageDirty(page);
+               } else {
+                       swp_entry_t entry;
+                       struct swap_info_struct *p;
+
+                       entry.val = page_private(page);
+                       p = swap_info_get(entry);
+                       if (p->flags & SWP_STABLE_WRITES) {
+                               spin_unlock(&p->lock);
+                               return false;
+                       }
+                       spin_unlock(&p->lock);
                }
        }
+out:
        return count <= 1;
 }
 
@@ -2448,6 +2462,10 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                error = -ENOMEM;
                goto bad_swap;
        }
+
+       if (bdi_cap_stable_pages_required(inode_to_bdi(inode)))
+               p->flags |= SWP_STABLE_WRITES;
+
        if (p->bdev && blk_queue_nonrot(bdev_get_queue(p->bdev))) {
                int cpu;
 
index 6aa5b01d3e757b9b462993f3421050fd8831ceea..532a2a750952daffed4e4242d36a449eb9ba8837 100644 (file)
@@ -242,6 +242,16 @@ unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru)
        return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
 }
 
+unsigned long lruvec_zone_lru_size(struct lruvec *lruvec, enum lru_list lru,
+                                  int zone_idx)
+{
+       if (!mem_cgroup_disabled())
+               return mem_cgroup_get_zone_lru_size(lruvec, lru, zone_idx);
+
+       return zone_page_state(&lruvec_pgdat(lruvec)->node_zones[zone_idx],
+                              NR_ZONE_LRU_BASE + lru);
+}
+
 /*
  * Add a shrinker callback to be called from the vm.
  */
@@ -1382,8 +1392,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
  * be complete before mem_cgroup_update_lru_size due to a santity check.
  */
 static __always_inline void update_lru_sizes(struct lruvec *lruvec,
-                       enum lru_list lru, unsigned long *nr_zone_taken,
-                       unsigned long nr_taken)
+                       enum lru_list lru, unsigned long *nr_zone_taken)
 {
        int zid;
 
@@ -1392,11 +1401,11 @@ static __always_inline void update_lru_sizes(struct lruvec *lruvec,
                        continue;
 
                __update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
-       }
-
 #ifdef CONFIG_MEMCG
-       mem_cgroup_update_lru_size(lruvec, lru, -nr_taken);
+               mem_cgroup_update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
 #endif
+       }
+
 }
 
 /*
@@ -1501,7 +1510,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
        *nr_scanned = scan;
        trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
                                    nr_taken, mode, is_file_lru(lru));
-       update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken);
+       update_lru_sizes(lruvec, lru, nr_zone_taken);
        return nr_taken;
 }
 
@@ -2047,10 +2056,8 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
                if (!managed_zone(zone))
                        continue;
 
-               inactive_zone = zone_page_state(zone,
-                               NR_ZONE_LRU_BASE + (file * LRU_FILE));
-               active_zone = zone_page_state(zone,
-                               NR_ZONE_LRU_BASE + (file * LRU_FILE) + LRU_ACTIVE);
+               inactive_zone = lruvec_zone_lru_size(lruvec, file * LRU_FILE, zid);
+               active_zone = lruvec_zone_lru_size(lruvec, (file * LRU_FILE) + LRU_ACTIVE, zid);
 
                inactive -= min(inactive, inactive_zone);
                active -= min(active, active_zone);
index a1005007224ca04ee673fb948776107d6ba075c4..a29bb4b41c50e3c55463eaee2a5dda1292b757f6 100644 (file)
@@ -258,10 +258,6 @@ config XPS
 config HWBM
        bool
 
-config SOCK_CGROUP_DATA
-       bool
-       default n
-
 config CGROUP_NET_PRIO
        bool "Network priority cgroup"
        depends on CGROUPS
index 8ca6a929bf1255cb432fd4bd59d34345d62e09c4..95087e6e8258366af95579bb308d1a6e18266f0e 100644 (file)
@@ -399,7 +399,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
                                br_nf_hook_thresh(NF_BR_PRE_ROUTING,
                                                  net, sk, skb, skb->dev,
                                                  NULL,
-                                                 br_nf_pre_routing_finish);
+                                                 br_nf_pre_routing_finish_bridge);
                                return 0;
                        }
                        ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
index 8db5a0b4b52061afe9cd44dead33cc69523d15df..07b307b0b414730688b64fdb2295b0fa1b721e51 100644 (file)
@@ -4441,7 +4441,9 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
            pinfo->nr_frags &&
            !PageHighMem(skb_frag_page(frag0))) {
                NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
-               NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
+               NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
+                                                   skb_frag_size(frag0),
+                                                   skb->end - skb->tail);
        }
 }
 
index fe4e1531976c3a36127b6ad4af33f24534af4c52..1b7673aac59d51a5f8b5ef3f2076f1440c017fae 100644 (file)
@@ -67,8 +67,8 @@ EXPORT_SYMBOL(skb_flow_dissector_init);
  * The function will try to retrieve a be32 entity at
  * offset poff
  */
-__be16 skb_flow_get_be16(const struct sk_buff *skb, int poff, void *data,
-                        int hlen)
+static __be16 skb_flow_get_be16(const struct sk_buff *skb, int poff,
+                               void *data, int hlen)
 {
        __be16 *u, _u;
 
index 5a03730fbc1a84376985d4d68d8b80d8f38b0985..734c71468b013838516cfe8c744dcd0e797a6e2b 100644 (file)
@@ -369,7 +369,7 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
 
        local_irq_save(flags);
        nc = this_cpu_ptr(&netdev_alloc_cache);
-       data = __alloc_page_frag(nc, fragsz, gfp_mask);
+       data = page_frag_alloc(nc, fragsz, gfp_mask);
        local_irq_restore(flags);
        return data;
 }
@@ -391,7 +391,7 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
 {
        struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
 
-       return __alloc_page_frag(&nc->page, fragsz, gfp_mask);
+       return page_frag_alloc(&nc->page, fragsz, gfp_mask);
 }
 
 void *napi_alloc_frag(unsigned int fragsz)
@@ -441,7 +441,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
        local_irq_save(flags);
 
        nc = this_cpu_ptr(&netdev_alloc_cache);
-       data = __alloc_page_frag(nc, len, gfp_mask);
+       data = page_frag_alloc(nc, len, gfp_mask);
        pfmemalloc = nc->pfmemalloc;
 
        local_irq_restore(flags);
@@ -505,7 +505,7 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
        if (sk_memalloc_socks())
                gfp_mask |= __GFP_MEMALLOC;
 
-       data = __alloc_page_frag(&nc->page, len, gfp_mask);
+       data = page_frag_alloc(&nc->page, len, gfp_mask);
        if (unlikely(!data))
                return NULL;
 
index f560e0826009851e79a1f8a8b90f4ded3cfc382d..4eca27dc5c9478e36120a5128a7c11d6208b45a9 100644 (file)
@@ -222,7 +222,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
   "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG"      ,
   "sk_lock-AF_NFC"   , "sk_lock-AF_VSOCK"    , "sk_lock-AF_KCM"      ,
-  "sk_lock-AF_MAX"
+  "sk_lock-AF_QIPCRTR", "sk_lock-AF_MAX"
 };
 static const char *const af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
@@ -239,7 +239,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
   "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG"      ,
   "slock-AF_NFC"   , "slock-AF_VSOCK"    ,"slock-AF_KCM"       ,
-  "slock-AF_MAX"
+  "slock-AF_QIPCRTR", "slock-AF_MAX"
 };
 static const char *const af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
@@ -256,7 +256,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
   "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG"      ,
   "clock-AF_NFC"   , "clock-AF_VSOCK"    , "clock-AF_KCM"      ,
-  "clock-AF_MAX"
+  "clock-AF_QIPCRTR", "clock-AF_MAX"
 };
 
 /*
index 5fff951a0a4928ccf28fb681be86c7df6a05e94f..da38621245458bae2506b0c030d92315f1be5775 100644 (file)
@@ -394,9 +394,11 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
                        return err;
        }
 
-       err = dsa_cpu_port_ethtool_setup(dst->ds[0]);
-       if (err)
-               return err;
+       if (dst->ds[0]) {
+               err = dsa_cpu_port_ethtool_setup(dst->ds[0]);
+               if (err)
+                       return err;
+       }
 
        /* If we use a tagging format that doesn't have an ethertype
         * field, make sure that all packets from this point on get
@@ -433,7 +435,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
                dsa_ds_unapply(dst, ds);
        }
 
-       dsa_cpu_port_ethtool_restore(dst->ds[0]);
+       if (dst->ds[0])
+               dsa_cpu_port_ethtool_restore(dst->ds[0]);
 
        pr_info("DSA: tree %d unapplied\n", dst->tree);
        dst->applied = false;
index 7a5b4c7d9a87b18051a94aa2e16e6b85c8d85aa6..eba1546b5031e6e280a558118e55b13befc4c8ea 100644 (file)
@@ -1618,8 +1618,13 @@ void fib_select_multipath(struct fib_result *res, int hash)
 void fib_select_path(struct net *net, struct fib_result *res,
                     struct flowi4 *fl4, int mp_hash)
 {
+       bool oif_check;
+
+       oif_check = (fl4->flowi4_oif == 0 ||
+                    fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF);
+
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-       if (res->fi->fib_nhs > 1 && fl4->flowi4_oif == 0) {
+       if (res->fi->fib_nhs > 1 && oif_check) {
                if (mp_hash < 0)
                        mp_hash = get_hash_from_flowi4(fl4) >> 1;
 
@@ -1629,7 +1634,7 @@ void fib_select_path(struct net *net, struct fib_result *res,
 #endif
        if (!res->prefixlen &&
            res->table->tb_num_default > 1 &&
-           res->type == RTN_UNICAST && !fl4->flowi4_oif)
+           res->type == RTN_UNICAST && oif_check)
                fib_select_default(fl4, res);
 
        if (!fl4->saddr)
index 21db00d0362bb60d48aed2c900b857f86cef5793..a6b8c1a4102ba7ab07efbcf504fa7ca4025c6f19 100644 (file)
@@ -144,7 +144,7 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
        rcu_read_lock_bh();
        c = __clusterip_config_find(net, clusterip);
        if (c) {
-               if (unlikely(!atomic_inc_not_zero(&c->refcount)))
+               if (!c->pde || unlikely(!atomic_inc_not_zero(&c->refcount)))
                        c = NULL;
                else if (entry)
                        atomic_inc(&c->entries);
@@ -166,14 +166,15 @@ clusterip_config_init_nodelist(struct clusterip_config *c,
 
 static struct clusterip_config *
 clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
-                       struct net_device *dev)
+                     struct net_device *dev)
 {
+       struct net *net = dev_net(dev);
        struct clusterip_config *c;
-       struct clusterip_net *cn = net_generic(dev_net(dev), clusterip_net_id);
+       struct clusterip_net *cn = net_generic(net, clusterip_net_id);
 
        c = kzalloc(sizeof(*c), GFP_ATOMIC);
        if (!c)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        c->dev = dev;
        c->clusterip = ip;
@@ -185,6 +186,17 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
        atomic_set(&c->refcount, 1);
        atomic_set(&c->entries, 1);
 
+       spin_lock_bh(&cn->lock);
+       if (__clusterip_config_find(net, ip)) {
+               spin_unlock_bh(&cn->lock);
+               kfree(c);
+
+               return ERR_PTR(-EBUSY);
+       }
+
+       list_add_rcu(&c->list, &cn->configs);
+       spin_unlock_bh(&cn->lock);
+
 #ifdef CONFIG_PROC_FS
        {
                char buffer[16];
@@ -195,16 +207,16 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
                                          cn->procdir,
                                          &clusterip_proc_fops, c);
                if (!c->pde) {
+                       spin_lock_bh(&cn->lock);
+                       list_del_rcu(&c->list);
+                       spin_unlock_bh(&cn->lock);
                        kfree(c);
-                       return NULL;
+
+                       return ERR_PTR(-ENOMEM);
                }
        }
 #endif
 
-       spin_lock_bh(&cn->lock);
-       list_add_rcu(&c->list, &cn->configs);
-       spin_unlock_bh(&cn->lock);
-
        return c;
 }
 
@@ -410,9 +422,9 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
 
                        config = clusterip_config_init(cipinfo,
                                                        e->ip.dst.s_addr, dev);
-                       if (!config) {
+                       if (IS_ERR(config)) {
                                dev_put(dev);
-                               return -ENOMEM;
+                               return PTR_ERR(config);
                        }
                        dev_mc_add(config->dev, config->clustermac);
                }
index 22cbd61079b5a9d2661583b7d96eea46eddb685d..b2fa498b15d173739d0ebc5b6dd0577bf8dc4c08 100644 (file)
@@ -951,7 +951,7 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_tcp_notsent_lowat,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_douintvec,
        },
        {
                .procname       = "tcp_tw_reuse",
index d46f4d5b1c62edf95791e9d47d966c3bc61e1888..ba8f02d0f283c6eaaf14ed89103adea135093353 100644 (file)
@@ -606,7 +606,6 @@ bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(tcp_peer_is_proven);
 
 void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst)
 {
index 89c59e656f44939863ceada610d3442d2de666ba..fc7b4017ba241f9dd39d49bd6258ecd4a16e3a3a 100644 (file)
@@ -191,6 +191,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
        ops = rcu_dereference(inet6_offloads[proto]);
        if (!ops || !ops->callbacks.gro_receive) {
                __pskb_pull(skb, skb_gro_offset(skb));
+               skb_gro_frag0_invalidate(skb);
                proto = ipv6_gso_pull_exthdrs(skb, proto);
                skb_gro_pull(skb, -skb_transport_offset(skb));
                skb_reset_transport_header(skb);
index f4b4a4a5f4ba740f4a290e2394034fe335941abe..d82042c8d8fd4b38eac12a58eb634438aab726a7 100644 (file)
@@ -189,12 +189,12 @@ static int vti6_tnl_create2(struct net_device *dev)
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
        int err;
 
+       dev->rtnl_link_ops = &vti6_link_ops;
        err = register_netdevice(dev);
        if (err < 0)
                goto out;
 
        strcpy(t->parms.name, dev->name);
-       dev->rtnl_link_ops = &vti6_link_ops;
 
        dev_hold(dev);
        vti6_tnl_link(ip6n, t);
index 8417c41d8ec8398a72c56f9b37b16d94702cbbf3..ce5aaf448c541079e8e08b170d5d24d4f499d7d8 100644 (file)
@@ -1464,7 +1464,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
        struct fib6_node *fn;
 
        /* Get the "current" route for this destination and
-        * check if the redirect has come from approriate router.
+        * check if the redirect has come from appropriate router.
         *
         * RFC 4861 specifies that redirects should only be
         * accepted if they come from the nexthop to the target.
@@ -2768,7 +2768,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
           old MTU is the lowest MTU in the path, update the route PMTU
           to reflect the increase. In this case if the other nodes' MTU
           also have the lowest MTU, TOO BIG MESSAGE will be lead to
-          PMTU discouvery.
+          PMTU discovery.
         */
        if (rt->dst.dev == arg->dev &&
            dst_metric_raw(&rt->dst, RTAX_MTU) &&
index cfb9e5f4e28f52c699072eaf41f12f3a6e667160..13190b38f22ee5116fb7701feed22ec436031a4e 100644 (file)
@@ -1044,7 +1044,8 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct iucv_sock *iucv = iucv_sk(sk);
-       size_t headroom, linear;
+       size_t headroom = 0;
+       size_t linear;
        struct sk_buff *skb;
        struct iucv_message txmsg = {0};
        struct cmsghdr *cmsg;
@@ -1122,18 +1123,20 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
         * this is fine for SOCK_SEQPACKET (unless we want to support
         * segmented records using the MSG_EOR flag), but
         * for SOCK_STREAM we might want to improve it in future */
-       headroom = (iucv->transport == AF_IUCV_TRANS_HIPER)
-                  ? sizeof(struct af_iucv_trans_hdr) + ETH_HLEN : 0;
-       if (headroom + len < PAGE_SIZE) {
+       if (iucv->transport == AF_IUCV_TRANS_HIPER) {
+               headroom = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
                linear = len;
        } else {
-               /* In nonlinear "classic" iucv skb,
-                * reserve space for iucv_array
-                */
-               if (iucv->transport != AF_IUCV_TRANS_HIPER)
-                       headroom += sizeof(struct iucv_array) *
-                                   (MAX_SKB_FRAGS + 1);
-               linear = PAGE_SIZE - headroom;
+               if (len < PAGE_SIZE) {
+                       linear = len;
+               } else {
+                       /* In nonlinear "classic" iucv skb,
+                        * reserve space for iucv_array
+                        */
+                       headroom = sizeof(struct iucv_array) *
+                                  (MAX_SKB_FRAGS + 1);
+                       linear = PAGE_SIZE - headroom;
+               }
        }
        skb = sock_alloc_send_pskb(sk, headroom + linear, len - linear,
                                   noblock, &err, 0);
index a019a87e58ee8151620eb3d8500979d02dba54c1..0db5f9782265ebb033f10d07da815495e8a7d278 100644 (file)
@@ -2115,7 +2115,7 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
         * is called on error from nf_tables_newrule().
         */
        expr = nft_expr_first(rule);
-       while (expr->ops && expr != nft_expr_last(rule)) {
+       while (expr != nft_expr_last(rule) && expr->ops) {
                nf_tables_expr_destroy(ctx, expr);
                expr = nft_expr_next(expr);
        }
index 36d2b10965464cd8abc3ad57326aefb00b003971..7d699bbd45b0eaae1574a094f54a85d8219d390a 100644 (file)
@@ -250,6 +250,22 @@ static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
        return 0;
 }
 
+static int nft_payload_csum_inet(struct sk_buff *skb, const u32 *src,
+                                __wsum fsum, __wsum tsum, int csum_offset)
+{
+       __sum16 sum;
+
+       if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+               return -1;
+
+       nft_csum_replace(&sum, fsum, tsum);
+       if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
+           skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+               return -1;
+
+       return 0;
+}
+
 static void nft_payload_set_eval(const struct nft_expr *expr,
                                 struct nft_regs *regs,
                                 const struct nft_pktinfo *pkt)
@@ -259,7 +275,6 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
        const u32 *src = &regs->data[priv->sreg];
        int offset, csum_offset;
        __wsum fsum, tsum;
-       __sum16 sum;
 
        switch (priv->base) {
        case NFT_PAYLOAD_LL_HEADER:
@@ -282,18 +297,14 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
        csum_offset = offset + priv->csum_offset;
        offset += priv->offset;
 
-       if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+       if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
            (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
             skb->ip_summed != CHECKSUM_PARTIAL)) {
-               if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
-                       goto err;
-
                fsum = skb_checksum(skb, offset, priv->len, 0);
                tsum = csum_partial(src, priv->len, 0);
-               nft_csum_replace(&sum, fsum, tsum);
 
-               if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
-                   skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+               if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+                   nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
                        goto err;
 
                if (priv->csum_flags &&
index 3e19fa1230dc6b9274090257be97b91827699485..dbb6aaff67ec5c151f8c8c6333721421f8e85076 100644 (file)
@@ -38,7 +38,7 @@ static void nft_queue_eval(const struct nft_expr *expr,
 
        if (priv->queues_total > 1) {
                if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) {
-                       int cpu = smp_processor_id();
+                       int cpu = raw_smp_processor_id();
 
                        queue = priv->queuenum + cpu % priv->queues_total;
                } else {
index bd6efc53f26d01d8c8ac246c36fa4b1cf970ce31..2d6fe3559912674385e7679557fc31ddeb901b38 100644 (file)
@@ -110,30 +110,32 @@ static int nft_quota_obj_init(const struct nlattr * const tb[],
 static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
                             bool reset)
 {
+       u64 consumed, consumed_cap;
        u32 flags = priv->flags;
-       u64 consumed;
-
-       if (reset) {
-               consumed = atomic64_xchg(&priv->consumed, 0);
-               if (test_and_clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
-                       flags |= NFT_QUOTA_F_DEPLETED;
-       } else {
-               consumed = atomic64_read(&priv->consumed);
-       }
 
        /* Since we inconditionally increment consumed quota for each packet
         * that we see, don't go over the quota boundary in what we send to
         * userspace.
         */
-       if (consumed > priv->quota)
-               consumed = priv->quota;
+       consumed = atomic64_read(&priv->consumed);
+       if (consumed >= priv->quota) {
+               consumed_cap = priv->quota;
+               flags |= NFT_QUOTA_F_DEPLETED;
+       } else {
+               consumed_cap = consumed;
+       }
 
        if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota),
                         NFTA_QUOTA_PAD) ||
-           nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed),
+           nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
                         NFTA_QUOTA_PAD) ||
            nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
                goto nla_put_failure;
+
+       if (reset) {
+               atomic64_sub(consumed, &priv->consumed);
+               clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
+       }
        return 0;
 
 nla_put_failure:
index 28c56b95fb7ff6ebaf5a99d8cfcbf583a01e73f5..ea7c67050792c9093c28b397e5ae164a570a0e33 100644 (file)
@@ -1502,10 +1502,7 @@ static int __init netlbl_init(void)
        printk(KERN_INFO "NetLabel: Initializing\n");
        printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
               (1 << NETLBL_DOMHSH_BITSIZE));
-       printk(KERN_INFO "NetLabel:  protocols ="
-              " UNLABELED"
-              " CIPSOv4"
-              "\n");
+       printk(KERN_INFO "NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO\n");
 
        ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
        if (ret_val != 0)
index c985ecbe9bd62a81899d43eb802003d6bb4ebe08..ae5ac175b2bef96ffa614bc799db5cd90a7bdc08 100644 (file)
@@ -252,7 +252,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
        const int pkt_len = 20;
        struct qrtr_hdr *hdr;
        struct sk_buff *skb;
-       u32 *buf;
+       __le32 *buf;
 
        skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
        if (!skb)
@@ -269,7 +269,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
        hdr->dst_node_id = cpu_to_le32(dst_node);
        hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
 
-       buf = (u32 *)skb_put(skb, pkt_len);
+       buf = (__le32 *)skb_put(skb, pkt_len);
        memset(buf, 0, pkt_len);
        buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
        buf[1] = cpu_to_le32(src_node);
index e54082699520ae40d8ab4c282c230f3b3787db92..34efaa4ef2f6acfbed9b490f948f214e91a5606c 100644 (file)
@@ -1048,7 +1048,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
                             (new_transport->state == SCTP_PF)))
                                new_transport = asoc->peer.active_path;
                        if (new_transport->state == SCTP_UNCONFIRMED) {
-                               WARN_ONCE(1, "Atempt to send packet on unconfirmed path.");
+                               WARN_ONCE(1, "Attempt to send packet on unconfirmed path.");
                                sctp_chunk_fail(chunk, 0);
                                sctp_chunk_free(chunk);
                                continue;
index a8c2307590b87ce5774f275fcbc1397f095d4c27..0758e13754e2faccb257d2f6ba9cca7b2da1baab 100644 (file)
@@ -533,7 +533,7 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
        return used;
 }
 
-int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
+static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        int err = simple_setattr(dentry, iattr);
 
index 3df85a751a85285f609c5583e7ad864c7c822560..ef5eff93a8b817dda5fa41bebf4fe4963663a9d6 100644 (file)
@@ -14502,13 +14502,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                bool schedule_destroy_work = false;
-               bool schedule_scan_stop = false;
                struct cfg80211_sched_scan_request *sched_scan_req =
                        rcu_dereference(rdev->sched_scan_req);
 
                if (sched_scan_req && notify->portid &&
-                   sched_scan_req->owner_nlportid == notify->portid)
-                       schedule_scan_stop = true;
+                   sched_scan_req->owner_nlportid == notify->portid) {
+                       sched_scan_req->owner_nlportid = 0;
+
+                       if (rdev->ops->sched_scan_stop &&
+                           rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+                               schedule_work(&rdev->sched_scan_stop_wk);
+               }
 
                list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
                        cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -14539,12 +14543,6 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
                                spin_unlock(&rdev->destroy_list_lock);
                                schedule_work(&rdev->destroy_work);
                        }
-               } else if (schedule_scan_stop) {
-                       sched_scan_req->owner_nlportid = 0;
-
-                       if (rdev->ops->sched_scan_stop &&
-                           rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
-                               schedule_work(&rdev->sched_scan_stop_wk);
                }
        }
 
index 09f7fe7e5fd74c289586711263d99bd9e25b1c2c..d8014065d479f9b85d96ae3d09664b1b14894467 100644 (file)
@@ -4,7 +4,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include <net/ethernet.h>
+#include <linux/if_ether.h>
 #include <net/if.h>
 #include <linux/if_packet.h>
 #include <arpa/inet.h>
index f4fa6af22def9fa9c01df1525c7a61b3aecb8cdd..ccca1e3480171501f01779ca88fc26305bff2491 100644 (file)
@@ -9,7 +9,6 @@
 #include <string.h>
 #include <fcntl.h>
 #include <poll.h>
-#include <sys/ioctl.h>
 #include <linux/perf_event.h>
 #include <linux/bpf.h>
 #include <errno.h>
index 1fc57a5093a7be425406cca55f4eb994e2eb979e..ca495686b9c31786d0df8c16407bd06d28ee1b40 100644 (file)
@@ -1073,7 +1073,7 @@ int mtty_get_region_info(struct mdev_device *mdev,
 {
        unsigned int size = 0;
        struct mdev_state *mdev_state;
-       int bar_index;
+       u32 bar_index;
 
        if (!mdev)
                return -EINVAL;
@@ -1082,8 +1082,11 @@ int mtty_get_region_info(struct mdev_device *mdev,
        if (!mdev_state)
                return -EINVAL;
 
-       mutex_lock(&mdev_state->ops_lock);
        bar_index = region_info->index;
+       if (bar_index >= VFIO_PCI_NUM_REGIONS)
+               return -EINVAL;
+
+       mutex_lock(&mdev_state->ops_lock);
 
        switch (bar_index) {
        case VFIO_PCI_CONFIG_REGION_INDEX:
@@ -1180,7 +1183,10 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
 
                memcpy(&mdev_state->dev_info, &info, sizeof(info));
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               if (copy_to_user((void __user *)arg, &info, minsz))
+                       return -EFAULT;
+
+               return 0;
        }
        case VFIO_DEVICE_GET_REGION_INFO:
        {
@@ -1201,7 +1207,10 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
                if (ret)
                        return ret;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               if (copy_to_user((void __user *)arg, &info, minsz))
+                       return -EFAULT;
+
+               return 0;
        }
 
        case VFIO_DEVICE_GET_IRQ_INFO:
@@ -1221,10 +1230,10 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
                if (ret)
                        return ret;
 
-               if (info.count == -1)
-                       return -EINVAL;
+               if (copy_to_user((void __user *)arg, &info, minsz))
+                       return -EFAULT;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return 0;
        }
        case VFIO_DEVICE_SET_IRQS:
        {
index 3820f00b066a73f6ab23e68b869a2f42e46c4e89..f1d6b14081ac68766bc60ea1c675952722c6962c 100755 (executable)
@@ -2,7 +2,7 @@
 
 """Find Kconfig symbols that are referenced but not defined."""
 
-# (c) 2014-2016 Valentin Rothberg <valentinrothberg@gmail.com>
+# (c) 2014-2017 Valentin Rothberg <valentinrothberg@gmail.com>
 # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
 #
 # Licensed under the terms of the GNU GPL License version 2
@@ -269,7 +269,7 @@ def find_sims(symbol, ignore, defined=[]):
     """Return a list of max. ten Kconfig symbols that are string-similar to
     @symbol."""
     if defined:
-        return sorted(difflib.get_close_matches(symbol, set(defined), 10))
+        return difflib.get_close_matches(symbol, set(defined), 10)
 
     pool = Pool(cpu_count(), init_worker)
     kfiles = []
@@ -284,7 +284,7 @@ def find_sims(symbol, ignore, defined=[]):
     for res in pool.map(parse_kconfig_files, arglist):
         defined.extend(res[0])
 
-    return sorted(difflib.get_close_matches(symbol, set(defined), 10))
+    return difflib.get_close_matches(symbol, set(defined), 10)
 
 
 def get_files():
index efe3a44658d5a5e6d3a82d5f23ed8f8afd190d5a..4576f987a4a5fec34a1bb780e0ba1ccb71dfeada 100644 (file)
@@ -561,9 +561,9 @@ static void nau8825_xtalk_prepare(struct nau8825 *nau8825)
        nau8825_xtalk_backup(nau8825);
        /* Config IIS as master to output signal by codec */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
-               NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK |
+               NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
                NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_MASTER |
-               (0x2 << NAU8825_I2S_DRV_SFT) | 0x1);
+               (0x2 << NAU8825_I2S_LRC_DIV_SFT) | 0x1);
        /* Ramp up headphone volume to 0dB to get better performance and
         * avoid pop noise in headphone.
         */
@@ -657,7 +657,7 @@ static void nau8825_xtalk_clean(struct nau8825 *nau8825)
                NAU8825_IRQ_RMS_EN, NAU8825_IRQ_RMS_EN);
        /* Recover default value for IIS */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
-               NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK |
+               NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
                NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE);
        /* Restore value of specific register for cross talk */
        nau8825_xtalk_restore(nau8825);
@@ -2006,7 +2006,8 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
                        NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
        /* FLL pre-scaler */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4,
-                       NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div);
+                       NAU8825_FLL_REF_DIV_MASK,
+                       fll_param->clk_ref_div << NAU8825_FLL_REF_DIV_SFT);
        /* select divided VCO input */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
                NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF);
index 5d1704e732415dd04134f44ddab9971156c97de1..514fd13c2f4624bb96b237422dfd63fae52adf17 100644 (file)
 #define NAU8825_FLL_CLK_SRC_FS                 (0x3 << NAU8825_FLL_CLK_SRC_SFT)
 
 /* FLL4 (0x07) */
-#define NAU8825_FLL_REF_DIV_MASK               (0x3 << 10)
+#define NAU8825_FLL_REF_DIV_SFT        10
+#define NAU8825_FLL_REF_DIV_MASK       (0x3 << NAU8825_FLL_REF_DIV_SFT)
 
 /* FLL5 (0x08) */
 #define NAU8825_FLL_PDB_DAC_EN         (0x1 << 15)
 
 /* I2S_PCM_CTRL2 (0x1d) */
 #define NAU8825_I2S_TRISTATE   (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
-#define NAU8825_I2S_DRV_SFT    12
-#define NAU8825_I2S_DRV_MASK   (0x3 << NAU8825_I2S_DRV_SFT)
+#define NAU8825_I2S_LRC_DIV_SFT        12
+#define NAU8825_I2S_LRC_DIV_MASK       (0x3 << NAU8825_I2S_LRC_DIV_SFT)
 #define NAU8825_I2S_MS_SFT     3
 #define NAU8825_I2S_MS_MASK    (1 << NAU8825_I2S_MS_SFT)
 #define NAU8825_I2S_MS_MASTER  (1 << NAU8825_I2S_MS_SFT)
index 10c2a564a715dc82e198a4bb50c5691662685c7a..1ac96ef9ee2077dc70ba940f939e8162ce1dec26 100644 (file)
@@ -3833,6 +3833,9 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
+               RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
+
        if (rt5645->pdata.jd_invert) {
                regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
                        RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
index 8877b74b0510fedefe81adc6637c9d72cf9c722f..bb94d50052d7a7233282b50afca134e4f2f7cf3f 100644 (file)
@@ -126,6 +126,16 @@ static const struct reg_default aic3x_reg[] = {
        { 108, 0x00 }, { 109, 0x00 },
 };
 
+static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AIC3X_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const struct regmap_config aic3x_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -133,6 +143,9 @@ static const struct regmap_config aic3x_regmap = {
        .max_register = DAC_ICC_ADJ,
        .reg_defaults = aic3x_reg,
        .num_reg_defaults = ARRAY_SIZE(aic3x_reg),
+
+       .volatile_reg = aic3x_volatile_reg,
+
        .cache_type = REGCACHE_RBTREE,
 };
 
index 593b7d1aed4695bbf6e538fa924bc6263901041f..d72ccef9e238d39807657597d1c8496022718bb5 100644 (file)
@@ -1551,7 +1551,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
        const struct wmfw_region *region;
        const struct wm_adsp_region *mem;
        const char *region_name;
-       char *file, *text;
+       char *file, *text = NULL;
        struct wm_adsp_buf *buf;
        unsigned int reg;
        int regions = 0;
@@ -1700,10 +1700,21 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                         regions, le32_to_cpu(region->len), offset,
                         region_name);
 
+               if ((pos + le32_to_cpu(region->len) + sizeof(*region)) >
+                   firmware->size) {
+                       adsp_err(dsp,
+                                "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+                                file, regions, region_name,
+                                le32_to_cpu(region->len), firmware->size);
+                       ret = -EINVAL;
+                       goto out_fw;
+               }
+
                if (text) {
                        memcpy(text, region->data, le32_to_cpu(region->len));
                        adsp_info(dsp, "%s: %s\n", file, text);
                        kfree(text);
+                       text = NULL;
                }
 
                if (reg) {
@@ -1748,6 +1759,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
        regmap_async_complete(regmap);
        wm_adsp_buf_free(&buf_list);
        release_firmware(firmware);
+       kfree(text);
 out:
        kfree(file);
 
@@ -2233,6 +2245,17 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                }
 
                if (reg) {
+                       if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) >
+                           firmware->size) {
+                               adsp_err(dsp,
+                                        "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+                                        file, blocks, region_name,
+                                        le32_to_cpu(blk->len),
+                                        firmware->size);
+                               ret = -EINVAL;
+                               goto out_fw;
+                       }
+
                        buf = wm_adsp_buf_alloc(blk->data,
                                                le32_to_cpu(blk->len),
                                                &buf_list);
index 2998954a1c7459e02c3397956e690a276120f06d..bdf8398cbc81b68b445f202636e8949db5e5cae5 100644 (file)
@@ -681,22 +681,19 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        if (!pdata) {
-               ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-               if (ret == -EPROBE_DEFER) {
-                       dev_err(&pdev->dev,
-                               "failed to register PCM, deferring probe\n");
-                       return ret;
-               } else if (ret) {
-                       dev_err(&pdev->dev,
-                               "Could not register DMA PCM: %d\n"
-                               "falling back to PIO mode\n", ret);
+               if (irq >= 0) {
                        ret = dw_pcm_register(pdev);
-                       if (ret) {
-                               dev_err(&pdev->dev,
-                                       "Could not register PIO PCM: %d\n",
+                       dev->use_pio = true;
+               } else {
+                       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+                                       0);
+                       dev->use_pio = false;
+               }
+
+               if (ret) {
+                       dev_err(&pdev->dev, "could not register pcm: %d\n",
                                        ret);
-                               goto err_clk_disable;
-                       }
+                       goto err_clk_disable;
                }
        }
 
index 50349437d9615107a3a08fa481b6b2d61612e51c..fde08660b63be270f95436424e32e443bdb8a0de 100644 (file)
@@ -224,6 +224,12 @@ struct fsl_ssi_soc_data {
  * @dbg_stats: Debugging statistics
  *
  * @soc: SoC specific data
+ *
+ * @fifo_watermark: the FIFO watermark setting.  Notifies DMA when
+ *             there are @fifo_watermark or fewer words in TX fifo or
+ *             @fifo_watermark or more empty words in RX fifo.
+ * @dma_maxburst: max number of words to transfer in one go.  So far,
+ *             this is always the same as fifo_watermark.
  */
 struct fsl_ssi_private {
        struct regmap *regs;
@@ -263,6 +269,9 @@ struct fsl_ssi_private {
 
        const struct fsl_ssi_soc_data *soc;
        struct device *dev;
+
+       u32 fifo_watermark;
+       u32 dma_maxburst;
 };
 
 /*
@@ -1051,21 +1060,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
        regmap_write(regs, CCSR_SSI_SRCR, srcr);
        regmap_write(regs, CCSR_SSI_SCR, scr);
 
-       /*
-        * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
-        * use FIFO 1. We program the transmit water to signal a DMA transfer
-        * if there are only two (or fewer) elements left in the FIFO. Two
-        * elements equals one frame (left channel, right channel). This value,
-        * however, depends on the depth of the transmit buffer.
-        *
-        * We set the watermark on the same level as the DMA burstsize.  For
-        * fiq it is probably better to use the biggest possible watermark
-        * size.
-        */
-       if (ssi_private->use_dma)
-               wm = ssi_private->fifo_depth - 2;
-       else
-               wm = ssi_private->fifo_depth;
+       wm = ssi_private->fifo_watermark;
 
        regmap_write(regs, CCSR_SSI_SFCSR,
                        CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
@@ -1373,12 +1368,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
                dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
                         PTR_ERR(ssi_private->baudclk));
 
-       /*
-        * We have burstsize be "fifo_depth - 2" to match the SSI
-        * watermark setting in fsl_ssi_startup().
-        */
-       ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2;
-       ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2;
+       ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst;
+       ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst;
        ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
        ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
 
@@ -1543,6 +1534,47 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                 /* Older 8610 DTs didn't have the fifo-depth property */
                ssi_private->fifo_depth = 8;
 
+       /*
+        * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't
+        * use FIFO 1 but set the watermark appropriately nontheless.
+        * We program the transmit water to signal a DMA transfer
+        * if there are N elements left in the FIFO. For chips with 15-deep
+        * FIFOs, set watermark to 8.  This allows the SSI to operate at a
+        * high data rate without channel slipping. Behavior is unchanged
+        * for the older chips with a fifo depth of only 8.  A value of 4
+        * might be appropriate for the older chips, but is left at
+        * fifo_depth-2 until sombody has a chance to test.
+        *
+        * We set the watermark on the same level as the DMA burstsize.  For
+        * fiq it is probably better to use the biggest possible watermark
+        * size.
+        */
+       switch (ssi_private->fifo_depth) {
+       case 15:
+               /*
+                * 2 samples is not enough when running at high data
+                * rates (like 48kHz @ 16 bits/channel, 16 channels)
+                * 8 seems to split things evenly and leave enough time
+                * for the DMA to fill the FIFO before it's over/under
+                * run.
+                */
+               ssi_private->fifo_watermark = 8;
+               ssi_private->dma_maxburst = 8;
+               break;
+       case 8:
+       default:
+               /*
+                * maintain old behavior for older chips.
+                * Keeping it the same because I don't have an older
+                * board to test with.
+                * I suspect this could be changed to be something to
+                * leave some more space in the fifo.
+                */
+               ssi_private->fifo_watermark = ssi_private->fifo_depth - 2;
+               ssi_private->dma_maxburst = ssi_private->fifo_depth - 2;
+               break;
+       }
+
        dev_set_drvdata(&pdev->dev, ssi_private);
 
        if (ssi_private->soc->imx) {
index 507a86a5eafe5646bb9731f865b85571eb6ffdfc..8d2fb2d6f532c833726e5dfbac2fe191eb95a15e 100644 (file)
@@ -142,7 +142,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
                 * for Jack detection and button press
                 */
                ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
-                                            0,
+                                            48000 * 512,
                                             SND_SOC_CLOCK_IN);
                if (!ret) {
                        if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
@@ -825,10 +825,20 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
        if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
                priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
                if (IS_ERR(priv->mclk)) {
+                       ret_val = PTR_ERR(priv->mclk);
+
                        dev_err(&pdev->dev,
-                               "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
-                               PTR_ERR(priv->mclk));
-                       return PTR_ERR(priv->mclk);
+                               "Failed to get MCLK from pmc_plt_clk_3: %d\n",
+                               ret_val);
+
+                       /*
+                        * Fall back to bit clock usage for -ENOENT (clock not
+                        * available likely due to missing dependencies), bail
+                        * for all other errors, including -EPROBE_DEFER
+                        */
+                       if (ret_val != -ENOENT)
+                               return ret_val;
+                       byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN;
                }
        }
 
index 84b5101e6ca691df0e0896b59a95e07a55e3b5e7..6c6b63a6b338f50f0eb218f231506f0017e56241 100644 (file)
@@ -180,6 +180,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        snd_pcm_set_sync(substream);
 
        mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       if (!mconfig)
+               return -EINVAL;
+
        skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
 
        return 0;
index 8fc3178bc79cf975809d7c808c0b03cb1d91f846..b30bd384c8d38338d50994e9a92673aba123824d 100644 (file)
@@ -515,6 +515,9 @@ EXPORT_SYMBOL_GPL(skl_sst_init_fw);
 
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
+
+       if (ctx->dsp->fw)
+               release_firmware(ctx->dsp->fw);
        skl_clear_module_table(ctx->dsp);
        skl_freeup_uuid_list(ctx);
        skl_ipc_free(&ctx->ipc);
index 4bd68de761309b57285bf203aa2ee46cabc440cc..99b5b0835c1e840c66e45676ff81cd57a4c1875c 100644 (file)
@@ -1030,10 +1030,8 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
                return -ENOMEM;
 
        ret = snd_ctl_add(card, kctrl);
-       if (ret < 0) {
-               snd_ctl_free_one(kctrl);
+       if (ret < 0)
                return ret;
-       }
 
        cfg->update = update;
        cfg->card = card;
index f1901bb1466ec67b12189713c66ad040f1ae75c7..baa1afa41e3dd57fdc36655b7d3bbd147ade820f 100644 (file)
@@ -1748,6 +1748,7 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 
        component->init = aux_dev->init;
        component->auxiliary = 1;
+       list_add(&component->card_aux_list, &card->aux_comp_list);
 
        return 0;
 
@@ -1758,16 +1759,14 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 
 static int soc_probe_aux_devices(struct snd_soc_card *card)
 {
-       struct snd_soc_component *comp;
+       struct snd_soc_component *comp, *tmp;
        int order;
        int ret;
 
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                order++) {
-               list_for_each_entry(comp, &card->component_dev_list, card_list) {
-                       if (!comp->auxiliary)
-                               continue;
-
+               list_for_each_entry_safe(comp, tmp, &card->aux_comp_list,
+                                        card_aux_list) {
                        if (comp->driver->probe_order == order) {
                                ret = soc_probe_component(card, comp);
                                if (ret < 0) {
@@ -1776,6 +1775,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card)
                                                comp->name, ret);
                                        return ret;
                                }
+                               list_del(&comp->card_aux_list);
                        }
                }
        }
index e7a1eaa2772f4418534d094e576b424a76aaa844..6aba14009c92abc853d72575ed447e934ed5e458 100644 (file)
@@ -2184,9 +2184,11 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
                break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+               break;
        }
 
 out:
index 65670b2b408cca0d4bffb2931cb7443cd4ba75b1..fbfb1fab88d5be60de7c40ed8fa1dd78d6fae727 100644 (file)
@@ -514,13 +514,12 @@ static void remove_widget(struct snd_soc_component *comp,
                            == SND_SOC_TPLG_TYPE_MIXER)
                                kfree(kcontrol->tlv.p);
 
-                       snd_ctl_remove(card, kcontrol);
-
                        /* Private value is used as struct soc_mixer_control
                         * for volume mixers or soc_bytes_ext for bytes
                         * controls.
                         */
                        kfree((void *)kcontrol->private_value);
+                       snd_ctl_remove(card, kcontrol);
                }
                kfree(w->kcontrol_news);
        }
index b3fd2382fdd9ed62f102e210489eadd17f4e3b8f..eb4b9f7a571e0f154fd7e00b81ef2c5ff7a17130 100644 (file)
@@ -1135,6 +1135,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */
        case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
        case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
+       case USB_ID(0x047F, 0x02F7): /* Plantronics BT-600 */
        case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */
        case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
index 3284bb14ae789bcb0513cba80e8ef0dd43e0812d..8aad81151d5068bacbc1e6d3c114248e9847bf84 100644 (file)
@@ -213,6 +213,9 @@ static int get_value(struct parse_opt_ctx_t *p,
                else
                        err = get_arg(p, opt, flags, (const char **)opt->value);
 
+               if (opt->set)
+                       *(bool *)opt->set = true;
+
                /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
                if (opt->flags & PARSE_OPT_NOEMPTY) {
                        const char *val = *(const char **)opt->value;
index 8866ac438b3441d9e82c739da41273e93466e48b..11c3be3bcce79598bd758d436270399f0f240842 100644 (file)
@@ -137,6 +137,11 @@ struct option {
        { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), \
          .value = check_vtype(v, const char **), (a), .help = (h), \
          .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
+#define OPT_STRING_OPTARG_SET(s, l, v, os, a, h, d) \
+       { .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
+         .value = check_vtype(v, const char **), (a), .help = (h), \
+         .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d), \
+         .set = check_vtype(os, bool *)}
 #define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
 #define OPT_DATE(s, l, v, h) \
        { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
index f1ce6006525886169fa239bfaa5cabffa33e3c9f..ec30c2fcbac05c2bef0268ac9494c0c5b4254a23 100644 (file)
@@ -111,7 +111,7 @@ static int sched_switch_handler(struct trace_seq *s,
        trace_seq_printf(s, "%lld ", val);
 
        if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
-               trace_seq_printf(s, "[%lld] ", val);
+               trace_seq_printf(s, "[%d] ", (int) val);
 
        if (pevent_get_field_val(s,  event, "prev_state", record, &val, 0) == 0)
                write_state(s, val);
@@ -129,7 +129,7 @@ static int sched_switch_handler(struct trace_seq *s,
        trace_seq_printf(s, "%lld", val);
 
        if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
-               trace_seq_printf(s, " [%lld]", val);
+               trace_seq_printf(s, " [%d]", (int) val);
 
        return 0;
 }
index 27fc3617c6a42066bf7a64bb2ace9961a350183b..5054d9147f0f03122f96338f96e9acd08cc36992 100644 (file)
@@ -430,6 +430,10 @@ that gets then processed, possibly via a perf script, to decide if that
 particular perf.data snapshot should be kept or not.
 
 Implies --timestamp-filename, --no-buildid and --no-buildid-cache.
+The reason for the latter two is to reduce the data file switching
+overhead. You can still switch them on with:
+
+  --switch-output --no-no-buildid  --no-no-buildid-cache
 
 --dry-run::
 Parse options then exit. --dry-run can be used to detect errors in cmdline
index 8fc24824705e0bfecd696bfc50a53ec4924cf9d7..8bb16aa9d661d0e5b8104adc0ef3d14a1fc296f9 100644 (file)
@@ -704,9 +704,9 @@ install-tests: all install-gtk
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
                $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
 
-install-bin: install-tools install-tests
+install-bin: install-tools install-tests install-traceevent-plugins
 
-install: install-bin try-install-man install-traceevent-plugins
+install: install-bin try-install-man
 
 install-python_ext:
        $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
index 35a02f8e5a4aa90548c643c0de80e85b07a0b3bb..915869e00d863af03ca409f0f9ffa98147c45385 100644 (file)
@@ -655,7 +655,6 @@ static const struct {
        { "__GFP_RECLAIM",              "R" },
        { "__GFP_DIRECT_RECLAIM",       "DR" },
        { "__GFP_KSWAPD_RECLAIM",       "KR" },
-       { "__GFP_OTHER_NODE",           "ON" },
 };
 
 static size_t max_gfp_len;
index 74d6a035133a96a7303287e130abe73af3fc4622..4ec10e9427d915a041e0510eaac2ded2daf9fc07 100644 (file)
@@ -1405,7 +1405,7 @@ static bool dry_run;
  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
  * using pipes, etc.
  */
-struct option __record_options[] = {
+static struct option __record_options[] = {
        OPT_CALLBACK('e', "event", &record.evlist, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events_option),
@@ -1636,7 +1636,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
                 * overhead. Still generate buildid if they are required
                 * explicitly using
                 *
-                *  perf record --signal-trigger --no-no-buildid \
+                *  perf record --switch-output --no-no-buildid \
                 *              --no-no-buildid-cache
                 *
                 * Following code equals to:
index d53e706a6f1706d2d69caa93132521f55d89d072..5b134b0d1ff37e42a1b82b5973528c4003bb80f3 100644 (file)
@@ -209,6 +209,7 @@ struct perf_sched {
        u64             skipped_samples;
        const char      *time_str;
        struct perf_time_interval ptime;
+       struct perf_time_interval hist_time;
 };
 
 /* per thread run time data */
@@ -2460,6 +2461,11 @@ static int timehist_sched_change_event(struct perf_tool *tool,
                timehist_print_sample(sched, sample, &al, thread, t);
 
 out:
+       if (sched->hist_time.start == 0 && t >= ptime->start)
+               sched->hist_time.start = t;
+       if (ptime->end == 0 || t <= ptime->end)
+               sched->hist_time.end = t;
+
        if (tr) {
                /* time of this sched_switch event becomes last time task seen */
                tr->last_time = sample->time;
@@ -2624,6 +2630,7 @@ static void timehist_print_summary(struct perf_sched *sched,
        struct thread *t;
        struct thread_runtime *r;
        int i;
+       u64 hist_time = sched->hist_time.end - sched->hist_time.start;
 
        memset(&totals, 0, sizeof(totals));
 
@@ -2665,7 +2672,7 @@ static void timehist_print_summary(struct perf_sched *sched,
                        totals.sched_count += r->run_stats.n;
                        printf("    CPU %2d idle for ", i);
                        print_sched_time(r->total_run_time, 6);
-                       printf(" msec\n");
+                       printf(" msec  (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time);
                } else
                        printf("    CPU %2d idle entire time window\n", i);
        }
@@ -2701,12 +2708,16 @@ static void timehist_print_summary(struct perf_sched *sched,
 
        printf("\n"
               "    Total number of unique tasks: %" PRIu64 "\n"
-              "Total number of context switches: %" PRIu64 "\n"
-              "           Total run time (msec): ",
+              "Total number of context switches: %" PRIu64 "\n",
               totals.task_count, totals.sched_count);
 
+       printf("           Total run time (msec): ");
        print_sched_time(totals.total_run_time, 2);
        printf("\n");
+
+       printf("    Total scheduling time (msec): ");
+       print_sched_time(hist_time, 2);
+       printf(" (x %d)\n", sched->max_cpu);
 }
 
 typedef int (*sched_handler)(struct perf_tool *tool,
index d281ae2b54e8fef7b85574a8b799dc33c21e9e44..4a57c8a60bd91990fad493b9a16e265831cb88a5 100644 (file)
@@ -163,7 +163,7 @@ static struct map *kernel_get_module_map(const char *module)
 
        /* A file path -- this is an offline module */
        if (module && strchr(module, '/'))
-               return machine__findnew_module_map(host_machine, 0, module);
+               return dso__new_map(module);
 
        if (!module)
                module = "kernel";
@@ -173,6 +173,7 @@ static struct map *kernel_get_module_map(const char *module)
                if (strncmp(pos->dso->short_name + 1, module,
                            pos->dso->short_name_len - 2) == 0 &&
                    module[pos->dso->short_name_len - 2] == '\0') {
+                       map__get(pos);
                        return pos;
                }
        }
@@ -188,15 +189,6 @@ struct map *get_target_map(const char *target, bool user)
                return kernel_get_module_map(target);
 }
 
-static void put_target_map(struct map *map, bool user)
-{
-       if (map && user) {
-               /* Only the user map needs to be released */
-               map__put(map);
-       }
-}
-
-
 static int convert_exec_to_group(const char *exec, char **result)
 {
        char *ptr1, *ptr2, *exec_copy;
@@ -267,21 +259,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
        return true;
 }
 
-/*
- * NOTE:
- * '.gnu.linkonce.this_module' section of kernel module elf directly
- * maps to 'struct module' from linux/module.h. This section contains
- * actual module name which will be used by kernel after loading it.
- * But, we cannot use 'struct module' here since linux/module.h is not
- * exposed to user-space. Offset of 'name' has remained same from long
- * time, so hardcoding it here.
- */
-#ifdef __LP64__
-#define MOD_NAME_OFFSET 24
-#else
-#define MOD_NAME_OFFSET 12
-#endif
-
 /*
  * @module can be module name of module file path. In case of path,
  * inspect elf and find out what is actual module name.
@@ -296,6 +273,7 @@ static char *find_module_name(const char *module)
        Elf_Data *data;
        Elf_Scn *sec;
        char *mod_name = NULL;
+       int name_offset;
 
        fd = open(module, O_RDONLY);
        if (fd < 0)
@@ -317,7 +295,21 @@ static char *find_module_name(const char *module)
        if (!data || !data->d_buf)
                goto ret_err;
 
-       mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
+       /*
+        * NOTE:
+        * '.gnu.linkonce.this_module' section of kernel module elf directly
+        * maps to 'struct module' from linux/module.h. This section contains
+        * actual module name which will be used by kernel after loading it.
+        * But, we cannot use 'struct module' here since linux/module.h is not
+        * exposed to user-space. Offset of 'name' has remained same from long
+        * time, so hardcoding it here.
+        */
+       if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+               name_offset = 12;
+       else    /* expect ELFCLASS64 by default */
+               name_offset = 24;
+
+       mod_name = strdup((char *)data->d_buf + name_offset);
 
 ret_err:
        elf_end(elf);
@@ -412,7 +404,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
        }
 
 out:
-       put_target_map(map, uprobes);
+       map__put(map);
        return ret;
 
 }
@@ -618,6 +610,51 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
        return ret ? : -ENOENT;
 }
 
+/*
+ * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
+ * and generate new symbols with suffixes such as .constprop.N or .isra.N
+ * etc. Since those symbols are not recorded in DWARF, we have to find
+ * correct generated symbols from offline ELF binary.
+ * For online kernel or uprobes we don't need this because those are
+ * rebased on _text, or already a section relative address.
+ */
+static int
+post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
+                                       int ntevs, const char *pathname)
+{
+       struct symbol *sym;
+       struct map *map;
+       unsigned long stext = 0;
+       u64 addr;
+       int i;
+
+       /* Prepare a map for offline binary */
+       map = dso__new_map(pathname);
+       if (!map || get_text_start_address(pathname, &stext) < 0) {
+               pr_warning("Failed to get ELF symbols for %s\n", pathname);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ntevs; i++) {
+               addr = tevs[i].point.address + tevs[i].point.offset - stext;
+               sym = map__find_symbol(map, addr);
+               if (!sym)
+                       continue;
+               if (!strcmp(sym->name, tevs[i].point.symbol))
+                       continue;
+               /* If we have no realname, use symbol for it */
+               if (!tevs[i].point.realname)
+                       tevs[i].point.realname = tevs[i].point.symbol;
+               else
+                       free(tevs[i].point.symbol);
+               tevs[i].point.symbol = strdup(sym->name);
+               tevs[i].point.offset = addr - sym->start;
+       }
+       map__put(map);
+
+       return 0;
+}
+
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
                                          int ntevs, const char *exec)
 {
@@ -679,7 +716,8 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
 
        /* Skip post process if the target is an offline kernel */
        if (symbol_conf.ignore_vmlinux_buildid)
-               return 0;
+               return post_process_offline_probe_trace_events(tevs, ntevs,
+                                               symbol_conf.vmlinux_name);
 
        reloc_sym = kernel_get_ref_reloc_sym();
        if (!reloc_sym) {
@@ -2869,7 +2907,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
        }
 
 out:
-       put_target_map(map, pev->uprobes);
+       map__put(map);
        free(syms);
        return ret;
 
@@ -3362,10 +3400,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
                return ret;
 
        /* Get a symbol map */
-       if (user)
-               map = dso__new_map(target);
-       else
-               map = kernel_get_module_map(target);
+       map = get_target_map(target, user);
        if (!map) {
                pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
                return -EINVAL;
@@ -3397,9 +3432,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
         }
 
 end:
-       if (user) {
-               map__put(map);
-       }
+       map__put(map);
        exit_probe_symbol_maps();
 
        return ret;
index 99400b0e8f2a892dcfbfe2572758ef3eae73be59..adbc6c02c3aaac757028e6bbe1ae63cd11ee437a 100644 (file)
@@ -537,6 +537,12 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
                                break;
                } else {
                        int n = namesz + descsz;
+
+                       if (n > (int)sizeof(bf)) {
+                               n = sizeof(bf);
+                               pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n",
+                                        __func__, filename, nhdr.n_namesz, nhdr.n_descsz);
+                       }
                        if (read(fd, bf, n) != n)
                                break;
                }
index 71b05891a6a14adfe7537e70333352b844966134..831022b12848de68695065040b38bd7ec55f7577 100644 (file)
@@ -90,7 +90,7 @@ ifdef INSTALL_PATH
        done;
 
        @# Ask all targets to emit their test scripts
-       echo "#!/bin/bash" > $(ALL_SCRIPT)
+       echo "#!/bin/sh" > $(ALL_SCRIPT)
        echo "cd \$$(dirname \$$0)" >> $(ALL_SCRIPT)
        echo "ROOT=\$$PWD" >> $(ALL_SCRIPT)
 
index 92e627adf3540f5c79ca4a2d372f81c74fa3bf8b..6d58cca8e23574a1fe15993d1da8f1558ecf8e06 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 SRC_TREE=../../../../
 
index c09a682df56ae9fb3cc91214ae9d79da19714633..16058bbea7a8501324ce6c9c639f5219d69979ba 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 echo "--------------------"
 echo "running socket test"
index bdd58c78902e96948f92475f4898de1ec0c14a57..df9e0a0cdf294e1e334c6558c9c4f87a38387e1d 100644 (file)
@@ -1367,7 +1367,7 @@ void run_tests_once(void)
                tracing_off();
                close_test_fds();
 
-               printf("test %2d PASSED (itertation %d)\n", test_nr, iteration_nr);
+               printf("test %2d PASSED (iteration %d)\n", test_nr, iteration_nr);
                dprintf1("======================\n\n");
        }
        iteration_nr++;
index 52abac4bb6a2532ad55f4ec690530a6a7b593df0..6d2fcd6fcb2509e801c84b88e6c18e3e7a1d1fa0 100644 (file)
@@ -195,7 +195,7 @@ int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer)
        mutex_lock(&lock);
 
        list_for_each_entry(tmp, &consumers, node) {
-               if (tmp->token == consumer->token) {
+               if (tmp->token == consumer->token || tmp == consumer) {
                        mutex_unlock(&lock);
                        module_put(THIS_MODULE);
                        return -EBUSY;
@@ -245,7 +245,7 @@ void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer)
        mutex_lock(&lock);
 
        list_for_each_entry(tmp, &consumers, node) {
-               if (tmp->token != consumer->token)
+               if (tmp != consumer)
                        continue;
 
                list_for_each_entry(producer, &producers, node) {