Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 11 Nov 2018 22:41:50 +0000 (16:41 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 11 Nov 2018 22:41:50 +0000 (16:41 -0600)
Pull x86 fixes from Thomas Gleixner:
 "A set of x86 fixes:

   - Cure the LDT remapping to user space on 5 level paging which ended
     up in the KASLR space

   - Remove LDT mapping before freeing the LDT pages

   - Make NFIT MCE handling more robust

   - Unbreak the VSMP build by removing the dependency on paravirt ops

   - Support broken PIT emulation on Microsoft hyperV

   - Don't trace vmware_sched_clock() to avoid tracer recursion

   - Remove -pipe from KBUILD CFLAGS which breaks clang and is also
     slower on GCC

   - Trivial coding style and typo fixes"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/cpu/vmware: Do not trace vmware_sched_clock()
  x86/vsmp: Remove dependency on pv_irq_ops
  x86/ldt: Remove unused variable in map_ldt_struct()
  x86/ldt: Unmap PTEs for the slot before freeing LDT pages
  x86/mm: Move LDT remap out of KASLR region on 5-level paging
  acpi/nfit, x86/mce: Validate a MCE's address before using it
  acpi/nfit, x86/mce: Handle only uncorrectable machine checks
  x86/build: Remove -pipe from KBUILD_CFLAGS
  x86/hyper-v: Fix indentation in hv_do_fast_hypercall16()
  Documentation/x86: Fix typo in zero-page.txt
  x86/hyper-v: Enable PIT shutdown quirk
  clockevents/drivers/i8253: Add support for PIT shutdown quirk

294 files changed:
.mailmap
Documentation/ABI/testing/sysfs-class-led-trigger-pattern
Documentation/devicetree/bindings/arm/shmobile.txt
Documentation/devicetree/bindings/i2c/i2c-omap.txt
Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/timer/csky,mptimer.txt [new file with mode: 0644]
Documentation/filesystems/ubifs-authentication.md [new file with mode: 0644]
Documentation/filesystems/ubifs.txt
Documentation/i2c/busses/i2c-nvidia-gpu [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/include/asm/termios.h
arch/alpha/include/uapi/asm/ioctls.h
arch/alpha/include/uapi/asm/termbits.h
arch/arm/boot/dts/imx53-ppd.dts
arch/arm/boot/dts/imx6sll.dtsi
arch/arm/boot/dts/imx6sx-sdb.dtsi
arch/arm/boot/dts/vf610m4-colibri.dts
arch/arm/configs/multi_v7_defconfig
arch/arm/include/asm/pgtable-2level.h
arch/arm/mm/proc-v7.S
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
arch/arm64/boot/dts/renesas/r8a7795.dtsi
arch/arm64/boot/dts/renesas/r8a77980-condor.dts
arch/arm64/include/asm/processor.h
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/m68k/include/asm/pgtable_mm.h
arch/microblaze/include/asm/pgtable.h
arch/mips/cavium-octeon/executive/cvmx-helper.c
arch/mips/mm/dma-noncoherent.c
arch/nds32/include/asm/pgtable.h
arch/parisc/include/asm/pgtable.h
arch/s390/Makefile
arch/s390/boot/compressed/Makefile
arch/s390/configs/debug_defconfig
arch/s390/configs/performance_defconfig
arch/s390/defconfig
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/tlb.h
arch/s390/kernel/entry.S
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/vdso32/Makefile
arch/s390/kernel/vdso64/Makefile
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/pgalloc.c
arch/s390/numa/numa.c
arch/um/drivers/ubd_kern.c
arch/x86/include/asm/qspinlock.h
arch/x86/include/asm/xen/page.h
arch/x86/xen/p2m.c
arch/x86/xen/spinlock.c
block/bio.c
block/blk-lib.c
block/blk-merge.c
block/blk.h
drivers/ata/sata_rcar.c
drivers/block/xen-blkfront.c
drivers/clk/clk-fixed-factor.c
drivers/clk/meson/axg.c
drivers/clk/meson/gxbb.c
drivers/clk/qcom/gcc-qcs404.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/timer-gx6605s.c [new file with mode: 0644]
drivers/clocksource/timer-mp-csky.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/include/atomfirmware.h
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h
drivers/gpu/drm/etnaviv/etnaviv_sched.c
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/gvt/gtt.h
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/mmio_context.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_cdclk.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_lpe_audio.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/selftests/huge_pages.c
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/sun4i/sun4i_lvds.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/vga/vga_switcheroo.c
drivers/hid/hid-alps.c
drivers/hid/hid-asus.c
drivers/hid/hid-ids.h
drivers/hid/hid-quirks.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmpowernv.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-nvidia-gpu.c [new file with mode: 0644]
drivers/i2c/busses/i2c-qcom-geni.c
drivers/leds/trigger/ledtrig-pattern.c
drivers/mtd/devices/Kconfig
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/build.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/ethernet/atheros/alx/alx.h
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ntb_netdev.c
drivers/net/phy/realtek.c
drivers/net/usb/smsc95xx.c
drivers/ntb/hw/idt/Kconfig
drivers/ntb/hw/idt/ntb_hw_idt.c
drivers/ntb/hw/idt/ntb_hw_idt.h
drivers/ntb/hw/intel/ntb_hw_gen1.c
drivers/ntb/ntb_transport.c
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/target/core.c
drivers/nvme/target/rdma.c
drivers/of/device.c
drivers/of/of_numa.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/tty/serial/sh-sci.c
drivers/tty/tty_baudrate.c
drivers/tty/vt/vt.c
drivers/usb/typec/ucsi/Kconfig
drivers/usb/typec/ucsi/Makefile
drivers/usb/typec/ucsi/ucsi_ccg.c [new file with mode: 0644]
drivers/xen/grant-table.c
drivers/xen/privcmd-buf.c
fs/ceph/file.c
fs/ceph/mds_client.c
fs/ceph/quota.c
fs/namespace.c
fs/nfs/nfs4proc.c
fs/ubifs/Kconfig
fs/ubifs/Makefile
fs/ubifs/auth.c [new file with mode: 0644]
fs/ubifs/debug.c
fs/ubifs/gc.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/log.c
fs/ubifs/lpt.c
fs/ubifs/lpt_commit.c
fs/ubifs/master.c
fs/ubifs/misc.h
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_commit.c
fs/ubifs/tnc_misc.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_message.c
include/asm-generic/4level-fixup.h
include/asm-generic/5level-fixup.h
include/asm-generic/pgtable-nop4d-hack.h
include/asm-generic/pgtable-nop4d.h
include/asm-generic/pgtable-nopmd.h
include/asm-generic/pgtable-nopud.h
include/asm-generic/pgtable.h
include/linux/ceph/ceph_features.h
include/linux/compiler-gcc.h
include/linux/compiler.h
include/linux/compiler_attributes.h
include/linux/compiler_types.h
include/linux/cpuhotplug.h
include/linux/hid.h
include/linux/mm.h
include/linux/mtd/nand.h
include/linux/netdevice.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/ipset/ip_set_comment.h
include/linux/nmi.h
include/linux/sunrpc/gss_krb5.h
include/net/addrconf.h
include/net/if_inet6.h
include/net/netfilter/nf_conntrack_l4proto.h
include/uapi/linux/kfd_ioctl.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/netfilter_bridge.h
include/uapi/linux/sctp.h
include/xen/xen-ops.h
kernel/bpf/core.c
kernel/bpf/syscall.c
kernel/resource.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/time/posix-cpu-timers.c
kernel/trace/trace_probe.c
kernel/user_namespace.c
lib/raid6/test/Makefile
net/core/dev.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/ip_fragment.c
net/ipv4/ip_sockglue.c
net/ipv6/af_inet6.c
net/ipv6/anycast.c
net/ipv6/ip6_fib.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_netportnet.c
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_generic.c
net/netfilter/nf_conntrack_proto_icmp.c
net/netfilter/nf_conntrack_proto_icmpv6.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nfnetlink_cttimeout.c
net/netfilter/nft_compat.c
net/netfilter/nft_numgen.c
net/netfilter/nft_osf.c
net/netfilter/xt_IDLETIMER.c
net/openvswitch/conntrack.c
net/rxrpc/ar-internal.h
net/rxrpc/call_event.c
net/rxrpc/output.c
net/sctp/outqueue.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_krb5_seal.c
net/sunrpc/auth_gss/gss_krb5_wrap.c
sound/pci/hda/thinkpad_helper.c
tools/arch/arm64/include/asm/barrier.h
tools/perf/Documentation/perf-list.txt
tools/perf/Makefile.perf
tools/perf/builtin-record.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/examples/bpf/augmented_raw_syscalls.c [new file with mode: 0644]
tools/perf/jvmti/jvmti_agent.c
tools/perf/scripts/python/exported-sql-viewer.py
tools/perf/tests/attr/test-record-group-sampling
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
tools/perf/util/intel-pt-decoder/intel-pt-log.c
tools/perf/util/intel-pt-decoder/intel-pt-log.h
tools/perf/util/intel-pt.c
tools/perf/util/pmu.c

index a76be45..28fecaf 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -159,6 +159,7 @@ Peter Oruba <peter@oruba.de>
 Peter Oruba <peter.oruba@amd.com>
 Pratyush Anand <pratyush.anand@gmail.com> <pratyush.anand@st.com>
 Praveen BP <praveenbp@ti.com>
+Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com>
 Qais Yousef <qsyousef@gmail.com> <qais.yousef@imgtec.com>
 Oleksij Rempel <linux@rempel-privat.de> <bug-track@fisher-privat.net>
 Oleksij Rempel <linux@rempel-privat.de> <external.Oleksij.Rempel@de.bosch.com>
index fb3d1e0..1e5d172 100644 (file)
@@ -37,8 +37,8 @@ Description:
                  0-|   /             \/             \/
                    +---0----1----2----3----4----5----6------------> time (s)
 
-               2. To make the LED go instantly from one brigntess value to another,
-               we should use use zero-time lengths (the brightness must be same as
+               2. To make the LED go instantly from one brightness value to another,
+               we should use zero-time lengths (the brightness must be same as
                the previous tuple's). So the format should be:
                "brightness_1 duration_1 brightness_1 0 brightness_2 duration_2
                brightness_2 0 ...". For example:
index f5e0f82..58c4256 100644 (file)
@@ -27,7 +27,7 @@ SoCs:
     compatible = "renesas,r8a77470"
   - RZ/G2M (R8A774A1)
     compatible = "renesas,r8a774a1"
-  - RZ/G2E (RA8774C0)
+  - RZ/G2E (R8A774C0)
     compatible = "renesas,r8a774c0"
   - R-Car M1A (R8A77781)
     compatible = "renesas,r8a7778"
index 7e49839..4b90ba9 100644 (file)
@@ -1,8 +1,12 @@
 I2C for OMAP platforms
 
 Required properties :
-- compatible : Must be "ti,omap2420-i2c", "ti,omap2430-i2c", "ti,omap3-i2c"
-  or "ti,omap4-i2c"
+- compatible : Must be
+       "ti,omap2420-i2c" for OMAP2420 SoCs
+       "ti,omap2430-i2c" for OMAP2430 SoCs
+       "ti,omap3-i2c" for OMAP3 SoCs
+       "ti,omap4-i2c" for OMAP4+ SoCs
+       "ti,am654-i2c", "ti,omap4-i2c" for AM654 SoCs
 - ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
 - #address-cells = <1>;
 - #size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt b/Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt
new file mode 100644 (file)
index 0000000..6b04344
--- /dev/null
@@ -0,0 +1,42 @@
+=================
+gx6605s SOC Timer
+=================
+
+The timer is used in gx6605s soc as system timer and the driver
+contain clk event and clk source.
+
+==============================
+timer node bindings definition
+==============================
+
+       Description: Describes gx6605s SOC timer
+
+       PROPERTIES
+
+       - compatible
+               Usage: required
+               Value type: <string>
+               Definition: must be "csky,gx6605s-timer"
+       - reg
+               Usage: required
+               Value type: <u32 u32>
+               Definition: <phyaddr size> in soc from cpu view
+       - clocks
+               Usage: required
+               Value type: phandle + clock specifier cells
+               Definition: must be input clk node
+       - interrupt
+               Usage: required
+               Value type: <u32>
+               Definition: must be timer irq num defined by soc
+
+Examples:
+---------
+
+       timer0: timer@20a000 {
+               compatible = "csky,gx6605s-timer";
+               reg = <0x0020a000 0x400>;
+               clocks = <&dummy_apb_clk>;
+               interrupts = <10>;
+               interrupt-parent = <&intc>;
+       };
diff --git a/Documentation/devicetree/bindings/timer/csky,mptimer.txt b/Documentation/devicetree/bindings/timer/csky,mptimer.txt
new file mode 100644 (file)
index 0000000..15cfec0
--- /dev/null
@@ -0,0 +1,42 @@
+============================
+C-SKY Multi-processors Timer
+============================
+
+C-SKY multi-processors timer is designed for C-SKY SMP system and the
+regs is accessed by cpu co-processor 4 registers with mtcr/mfcr.
+
+ - PTIM_CTLR "cr<0, 14>" Control reg to start reset timer.
+ - PTIM_TSR  "cr<1, 14>" Interrupt cleanup status reg.
+ - PTIM_CCVR "cr<3, 14>" Current counter value reg.
+ - PTIM_LVR  "cr<6, 14>" Window value reg to triger next event.
+
+==============================
+timer node bindings definition
+==============================
+
+       Description: Describes SMP timer
+
+       PROPERTIES
+
+       - compatible
+               Usage: required
+               Value type: <string>
+               Definition: must be "csky,mptimer"
+       - clocks
+               Usage: required
+               Value type: <node>
+               Definition: must be input clk node
+       - interrupts
+               Usage: required
+               Value type: <u32>
+               Definition: must be timer irq num defined by soc
+
+Examples:
+---------
+
+       timer: timer {
+               compatible = "csky,mptimer";
+               clocks = <&dummy_apb_clk>;
+               interrupts = <16>;
+               interrupt-parent = <&intc>;
+       };
diff --git a/Documentation/filesystems/ubifs-authentication.md b/Documentation/filesystems/ubifs-authentication.md
new file mode 100644 (file)
index 0000000..028b3e2
--- /dev/null
@@ -0,0 +1,426 @@
+% UBIFS Authentication
+% sigma star gmbh
+% 2018
+
+# Introduction
+
+UBIFS utilizes the fscrypt framework to provide confidentiality for file
+contents and file names. This prevents attacks where an attacker is able to
+read contents of the filesystem on a single point in time. A classic example
+is a lost smartphone where the attacker is unable to read personal data stored
+on the device without the filesystem decryption key.
+
+At the current state, UBIFS encryption however does not prevent attacks where
+the attacker is able to modify the filesystem contents and the user uses the
+device afterwards. In such a scenario an attacker can modify filesystem
+contents arbitrarily without the user noticing. One example is to modify a
+binary to perform a malicious action when executed [DMC-CBC-ATTACK]. Since
+most of the filesystem metadata of UBIFS is stored in plain, this makes it
+fairly easy to swap files and replace their contents.
+
+Other full disk encryption systems like dm-crypt cover all filesystem metadata,
+which makes such kinds of attacks more complicated, but not impossible.
+Especially, if the attacker is given access to the device multiple points in
+time. For dm-crypt and other filesystems that build upon the Linux block IO
+layer, the dm-integrity or dm-verity subsystems [DM-INTEGRITY, DM-VERITY]
+can be used to get full data authentication at the block layer.
+These can also be combined with dm-crypt [CRYPTSETUP2].
+
+This document describes an approach to get file contents _and_ full metadata
+authentication for UBIFS. Since UBIFS uses fscrypt for file contents and file
+name encryption, the authentication system could be tied into fscrypt such that
+existing features like key derivation can be utilized. It should however also
+be possible to use UBIFS authentication without using encryption.
+
+
+## MTD, UBI & UBIFS
+
+On Linux, the MTD (Memory Technology Devices) subsystem provides a uniform
+interface to access raw flash devices. One of the more prominent subsystems that
+work on top of MTD is UBI (Unsorted Block Images). It provides volume management
+for flash devices and is thus somewhat similar to LVM for block devices. In
+addition, it deals with flash-specific wear-leveling and transparent I/O error
+handling. UBI offers logical erase blocks (LEBs) to the layers on top of it
+and maps them transparently to physical erase blocks (PEBs) on the flash.
+
+UBIFS is a filesystem for raw flash which operates on top of UBI. Thus, wear
+leveling and some flash specifics are left to UBI, while UBIFS focuses on
+scalability, performance and recoverability.
+
+
+
+       +------------+ +*******+ +-----------+ +-----+
+       |            | * UBIFS * | UBI-BLOCK | | ... |
+       | JFFS/JFFS2 | +*******+ +-----------+ +-----+
+       |            | +-----------------------------+ +-----------+ +-----+
+       |            | |              UBI            | | MTD-BLOCK | | ... |
+       +------------+ +-----------------------------+ +-----------+ +-----+
+       +------------------------------------------------------------------+
+       |                  MEMORY TECHNOLOGY DEVICES (MTD)                 |
+       +------------------------------------------------------------------+
+       +-----------------------------+ +--------------------------+ +-----+
+       |         NAND DRIVERS        | |        NOR DRIVERS       | | ... |
+       +-----------------------------+ +--------------------------+ +-----+
+
+            Figure 1: Linux kernel subsystems for dealing with raw flash
+
+
+
+Internally, UBIFS maintains multiple data structures which are persisted on
+the flash:
+
+- *Index*: an on-flash B+ tree where the leaf nodes contain filesystem data
+- *Journal*: an additional data structure to collect FS changes before updating
+  the on-flash index and reduce flash wear.
+- *Tree Node Cache (TNC)*: an in-memory B+ tree that reflects the current FS
+  state to avoid frequent flash reads. It is basically the in-memory
+  representation of the index, but contains additional attributes.
+- *LEB property tree (LPT)*: an on-flash B+ tree for free space accounting per
+  UBI LEB.
+
+In the remainder of this section we will cover the on-flash UBIFS data
+structures in more detail. The TNC is of less importance here since it is never
+persisted onto the flash directly. More details on UBIFS can also be found in
+[UBIFS-WP].
+
+
+### UBIFS Index & Tree Node Cache
+
+Basic on-flash UBIFS entities are called *nodes*. UBIFS knows different types
+of nodes. Eg. data nodes (`struct ubifs_data_node`) which store chunks of file
+contents or inode nodes (`struct ubifs_ino_node`) which represent VFS inodes.
+Almost all types of nodes share a common header (`ubifs_ch`) containing basic
+information like node type, node length, a sequence number, etc. (see
+`fs/ubifs/ubifs-media.h`in kernel source). Exceptions are entries of the LPT
+and some less important node types like padding nodes which are used to pad
+unusable content at the end of LEBs.
+
+To avoid re-writing the whole B+ tree on every single change, it is implemented
+as *wandering tree*, where only the changed nodes are re-written and previous
+versions of them are obsoleted without erasing them right away. As a result,
+the index is not stored in a single place on the flash, but *wanders* around
+and there are obsolete parts on the flash as long as the LEB containing them is
+not reused by UBIFS. To find the most recent version of the index, UBIFS stores
+a special node called *master node* into UBI LEB 1 which always points to the
+most recent root node of the UBIFS index. For recoverability, the master node
+is additionally duplicated to LEB 2. Mounting UBIFS is thus a simple read of
+LEB 1 and 2 to get the current master node and from there get the location of
+the most recent on-flash index.
+
+The TNC is the in-memory representation of the on-flash index. It contains some
+additional runtime attributes per node which are not persisted. One of these is
+a dirty-flag which marks nodes that have to be persisted the next time the
+index is written onto the flash. The TNC acts as a write-back cache and all
+modifications of the on-flash index are done through the TNC. Like other caches,
+the TNC does not have to mirror the full index into memory, but reads parts of
+it from flash whenever needed. A *commit* is the UBIFS operation of updating the
+on-flash filesystem structures like the index. On every commit, the TNC nodes
+marked as dirty are written to the flash to update the persisted index.
+
+
+### Journal
+
+To avoid wearing out the flash, the index is only persisted (*commited*) when
+certain conditions are met (eg. `fsync(2)`). The journal is used to record
+any changes (in form of inode nodes, data nodes etc.) between commits
+of the index. During mount, the journal is read from the flash and replayed
+onto the TNC (which will be created on-demand from the on-flash index).
+
+UBIFS reserves a bunch of LEBs just for the journal called *log area*. The
+amount of log area LEBs is configured on filesystem creation (using
+`mkfs.ubifs`) and stored in the superblock node. The log area contains only
+two types of nodes: *reference nodes* and *commit start nodes*. A commit start
+node is written whenever an index commit is performed. Reference nodes are
+written on every journal update. Each reference node points to the position of
+other nodes (inode nodes, data nodes etc.) on the flash that are part of this
+journal entry. These nodes are called *buds* and describe the actual filesystem
+changes including their data.
+
+The log area is maintained as a ring. Whenever the journal is almost full,
+a commit is initiated. This also writes a commit start node so that during
+mount, UBIFS will seek for the most recent commit start node and just replay
+every reference node after that. Every reference node before the commit start
+node will be ignored as they are already part of the on-flash index.
+
+When writing a journal entry, UBIFS first ensures that enough space is
+available to write the reference node and buds part of this entry. Then, the
+reference node is written and afterwards the buds describing the file changes.
+On replay, UBIFS will record every reference node and inspect the location of
+the referenced LEBs to discover the buds. If these are corrupt or missing,
+UBIFS will attempt to recover them by re-reading the LEB. This is however only
+done for the last referenced LEB of the journal. Only this can become corrupt
+because of a power cut. If the recovery fails, UBIFS will not mount. An error
+for every other LEB will directly cause UBIFS to fail the mount operation.
+
+
+       | ----    LOG AREA     ---- | ----------    MAIN AREA    ------------ |
+
+        -----+------+-----+--------+----   ------+-----+-----+---------------
+        \    |      |     |        |   /  /      |     |     |               \
+        / CS |  REF | REF |        |   \  \ DENT | INO | INO |               /
+        \    |      |     |        |   /  /      |     |     |               \
+         ----+------+-----+--------+---   -------+-----+-----+----------------
+                 |     |                  ^            ^
+                 |     |                  |            |
+                 +------------------------+            |
+                       |                               |
+                       +-------------------------------+
+
+
+                Figure 2: UBIFS flash layout of log area with commit start nodes
+                          (CS) and reference nodes (REF) pointing to main area
+                          containing their buds
+
+
+### LEB Property Tree/Table
+
+The LEB property tree is used to store per-LEB information. This includes the
+LEB type and amount of free and *dirty* (old, obsolete content) space [1] on
+the LEB. The type is important, because UBIFS never mixes index nodes with data
+nodes on a single LEB and thus each LEB has a specific purpose. This again is
+useful for free space calculations. See [UBIFS-WP] for more details.
+
+The LEB property tree again is a B+ tree, but it is much smaller than the
+index. Due to its smaller size it is always written as one chunk on every
+commit. Thus, saving the LPT is an atomic operation.
+
+
+[1] Since LEBs can only be appended and never overwritten, there is a
+difference between free space ie. the remaining space left on the LEB to be
+written to without erasing it and previously written content that is obsolete
+but can't be overwritten without erasing the full LEB.
+
+
+# UBIFS Authentication
+
+This chapter introduces UBIFS authentication which enables UBIFS to verify
+the authenticity and integrity of metadata and file contents stored on flash.
+
+
+## Threat Model
+
+UBIFS authentication enables detection of offline data modification. While it
+does not prevent it, it enables (trusted) code to check the integrity and
+authenticity of on-flash file contents and filesystem metadata. This covers
+attacks where file contents are swapped.
+
+UBIFS authentication will not protect against rollback of full flash contents.
+Ie. an attacker can still dump the flash and restore it at a later time without
+detection. It will also not protect against partial rollback of individual
+index commits. That means that an attacker is able to partially undo changes.
+This is possible because UBIFS does not immediately overwrites obsolete
+versions of the index tree or the journal, but instead marks them as obsolete
+and garbage collection erases them at a later time. An attacker can use this by
+erasing parts of the current tree and restoring old versions that are still on
+the flash and have not yet been erased. This is possible, because every commit
+will always write a new version of the index root node and the master node
+without overwriting the previous version. This is further helped by the
+wear-leveling operations of UBI which copies contents from one physical
+eraseblock to another and does not atomically erase the first eraseblock.
+
+UBIFS authentication does not cover attacks where an attacker is able to
+execute code on the device after the authentication key was provided.
+Additional measures like secure boot and trusted boot have to be taken to
+ensure that only trusted code is executed on a device.
+
+
+## Authentication
+
+To be able to fully trust data read from flash, all UBIFS data structures
+stored on flash are authenticated. That is:
+
+- The index which includes file contents, file metadata like extended
+  attributes, file length etc.
+- The journal which also contains file contents and metadata by recording changes
+  to the filesystem
+- The LPT which stores UBI LEB metadata which UBIFS uses for free space accounting
+
+
+### Index Authentication
+
+Through UBIFS' concept of a wandering tree, it already takes care of only
+updating and persisting changed parts from leaf node up to the root node
+of the full B+ tree. This enables us to augment the index nodes of the tree
+with a hash over each node's child nodes. As a result, the index basically also
+a Merkle tree. Since the leaf nodes of the index contain the actual filesystem
+data, the hashes of their parent index nodes thus cover all the file contents
+and file metadata. When a file changes, the UBIFS index is updated accordingly
+from the leaf nodes up to the root node including the master node. This process
+can be hooked to recompute the hash only for each changed node at the same time.
+Whenever a file is read, UBIFS can verify the hashes from each leaf node up to
+the root node to ensure the node's integrity.
+
+To ensure the authenticity of the whole index, the UBIFS master node stores a
+keyed hash (HMAC) over its own contents and a hash of the root node of the index
+tree. As mentioned above, the master node is always written to the flash whenever
+the index is persisted (ie. on index commit).
+
+Using this approach only UBIFS index nodes and the master node are changed to
+include a hash. All other types of nodes will remain unchanged. This reduces
+the storage overhead which is precious for users of UBIFS (ie. embedded
+devices).
+
+
+                             +---------------+
+                             |  Master Node  |
+                             |    (hash)     |
+                             +---------------+
+                                     |
+                                     v
+                            +-------------------+
+                            |  Index Node #1    |
+                            |                   |
+                            | branch0   branchn |
+                            | (hash)    (hash)  |
+                            +-------------------+
+                               |    ...   |  (fanout: 8)
+                               |          |
+                       +-------+          +------+
+                       |                         |
+                       v                         v
+            +-------------------+       +-------------------+
+            |  Index Node #2    |       |  Index Node #3    |
+            |                   |       |                   |
+            | branch0   branchn |       | branch0   branchn |
+            | (hash)    (hash)  |       | (hash)    (hash)  |
+            +-------------------+       +-------------------+
+                 |   ...                     |   ...   |
+                 v                           v         v
+               +-----------+         +----------+  +-----------+
+               | Data Node |         | INO Node |  | DENT Node |
+               +-----------+         +----------+  +-----------+
+
+
+           Figure 3: Coverage areas of index node hash and master node HMAC
+
+
+
+The most important part for robustness and power-cut safety is to atomically
+persist the hash and file contents. Here the existing UBIFS logic for how
+changed nodes are persisted is already designed for this purpose such that
+UBIFS can safely recover if a power-cut occurs while persisting. Adding
+hashes to index nodes does not change this since each hash will be persisted
+atomically together with its respective node.
+
+
+### Journal Authentication
+
+The journal is authenticated too. Since the journal is continuously written
+it is necessary to also add authentication information frequently to the
+journal so that in case of a powercut not too much data can't be authenticated.
+This is done by creating a continuous hash beginning from the commit start node
+over the previous reference nodes, the current reference node, and the bud
+nodes. From time to time whenever it is suitable authentication nodes are added
+between the bud nodes. This new node type contains a HMAC over the current state
+of the hash chain. That way a journal can be authenticated up to the last
+authentication node. The tail of the journal which may not have a authentication
+node cannot be authenticated and is skipped during journal replay.
+
+We get this picture for journal authentication:
+
+    ,,,,,,,,
+    ,......,...........................................
+    ,. CS  ,               hash1.----.           hash2.----.
+    ,.  |  ,                    .    |hmac            .    |hmac
+    ,.  v  ,                    .    v                .    v
+    ,.REF#0,-> bud -> bud -> bud.-> auth -> bud -> bud.-> auth ...
+    ,..|...,...........................................
+    ,  |   ,
+    ,  |   ,,,,,,,,,,,,,,,
+    .  |            hash3,----.
+    ,  |                 ,    |hmac
+    ,  v                 ,    v
+    , REF#1 -> bud -> bud,-> auth ...
+    ,,,|,,,,,,,,,,,,,,,,,,
+       v
+      REF#2 -> ...
+       |
+       V
+      ...
+
+Since the hash also includes the reference nodes an attacker cannot reorder or
+skip any journal heads for replay. An attacker can only remove bud nodes or
+reference nodes from the end of the journal, effectively rewinding the
+filesystem at maximum back to the last commit.
+
+The location of the log area is stored in the master node. Since the master
+node is authenticated with a HMAC as described above, it is not possible to
+tamper with that without detection. The size of the log area is specified when
+the filesystem is created using `mkfs.ubifs` and stored in the superblock node.
+To avoid tampering with this and other values stored there, a HMAC is added to
+the superblock struct. The superblock node is stored in LEB 0 and is only
+modified on feature flag or similar changes, but never on file changes.
+
+
+### LPT Authentication
+
+The location of the LPT root node on the flash is stored in the UBIFS master
+node. Since the LPT is written and read atomically on every commit, there is
+no need to authenticate individual nodes of the tree. It suffices to
+protect the integrity of the full LPT by a simple hash stored in the master
+node. Since the master node itself is authenticated, the LPTs authenticity can
+be verified by verifying the authenticity of the master node and comparing the
+LTP hash stored there with the hash computed from the read on-flash LPT.
+
+
+## Key Management
+
+For simplicity, UBIFS authentication uses a single key to compute the HMACs
+of superblock, master, commit start and reference nodes. This key has to be
+available on creation of the filesystem (`mkfs.ubifs`) to authenticate the
+superblock node. Further, it has to be available on mount of the filesystem
+to verify authenticated nodes and generate new HMACs for changes.
+
+UBIFS authentication is intended to operate side-by-side with UBIFS encryption
+(fscrypt) to provide confidentiality and authenticity. Since UBIFS encryption
+has a different approach of encryption policies per directory, there can be
+multiple fscrypt master keys and there might be folders without encryption.
+UBIFS authentication on the other hand has an all-or-nothing approach in the
+sense that it either authenticates everything of the filesystem or nothing.
+Because of this and because UBIFS authentication should also be usable without
+encryption, it does not share the same master key with fscrypt, but manages
+a dedicated authentication key.
+
+The API for providing the authentication key has yet to be defined, but the
+key can eg. be provided by userspace through a keyring similar to the way it
+is currently done in fscrypt. It should however be noted that the current
+fscrypt approach has shown its flaws and the userspace API will eventually
+change [FSCRYPT-POLICY2].
+
+Nevertheless, it will be possible for a user to provide a single passphrase
+or key in userspace that covers UBIFS authentication and encryption. This can
+be solved by the corresponding userspace tools which derive a second key for
+authentication in addition to the derived fscrypt master key used for
+encryption.
+
+To be able to check if the proper key is available on mount, the UBIFS
+superblock node will additionally store a hash of the authentication key. This
+approach is similar to the approach proposed for fscrypt encryption policy v2
+[FSCRYPT-POLICY2].
+
+
+# Future Extensions
+
+In certain cases where a vendor wants to provide an authenticated filesystem
+image to customers, it should be possible to do so without sharing the secret
+UBIFS authentication key. Instead, in addition the each HMAC a digital
+signature could be stored where the vendor shares the public key alongside the
+filesystem image. In case this filesystem has to be modified afterwards,
+UBIFS can exchange all digital signatures with HMACs on first mount similar
+to the way the IMA/EVM subsystem deals with such situations. The HMAC key
+will then have to be provided beforehand in the normal way.
+
+
+# References
+
+[CRYPTSETUP2]        http://www.saout.de/pipermail/dm-crypt/2017-November/005745.html
+
+[DMC-CBC-ATTACK]     http://www.jakoblell.com/blog/2013/12/22/practical-malleability-attack-against-cbc-encrypted-luks-partitions/
+
+[DM-INTEGRITY]       https://www.kernel.org/doc/Documentation/device-mapper/dm-integrity.txt
+
+[DM-VERITY]          https://www.kernel.org/doc/Documentation/device-mapper/verity.txt
+
+[FSCRYPT-POLICY2]    https://www.spinics.net/lists/linux-ext4/msg58710.html
+
+[UBIFS-WP]           http://www.linux-mtd.infradead.org/doc/ubifs_whitepaper.pdf
index a0a61d2..acc8044 100644 (file)
@@ -91,6 +91,13 @@ chk_data_crc         do not skip checking CRCs on data nodes
 compr=none              override default compressor and set it to "none"
 compr=lzo               override default compressor and set it to "lzo"
 compr=zlib              override default compressor and set it to "zlib"
+auth_key=              specify the key used for authenticating the filesystem.
+                       Passing this option makes authentication mandatory.
+                       The passed key must be present in the kernel keyring
+                       and must be of type 'logon'
+auth_hash_name=                The hash algorithm used for authentication. Used for
+                       both hashing and for creating HMACs. Typical values
+                       include "sha256" or "sha512"
 
 
 Quick usage instructions
diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644 (file)
index 0000000..31884d2
--- /dev/null
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+       Ajay Gupta <ajayg@nvidia.com>
+
+Description
+-----------
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
index f485597..0abecc5 100644 (file)
@@ -6607,9 +6607,9 @@ F:        arch/*/include/asm/suspend*.h
 
 HID CORE LAYER
 M:     Jiri Kosina <jikos@kernel.org>
-R:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
+M:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-input@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
 F:     drivers/hid/
 F:     include/linux/hid*
@@ -6861,6 +6861,13 @@ L:       linux-acpi@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M:     Ajay Gupta <ajayg@nvidia.com>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     Documentation/i2c/busses/i2c-nvidia-gpu
+F:     drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-i2c@vger.kernel.org
@@ -8367,7 +8374,7 @@ F:        drivers/media/dvb-frontends/lgdt3305.*
 LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
 F:     include/linux/pata_arasan_cf_data.h
 F:     drivers/ata/pata_arasan_cf.c
@@ -8384,7 +8391,7 @@ F:        drivers/ata/ata_generic.c
 LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
 F:     drivers/ata/pata_ftide010.c
 F:     drivers/ata/sata_gemini.c
@@ -8403,7 +8410,7 @@ F:        include/linux/ahci_platform.h
 LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
 M:     Mikael Pettersson <mikpelinux@gmail.com>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
 F:     drivers/ata/sata_promise.*
 
@@ -10784,6 +10791,14 @@ L:     linux-omap@vger.kernel.org
 S:     Maintained
 F:     arch/arm/mach-omap2/omap_hwmod.*
 
+OMAP I2C DRIVER
+M:     Vignesh R <vigneshr@ti.com>
+L:     linux-omap@vger.kernel.org
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/i2c/i2c-omap.txt
+F:     drivers/i2c/busses/i2c-omap.c
+
 OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
@@ -15436,9 +15451,9 @@ F:      include/linux/usb/gadget*
 
 USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
 M:     Jiri Kosina <jikos@kernel.org>
-R:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
+M:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
 F:     Documentation/hid/hiddev.txt
 F:     drivers/hid/usbhid/
index bce41f4..9fce8b9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 4
-PATCHLEVEL = 19
+PATCHLEVEL = 20
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = "People's Front"
 
 # *DOCUMENTATION*
index 6a8c53d..b7c77bb 100644 (file)
 })
 
 #define user_termios_to_kernel_termios(k, u) \
-       copy_from_user(k, u, sizeof(struct termios))
+       copy_from_user(k, u, sizeof(struct termios2))
 
 #define kernel_termios_to_user_termios(u, k) \
+       copy_to_user(u, k, sizeof(struct termios2))
+
+#define user_termios_to_kernel_termios_1(k, u) \
+       copy_from_user(k, u, sizeof(struct termios))
+
+#define kernel_termios_to_user_termios_1(u, k) \
        copy_to_user(u, k, sizeof(struct termios))
 
 #endif /* _ALPHA_TERMIOS_H */
index 1e9121c..9713116 100644 (file)
 #define TCXONC         _IO('t', 30)
 #define TCFLSH         _IO('t', 31)
 
+#define TCGETS2                _IOR('T', 42, struct termios2)
+#define TCSETS2                _IOW('T', 43, struct termios2)
+#define TCSETSW2       _IOW('T', 44, struct termios2)
+#define TCSETSF2       _IOW('T', 45, struct termios2)
+
 #define TIOCSWINSZ     _IOW('t', 103, struct winsize)
 #define TIOCGWINSZ     _IOR('t', 104, struct winsize)
 #define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
index de6c836..4575ba3 100644 (file)
@@ -26,6 +26,19 @@ struct termios {
        speed_t c_ospeed;               /* output speed */
 };
 
+/* Alpha has identical termios and termios2 */
+
+struct termios2 {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_cc[NCCS];                /* control characters */
+       cc_t c_line;                    /* line discipline (== c_cc[19]) */
+       speed_t c_ispeed;               /* input speed */
+       speed_t c_ospeed;               /* output speed */
+};
+
 /* Alpha has matching termios and ktermios */
 
 struct ktermios {
@@ -152,6 +165,7 @@ struct ktermios {
 #define B3000000  00034
 #define B3500000  00035
 #define B4000000  00036
+#define BOTHER    00037
 
 #define CSIZE  00001400
 #define   CS5  00000000
@@ -169,6 +183,9 @@ struct ktermios {
 #define CMSPAR   010000000000          /* mark or space (stick) parity */
 #define CRTSCTS          020000000000          /* flow control */
 
+#define CIBAUD 07600000
+#define IBSHIFT        16
+
 /* c_lflag bits */
 #define ISIG   0x00000080
 #define ICANON 0x00000100
index b560ff8..5ff9a17 100644 (file)
@@ -55,7 +55,7 @@
        };
 
        chosen {
-               stdout-path = "&uart1:115200n8";
+               stdout-path = "serial0:115200n8";
        };
 
        memory@70000000 {
index ed9a980..beefa1b 100644 (file)
                        i2c1: i2c@21a0000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "fs,imx6sll-i2c", "fsl,imx21-i2c";
+                               compatible = "fsl,imx6sll-i2c", "fsl,imx21-i2c";
                                reg = <0x021a0000 0x4000>;
                                interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6SLL_CLK_I2C1>;
index 53b3408..7d7d679 100644 (file)
                regulator-name = "enet_3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
-               gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+               gpio = <&gpio2 6 GPIO_ACTIVE_LOW>;
+               regulator-boot-on;
+               regulator-always-on;
        };
 
        reg_pcie_gpio: regulator-pcie-gpio {
        phy-supply = <&reg_enet_3v3>;
        phy-mode = "rgmii";
        phy-handle = <&ethphy1>;
+       phy-reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        mdio {
                                MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3   0x3081
                                MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN    0x3081
                                MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M       0x91
+                               /* phy reset */
+                               MX6SX_PAD_ENET2_CRS__GPIO2_IO_7         0x10b0
                        >;
                };
 
index 41ec66a..ca62495 100644 (file)
@@ -50,8 +50,8 @@
        compatible = "fsl,vf610m4";
 
        chosen {
-               bootargs = "console=ttyLP2,115200 clk_ignore_unused init=/linuxrc rw";
-               stdout-path = "&uart2";
+               bootargs = "clk_ignore_unused init=/linuxrc rw";
+               stdout-path = "serial2:115200";
        };
 
        memory@8c000000 {
index 1c76168..63af623 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
index 92fd2c8..12659ce 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _ASM_PGTABLE_2LEVEL_H
 #define _ASM_PGTABLE_2LEVEL_H
 
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 
 /*
  * Hardware-wise, we have a two level page table structure, where the first
index 6fe5281..339eb17 100644 (file)
@@ -112,7 +112,7 @@ ENTRY(cpu_v7_hvc_switch_mm)
        hvc     #0
        ldmfd   sp!, {r0 - r3}
        b       cpu_v7_switch_mm
-ENDPROC(cpu_v7_smc_switch_mm)
+ENDPROC(cpu_v7_hvc_switch_mm)
 #endif
 ENTRY(cpu_v7_iciallu_switch_mm)
        mov     r3, #0
index 8253a1a..fef7351 100644 (file)
                        clock-names = "stmmaceth";
                        tx-fifo-depth = <16384>;
                        rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
                        status = "disabled";
                };
 
                        clock-names = "stmmaceth";
                        tx-fifo-depth = <16384>;
                        rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
                        status = "disabled";
                };
 
                        clock-names = "stmmaceth";
                        tx-fifo-depth = <16384>;
                        rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
                        status = "disabled";
                };
 
index b5f2273..a79c8d3 100644 (file)
                        clock-names = "fck", "brg_int", "scif_clk";
                        dmas = <&dmac1 0x35>, <&dmac1 0x34>,
                               <&dmac2 0x35>, <&dmac2 0x34>;
-                       dma-names = "tx", "rx";
+                       dma-names = "tx", "rx", "tx", "rx";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 518>;
                        status = "disabled";
index fe2e2c0..5a7012b 100644 (file)
@@ -15,7 +15,7 @@
 
        aliases {
                serial0 = &scif0;
-               ethernet0 = &avb;
+               ethernet0 = &gether;
        };
 
        chosen {
        };
 };
 
-&avb {
-       pinctrl-0 = <&avb_pins>;
-       pinctrl-names = "default";
-
-       phy-mode = "rgmii-id";
-       phy-handle = <&phy0>;
-       renesas,no-ether-link;
-       status = "okay";
-
-       phy0: ethernet-phy@0 {
-               rxc-skew-ps = <1500>;
-               reg = <0>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
-       };
-};
-
 &canfd {
        pinctrl-0 = <&canfd0_pins>;
        pinctrl-names = "default";
        clock-frequency = <32768>;
 };
 
+&gether {
+       pinctrl-0 = <&gether_pins>;
+       pinctrl-names = "default";
+
+       phy-mode = "rgmii-id";
+       phy-handle = <&phy0>;
+       renesas,no-ether-link;
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               rxc-skew-ps = <1500>;
+               reg = <0>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
 &i2c0 {
        pinctrl-0 = <&i2c0_pins>;
        pinctrl-names = "default";
 };
 
 &pfc {
-       avb_pins: avb {
-               groups = "avb_mdio", "avb_rgmii";
-               function = "avb";
-       };
-
        canfd0_pins: canfd0 {
                groups = "canfd0_data_a";
                function = "canfd0";
        };
 
+       gether_pins: gether {
+               groups = "gether_mdio_a", "gether_rgmii",
+                        "gether_txcrefclk", "gether_txcrefclk_mega";
+               function = "gether";
+       };
+
        i2c0_pins: i2c0 {
                groups = "i2c0";
                function = "i2c0";
index 3e20917..6b0d4df 100644 (file)
 #define KERNEL_DS      UL(-1)
 #define USER_DS                (TASK_SIZE_64 - 1)
 
+/*
+ * On arm64 systems, unaligned accesses by the CPU are cheap, and so there is
+ * no point in shifting all network buffers by 2 bytes just to make some IP
+ * header fields appear aligned in memory, potentially sacrificing some DMA
+ * performance on some platforms.
+ */
+#define NET_IP_ALIGN   0
+
 #ifndef __ASSEMBLY__
 #ifdef __KERNEL__
 
index 9d9582c..9b432d9 100644 (file)
@@ -483,8 +483,6 @@ void __init arm64_memblock_init(void)
        high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
 
        dma_contiguous_reserve(arm64_dma_phys_limit);
-
-       memblock_allow_resize();
 }
 
 void __init bootmem_init(void)
index 394b8d5..d1d6601 100644 (file)
@@ -659,6 +659,8 @@ void __init paging_init(void)
 
        memblock_free(__pa_symbol(init_pg_dir),
                      __pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));
+
+       memblock_allow_resize();
 }
 
 /*
index 6181e41..fe3ddd7 100644 (file)
  */
 #ifdef CONFIG_SUN3
 #define PTRS_PER_PTE   16
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   2048
 #elif defined(CONFIG_COLDFIRE)
 #define PTRS_PER_PTE   512
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
 #else
index f64ebb9..e14b662 100644 (file)
@@ -63,7 +63,7 @@ extern int mem_init_done;
 
 #include <asm-generic/4level-fixup.h>
 
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
index 75108ec..6c79e8a 100644 (file)
@@ -67,7 +67,7 @@ void (*cvmx_override_pko_queue_priority) (int pko_port,
 void (*cvmx_override_ipd_port_setup) (int ipd_port);
 
 /* Port count per interface */
-static int interface_port_count[5];
+static int interface_port_count[9];
 
 /**
  * Return the number of interfaces the chip has. Each interface
index e6c9485..cb38461 100644 (file)
@@ -50,7 +50,7 @@ void *arch_dma_alloc(struct device *dev, size_t size,
        void *ret;
 
        ret = dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
-       if (!ret && !(attrs & DMA_ATTR_NON_CONSISTENT)) {
+       if (ret && !(attrs & DMA_ATTR_NON_CONSISTENT)) {
                dma_cache_wback_inv((unsigned long) ret, size);
                ret = (void *)UNCAC_ADDR(ret);
        }
index d3e19a5..9f52db9 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef _ASMNDS32_PGTABLE_H
 #define _ASMNDS32_PGTABLE_H
 
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 #include <asm-generic/4level-fixup.h>
 #include <asm-generic/sizes.h>
 
index b941ac7..c7bb74e 100644 (file)
@@ -111,7 +111,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #if CONFIG_PGTABLE_LEVELS == 3
 #define BITS_PER_PMD   (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
 #else
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 #define BITS_PER_PMD   0
 #endif
 #define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
index 0b33577..e21053e 100644 (file)
@@ -27,7 +27,7 @@ KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-option,-ffreestanding)
 KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO),-g)
 KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO_DWARF4), $(call cc-option, -gdwarf-4,))
 UTS_MACHINE    := s390x
-STACK_SIZE     := $(if $(CONFIG_KASAN),32768,16384)
+STACK_SIZE     := $(if $(CONFIG_KASAN),65536,16384)
 CHECKFLAGS     += -D__s390__ -D__s390x__
 
 export LD_BFD
index 5930396..b1bdd15 100644 (file)
@@ -22,10 +22,10 @@ OBJCOPYFLAGS :=
 OBJECTS := $(addprefix $(obj)/,$(obj-y))
 
 LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(objtree)/arch/s390/boot/startup.a $(OBJECTS)
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(objtree)/arch/s390/boot/startup.a $(OBJECTS) FORCE
        $(call if_changed,ld)
 
-OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info
+OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info --set-section-flags .vmlinux.info=load
 $(obj)/info.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
@@ -46,17 +46,17 @@ suffix-$(CONFIG_KERNEL_LZMA)  := .lzma
 suffix-$(CONFIG_KERNEL_LZO)  := .lzo
 suffix-$(CONFIG_KERNEL_XZ)  := .xz
 
-$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,gzip)
-$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,bzip2)
-$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lz4)
-$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzma)
-$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzo)
-$(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y)
+$(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,xzkern)
 
 OBJCOPYFLAGS_piggy.o := -I binary -O elf64-s390 -B s390:64-bit --rename-section .data=.vmlinux.bin.compressed
index 259d169..c69cb04 100644 (file)
@@ -64,6 +64,8 @@ CONFIG_NUMA=y
 CONFIG_PREEMPT=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC_FILE=y
+CONFIG_EXPOLINE=y
+CONFIG_EXPOLINE_AUTO=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
@@ -84,9 +86,11 @@ CONFIG_PCI_DEBUG=y
 CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_CHSC_SCH=y
+CONFIG_VFIO_AP=m
 CONFIG_CRASH_DUMP=y
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
+CONFIG_PM_DEBUG=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -161,8 +165,6 @@ CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
-CONFIG_NFT_EXTHDR=m
-CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
@@ -365,6 +367,8 @@ CONFIG_NET_ACT_SKBEDIT=m
 CONFIG_NET_ACT_CSUM=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_OPENVSWITCH=m
+CONFIG_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_BPF_JIT=y
@@ -461,6 +465,7 @@ CONFIG_PPTP=m
 CONFIG_PPPOL2TP=m
 CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
+CONFIG_ISM=m
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -486,9 +491,12 @@ CONFIG_MLX4_INFINIBAND=m
 CONFIG_MLX5_INFINIBAND=m
 CONFIG_VFIO=m
 CONFIG_VFIO_PCI=m
+CONFIG_VFIO_MDEV=m
+CONFIG_VFIO_MDEV_DEVICE=m
 CONFIG_VIRTIO_PCI=m
 CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
+CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -615,7 +623,6 @@ CONFIG_DEBUG_CREDENTIALS=y
 CONFIG_RCU_TORTURE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=300
 CONFIG_NOTIFIER_ERROR_INJECTION=m
-CONFIG_PM_NOTIFIER_ERROR_INJECT=m
 CONFIG_NETDEV_NOTIFIER_ERROR_INJECT=m
 CONFIG_FAULT_INJECTION=y
 CONFIG_FAILSLAB=y
@@ -727,3 +734,4 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_KVM_S390_UCONTROL=y
 CONFIG_VHOST_NET=m
+CONFIG_VHOST_VSOCK=m
index 37fd60c..32f539d 100644 (file)
@@ -65,6 +65,8 @@ CONFIG_NR_CPUS=512
 CONFIG_NUMA=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC_FILE=y
+CONFIG_EXPOLINE=y
+CONFIG_EXPOLINE_AUTO=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
@@ -82,9 +84,11 @@ CONFIG_PCI=y
 CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_CHSC_SCH=y
+CONFIG_VFIO_AP=m
 CONFIG_CRASH_DUMP=y
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
+CONFIG_PM_DEBUG=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -159,8 +163,6 @@ CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
-CONFIG_NFT_EXTHDR=m
-CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
@@ -362,6 +364,8 @@ CONFIG_NET_ACT_SKBEDIT=m
 CONFIG_NET_ACT_CSUM=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_OPENVSWITCH=m
+CONFIG_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_BPF_JIT=y
@@ -458,6 +462,7 @@ CONFIG_PPTP=m
 CONFIG_PPPOL2TP=m
 CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
+CONFIG_ISM=m
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -483,9 +488,12 @@ CONFIG_MLX4_INFINIBAND=m
 CONFIG_MLX5_INFINIBAND=m
 CONFIG_VFIO=m
 CONFIG_VFIO_PCI=m
+CONFIG_VFIO_MDEV=m
+CONFIG_VFIO_MDEV_DEVICE=m
 CONFIG_VIRTIO_PCI=m
 CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
+CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -666,3 +674,4 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_KVM_S390_UCONTROL=y
 CONFIG_VHOST_NET=m
+CONFIG_VHOST_VSOCK=m
index 7cb6a52..4d58a92 100644 (file)
@@ -26,14 +26,23 @@ CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_PERF=y
 CONFIG_NAMESPACES=y
 CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_SYSFS_SYSCALL is not set
-CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_USERFAULTFD=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
+CONFIG_LIVEPATCH=y
+CONFIG_NR_CPUS=256
+CONFIG_NUMA=y
+CONFIG_HZ_100=y
+CONFIG_KEXEC_FILE=y
+CONFIG_CRASH_DUMP=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_DEBUG=y
+CONFIG_CMM=m
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
@@ -44,11 +53,7 @@ CONFIG_BLK_DEV_INTEGRITY=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_IBM_PARTITION=y
 CONFIG_DEFAULT_DEADLINE=y
-CONFIG_LIVEPATCH=y
-CONFIG_NR_CPUS=256
-CONFIG_NUMA=y
-CONFIG_HZ_100=y
-CONFIG_KEXEC_FILE=y
+CONFIG_BINFMT_MISC=m
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
@@ -60,9 +65,6 @@ CONFIG_ZBUD=m
 CONFIG_ZSMALLOC=m
 CONFIG_ZSMALLOC_STAT=y
 CONFIG_IDLE_PAGE_TRACKING=y
-CONFIG_CRASH_DUMP=y
-CONFIG_BINFMT_MISC=m
-CONFIG_HIBERNATION=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -98,6 +100,7 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_VIRTIO_BLK=y
 CONFIG_SCSI=y
+# CONFIG_SCSI_MQ_DEFAULT is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
@@ -131,6 +134,7 @@ CONFIG_EQUALIZER=m
 CONFIG_TUN=m
 CONFIG_VIRTIO_NET=y
 # CONFIG_NET_VENDOR_ALACRITECH is not set
+# CONFIG_NET_VENDOR_AURORA is not set
 # CONFIG_NET_VENDOR_CORTINA is not set
 # CONFIG_NET_VENDOR_SOLARFLARE is not set
 # CONFIG_NET_VENDOR_SOCIONEXT is not set
@@ -157,33 +161,6 @@ CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_DWARF4=y
-CONFIG_GDB_SCRIPTS=y
-CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
-CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_PANIC_ON_OOPS=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_LOCKDEP=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_SG=y
-CONFIG_DEBUG_NOTIFIERS=y
-CONFIG_RCU_CPU_STALL_TIMEOUT=60
-CONFIG_LATENCYTOP=y
-CONFIG_SCHED_TRACER=y
-CONFIG_FTRACE_SYSCALLS=y
-CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
-CONFIG_STACK_TRACER=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_FUNCTION_PROFILER=y
-# CONFIG_RUNTIME_TESTING_MENU is not set
-CONFIG_S390_PTDUMP=y
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
@@ -193,6 +170,7 @@ CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_CMAC=m
@@ -231,7 +209,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_ZCRYPT=m
-CONFIG_ZCRYPT_MULTIDEVNODES=y
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
@@ -247,4 +224,30 @@ CONFIG_CRC7=m
 # CONFIG_XZ_DEC_ARM is not set
 # CONFIG_XZ_DEC_ARMTHUMB is not set
 # CONFIG_XZ_DEC_SPARC is not set
-CONFIG_CMM=m
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_GDB_SCRIPTS=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_LOCK_STAT=y
+CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_LATENCYTOP=y
+CONFIG_SCHED_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
+CONFIG_STACK_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_FUNCTION_PROFILER=y
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_S390_PTDUMP=y
index dbd689d..ccbb53e 100644 (file)
@@ -46,8 +46,6 @@ static inline int init_new_context(struct task_struct *tsk,
                mm->context.asce_limit = STACK_TOP_MAX;
                mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
                                   _ASCE_USER_BITS | _ASCE_TYPE_REGION3;
-               /* pgd_alloc() did not account this pud */
-               mm_inc_nr_puds(mm);
                break;
        case -PAGE_SIZE:
                /* forked 5-level task, set new asce with new_mm->pgd */
@@ -63,9 +61,6 @@ static inline int init_new_context(struct task_struct *tsk,
                /* forked 2-level compat task, set new asce with new mm->pgd */
                mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
                                   _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
-               /* pgd_alloc() did not account this pmd */
-               mm_inc_nr_pmds(mm);
-               mm_inc_nr_puds(mm);
        }
        crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
        return 0;
index f0f9bcf..5ee7337 100644 (file)
@@ -36,11 +36,11 @@ static inline void crst_table_init(unsigned long *crst, unsigned long entry)
 
 static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 {
-       if (mm->context.asce_limit <= _REGION3_SIZE)
+       if (mm_pmd_folded(mm))
                return _SEGMENT_ENTRY_EMPTY;
-       if (mm->context.asce_limit <= _REGION2_SIZE)
+       if (mm_pud_folded(mm))
                return _REGION3_ENTRY_EMPTY;
-       if (mm->context.asce_limit <= _REGION1_SIZE)
+       if (mm_p4d_folded(mm))
                return _REGION2_ENTRY_EMPTY;
        return _REGION1_ENTRY_EMPTY;
 }
index 411d435..0637324 100644 (file)
@@ -493,6 +493,24 @@ static inline int is_module_addr(void *addr)
                                   _REGION_ENTRY_PROTECT | \
                                   _REGION_ENTRY_NOEXEC)
 
+static inline bool mm_p4d_folded(struct mm_struct *mm)
+{
+       return mm->context.asce_limit <= _REGION1_SIZE;
+}
+#define mm_p4d_folded(mm) mm_p4d_folded(mm)
+
+static inline bool mm_pud_folded(struct mm_struct *mm)
+{
+       return mm->context.asce_limit <= _REGION2_SIZE;
+}
+#define mm_pud_folded(mm) mm_pud_folded(mm)
+
+static inline bool mm_pmd_folded(struct mm_struct *mm)
+{
+       return mm->context.asce_limit <= _REGION3_SIZE;
+}
+#define mm_pmd_folded(mm) mm_pmd_folded(mm)
+
 static inline int mm_has_pgste(struct mm_struct *mm)
 {
 #ifdef CONFIG_PGSTE
index 302795c..81038ab 100644 (file)
@@ -236,7 +236,7 @@ static inline unsigned long current_stack_pointer(void)
        return sp;
 }
 
-static __no_sanitize_address_or_inline unsigned short stap(void)
+static __no_kasan_or_inline unsigned short stap(void)
 {
        unsigned short cpu_address;
 
@@ -330,7 +330,7 @@ static inline void __load_psw(psw_t psw)
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
  */
-static __no_sanitize_address_or_inline void __load_psw_mask(unsigned long mask)
+static __no_kasan_or_inline void __load_psw_mask(unsigned long mask)
 {
        unsigned long addr;
        psw_t psw;
index 27248f4..ce4e17c 100644 (file)
@@ -14,7 +14,7 @@
  * General size of kernel stacks
  */
 #ifdef CONFIG_KASAN
-#define THREAD_SIZE_ORDER 3
+#define THREAD_SIZE_ORDER 4
 #else
 #define THREAD_SIZE_ORDER 2
 #endif
index 457b7ba..b31c779 100644 (file)
@@ -136,7 +136,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
 static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
                                unsigned long address)
 {
-       if (tlb->mm->context.asce_limit <= _REGION3_SIZE)
+       if (mm_pmd_folded(tlb->mm))
                return;
        pgtable_pmd_page_dtor(virt_to_page(pmd));
        tlb_remove_table(tlb, pmd);
@@ -152,7 +152,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
 static inline void p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d,
                                unsigned long address)
 {
-       if (tlb->mm->context.asce_limit <= _REGION1_SIZE)
+       if (mm_p4d_folded(tlb->mm))
                return;
        tlb_remove_table(tlb, p4d);
 }
@@ -167,7 +167,7 @@ static inline void p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d,
 static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
                                unsigned long address)
 {
-       if (tlb->mm->context.asce_limit <= _REGION2_SIZE)
+       if (mm_pud_folded(tlb->mm))
                return;
        tlb_remove_table(tlb, pud);
 }
index 724fba4..39191a0 100644 (file)
@@ -236,10 +236,10 @@ ENTRY(__switch_to)
        stmg    %r6,%r15,__SF_GPRS(%r15)        # store gprs of prev task
        lghi    %r4,__TASK_stack
        lghi    %r1,__TASK_thread
-       lg      %r5,0(%r4,%r3)                  # start of kernel stack of next
+       llill   %r5,STACK_INIT
        stg     %r15,__THREAD_ksp(%r1,%r2)      # store kernel stack of prev
-       lgr     %r15,%r5
-       aghi    %r15,STACK_INIT                 # end of kernel stack of next
+       lg      %r15,0(%r4,%r3)                 # start of kernel stack of next
+       agr     %r15,%r5                        # end of kernel stack of next
        stg     %r3,__LC_CURRENT                # store task struct of next
        stg     %r15,__LC_KERNEL_STACK          # store end of kernel stack
        lg      %r15,__THREAD_ksp(%r1,%r3)      # load kernel stack of next
index cc085e2..74091fd 100644 (file)
@@ -373,7 +373,7 @@ static int __hw_perf_event_init(struct perf_event *event)
                return -ENOENT;
 
        if (ev > PERF_CPUM_CF_MAX_CTR)
-               return -EINVAL;
+               return -ENOENT;
 
        /* Obtain the counter set to which the specified counter belongs */
        set = get_counter_set(ev);
index 7bf604f..bfabeb1 100644 (file)
@@ -1842,10 +1842,30 @@ static void cpumsf_pmu_del(struct perf_event *event, int flags)
 CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC, PERF_EVENT_CPUM_SF);
 CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
 
-static struct attribute *cpumsf_pmu_events_attr[] = {
-       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC),
-       NULL,
-       NULL,
+/* Attribute list for CPU_SF.
+ *
+ * The availablitiy depends on the CPU_MF sampling facility authorization
+ * for basic + diagnositic samples. This is determined at initialization
+ * time by the sampling facility device driver.
+ * If the authorization for basic samples is turned off, it should be
+ * also turned off for diagnostic sampling.
+ *
+ * During initialization of the device driver, check the authorization
+ * level for diagnostic sampling and installs the attribute
+ * file for diagnostic sampling if necessary.
+ *
+ * For now install a placeholder to reference all possible attributes:
+ * SF_CYCLES_BASIC and SF_CYCLES_BASIC_DIAG.
+ * Add another entry for the final NULL pointer.
+ */
+enum {
+       SF_CYCLES_BASIC_ATTR_IDX = 0,
+       SF_CYCLES_BASIC_DIAG_ATTR_IDX,
+       SF_CYCLES_ATTR_MAX
+};
+
+static struct attribute *cpumsf_pmu_events_attr[SF_CYCLES_ATTR_MAX + 1] = {
+       [SF_CYCLES_BASIC_ATTR_IDX] = CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC)
 };
 
 PMU_FORMAT_ATTR(event, "config:0-63");
@@ -2040,7 +2060,10 @@ static int __init init_cpum_sampling_pmu(void)
 
        if (si.ad) {
                sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
-               cpumsf_pmu_events_attr[1] =
+               /* Sampling of diagnostic data authorized,
+                * install event into attribute list of PMU device.
+                */
+               cpumsf_pmu_events_attr[SF_CYCLES_BASIC_DIAG_ATTR_IDX] =
                        CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG);
        }
 
index eb8aebe..e76309f 100644 (file)
@@ -37,7 +37,7 @@ KASAN_SANITIZE := n
 $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
 
 # link rule for the .so file, .lds has to be first
-$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32)
+$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) FORCE
        $(call if_changed,vdso32ld)
 
 # strip rule for the .so file
@@ -46,12 +46,12 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
        $(call if_changed,objcopy)
 
 # assembly rules for the .S files
-$(obj-vdso32): %.o: %.S
+$(obj-vdso32): %.o: %.S FORCE
        $(call if_changed_dep,vdso32as)
 
 # actual build commands
 quiet_cmd_vdso32ld = VDSO32L $@
-      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
 quiet_cmd_vdso32as = VDSO32A $@
       cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $<
 
index a22b2cf..f849ac6 100644 (file)
@@ -37,7 +37,7 @@ KASAN_SANITIZE := n
 $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
 
 # link rule for the .so file, .lds has to be first
-$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64)
+$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) FORCE
        $(call if_changed,vdso64ld)
 
 # strip rule for the .so file
@@ -46,12 +46,12 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
        $(call if_changed,objcopy)
 
 # assembly rules for the .S files
-$(obj-vdso64): %.o: %.S
+$(obj-vdso64): %.o: %.S FORCE
        $(call if_changed_dep,vdso64as)
 
 # actual build commands
 quiet_cmd_vdso64ld = VDSO64L $@
-      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
 quiet_cmd_vdso64as = VDSO64A $@
       cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
 
index 21eb740..8429ab0 100644 (file)
@@ -154,14 +154,14 @@ SECTIONS
         * uncompressed image info used by the decompressor
         * it should match struct vmlinux_info
         */
-       .vmlinux.info 0 : {
+       .vmlinux.info 0 (INFO) : {
                QUAD(_stext)                                    /* default_lma */
                QUAD(startup_continue)                          /* entry */
                QUAD(__bss_start - _stext)                      /* image_size */
                QUAD(__bss_stop - __bss_start)                  /* bss_size */
                QUAD(__boot_data_start)                         /* bootdata_off */
                QUAD(__boot_data_end - __boot_data_start)       /* bootdata_size */
-       }
+       } :NONE
 
        /* Debugging sections.  */
        STABS_DEBUG
index 76d89ee..814f265 100644 (file)
@@ -101,6 +101,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long end)
                        mm->context.asce_limit = _REGION1_SIZE;
                        mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
                                _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
+                       mm_inc_nr_puds(mm);
                } else {
                        crst_table_init(table, _REGION1_ENTRY_EMPTY);
                        pgd_populate(mm, (pgd_t *) table, (p4d_t *) pgd);
index ae0d9e8..d31bde0 100644 (file)
@@ -53,6 +53,7 @@ int __node_distance(int a, int b)
 {
        return mode->distance ? mode->distance(a, b) : 0;
 }
+EXPORT_SYMBOL(__node_distance);
 
 int numa_debug_enabled;
 
index 74c002d..28c4062 100644 (file)
@@ -1305,6 +1305,7 @@ static int ubd_queue_one_vec(struct blk_mq_hw_ctx *hctx, struct request *req,
                io_req->fds[0] = dev->cow.fd;
        else
                io_req->fds[0] = dev->fd;
+       io_req->error = 0;
 
        if (req_op(req) == REQ_OP_FLUSH) {
                io_req->op = UBD_FLUSH;
@@ -1313,9 +1314,7 @@ static int ubd_queue_one_vec(struct blk_mq_hw_ctx *hctx, struct request *req,
                io_req->cow_offset = -1;
                io_req->offset = off;
                io_req->length = bvec->bv_len;
-               io_req->error = 0;
                io_req->sector_mask = 0;
-
                io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE;
                io_req->offsets[0] = 0;
                io_req->offsets[1] = dev->cow.data_offset;
@@ -1341,11 +1340,14 @@ static int ubd_queue_one_vec(struct blk_mq_hw_ctx *hctx, struct request *req,
 static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx,
                                 const struct blk_mq_queue_data *bd)
 {
+       struct ubd *ubd_dev = hctx->queue->queuedata;
        struct request *req = bd->rq;
        int ret = 0;
 
        blk_mq_start_request(req);
 
+       spin_lock_irq(&ubd_dev->lock);
+
        if (req_op(req) == REQ_OP_FLUSH) {
                ret = ubd_queue_one_vec(hctx, req, 0, NULL);
        } else {
@@ -1361,9 +1363,11 @@ static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx,
                }
        }
 out:
-       if (ret < 0) {
+       spin_unlock_irq(&ubd_dev->lock);
+
+       if (ret < 0)
                blk_mq_requeue_request(req, true);
-       }
+
        return BLK_STS_OK;
 }
 
index 87623c6..bd5ac6c 100644 (file)
 #define queued_fetch_set_pending_acquire queued_fetch_set_pending_acquire
 static __always_inline u32 queued_fetch_set_pending_acquire(struct qspinlock *lock)
 {
-       u32 val = 0;
-
-       if (GEN_BINARY_RMWcc(LOCK_PREFIX "btsl", lock->val.counter, c,
-                            "I", _Q_PENDING_OFFSET))
-               val |= _Q_PENDING_VAL;
+       u32 val;
 
+       /*
+        * We can't use GEN_BINARY_RMWcc() inside an if() stmt because asm goto
+        * and CONFIG_PROFILE_ALL_BRANCHES=y results in a label inside a
+        * statement expression, which GCC doesn't like.
+        */
+       val = GEN_BINARY_RMWcc(LOCK_PREFIX "btsl", lock->val.counter, c,
+                              "I", _Q_PENDING_OFFSET) * _Q_PENDING_VAL;
        val |= atomic_read(&lock->val) & ~_Q_PENDING_MASK;
 
        return val;
index 123e669..790ce08 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/mm.h>
 #include <linux/device.h>
 
-#include <linux/uaccess.h>
+#include <asm/extable.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
@@ -93,12 +93,39 @@ clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
  */
 static inline int xen_safe_write_ulong(unsigned long *addr, unsigned long val)
 {
-       return __put_user(val, (unsigned long __user *)addr);
+       int ret = 0;
+
+       asm volatile("1: mov %[val], %[ptr]\n"
+                    "2:\n"
+                    ".section .fixup, \"ax\"\n"
+                    "3: sub $1, %[ret]\n"
+                    "   jmp 2b\n"
+                    ".previous\n"
+                    _ASM_EXTABLE(1b, 3b)
+                    : [ret] "+r" (ret), [ptr] "=m" (*addr)
+                    : [val] "r" (val));
+
+       return ret;
 }
 
-static inline int xen_safe_read_ulong(unsigned long *addr, unsigned long *val)
+static inline int xen_safe_read_ulong(const unsigned long *addr,
+                                     unsigned long *val)
 {
-       return __get_user(*val, (unsigned long __user *)addr);
+       int ret = 0;
+       unsigned long rval = ~0ul;
+
+       asm volatile("1: mov %[ptr], %[rval]\n"
+                    "2:\n"
+                    ".section .fixup, \"ax\"\n"
+                    "3: sub $1, %[ret]\n"
+                    "   jmp 2b\n"
+                    ".previous\n"
+                    _ASM_EXTABLE(1b, 3b)
+                    : [ret] "+r" (ret), [rval] "+r" (rval)
+                    : [ptr] "m" (*addr));
+       *val = rval;
+
+       return ret;
 }
 
 #ifdef CONFIG_XEN_PV
index b067317..055e37e 100644 (file)
@@ -656,8 +656,7 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 
        /*
         * The interface requires atomic updates on p2m elements.
-        * xen_safe_write_ulong() is using __put_user which does an atomic
-        * store via asm().
+        * xen_safe_write_ulong() is using an atomic store via asm().
         */
        if (likely(!xen_safe_write_ulong(xen_p2m_addr + pfn, mfn)))
                return true;
index 441c882..1c8a881 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/log2.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/atomic.h>
 
 #include <asm/paravirt.h>
 #include <asm/qspinlock.h>
@@ -21,6 +22,7 @@
 
 static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
 static DEFINE_PER_CPU(char *, irq_name);
+static DEFINE_PER_CPU(atomic_t, xen_qlock_wait_nest);
 static bool xen_pvspin = true;
 
 static void xen_qlock_kick(int cpu)
@@ -39,25 +41,25 @@ static void xen_qlock_kick(int cpu)
  */
 static void xen_qlock_wait(u8 *byte, u8 val)
 {
-       unsigned long flags;
        int irq = __this_cpu_read(lock_kicker_irq);
+       atomic_t *nest_cnt = this_cpu_ptr(&xen_qlock_wait_nest);
 
        /* If kicker interrupts not initialized yet, just spin */
        if (irq == -1 || in_nmi())
                return;
 
-       /* Guard against reentry. */
-       local_irq_save(flags);
+       /* Detect reentry. */
+       atomic_inc(nest_cnt);
 
-       /* If irq pending already clear it. */
-       if (xen_test_irq_pending(irq)) {
+       /* If irq pending already and no nested call clear it. */
+       if (atomic_read(nest_cnt) == 1 && xen_test_irq_pending(irq)) {
                xen_clear_irq_pending(irq);
        } else if (READ_ONCE(*byte) == val) {
                /* Block until irq becomes pending (or a spurious wakeup) */
                xen_poll_irq(irq);
        }
 
-       local_irq_restore(flags);
+       atomic_dec(nest_cnt);
 }
 
 static irqreturn_t dummy_handler(int irq, void *dev_id)
index d5368a4..a50d592 100644 (file)
@@ -1260,6 +1260,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
                if (ret)
                        goto cleanup;
        } else {
+               zero_fill_bio(bio);
                iov_iter_advance(iter, bio->bi_iter.bi_size);
        }
 
index 76f867e..e8b3bb9 100644 (file)
@@ -51,16 +51,12 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        if ((sector | nr_sects) & bs_mask)
                return -EINVAL;
 
-       while (nr_sects) {
-               unsigned int req_sects = nr_sects;
-               sector_t end_sect;
-
-               if (!req_sects)
-                       goto fail;
-               if (req_sects > UINT_MAX >> 9)
-                       req_sects = UINT_MAX >> 9;
+       if (!nr_sects)
+               return -EINVAL;
 
-               end_sect = sector + req_sects;
+       while (nr_sects) {
+               unsigned int req_sects = min_t(unsigned int, nr_sects,
+                               bio_allowed_max_sectors(q));
 
                bio = blk_next_bio(bio, 0, gfp_mask);
                bio->bi_iter.bi_sector = sector;
@@ -68,8 +64,8 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                bio_set_op_attrs(bio, op, 0);
 
                bio->bi_iter.bi_size = req_sects << 9;
+               sector += req_sects;
                nr_sects -= req_sects;
-               sector = end_sect;
 
                /*
                 * We can loop for a long time in here, if someone does
@@ -82,14 +78,6 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 
        *biop = bio;
        return 0;
-
-fail:
-       if (bio) {
-               submit_bio_wait(bio);
-               bio_put(bio);
-       }
-       *biop = NULL;
-       return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL(__blkdev_issue_discard);
 
@@ -161,7 +149,7 @@ static int __blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
                return -EOPNOTSUPP;
 
        /* Ensure that max_write_same_sectors doesn't overflow bi_size */
-       max_write_same_sectors = UINT_MAX >> 9;
+       max_write_same_sectors = bio_allowed_max_sectors(q);
 
        while (nr_sects) {
                bio = blk_next_bio(bio, 1, gfp_mask);
index 6b5ad27..e7696c4 100644 (file)
@@ -46,7 +46,7 @@ static inline bool bio_will_gap(struct request_queue *q,
                bio_get_first_bvec(prev_rq->bio, &pb);
        else
                bio_get_first_bvec(prev, &pb);
-       if (pb.bv_offset)
+       if (pb.bv_offset & queue_virt_boundary(q))
                return true;
 
        /*
@@ -90,7 +90,8 @@ static struct bio *blk_bio_discard_split(struct request_queue *q,
        /* Zero-sector (unknown) and one-sector granularities are the same.  */
        granularity = max(q->limits.discard_granularity >> 9, 1U);
 
-       max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
+       max_discard_sectors = min(q->limits.max_discard_sectors,
+                       bio_allowed_max_sectors(q));
        max_discard_sectors -= max_discard_sectors % granularity;
 
        if (unlikely(!max_discard_sectors)) {
index a1841b8..0089fef 100644 (file)
@@ -169,7 +169,7 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
 static inline bool __bvec_gap_to_prev(struct request_queue *q,
                struct bio_vec *bprv, unsigned int offset)
 {
-       return offset ||
+       return (offset & queue_virt_boundary(q)) ||
                ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
 }
 
@@ -396,6 +396,16 @@ static inline unsigned long blk_rq_deadline(struct request *rq)
 }
 
 /*
+ * The max size one bio can handle is UINT_MAX becasue bvec_iter.bi_size
+ * is defined as 'unsigned int', meantime it has to aligned to with logical
+ * block size which is the minimum accepted unit by hardware.
+ */
+static inline unsigned int bio_allowed_max_sectors(struct request_queue *q)
+{
+       return round_down(UINT_MAX, queue_logical_block_size(q)) >> 9;
+}
+
+/*
  * Internal io_context interface
  */
 void get_io_context(struct io_context *ioc);
index 10ecb23..4b1ff5b 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Renesas R-Car SATA driver
  *
  * Author: Vladimir Barinov <source@cogentembedded.com>
  * Copyright (C) 2013-2015 Cogent Embedded, Inc.
  * Copyright (C) 2013-2015 Renesas Solutions Corp.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
  */
 
 #include <linux/kernel.h>
index 56452ca..0ed4b20 100644 (file)
@@ -1919,6 +1919,7 @@ static int negotiate_mq(struct blkfront_info *info)
                              GFP_KERNEL);
        if (!info->rinfo) {
                xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
+               info->nr_rings = 0;
                return -ENOMEM;
        }
 
index ef0ca94..ff83e89 100644 (file)
@@ -210,6 +210,7 @@ static int of_fixed_factor_clk_remove(struct platform_device *pdev)
 {
        struct clk *clk = platform_get_drvdata(pdev);
 
+       of_clk_del_provider(pdev->dev.of_node);
        clk_unregister_fixed_factor(clk);
 
        return 0;
index c981159..792735d 100644 (file)
@@ -325,6 +325,7 @@ static struct clk_regmap axg_fclk_div2 = {
                .ops = &clk_regmap_gate_ops,
                .parent_names = (const char *[]){ "fclk_div2_div" },
                .num_parents = 1,
+               .flags = CLK_IS_CRITICAL,
        },
 };
 
@@ -349,6 +350,18 @@ static struct clk_regmap axg_fclk_div3 = {
                .ops = &clk_regmap_gate_ops,
                .parent_names = (const char *[]){ "fclk_div3_div" },
                .num_parents = 1,
+               /*
+                * FIXME:
+                * This clock, as fdiv2, is used by the SCPI FW and is required
+                * by the platform to operate correctly.
+                * Until the following condition are met, we need this clock to
+                * be marked as critical:
+                * a) The SCPI generic driver claims and enable all the clocks
+                *    it needs
+                * b) CCF has a clock hand-off mechanism to make the sure the
+                *    clock stays on until the proper driver comes along
+                */
+               .flags = CLK_IS_CRITICAL,
        },
 };
 
index 9309cfa..4ada966 100644 (file)
@@ -506,6 +506,18 @@ static struct clk_regmap gxbb_fclk_div3 = {
                .ops = &clk_regmap_gate_ops,
                .parent_names = (const char *[]){ "fclk_div3_div" },
                .num_parents = 1,
+               /*
+                * FIXME:
+                * This clock, as fdiv2, is used by the SCPI FW and is required
+                * by the platform to operate correctly.
+                * Until the following condition are met, we need this clock to
+                * be marked as critical:
+                * a) The SCPI generic driver claims and enable all the clocks
+                *    it needs
+                * b) CCF has a clock hand-off mechanism to make the sure the
+                *    clock stays on until the proper driver comes along
+                */
+               .flags = CLK_IS_CRITICAL,
        },
 };
 
index e4ca6a4..ef1b267 100644 (file)
@@ -265,7 +265,7 @@ static struct clk_fixed_factor cxo = {
        .div = 1,
        .hw.init = &(struct clk_init_data){
                .name = "cxo",
-               .parent_names = (const char *[]){ "xo_board" },
+               .parent_names = (const char *[]){ "xo-board" },
                .num_parents = 1,
                .ops = &clk_fixed_factor_ops,
        },
index a11f4ba..55c77e4 100644 (file)
@@ -620,4 +620,22 @@ config RISCV_TIMER
          is accessed via both the SBI and the rdcycle instruction.  This is
          required for all RISC-V systems.
 
+config CSKY_MP_TIMER
+       bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
+       depends on CSKY
+       select TIMER_OF
+       help
+         Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
+         system.
+         csky,mptimer is not only used in SMP system, it also could be used
+         single core system. It's not a mmio reg and it use mtcr/mfcr instruction.
+
+config GX6605S_TIMER
+       bool "Gx6605s SOC system timer driver" if COMPILE_TEST
+       depends on CSKY
+       select CLKSRC_MMIO
+       select TIMER_OF
+       help
+         This option enables support for gx6605s SOC's timer.
+
 endmenu
index e33b21d..dd91381 100644 (file)
@@ -79,3 +79,5 @@ obj-$(CONFIG_CLKSRC_ST_LPC)           += clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)             += numachip.o
 obj-$(CONFIG_ATCPIT100_TIMER)          += timer-atcpit100.o
 obj-$(CONFIG_RISCV_TIMER)              += riscv_timer.o
+obj-$(CONFIG_CSKY_MP_TIMER)            += timer-mp-csky.o
+obj-$(CONFIG_GX6605S_TIMER)            += timer-gx6605s.o
diff --git a/drivers/clocksource/timer-gx6605s.c b/drivers/clocksource/timer-gx6605s.c
new file mode 100644 (file)
index 0000000..80d0939
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+
+#include "timer-of.h"
+
+#define CLKSRC_OFFSET  0x40
+
+#define TIMER_STATUS   0x00
+#define TIMER_VALUE    0x04
+#define TIMER_CONTRL   0x10
+#define TIMER_CONFIG   0x20
+#define TIMER_DIV      0x24
+#define TIMER_INI      0x28
+
+#define GX6605S_STATUS_CLR     BIT(0)
+#define GX6605S_CONTRL_RST     BIT(0)
+#define GX6605S_CONTRL_START   BIT(1)
+#define GX6605S_CONFIG_EN      BIT(0)
+#define GX6605S_CONFIG_IRQ_EN  BIT(1)
+
+static irqreturn_t gx6605s_timer_interrupt(int irq, void *dev)
+{
+       struct clock_event_device *ce = dev;
+       void __iomem *base = timer_of_base(to_timer_of(ce));
+
+       writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS);
+
+       ce->event_handler(ce);
+
+       return IRQ_HANDLED;
+}
+
+static int gx6605s_timer_set_oneshot(struct clock_event_device *ce)
+{
+       void __iomem *base = timer_of_base(to_timer_of(ce));
+
+       /* reset and stop counter */
+       writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+       /* enable with irq and start */
+       writel_relaxed(GX6605S_CONFIG_EN | GX6605S_CONFIG_IRQ_EN,
+                      base + TIMER_CONFIG);
+
+       return 0;
+}
+
+static int gx6605s_timer_set_next_event(unsigned long delta,
+                                       struct clock_event_device *ce)
+{
+       void __iomem *base = timer_of_base(to_timer_of(ce));
+
+       /* use reset to pause timer */
+       writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+       /* config next timeout value */
+       writel_relaxed(ULONG_MAX - delta, base + TIMER_INI);
+       writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
+
+       return 0;
+}
+
+static int gx6605s_timer_shutdown(struct clock_event_device *ce)
+{
+       void __iomem *base = timer_of_base(to_timer_of(ce));
+
+       writel_relaxed(0, base + TIMER_CONTRL);
+       writel_relaxed(0, base + TIMER_CONFIG);
+
+       return 0;
+}
+
+static struct timer_of to = {
+       .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
+       .clkevt = {
+               .rating                 = 300,
+               .features               = CLOCK_EVT_FEAT_DYNIRQ |
+                                         CLOCK_EVT_FEAT_ONESHOT,
+               .set_state_shutdown     = gx6605s_timer_shutdown,
+               .set_state_oneshot      = gx6605s_timer_set_oneshot,
+               .set_next_event         = gx6605s_timer_set_next_event,
+               .cpumask                = cpu_possible_mask,
+       },
+       .of_irq = {
+               .handler                = gx6605s_timer_interrupt,
+               .flags                  = IRQF_TIMER | IRQF_IRQPOLL,
+       },
+};
+
+static u64 notrace gx6605s_sched_clock_read(void)
+{
+       void __iomem *base;
+
+       base = timer_of_base(&to) + CLKSRC_OFFSET;
+
+       return (u64)readl_relaxed(base + TIMER_VALUE);
+}
+
+static void gx6605s_clkevt_init(void __iomem *base)
+{
+       writel_relaxed(0, base + TIMER_DIV);
+       writel_relaxed(0, base + TIMER_CONFIG);
+
+       clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 2,
+                                       ULONG_MAX);
+}
+
+static int gx6605s_clksrc_init(void __iomem *base)
+{
+       writel_relaxed(0, base + TIMER_DIV);
+       writel_relaxed(0, base + TIMER_INI);
+
+       writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+       writel_relaxed(GX6605S_CONFIG_EN, base + TIMER_CONFIG);
+
+       writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
+
+       sched_clock_register(gx6605s_sched_clock_read, 32, timer_of_rate(&to));
+
+       return clocksource_mmio_init(base + TIMER_VALUE, "gx6605s",
+                       timer_of_rate(&to), 200, 32, clocksource_mmio_readl_up);
+}
+
+static int __init gx6605s_timer_init(struct device_node *np)
+{
+       int ret;
+
+       /*
+        * The timer driver is for nationalchip gx6605s SOC and there are two
+        * same timer in gx6605s. We use one for clkevt and another for clksrc.
+        *
+        * The timer is mmio map to access, so we need give mmio address in dts.
+        *
+        * It provides a 32bit countup timer and interrupt will be caused by
+        * count-overflow.
+        * So we need set-next-event by ULONG_MAX - delta in TIMER_INI reg.
+        *
+        * The counter at 0x0  offset is clock event.
+        * The counter at 0x40 offset is clock source.
+        * They are the same in hardware, just different used by driver.
+        */
+       ret = timer_of_init(np, &to);
+       if (ret)
+               return ret;
+
+       gx6605s_clkevt_init(timer_of_base(&to));
+
+       return gx6605s_clksrc_init(timer_of_base(&to) + CLKSRC_OFFSET);
+}
+TIMER_OF_DECLARE(csky_gx6605s_timer, "csky,gx6605s-timer", gx6605s_timer_init);
diff --git a/drivers/clocksource/timer-mp-csky.c b/drivers/clocksource/timer-mp-csky.c
new file mode 100644 (file)
index 0000000..a8acc43
--- /dev/null
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+#include <linux/cpu.h>
+#include <linux/of_irq.h>
+#include <asm/reg_ops.h>
+
+#include "timer-of.h"
+
+#define PTIM_CCVR      "cr<3, 14>"
+#define PTIM_CTLR      "cr<0, 14>"
+#define PTIM_LVR       "cr<6, 14>"
+#define PTIM_TSR       "cr<1, 14>"
+
+static int csky_mptimer_irq;
+
+static int csky_mptimer_set_next_event(unsigned long delta,
+                                      struct clock_event_device *ce)
+{
+       mtcr(PTIM_LVR, delta);
+
+       return 0;
+}
+
+static int csky_mptimer_shutdown(struct clock_event_device *ce)
+{
+       mtcr(PTIM_CTLR, 0);
+
+       return 0;
+}
+
+static int csky_mptimer_oneshot(struct clock_event_device *ce)
+{
+       mtcr(PTIM_CTLR, 1);
+
+       return 0;
+}
+
+static int csky_mptimer_oneshot_stopped(struct clock_event_device *ce)
+{
+       mtcr(PTIM_CTLR, 0);
+
+       return 0;
+}
+
+static DEFINE_PER_CPU(struct timer_of, csky_to) = {
+       .flags                                  = TIMER_OF_CLOCK,
+       .clkevt = {
+               .rating                         = 300,
+               .features                       = CLOCK_EVT_FEAT_PERCPU |
+                                                 CLOCK_EVT_FEAT_ONESHOT,
+               .set_state_shutdown             = csky_mptimer_shutdown,
+               .set_state_oneshot              = csky_mptimer_oneshot,
+               .set_state_oneshot_stopped      = csky_mptimer_oneshot_stopped,
+               .set_next_event                 = csky_mptimer_set_next_event,
+       },
+};
+
+static irqreturn_t csky_timer_interrupt(int irq, void *dev)
+{
+       struct timer_of *to = this_cpu_ptr(&csky_to);
+
+       mtcr(PTIM_TSR, 0);
+
+       to->clkevt.event_handler(&to->clkevt);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * clock event for percpu
+ */
+static int csky_mptimer_starting_cpu(unsigned int cpu)
+{
+       struct timer_of *to = per_cpu_ptr(&csky_to, cpu);
+
+       to->clkevt.cpumask = cpumask_of(cpu);
+
+       clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
+                                       2, ULONG_MAX);
+
+       enable_percpu_irq(csky_mptimer_irq, 0);
+
+       return 0;
+}
+
+static int csky_mptimer_dying_cpu(unsigned int cpu)
+{
+       disable_percpu_irq(csky_mptimer_irq);
+
+       return 0;
+}
+
+/*
+ * clock source
+ */
+static u64 sched_clock_read(void)
+{
+       return (u64)mfcr(PTIM_CCVR);
+}
+
+static u64 clksrc_read(struct clocksource *c)
+{
+       return (u64)mfcr(PTIM_CCVR);
+}
+
+struct clocksource csky_clocksource = {
+       .name   = "csky",
+       .rating = 400,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .read   = clksrc_read,
+};
+
+static int __init csky_mptimer_init(struct device_node *np)
+{
+       int ret, cpu, cpu_rollback;
+       struct timer_of *to = NULL;
+
+       /*
+        * Csky_mptimer is designed for C-SKY SMP multi-processors and
+        * every core has it's own private irq and regs for clkevt and
+        * clksrc.
+        *
+        * The regs is accessed by cpu instruction: mfcr/mtcr instead of
+        * mmio map style. So we needn't mmio-address in dts, but we still
+        * need to give clk and irq number.
+        *
+        * We use private irq for the mptimer and irq number is the same
+        * for every core. So we use request_percpu_irq() in timer_of_init.
+        */
+       csky_mptimer_irq = irq_of_parse_and_map(np, 0);
+       if (csky_mptimer_irq <= 0)
+               return -EINVAL;
+
+       ret = request_percpu_irq(csky_mptimer_irq, csky_timer_interrupt,
+                                "csky_mp_timer", &csky_to);
+       if (ret)
+               return -EINVAL;
+
+       for_each_possible_cpu(cpu) {
+               to = per_cpu_ptr(&csky_to, cpu);
+               ret = timer_of_init(np, to);
+               if (ret)
+                       goto rollback;
+       }
+
+       clocksource_register_hz(&csky_clocksource, timer_of_rate(to));
+       sched_clock_register(sched_clock_read, 32, timer_of_rate(to));
+
+       ret = cpuhp_setup_state(CPUHP_AP_CSKY_TIMER_STARTING,
+                               "clockevents/csky/timer:starting",
+                               csky_mptimer_starting_cpu,
+                               csky_mptimer_dying_cpu);
+       if (ret)
+               return -EINVAL;
+
+       return 0;
+
+rollback:
+       for_each_possible_cpu(cpu_rollback) {
+               if (cpu_rollback == cpu)
+                       break;
+
+               to = per_cpu_ptr(&csky_to, cpu_rollback);
+               timer_of_cleanup(to);
+       }
+       return -EINVAL;
+}
+TIMER_OF_DECLARE(csky_mptimer, "csky,mptimer", csky_mptimer_init);
index d0102cf..104b2e0 100644 (file)
@@ -151,6 +151,7 @@ extern int amdgpu_compute_multipipe;
 extern int amdgpu_gpu_recovery;
 extern int amdgpu_emu_mode;
 extern uint amdgpu_smu_memory_pool_size;
+extern uint amdgpu_dc_feature_mask;
 extern struct amdgpu_mgpu_info mgpu_info;
 
 #ifdef CONFIG_DRM_AMDGPU_SI
index 943dbf3..8de55f7 100644 (file)
@@ -127,6 +127,9 @@ int amdgpu_compute_multipipe = -1;
 int amdgpu_gpu_recovery = -1; /* auto */
 int amdgpu_emu_mode = 0;
 uint amdgpu_smu_memory_pool_size = 0;
+/* FBC (bit 0) disabled by default*/
+uint amdgpu_dc_feature_mask = 0;
+
 struct amdgpu_mgpu_info mgpu_info = {
        .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
 };
@@ -631,6 +634,14 @@ module_param(halt_if_hws_hang, int, 0644);
 MODULE_PARM_DESC(halt_if_hws_hang, "Halt if HWS hang is detected (0 = off (default), 1 = on)");
 #endif
 
+/**
+ * DOC: dcfeaturemask (uint)
+ * Override display features enabled. See enum DC_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h.
+ * The default is the current set of stable display features.
+ */
+MODULE_PARM_DESC(dcfeaturemask, "all stable DC features enabled (default))");
+module_param_named(dcfeaturemask, amdgpu_dc_feature_mask, uint, 0444);
+
 static const struct pci_device_id pciidlist[] = {
 #ifdef  CONFIG_DRM_AMDGPU_SI
        {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
index 2d44735..d13fc4f 100644 (file)
@@ -49,6 +49,7 @@ int vega20_reg_base_init(struct amdgpu_device *adev)
                adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i]));
                adev->reg_offset[NBIF_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i]));
                adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i]));
+               adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i]));
        }
        return 0;
 }
index b0df6dc..c1262f6 100644 (file)
@@ -429,6 +429,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
            adev->asic_type < CHIP_RAVEN)
                init_data.flags.gpu_vm_support = true;
 
+       if (amdgpu_dc_feature_mask & DC_FBC_MASK)
+               init_data.flags.fbc_support = true;
+
        /* Display Core create. */
        adev->dm.dc = dc_create(&init_data);
 
@@ -1524,13 +1527,6 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
 {
        struct amdgpu_display_manager *dm = bl_get_data(bd);
 
-       /*
-        * PWM interperts 0 as 100% rather than 0% because of HW
-        * limitation for level 0.So limiting minimum brightness level
-        * to 1.
-        */
-       if (bd->props.brightness < 1)
-               return 1;
        if (dc_link_set_backlight_level(dm->backlight_link,
                        bd->props.brightness, 0, 0))
                return 0;
@@ -2707,18 +2703,11 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        drm_connector = &aconnector->base;
 
        if (!aconnector->dc_sink) {
-               /*
-                * Create dc_sink when necessary to MST
-                * Don't apply fake_sink to MST
-                */
-               if (aconnector->mst_port) {
-                       dm_dp_mst_dc_sink_create(drm_connector);
-                       return stream;
+               if (!aconnector->mst_port) {
+                       sink = create_fake_sink(aconnector);
+                       if (!sink)
+                               return stream;
                }
-
-               sink = create_fake_sink(aconnector);
-               if (!sink)
-                       return stream;
        } else {
                sink = aconnector->dc_sink;
        }
@@ -3308,7 +3297,7 @@ void dm_drm_plane_destroy_state(struct drm_plane *plane,
 static const struct drm_plane_funcs dm_plane_funcs = {
        .update_plane   = drm_atomic_helper_update_plane,
        .disable_plane  = drm_atomic_helper_disable_plane,
-       .destroy        = drm_plane_cleanup,
+       .destroy        = drm_primary_helper_destroy,
        .reset = dm_drm_plane_reset,
        .atomic_duplicate_state = dm_drm_plane_duplicate_state,
        .atomic_destroy_state = dm_drm_plane_destroy_state,
index 978b34a..924a38a 100644 (file)
@@ -160,8 +160,6 @@ struct amdgpu_dm_connector {
        struct mutex hpd_lock;
 
        bool fake_enable;
-
-       bool mst_connected;
 };
 
 #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base)
index 03601d7..d02c32a 100644 (file)
@@ -205,40 +205,6 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
        .atomic_get_property = amdgpu_dm_connector_atomic_get_property
 };
 
-void dm_dp_mst_dc_sink_create(struct drm_connector *connector)
-{
-       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       struct dc_sink *dc_sink;
-       struct dc_sink_init_data init_params = {
-                       .link = aconnector->dc_link,
-                       .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
-
-       /* FIXME none of this is safe. we shouldn't touch aconnector here in
-        * atomic_check
-        */
-
-       /*
-        * TODO: Need to further figure out why ddc.algo is NULL while MST port exists
-        */
-       if (!aconnector->port || !aconnector->port->aux.ddc.algo)
-               return;
-
-       ASSERT(aconnector->edid);
-
-       dc_sink = dc_link_add_remote_sink(
-               aconnector->dc_link,
-               (uint8_t *)aconnector->edid,
-               (aconnector->edid->extensions + 1) * EDID_LENGTH,
-               &init_params);
-
-       dc_sink->priv = aconnector;
-       aconnector->dc_sink = dc_sink;
-
-       if (aconnector->dc_sink)
-               amdgpu_dm_update_freesync_caps(
-                               connector, aconnector->edid);
-}
-
 static int dm_dp_mst_get_modes(struct drm_connector *connector)
 {
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
@@ -319,12 +285,7 @@ dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_encoder *amdgpu_encoder;
        struct drm_encoder *encoder;
-       const struct drm_connector_helper_funcs *connector_funcs =
-               connector->base.helper_private;
-       struct drm_encoder *enc_master =
-               connector_funcs->best_encoder(&connector->base);
 
-       DRM_DEBUG_KMS("enc master is %p\n", enc_master);
        amdgpu_encoder = kzalloc(sizeof(*amdgpu_encoder), GFP_KERNEL);
        if (!amdgpu_encoder)
                return NULL;
@@ -354,25 +315,6 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_dm_connector *aconnector;
        struct drm_connector *connector;
-       struct drm_connector_list_iter conn_iter;
-
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       drm_for_each_connector_iter(connector, &conn_iter) {
-               aconnector = to_amdgpu_dm_connector(connector);
-               if (aconnector->mst_port == master
-                               && !aconnector->port) {
-                       DRM_INFO("DM_MST: reusing connector: %p [id: %d] [master: %p]\n",
-                                               aconnector, connector->base.id, aconnector->mst_port);
-
-                       aconnector->port = port;
-                       drm_connector_set_path_property(connector, pathprop);
-
-                       drm_connector_list_iter_end(&conn_iter);
-                       aconnector->mst_connected = true;
-                       return &aconnector->base;
-               }
-       }
-       drm_connector_list_iter_end(&conn_iter);
 
        aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
        if (!aconnector)
@@ -421,8 +363,6 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
         */
        amdgpu_dm_connector_funcs_reset(connector);
 
-       aconnector->mst_connected = true;
-
        DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
                        aconnector, connector->base.id, aconnector->mst_port);
 
@@ -434,6 +374,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
                                        struct drm_connector *connector)
 {
+       struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+       struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
 
        DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
@@ -447,7 +390,10 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
                aconnector->dc_sink = NULL;
        }
 
-       aconnector->mst_connected = false;
+       drm_connector_unregister(connector);
+       if (adev->mode_info.rfbdev)
+               drm_fb_helper_remove_one_connector(&adev->mode_info.rfbdev->helper, connector);
+       drm_connector_put(connector);
 }
 
 static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
@@ -458,18 +404,10 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
        drm_kms_helper_hotplug_event(dev);
 }
 
-static void dm_dp_mst_link_status_reset(struct drm_connector *connector)
-{
-       mutex_lock(&connector->dev->mode_config.mutex);
-       drm_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD);
-       mutex_unlock(&connector->dev->mode_config.mutex);
-}
-
 static void dm_dp_mst_register_connector(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct amdgpu_device *adev = dev->dev_private;
-       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
 
        if (adev->mode_info.rfbdev)
                drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector);
@@ -477,9 +415,6 @@ static void dm_dp_mst_register_connector(struct drm_connector *connector)
                DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
 
        drm_connector_register(connector);
-
-       if (aconnector->mst_connected)
-               dm_dp_mst_link_status_reset(connector);
 }
 
 static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
index 8cf51da..2da851b 100644 (file)
@@ -31,6 +31,5 @@ struct amdgpu_dm_connector;
 
 void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
                                       struct amdgpu_dm_connector *aconnector);
-void dm_dp_mst_dc_sink_create(struct drm_connector *connector);
 
 #endif
index fb04a4a..5da2186 100644 (file)
@@ -1722,7 +1722,7 @@ static void write_i2c_retimer_setting(
                i2c_success = i2c_write(pipe_ctx, slave_address,
                                buffer, sizeof(buffer));
                RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
-                       offset = 0x%d, reg_val = 0x%d, i2c_success = %d\n",
+                       offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
                        slave_address, buffer[0], buffer[1], i2c_success?1:0);
                if (!i2c_success)
                        /* Write failure */
@@ -1734,7 +1734,7 @@ static void write_i2c_retimer_setting(
                i2c_success = i2c_write(pipe_ctx, slave_address,
                                buffer, sizeof(buffer));
                RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
-                       offset = 0x%d, reg_val = 0x%d, i2c_success = %d\n",
+                       offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
                        slave_address, buffer[0], buffer[1], i2c_success?1:0);
                if (!i2c_success)
                        /* Write failure */
index 1995271..b57fa61 100644 (file)
@@ -169,6 +169,7 @@ struct link_training_settings;
 struct dc_config {
        bool gpu_vm_support;
        bool disable_disp_pll_sharing;
+       bool fbc_support;
 };
 
 enum visual_confirm {
index b75ede5..b459867 100644 (file)
@@ -1736,7 +1736,12 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
        if (events->force_trigger)
                value |= 0x1;
 
-       value |= 0x84;
+       if (num_pipes) {
+               struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
+
+               if (dc->fbc_compressor)
+                       value |= 0x84;
+       }
 
        for (i = 0; i < num_pipes; i++)
                pipe_ctx[i]->stream_res.tg->funcs->
index e3624ca..7c9fd90 100644 (file)
@@ -1362,7 +1362,8 @@ static bool construct(
                pool->base.sw_i2cs[i] = NULL;
        }
 
-       dc->fbc_compressor = dce110_compressor_create(ctx);
+       if (dc->config.fbc_support)
+               dc->fbc_compressor = dce110_compressor_create(ctx);
 
        if (!underlay_create(ctx, &pool->base))
                goto res_create_fail;
index 2083c30..470d7b8 100644 (file)
@@ -133,6 +133,10 @@ enum PP_FEATURE_MASK {
        PP_AVFS_MASK = 0x40000,
 };
 
+enum DC_FEATURE_MASK {
+       DC_FBC_MASK = 0x1,
+};
+
 /**
  * struct amd_ip_funcs - general hooks for managing amdgpu IP Blocks
  */
index d2e7c0f..8eb0bb2 100644 (file)
@@ -1325,7 +1325,7 @@ struct atom_smu_info_v3_3 {
   struct   atom_common_table_header  table_header;
   uint8_t  smuip_min_ver;
   uint8_t  smuip_max_ver;
-  uint8_t  smu_rsd1;
+  uint8_t  waflclk_ss_mode;
   uint8_t  gpuclk_ss_mode;
   uint16_t sclk_ss_percentage;
   uint16_t sclk_ss_rate_10hz;
@@ -1355,7 +1355,10 @@ struct atom_smu_info_v3_3 {
   uint32_t syspll3_1_vco_freq_10khz;
   uint32_t bootup_fclk_10khz;
   uint32_t bootup_waflclk_10khz;
-  uint32_t reserved[3];
+  uint32_t smu_info_caps;
+  uint16_t waflclk_ss_percentage;    // in unit of 0.001%
+  uint16_t smuinitoffset;
+  uint32_t reserved;
 };
 
 /*
index 57143d5..99861f3 100644 (file)
@@ -120,6 +120,7 @@ static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
        data->registry_data.disable_auto_wattman = 1;
        data->registry_data.auto_wattman_debug = 0;
        data->registry_data.auto_wattman_sample_period = 100;
+       data->registry_data.fclk_gfxclk_ratio = 0x3F6CCCCD;
        data->registry_data.auto_wattman_threshold = 50;
        data->registry_data.gfxoff_controlled_by_driver = 1;
        data->gfxoff_allowed = false;
@@ -829,6 +830,28 @@ static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
        return 0;
 }
 
+static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr)
+{
+       struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
+
+       if (data->smu_features[GNLD_DPM_UCLK].enabled)
+               return smum_send_msg_to_smc_with_parameter(hwmgr,
+                       PPSMC_MSG_SetUclkFastSwitch,
+                       1);
+
+       return 0;
+}
+
+static int vega20_send_clock_ratio(struct pp_hwmgr *hwmgr)
+{
+       struct vega20_hwmgr *data =
+                       (struct vega20_hwmgr *)(hwmgr->backend);
+
+       return smum_send_msg_to_smc_with_parameter(hwmgr,
+                       PPSMC_MSG_SetFclkGfxClkRatio,
+                       data->registry_data.fclk_gfxclk_ratio);
+}
+
 static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
 {
        struct vega20_hwmgr *data =
@@ -1532,6 +1555,16 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
                        "[EnableDPMTasks] Failed to enable all smu features!",
                        return result);
 
+       result = vega20_notify_smc_display_change(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+                       "[EnableDPMTasks] Failed to notify smc display change!",
+                       return result);
+
+       result = vega20_send_clock_ratio(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+                       "[EnableDPMTasks] Failed to send clock ratio!",
+                       return result);
+
        /* Initialize UVD/VCE powergating state */
        vega20_init_powergate_state(hwmgr);
 
@@ -1972,19 +2005,6 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
        return ret;
 }
 
-static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr,
-               bool has_disp)
-{
-       struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
-
-       if (data->smu_features[GNLD_DPM_UCLK].enabled)
-               return smum_send_msg_to_smc_with_parameter(hwmgr,
-                       PPSMC_MSG_SetUclkFastSwitch,
-                       has_disp ? 1 : 0);
-
-       return 0;
-}
-
 int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
                struct pp_display_clock_request *clock_req)
 {
@@ -2044,13 +2064,6 @@ static int vega20_notify_smc_display_config_after_ps_adjustment(
        struct pp_display_clock_request clock_req;
        int ret = 0;
 
-       if ((hwmgr->display_config->num_display > 1) &&
-            !hwmgr->display_config->multi_monitor_in_sync &&
-            !hwmgr->display_config->nb_pstate_switch_disable)
-               vega20_notify_smc_display_change(hwmgr, false);
-       else
-               vega20_notify_smc_display_change(hwmgr, true);
-
        min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
        min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
        min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
index 56fe6a0..25faaa5 100644 (file)
@@ -328,6 +328,7 @@ struct vega20_registry_data {
        uint8_t   disable_auto_wattman;
        uint32_t  auto_wattman_debug;
        uint32_t  auto_wattman_sample_period;
+       uint32_t  fclk_gfxclk_ratio;
        uint8_t   auto_wattman_threshold;
        uint8_t   log_avfs_param;
        uint8_t   enable_enginess;
index 45d64a8..4f63a73 100644 (file)
 #define PPSMC_MSG_SetSystemVirtualDramAddrHigh   0x4B
 #define PPSMC_MSG_SetSystemVirtualDramAddrLow    0x4C
 #define PPSMC_MSG_WaflTest                       0x4D
-// Unused ID 0x4E to 0x50
+#define PPSMC_MSG_SetFclkGfxClkRatio             0x4E
+// Unused ID 0x4F to 0x50
 #define PPSMC_MSG_AllowGfxOff                    0x51
 #define PPSMC_MSG_DisallowGfxOff                 0x52
 #define PPSMC_MSG_GetPptLimit                    0x53
index e7c3ed6..9b47636 100644 (file)
@@ -93,7 +93,7 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
         * If the GPU managed to complete this jobs fence, the timout is
         * spurious. Bail out.
         */
-       if (fence_completed(gpu, submit->out_fence->seqno))
+       if (dma_fence_is_signaled(submit->out_fence))
                return;
 
        /*
index 94529aa..aef487d 100644 (file)
@@ -164,13 +164,6 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
        return frm;
 }
 
-static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc)
-{
-       struct decon_context *ctx = crtc->ctx;
-
-       return decon_get_frame_count(ctx, false);
-}
-
 static void decon_setup_trigger(struct decon_context *ctx)
 {
        if (!ctx->crtc->i80_mode && !(ctx->out_type & I80_HW_TRG))
@@ -536,7 +529,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
        .disable                = decon_disable,
        .enable_vblank          = decon_enable_vblank,
        .disable_vblank         = decon_disable_vblank,
-       .get_vblank_counter     = decon_get_vblank_counter,
        .atomic_begin           = decon_atomic_begin,
        .update_plane           = decon_update_plane,
        .disable_plane          = decon_disable_plane,
@@ -554,7 +546,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
        int ret;
 
        ctx->drm_dev = drm_dev;
-       drm_dev->max_vblank_count = 0xffffffff;
 
        for (win = ctx->first_win; win < WINDOWS_NR; win++) {
                ctx->configs[win].pixel_formats = decon_formats;
index eea9025..2696289 100644 (file)
@@ -162,16 +162,6 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
                exynos_crtc->ops->disable_vblank(exynos_crtc);
 }
 
-static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc)
-{
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
-       if (exynos_crtc->ops->get_vblank_counter)
-               return exynos_crtc->ops->get_vblank_counter(exynos_crtc);
-
-       return 0;
-}
-
 static const struct drm_crtc_funcs exynos_crtc_funcs = {
        .set_config     = drm_atomic_helper_set_config,
        .page_flip      = drm_atomic_helper_page_flip,
@@ -181,7 +171,6 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = {
        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
        .enable_vblank = exynos_drm_crtc_enable_vblank,
        .disable_vblank = exynos_drm_crtc_disable_vblank,
-       .get_vblank_counter = exynos_drm_crtc_get_vblank_counter,
 };
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
index ec9604f..5e61e70 100644 (file)
@@ -135,7 +135,6 @@ struct exynos_drm_crtc_ops {
        void (*disable)(struct exynos_drm_crtc *crtc);
        int (*enable_vblank)(struct exynos_drm_crtc *crtc);
        void (*disable_vblank)(struct exynos_drm_crtc *crtc);
-       u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc);
        enum drm_mode_status (*mode_valid)(struct exynos_drm_crtc *crtc,
                const struct drm_display_mode *mode);
        bool (*mode_fixup)(struct exynos_drm_crtc *crtc,
index 07af775..d81e62a 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_atomic_helper.h>
@@ -1474,12 +1475,12 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
 {
        struct exynos_dsi *dsi = encoder_to_dsi(encoder);
        struct drm_connector *connector = &dsi->connector;
+       struct drm_device *drm = encoder->dev;
        int ret;
 
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
-       ret = drm_connector_init(encoder->dev, connector,
-                                &exynos_dsi_connector_funcs,
+       ret = drm_connector_init(drm, connector, &exynos_dsi_connector_funcs,
                                 DRM_MODE_CONNECTOR_DSI);
        if (ret) {
                DRM_ERROR("Failed to initialize connector with drm\n");
@@ -1489,7 +1490,12 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
        connector->status = connector_status_disconnected;
        drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
        drm_connector_attach_encoder(connector, encoder);
+       if (!drm->registered)
+               return 0;
 
+       connector->funcs->reset(connector);
+       drm_fb_helper_add_one_connector(drm->fb_helper, connector);
+       drm_connector_register(connector);
        return 0;
 }
 
@@ -1527,7 +1533,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
                }
 
                dsi->panel = of_drm_find_panel(device->dev.of_node);
-               if (dsi->panel) {
+               if (IS_ERR(dsi->panel)) {
+                       dsi->panel = NULL;
+               } else {
                        drm_panel_attach(dsi->panel, &dsi->connector);
                        dsi->connector.status = connector_status_connected;
                }
index 918dd2c..01d1822 100644 (file)
@@ -192,7 +192,7 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
        struct drm_fb_helper *helper;
        int ret;
 
-       if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
+       if (!dev->mode_config.num_crtc)
                return 0;
 
        fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
index 2402395..58e166e 100644 (file)
@@ -1905,7 +1905,6 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
                vgpu_free_mm(mm);
                return ERR_PTR(-ENOMEM);
        }
-       mm->ggtt_mm.last_partial_off = -1UL;
 
        return mm;
 }
@@ -1930,7 +1929,6 @@ void _intel_vgpu_mm_release(struct kref *mm_ref)
                invalidate_ppgtt_mm(mm);
        } else {
                vfree(mm->ggtt_mm.virtual_ggtt);
-               mm->ggtt_mm.last_partial_off = -1UL;
        }
 
        vgpu_free_mm(mm);
@@ -2168,6 +2166,8 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
        struct intel_gvt_gtt_entry e, m;
        dma_addr_t dma_addr;
        int ret;
+       struct intel_gvt_partial_pte *partial_pte, *pos, *n;
+       bool partial_update = false;
 
        if (bytes != 4 && bytes != 8)
                return -EINVAL;
@@ -2178,68 +2178,57 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
        if (!vgpu_gmadr_is_valid(vgpu, gma))
                return 0;
 
-       ggtt_get_guest_entry(ggtt_mm, &e, g_gtt_index);
-
+       e.type = GTT_TYPE_GGTT_PTE;
        memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
                        bytes);
 
        /* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
-        * write, we assume the two 4 bytes writes are consecutive.
-        * Otherwise, we abort and report error
+        * write, save the first 4 bytes in a list and update virtual
+        * PTE. Only update shadow PTE when the second 4 bytes comes.
         */
        if (bytes < info->gtt_entry_size) {
-               if (ggtt_mm->ggtt_mm.last_partial_off == -1UL) {
-                       /* the first partial part*/
-                       ggtt_mm->ggtt_mm.last_partial_off = off;
-                       ggtt_mm->ggtt_mm.last_partial_data = e.val64;
-                       return 0;
-               } else if ((g_gtt_index ==
-                               (ggtt_mm->ggtt_mm.last_partial_off >>
-                               info->gtt_entry_size_shift)) &&
-                       (off != ggtt_mm->ggtt_mm.last_partial_off)) {
-                       /* the second partial part */
-
-                       int last_off = ggtt_mm->ggtt_mm.last_partial_off &
-                               (info->gtt_entry_size - 1);
-
-                       memcpy((void *)&e.val64 + last_off,
-                               (void *)&ggtt_mm->ggtt_mm.last_partial_data +
-                               last_off, bytes);
-
-                       ggtt_mm->ggtt_mm.last_partial_off = -1UL;
-               } else {
-                       int last_offset;
-
-                       gvt_vgpu_err("failed to populate guest ggtt entry: abnormal ggtt entry write sequence, last_partial_off=%lx, offset=%x, bytes=%d, ggtt entry size=%d\n",
-                                       ggtt_mm->ggtt_mm.last_partial_off, off,
-                                       bytes, info->gtt_entry_size);
-
-                       /* set host ggtt entry to scratch page and clear
-                        * virtual ggtt entry as not present for last
-                        * partially write offset
-                        */
-                       last_offset = ggtt_mm->ggtt_mm.last_partial_off &
-                                       (~(info->gtt_entry_size - 1));
-
-                       ggtt_get_host_entry(ggtt_mm, &m, last_offset);
-                       ggtt_invalidate_pte(vgpu, &m);
-                       ops->set_pfn(&m, gvt->gtt.scratch_mfn);
-                       ops->clear_present(&m);
-                       ggtt_set_host_entry(ggtt_mm, &m, last_offset);
-                       ggtt_invalidate(gvt->dev_priv);
-
-                       ggtt_get_guest_entry(ggtt_mm, &e, last_offset);
-                       ops->clear_present(&e);
-                       ggtt_set_guest_entry(ggtt_mm, &e, last_offset);
-
-                       ggtt_mm->ggtt_mm.last_partial_off = off;
-                       ggtt_mm->ggtt_mm.last_partial_data = e.val64;
+               bool found = false;
+
+               list_for_each_entry_safe(pos, n,
+                               &ggtt_mm->ggtt_mm.partial_pte_list, list) {
+                       if (g_gtt_index == pos->offset >>
+                                       info->gtt_entry_size_shift) {
+                               if (off != pos->offset) {
+                                       /* the second partial part*/
+                                       int last_off = pos->offset &
+                                               (info->gtt_entry_size - 1);
+
+                                       memcpy((void *)&e.val64 + last_off,
+                                               (void *)&pos->data + last_off,
+                                               bytes);
+
+                                       list_del(&pos->list);
+                                       kfree(pos);
+                                       found = true;
+                                       break;
+                               }
+
+                               /* update of the first partial part */
+                               pos->data = e.val64;
+                               ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
+                               return 0;
+                       }
+               }
 
-                       return 0;
+               if (!found) {
+                       /* the first partial part */
+                       partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
+                       if (!partial_pte)
+                               return -ENOMEM;
+                       partial_pte->offset = off;
+                       partial_pte->data = e.val64;
+                       list_add_tail(&partial_pte->list,
+                               &ggtt_mm->ggtt_mm.partial_pte_list);
+                       partial_update = true;
                }
        }
 
-       if (ops->test_present(&e)) {
+       if (!partial_update && (ops->test_present(&e))) {
                gfn = ops->get_pfn(&e);
                m = e;
 
@@ -2263,16 +2252,18 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
                } else
                        ops->set_pfn(&m, dma_addr >> PAGE_SHIFT);
        } else {
-               ggtt_get_host_entry(ggtt_mm, &m, g_gtt_index);
-               ggtt_invalidate_pte(vgpu, &m);
                ops->set_pfn(&m, gvt->gtt.scratch_mfn);
                ops->clear_present(&m);
        }
 
 out:
+       ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
+
+       ggtt_get_host_entry(ggtt_mm, &e, g_gtt_index);
+       ggtt_invalidate_pte(vgpu, &e);
+
        ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index);
        ggtt_invalidate(gvt->dev_priv);
-       ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
        return 0;
 }
 
@@ -2430,6 +2421,8 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
 
        intel_vgpu_reset_ggtt(vgpu, false);
 
+       INIT_LIST_HEAD(&gtt->ggtt_mm->ggtt_mm.partial_pte_list);
+
        return create_scratch_page_tree(vgpu);
 }
 
@@ -2454,6 +2447,14 @@ static void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
 
 static void intel_vgpu_destroy_ggtt_mm(struct intel_vgpu *vgpu)
 {
+       struct intel_gvt_partial_pte *pos;
+
+       list_for_each_entry(pos,
+                       &vgpu->gtt.ggtt_mm->ggtt_mm.partial_pte_list, list) {
+               gvt_dbg_mm("partial PTE update on hold 0x%lx : 0x%llx\n",
+                       pos->offset, pos->data);
+               kfree(pos);
+       }
        intel_vgpu_destroy_mm(vgpu->gtt.ggtt_mm);
        vgpu->gtt.ggtt_mm = NULL;
 }
index 7a9b361..d8cb04c 100644 (file)
@@ -35,7 +35,6 @@
 #define _GVT_GTT_H_
 
 #define I915_GTT_PAGE_SHIFT         12
-#define I915_GTT_PAGE_MASK             (~(I915_GTT_PAGE_SIZE - 1))
 
 struct intel_vgpu_mm;
 
@@ -133,6 +132,12 @@ enum intel_gvt_mm_type {
 
 #define GVT_RING_CTX_NR_PDPS   GEN8_3LVL_PDPES
 
+struct intel_gvt_partial_pte {
+       unsigned long offset;
+       u64 data;
+       struct list_head list;
+};
+
 struct intel_vgpu_mm {
        enum intel_gvt_mm_type type;
        struct intel_vgpu *vgpu;
@@ -157,8 +162,7 @@ struct intel_vgpu_mm {
                } ppgtt_mm;
                struct {
                        void *virtual_ggtt;
-                       unsigned long last_partial_off;
-                       u64 last_partial_data;
+                       struct list_head partial_pte_list;
                } ggtt_mm;
        };
 };
index 90f50f6..aa280bb 100644 (file)
@@ -1609,7 +1609,7 @@ static int bxt_gt_disp_pwron_write(struct intel_vgpu *vgpu,
        return 0;
 }
 
-static int bxt_edp_psr_imr_iir_write(struct intel_vgpu *vgpu,
+static int edp_psr_imr_iir_write(struct intel_vgpu *vgpu,
                unsigned int offset, void *p_data, unsigned int bytes)
 {
        vgpu_vreg(vgpu, offset) = 0;
@@ -2607,6 +2607,9 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
        MMIO_DFH(_MMIO(0x1a178), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
        MMIO_DFH(_MMIO(0x1a17c), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
        MMIO_DFH(_MMIO(0x2217c), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
+
+       MMIO_DH(EDP_PSR_IMR, D_BDW_PLUS, NULL, edp_psr_imr_iir_write);
+       MMIO_DH(EDP_PSR_IIR, D_BDW_PLUS, NULL, edp_psr_imr_iir_write);
        return 0;
 }
 
@@ -3205,9 +3208,6 @@ static int init_bxt_mmio_info(struct intel_gvt *gvt)
        MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_B), D_BXT);
        MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_C), D_BXT);
 
-       MMIO_DH(EDP_PSR_IMR, D_BXT, NULL, bxt_edp_psr_imr_iir_write);
-       MMIO_DH(EDP_PSR_IIR, D_BXT, NULL, bxt_edp_psr_imr_iir_write);
-
        MMIO_D(RC6_CTX_BASE, D_BXT);
 
        MMIO_D(GEN8_PUSHBUS_CONTROL, D_BXT);
index 10e63ee..36a5147 100644 (file)
@@ -131,7 +131,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
        {RCS, GAMT_CHKN_BIT_REG, 0x0, false}, /* 0x4ab8 */
 
        {RCS, GEN9_GAMT_ECO_REG_RW_IA, 0x0, false}, /* 0x4ab0 */
-       {RCS, GEN9_CSFE_CHICKEN1_RCS, 0x0, false}, /* 0x20d4 */
+       {RCS, GEN9_CSFE_CHICKEN1_RCS, 0xffff, false}, /* 0x20d4 */
 
        {RCS, GEN8_GARBCNTL, 0x0, false}, /* 0xb004 */
        {RCS, GEN7_FF_THREAD_MODE, 0x0, false}, /* 0x20a0 */
index 44e2c0f..ffdbbac 100644 (file)
@@ -1175,8 +1175,6 @@ skl_dram_get_channels_info(struct drm_i915_private *dev_priv)
                return -EINVAL;
        }
 
-       dram_info->valid_dimm = true;
-
        /*
         * If any of the channel is single rank channel, worst case output
         * will be same as if single rank memory, so consider single rank
@@ -1193,8 +1191,7 @@ skl_dram_get_channels_info(struct drm_i915_private *dev_priv)
                return -EINVAL;
        }
 
-       if (ch0.is_16gb_dimm || ch1.is_16gb_dimm)
-               dram_info->is_16gb_dimm = true;
+       dram_info->is_16gb_dimm = ch0.is_16gb_dimm || ch1.is_16gb_dimm;
 
        dev_priv->dram_info.symmetric_memory = intel_is_dram_symmetric(val_ch0,
                                                                       val_ch1,
@@ -1314,7 +1311,6 @@ bxt_get_dram_info(struct drm_i915_private *dev_priv)
                return -EINVAL;
        }
 
-       dram_info->valid_dimm = true;
        dram_info->valid = true;
        return 0;
 }
@@ -1327,12 +1323,17 @@ intel_get_dram_info(struct drm_i915_private *dev_priv)
        int ret;
 
        dram_info->valid = false;
-       dram_info->valid_dimm = false;
-       dram_info->is_16gb_dimm = false;
        dram_info->rank = I915_DRAM_RANK_INVALID;
        dram_info->bandwidth_kbps = 0;
        dram_info->num_channels = 0;
 
+       /*
+        * Assume 16Gb DIMMs are present until proven otherwise.
+        * This is only used for the level 0 watermark latency
+        * w/a which does not apply to bxt/glk.
+        */
+       dram_info->is_16gb_dimm = !IS_GEN9_LP(dev_priv);
+
        if (INTEL_GEN(dev_priv) < 9 || IS_GEMINILAKE(dev_priv))
                return;
 
index 8624b4b..9102571 100644 (file)
@@ -1948,7 +1948,6 @@ struct drm_i915_private {
 
        struct dram_info {
                bool valid;
-               bool valid_dimm;
                bool is_16gb_dimm;
                u8 num_channels;
                enum dram_rank {
index 0918728..1aaccbe 100644 (file)
@@ -460,7 +460,7 @@ eb_validate_vma(struct i915_execbuffer *eb,
         * any non-page-aligned or non-canonical addresses.
         */
        if (unlikely(entry->flags & EXEC_OBJECT_PINNED &&
-                    entry->offset != gen8_canonical_addr(entry->offset & PAGE_MASK)))
+                    entry->offset != gen8_canonical_addr(entry->offset & I915_GTT_PAGE_MASK)))
                return -EINVAL;
 
        /* pad_to_size was once a reserved field, so sanitize it */
index 56c7f86..47c3025 100644 (file)
@@ -1757,7 +1757,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m)
                        if (i == 4)
                                continue;
 
-                       seq_printf(m, "\t\t(%03d, %04d) %08lx: ",
+                       seq_printf(m, "\t\t(%03d, %04d) %08llx: ",
                                   pde, pte,
                                   (pde * GEN6_PTES + pte) * I915_GTT_PAGE_SIZE);
                        for (i = 0; i < 4; i++) {
index 7e2af5f..2803929 100644 (file)
 #include "i915_selftest.h"
 #include "i915_timeline.h"
 
-#define I915_GTT_PAGE_SIZE_4K BIT(12)
-#define I915_GTT_PAGE_SIZE_64K BIT(16)
-#define I915_GTT_PAGE_SIZE_2M BIT(21)
+#define I915_GTT_PAGE_SIZE_4K  BIT_ULL(12)
+#define I915_GTT_PAGE_SIZE_64K BIT_ULL(16)
+#define I915_GTT_PAGE_SIZE_2M  BIT_ULL(21)
 
 #define I915_GTT_PAGE_SIZE I915_GTT_PAGE_SIZE_4K
 #define I915_GTT_MAX_PAGE_SIZE I915_GTT_PAGE_SIZE_2M
 
+#define I915_GTT_PAGE_MASK -I915_GTT_PAGE_SIZE
+
 #define I915_GTT_MIN_ALIGNMENT I915_GTT_PAGE_SIZE
 
 #define I915_FENCE_REG_NONE -1
@@ -659,20 +661,20 @@ int i915_gem_gtt_insert(struct i915_address_space *vm,
                        u64 start, u64 end, unsigned int flags);
 
 /* Flags used by pin/bind&friends. */
-#define PIN_NONBLOCK           BIT(0)
-#define PIN_MAPPABLE           BIT(1)
-#define PIN_ZONE_4G            BIT(2)
-#define PIN_NONFAULT           BIT(3)
-#define PIN_NOEVICT            BIT(4)
-
-#define PIN_MBZ                        BIT(5) /* I915_VMA_PIN_OVERFLOW */
-#define PIN_GLOBAL             BIT(6) /* I915_VMA_GLOBAL_BIND */
-#define PIN_USER               BIT(7) /* I915_VMA_LOCAL_BIND */
-#define PIN_UPDATE             BIT(8)
-
-#define PIN_HIGH               BIT(9)
-#define PIN_OFFSET_BIAS                BIT(10)
-#define PIN_OFFSET_FIXED       BIT(11)
+#define PIN_NONBLOCK           BIT_ULL(0)
+#define PIN_MAPPABLE           BIT_ULL(1)
+#define PIN_ZONE_4G            BIT_ULL(2)
+#define PIN_NONFAULT           BIT_ULL(3)
+#define PIN_NOEVICT            BIT_ULL(4)
+
+#define PIN_MBZ                        BIT_ULL(5) /* I915_VMA_PIN_OVERFLOW */
+#define PIN_GLOBAL             BIT_ULL(6) /* I915_VMA_GLOBAL_BIND */
+#define PIN_USER               BIT_ULL(7) /* I915_VMA_LOCAL_BIND */
+#define PIN_UPDATE             BIT_ULL(8)
+
+#define PIN_HIGH               BIT_ULL(9)
+#define PIN_OFFSET_BIAS                BIT_ULL(10)
+#define PIN_OFFSET_FIXED       BIT_ULL(11)
 #define PIN_OFFSET_MASK                (-I915_GTT_PAGE_SIZE)
 
 #endif
index 7c491ea..e31c27e 100644 (file)
@@ -2095,8 +2095,12 @@ enum i915_power_well_id {
 
 /* ICL PHY DFLEX registers */
 #define PORT_TX_DFLEXDPMLE1            _MMIO(0x1638C0)
-#define   DFLEXDPMLE1_DPMLETC_MASK(n)  (0xf << (4 * (n)))
-#define   DFLEXDPMLE1_DPMLETC(n, x)    ((x) << (4 * (n)))
+#define   DFLEXDPMLE1_DPMLETC_MASK(tc_port)    (0xf << (4 * (tc_port)))
+#define   DFLEXDPMLE1_DPMLETC_ML0(tc_port)     (1 << (4 * (tc_port)))
+#define   DFLEXDPMLE1_DPMLETC_ML1_0(tc_port)   (3 << (4 * (tc_port)))
+#define   DFLEXDPMLE1_DPMLETC_ML3(tc_port)     (8 << (4 * (tc_port)))
+#define   DFLEXDPMLE1_DPMLETC_ML3_2(tc_port)   (12 << (4 * (tc_port)))
+#define   DFLEXDPMLE1_DPMLETC_ML3_0(tc_port)   (15 << (4 * (tc_port)))
 
 /* BXT PHY Ref registers */
 #define _PORT_REF_DW3_A                        0x16218C
@@ -4593,12 +4597,12 @@ enum {
 
 #define  DRM_DIP_ENABLE                        (1 << 28)
 #define  PSR_VSC_BIT_7_SET             (1 << 27)
-#define  VSC_SELECT_MASK               (0x3 << 26)
-#define  VSC_SELECT_SHIFT              26
-#define  VSC_DIP_HW_HEA_DATA           (0 << 26)
-#define  VSC_DIP_HW_HEA_SW_DATA                (1 << 26)
-#define  VSC_DIP_HW_DATA_SW_HEA                (2 << 26)
-#define  VSC_DIP_SW_HEA_DATA           (3 << 26)
+#define  VSC_SELECT_MASK               (0x3 << 25)
+#define  VSC_SELECT_SHIFT              25
+#define  VSC_DIP_HW_HEA_DATA           (0 << 25)
+#define  VSC_DIP_HW_HEA_SW_DATA                (1 << 25)
+#define  VSC_DIP_HW_DATA_SW_HEA                (2 << 25)
+#define  VSC_DIP_SW_HEA_DATA           (3 << 25)
 #define  VDIP_ENABLE_PPS               (1 << 24)
 
 /* Panel power sequencing */
index 769f3f5..ee3ca2d 100644 (file)
@@ -144,6 +144,9 @@ static const struct {
 /* HDMI N/CTS table */
 #define TMDS_297M 297000
 #define TMDS_296M 296703
+#define TMDS_594M 594000
+#define TMDS_593M 593407
+
 static const struct {
        int sample_rate;
        int clock;
@@ -164,6 +167,20 @@ static const struct {
        { 176400, TMDS_297M, 18816, 247500 },
        { 192000, TMDS_296M, 23296, 281250 },
        { 192000, TMDS_297M, 20480, 247500 },
+       { 44100, TMDS_593M, 8918, 937500 },
+       { 44100, TMDS_594M, 9408, 990000 },
+       { 48000, TMDS_593M, 5824, 562500 },
+       { 48000, TMDS_594M, 6144, 594000 },
+       { 32000, TMDS_593M, 5824, 843750 },
+       { 32000, TMDS_594M, 3072, 445500 },
+       { 88200, TMDS_593M, 17836, 937500 },
+       { 88200, TMDS_594M, 18816, 990000 },
+       { 96000, TMDS_593M, 11648, 562500 },
+       { 96000, TMDS_594M, 12288, 594000 },
+       { 176400, TMDS_593M, 35672, 937500 },
+       { 176400, TMDS_594M, 37632, 990000 },
+       { 192000, TMDS_593M, 23296, 562500 },
+       { 192000, TMDS_594M, 24576, 594000 },
 };
 
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
index 29075c7..8d74276 100644 (file)
@@ -2138,16 +2138,8 @@ void intel_set_cdclk(struct drm_i915_private *dev_priv,
 static int intel_pixel_rate_to_cdclk(struct drm_i915_private *dev_priv,
                                     int pixel_rate)
 {
-       if (INTEL_GEN(dev_priv) >= 10)
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
                return DIV_ROUND_UP(pixel_rate, 2);
-       else if (IS_GEMINILAKE(dev_priv))
-               /*
-                * FIXME: Avoid using a pixel clock that is more than 99% of the cdclk
-                * as a temporary workaround. Use a higher cdclk instead. (Note that
-                * intel_compute_max_dotclk() limits the max pixel clock to 99% of max
-                * cdclk.)
-                */
-               return DIV_ROUND_UP(pixel_rate * 100, 2 * 99);
        else if (IS_GEN9(dev_priv) ||
                 IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
                return pixel_rate;
@@ -2543,14 +2535,8 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
 {
        int max_cdclk_freq = dev_priv->max_cdclk_freq;
 
-       if (INTEL_GEN(dev_priv) >= 10)
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
                return 2 * max_cdclk_freq;
-       else if (IS_GEMINILAKE(dev_priv))
-               /*
-                * FIXME: Limiting to 99% as a temporary workaround. See
-                * intel_min_cdclk() for details.
-                */
-               return 2 * max_cdclk_freq * 99 / 100;
        else if (IS_GEN9(dev_priv) ||
                 IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
                return max_cdclk_freq;
index 9741cc4..23d8008 100644 (file)
@@ -12768,17 +12768,12 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                        intel_check_cpu_fifo_underruns(dev_priv);
                        intel_check_pch_fifo_underruns(dev_priv);
 
-                       if (!new_crtc_state->active) {
-                               /*
-                                * Make sure we don't call initial_watermarks
-                                * for ILK-style watermark updates.
-                                *
-                                * No clue what this is supposed to achieve.
-                                */
-                               if (INTEL_GEN(dev_priv) >= 9)
-                                       dev_priv->display.initial_watermarks(intel_state,
-                                                                            to_intel_crtc_state(new_crtc_state));
-                       }
+                       /* FIXME unify this for all platforms */
+                       if (!new_crtc_state->active &&
+                           !HAS_GMCH_DISPLAY(dev_priv) &&
+                           dev_priv->display.initial_watermarks)
+                               dev_priv->display.initial_watermarks(intel_state,
+                                                                    to_intel_crtc_state(new_crtc_state));
                }
        }
 
@@ -14646,7 +14641,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
             fb->height < SKL_MIN_YUV_420_SRC_H ||
             (fb->width % 4) != 0 || (fb->height % 4) != 0)) {
                DRM_DEBUG_KMS("src dimensions not correct for NV12\n");
-               return -EINVAL;
+               goto err;
        }
 
        for (i = 0; i < fb->format->num_planes; i++) {
index cdf1955..5d5336f 100644 (file)
@@ -297,8 +297,10 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
        lpe_audio_platdev_destroy(dev_priv);
 
        irq_free_desc(dev_priv->lpe_audio.irq);
-}
 
+       dev_priv->lpe_audio.irq = -1;
+       dev_priv->lpe_audio.platdev = NULL;
+}
 
 /**
  * intel_lpe_audio_notify() - notify lpe audio event
index 1db9b83..245f002 100644 (file)
@@ -2881,8 +2881,7 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
                 * any underrun. If not able to get Dimm info assume 16GB dimm
                 * to avoid any underrun.
                 */
-               if (!dev_priv->dram_info.valid_dimm ||
-                   dev_priv->dram_info.is_16gb_dimm)
+               if (dev_priv->dram_info.is_16gb_dimm)
                        wm[0] += 1;
 
        } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
index 8d03f64..5c22f2c 100644 (file)
@@ -551,7 +551,7 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg)
                        err = igt_check_page_sizes(vma);
 
                        if (vma->page_sizes.gtt != I915_GTT_PAGE_SIZE_4K) {
-                               pr_err("page_sizes.gtt=%u, expected %lu\n",
+                               pr_err("page_sizes.gtt=%u, expected %llu\n",
                                       vma->page_sizes.gtt, I915_GTT_PAGE_SIZE_4K);
                                err = -EINVAL;
                        }
index 8e2e269..127d815 100644 (file)
@@ -1337,7 +1337,7 @@ static int igt_gtt_reserve(void *arg)
                GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
                if (vma->node.start != total ||
                    vma->node.size != 2*I915_GTT_PAGE_SIZE) {
-                       pr_err("i915_gem_gtt_reserve (pass 1) placement failed, found (%llx + %llx), expected (%llx + %lx)\n",
+                       pr_err("i915_gem_gtt_reserve (pass 1) placement failed, found (%llx + %llx), expected (%llx + %llx)\n",
                               vma->node.start, vma->node.size,
                               total, 2*I915_GTT_PAGE_SIZE);
                        err = -EINVAL;
@@ -1386,7 +1386,7 @@ static int igt_gtt_reserve(void *arg)
                GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
                if (vma->node.start != total ||
                    vma->node.size != 2*I915_GTT_PAGE_SIZE) {
-                       pr_err("i915_gem_gtt_reserve (pass 2) placement failed, found (%llx + %llx), expected (%llx + %lx)\n",
+                       pr_err("i915_gem_gtt_reserve (pass 2) placement failed, found (%llx + %llx), expected (%llx + %llx)\n",
                               vma->node.start, vma->node.size,
                               total, 2*I915_GTT_PAGE_SIZE);
                        err = -EINVAL;
@@ -1430,7 +1430,7 @@ static int igt_gtt_reserve(void *arg)
                GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
                if (vma->node.start != offset ||
                    vma->node.size != 2*I915_GTT_PAGE_SIZE) {
-                       pr_err("i915_gem_gtt_reserve (pass 3) placement failed, found (%llx + %llx), expected (%llx + %lx)\n",
+                       pr_err("i915_gem_gtt_reserve (pass 3) placement failed, found (%llx + %llx), expected (%llx + %llx)\n",
                               vma->node.start, vma->node.size,
                               offset, 2*I915_GTT_PAGE_SIZE);
                        err = -EINVAL;
index af7dcb6..e7eb0d1 100644 (file)
@@ -75,7 +75,7 @@ static void sun4i_lvds_encoder_enable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Enabling LVDS output\n");
 
-       if (!IS_ERR(tcon->panel)) {
+       if (tcon->panel) {
                drm_panel_prepare(tcon->panel);
                drm_panel_enable(tcon->panel);
        }
@@ -88,7 +88,7 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Disabling LVDS output\n");
 
-       if (!IS_ERR(tcon->panel)) {
+       if (tcon->panel) {
                drm_panel_disable(tcon->panel);
                drm_panel_unprepare(tcon->panel);
        }
index bf068da..f4a2268 100644 (file)
@@ -135,7 +135,7 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Enabling RGB output\n");
 
-       if (!IS_ERR(tcon->panel)) {
+       if (tcon->panel) {
                drm_panel_prepare(tcon->panel);
                drm_panel_enable(tcon->panel);
        }
@@ -148,7 +148,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Disabling RGB output\n");
 
-       if (!IS_ERR(tcon->panel)) {
+       if (tcon->panel) {
                drm_panel_disable(tcon->panel);
                drm_panel_unprepare(tcon->panel);
        }
index c78cd35..f949287 100644 (file)
@@ -491,7 +491,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
        sun4i_tcon0_mode_set_common(tcon, mode);
 
        /* Set dithering if needed */
-       sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
+       if (tcon->panel)
+               sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
 
        /* Adjust clock delay */
        clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -555,7 +556,7 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
         * Following code is a way to avoid quirks all around TCON
         * and DOTCLOCK drivers.
         */
-       if (!IS_ERR(tcon->panel)) {
+       if (tcon->panel) {
                struct drm_panel *panel = tcon->panel;
                struct drm_connector *connector = panel->connector;
                struct drm_display_info display_info = connector->display_info;
index cf2a185..a132c37 100644 (file)
@@ -380,6 +380,9 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
                        mutex_unlock(&vgasr_mutex);
                        return -EINVAL;
                }
+               /* notify if GPU has been already bound */
+               if (ops->gpu_bound)
+                       ops->gpu_bound(pdev, id);
        }
        mutex_unlock(&vgasr_mutex);
 
index aec253b..3cd7229 100644 (file)
@@ -660,6 +660,20 @@ exit:
        return ret;
 }
 
+static int alps_sp_open(struct input_dev *dev)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+
+       return hid_hw_open(hid);
+}
+
+static void alps_sp_close(struct input_dev *dev)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+
+       hid_hw_close(hid);
+}
+
 static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct alps_dev *data = hid_get_drvdata(hdev);
@@ -733,6 +747,10 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
                input2->id.version = input->id.version;
                input2->dev.parent = input->dev.parent;
 
+               input_set_drvdata(input2, hdev);
+               input2->open = alps_sp_open;
+               input2->close = alps_sp_close;
+
                __set_bit(EV_KEY, input2->evbit);
                data->sp_btn_cnt = (data->sp_btn_info & 0x0F);
                for (i = 0; i < data->sp_btn_cnt; i++)
index dc6d647..a1fa2fc 100644 (file)
@@ -359,6 +359,9 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
        u32 value;
        int ret;
 
+       if (!IS_ENABLED(CONFIG_ASUS_WMI))
+               return false;
+
        ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
                                       ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
        hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
index f63489c..c0d6689 100644 (file)
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003                0x3003
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008                0x3008
 
+#define I2C_VENDOR_ID_RAYDIUM          0x2386
+#define I2C_PRODUCT_ID_RAYDIUM_4B33    0x4b33
+
 #define USB_VENDOR_ID_RAZER            0x1532
 #define USB_DEVICE_ID_RAZER_BLADE_14   0x011D
 
index 52c3b01..8237dd8 100644 (file)
@@ -107,7 +107,6 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
-       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
index 4aab96c..3cde7c1 100644 (file)
@@ -49,6 +49,7 @@
 #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV       BIT(0)
 #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET       BIT(1)
 #define I2C_HID_QUIRK_NO_RUNTIME_PM            BIT(2)
+#define I2C_HID_QUIRK_DELAY_AFTER_SLEEP                BIT(3)
 
 /* flags */
 #define I2C_HID_STARTED                0
@@ -158,6 +159,8 @@ struct i2c_hid {
 
        bool                    irq_wake_enabled;
        struct mutex            reset_lock;
+
+       unsigned long           sleep_delay;
 };
 
 static const struct i2c_hid_quirks {
@@ -172,6 +175,8 @@ static const struct i2c_hid_quirks {
        { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
                I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
                I2C_HID_QUIRK_NO_RUNTIME_PM },
+       { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33,
+               I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
        { 0, 0 }
 };
 
@@ -387,6 +392,7 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
 {
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        int ret;
+       unsigned long now, delay;
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
 
@@ -404,9 +410,22 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
                        goto set_pwr_exit;
        }
 
+       if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+           power_state == I2C_HID_PWR_ON) {
+               now = jiffies;
+               if (time_after(ihid->sleep_delay, now)) {
+                       delay = jiffies_to_usecs(ihid->sleep_delay - now);
+                       usleep_range(delay, delay + 1);
+               }
+       }
+
        ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
                0, NULL, 0, NULL, 0);
 
+       if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+           power_state == I2C_HID_PWR_SLEEP)
+               ihid->sleep_delay = jiffies + msecs_to_jiffies(20);
+
        if (ret)
                dev_err(&client->dev, "failed to change power setting.\n");
 
index cac262a..89f2976 100644 (file)
@@ -331,6 +331,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
                .driver_data = (void *)&sipodev_desc
        },
        {
+               .ident = "Direkt-Tek DTLAPY133-1",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY133-1"),
+               },
+               .driver_data = (void *)&sipodev_desc
+       },
+       {
                .ident = "Mediacom Flexbook Edge 11",
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
index 23872d0..a746017 100644 (file)
@@ -512,14 +512,24 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
                        if (cmd == HIDIOCGCOLLECTIONINDEX) {
                                if (uref->usage_index >= field->maxusage)
                                        goto inval;
+                               uref->usage_index =
+                                       array_index_nospec(uref->usage_index,
+                                                          field->maxusage);
                        } else if (uref->usage_index >= field->report_count)
                                goto inval;
                }
 
-               if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-                   (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
-                    uref->usage_index + uref_multi->num_values > field->report_count))
-                       goto inval;
+               if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+                       if (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+                           uref->usage_index + uref_multi->num_values >
+                           field->report_count)
+                               goto inval;
+
+                       uref->usage_index =
+                               array_index_nospec(uref->usage_index,
+                                                  field->report_count -
+                                                  uref_multi->num_values);
+               }
 
                switch (cmd) {
                case HIDIOCGUSAGE:
index 975c951..84f61ce 100644 (file)
@@ -649,8 +649,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
                                if (info[i]->config[j] & HWMON_T_INPUT) {
                                        err = hwmon_thermal_add_sensor(dev,
                                                                hwdev, j);
-                                       if (err)
-                                               goto free_device;
+                                       if (err) {
+                                               device_unregister(hdev);
+                                               goto ida_remove;
+                                       }
                                }
                        }
                }
@@ -658,8 +660,6 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
 
        return hdev;
 
-free_device:
-       device_unregister(hdev);
 free_hwmon:
        kfree(hwdev);
 ida_remove:
index 0ccca87..293dd1c 100644 (file)
@@ -181,7 +181,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
        return sprintf(buf, "%s\n", sdata->label);
 }
 
-static int __init get_logical_cpu(int hwcpu)
+static int get_logical_cpu(int hwcpu)
 {
        int cpu;
 
@@ -192,9 +192,8 @@ static int __init get_logical_cpu(int hwcpu)
        return -ENOENT;
 }
 
-static void __init make_sensor_label(struct device_node *np,
-                                    struct sensor_data *sdata,
-                                    const char *label)
+static void make_sensor_label(struct device_node *np,
+                             struct sensor_data *sdata, const char *label)
 {
        u32 id;
        size_t n;
index 56ccb1e..f2c6819 100644 (file)
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
          This driver can also be built as a module.  If so, the module
          will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+       tristate "NVIDIA GPU I2C controller"
+       depends on PCI
+       help
+         If you say yes to this option, support will be included for the
+         NVIDIA GPU I2C controller which is used to communicate with the GPU's
+         Type-C controller. This driver can also be built as a module called
+         i2c-nvidia-gpu.
+
 config I2C_SIS5595
        tristate "SiS 5595"
        depends on PCI
@@ -752,7 +761,7 @@ config I2C_OCORES
 
 config I2C_OMAP
        tristate "OMAP I2C adapter"
-       depends on ARCH_OMAP
+       depends on ARCH_OMAP || ARCH_K3
        default y if MACH_OMAP_H3 || MACH_OMAP_OSK
        help
          If you say yes to this option, support will be included for the
index 18b26af..5f0cb69 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_I2C_ISCH)                += i2c-isch.o
 obj-$(CONFIG_I2C_ISMT)         += i2c-ismt.o
 obj-$(CONFIG_I2C_NFORCE2)      += i2c-nforce2.o
 obj-$(CONFIG_I2C_NFORCE2_S4985)        += i2c-nforce2-s4985.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 obj-$(CONFIG_I2C_PIIX4)                += i2c-piix4.o
 obj-$(CONFIG_I2C_SIS5595)      += i2c-sis5595.o
 obj-$(CONFIG_I2C_SIS630)       += i2c-sis630.o
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644 (file)
index 0000000..8822357
--- /dev/null
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta <ajayg@nvidia.com>
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/unaligned.h>
+
+/* I2C definitions */
+#define I2C_MST_CNTL                           0x00
+#define I2C_MST_CNTL_GEN_START                 BIT(0)
+#define I2C_MST_CNTL_GEN_STOP                  BIT(1)
+#define I2C_MST_CNTL_CMD_READ                  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE                 (2 << 2)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT          6
+#define I2C_MST_CNTL_GEN_NACK                  BIT(28)
+#define I2C_MST_CNTL_STATUS                    GENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY               (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK             (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT            (2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY           (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER             BIT(31)
+
+#define I2C_MST_ADDR                           0x04
+
+#define I2C_MST_I2C0_TIMING                            0x08
+#define I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ          0x10e
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT            16
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX                255
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CHECK              BIT(24)
+
+#define I2C_MST_DATA                                   0x0c
+
+#define I2C_MST_HYBRID_PADCTL                          0x20
+#define I2C_MST_HYBRID_PADCTL_MODE_I2C                 BIT(0)
+#define I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV                BIT(14)
+#define I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV                BIT(15)
+
+struct gpu_i2c_dev {
+       struct device *dev;
+       void __iomem *regs;
+       struct i2c_adapter adapter;
+       struct i2c_board_info *gpu_ccgx_ucsi;
+};
+
+static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
+{
+       u32 val;
+
+       /* enable I2C */
+       val = readl(i2cd->regs + I2C_MST_HYBRID_PADCTL);
+       val |= I2C_MST_HYBRID_PADCTL_MODE_I2C |
+               I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
+               I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV;
+       writel(val, i2cd->regs + I2C_MST_HYBRID_PADCTL);
+
+       /* enable 100KHZ mode */
+       val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ;
+       val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX
+           << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT);
+       val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK;
+       writel(val, i2cd->regs + I2C_MST_I2C0_TIMING);
+}
+
+static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
+{
+       unsigned long target = jiffies + msecs_to_jiffies(1000);
+       u32 val;
+
+       do {
+               val = readl(i2cd->regs + I2C_MST_CNTL);
+               if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
+                       break;
+               if ((val & I2C_MST_CNTL_STATUS) !=
+                               I2C_MST_CNTL_STATUS_BUS_BUSY)
+                       break;
+               usleep_range(500, 600);
+       } while (time_is_after_jiffies(target));
+
+       if (time_is_before_jiffies(target)) {
+               dev_err(i2cd->dev, "i2c timeout error %x\n", val);
+               return -ETIME;
+       }
+
+       val = readl(i2cd->regs + I2C_MST_CNTL);
+       switch (val & I2C_MST_CNTL_STATUS) {
+       case I2C_MST_CNTL_STATUS_OKAY:
+               return 0;
+       case I2C_MST_CNTL_STATUS_NO_ACK:
+               return -EIO;
+       case I2C_MST_CNTL_STATUS_TIMEOUT:
+               return -ETIME;
+       default:
+               return 0;
+       }
+}
+
+static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len)
+{
+       int status;
+       u32 val;
+
+       val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_READ |
+               (len << I2C_MST_CNTL_BURST_SIZE_SHIFT) |
+               I2C_MST_CNTL_CYCLE_TRIGGER | I2C_MST_CNTL_GEN_NACK;
+       writel(val, i2cd->regs + I2C_MST_CNTL);
+
+       status = gpu_i2c_check_status(i2cd);
+       if (status < 0)
+               return status;
+
+       val = readl(i2cd->regs + I2C_MST_DATA);
+       switch (len) {
+       case 1:
+               data[0] = val;
+               break;
+       case 2:
+               put_unaligned_be16(val, data);
+               break;
+       case 3:
+               put_unaligned_be16(val >> 8, data);
+               data[2] = val;
+               break;
+       case 4:
+               put_unaligned_be32(val, data);
+               break;
+       default:
+               break;
+       }
+       return status;
+}
+
+static int gpu_i2c_start(struct gpu_i2c_dev *i2cd)
+{
+       writel(I2C_MST_CNTL_GEN_START, i2cd->regs + I2C_MST_CNTL);
+       return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_stop(struct gpu_i2c_dev *i2cd)
+{
+       writel(I2C_MST_CNTL_GEN_STOP, i2cd->regs + I2C_MST_CNTL);
+       return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data)
+{
+       u32 val;
+
+       writel(data, i2cd->regs + I2C_MST_DATA);
+
+       val = I2C_MST_CNTL_CMD_WRITE | (1 << I2C_MST_CNTL_BURST_SIZE_SHIFT);
+       writel(val, i2cd->regs + I2C_MST_CNTL);
+
+       return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
+                              struct i2c_msg *msgs, int num)
+{
+       struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
+       int status, status2;
+       int i, j;
+
+       /*
+        * The controller supports maximum 4 byte read due to known
+        * limitation of sending STOP after every read.
+        */
+       for (i = 0; i < num; i++) {
+               if (msgs[i].flags & I2C_M_RD) {
+                       /* program client address before starting read */
+                       writel(msgs[i].addr, i2cd->regs + I2C_MST_ADDR);
+                       /* gpu_i2c_read has implicit start */
+                       status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
+                       if (status < 0)
+                               goto stop;
+               } else {
+                       u8 addr = i2c_8bit_addr_from_msg(msgs + i);
+
+                       status = gpu_i2c_start(i2cd);
+                       if (status < 0) {
+                               if (i == 0)
+                                       return status;
+                               goto stop;
+                       }
+
+                       status = gpu_i2c_write(i2cd, addr);
+                       if (status < 0)
+                               goto stop;
+
+                       for (j = 0; j < msgs[i].len; j++) {
+                               status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
+                               if (status < 0)
+                                       goto stop;
+                       }
+               }
+       }
+       status = gpu_i2c_stop(i2cd);
+       if (status < 0)
+               return status;
+
+       return i;
+stop:
+       status2 = gpu_i2c_stop(i2cd);
+       if (status2 < 0)
+               dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+       return status;
+}
+
+static const struct i2c_adapter_quirks gpu_i2c_quirks = {
+       .max_read_len = 4,
+       .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static u32 gpu_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm gpu_i2c_algorithm = {
+       .master_xfer    = gpu_i2c_master_xfer,
+       .functionality  = gpu_i2c_functionality,
+};
+
+/*
+ * This driver is for Nvidia GPU cards with USB Type-C interface.
+ * We want to identify the cards using vendor ID and class code only
+ * to avoid dependency of adding product id for any new card which
+ * requires this driver.
+ * Currently there is no class code defined for UCSI device over PCI
+ * so using UNKNOWN class for now and it will be updated when UCSI
+ * over PCI gets a class code.
+ * There is no other NVIDIA cards with UNKNOWN class code. Even if the
+ * driver gets loaded for an undesired card then eventually i2c_read()
+ * (initiated from UCSI i2c_client) will timeout or UCSI commands will
+ * timeout.
+ */
+#define PCI_CLASS_SERIAL_UNKNOWN       0x0c80
+static const struct pci_device_id gpu_i2c_ids[] = {
+       { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_SERIAL_UNKNOWN << 8, 0xffffff00},
+       { }
+};
+MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
+
+static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
+{
+       struct i2c_client *ccgx_client;
+
+       i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
+                                          sizeof(*i2cd->gpu_ccgx_ucsi),
+                                          GFP_KERNEL);
+       if (!i2cd->gpu_ccgx_ucsi)
+               return -ENOMEM;
+
+       strlcpy(i2cd->gpu_ccgx_ucsi->type, "ccgx-ucsi",
+               sizeof(i2cd->gpu_ccgx_ucsi->type));
+       i2cd->gpu_ccgx_ucsi->addr = 0x8;
+       i2cd->gpu_ccgx_ucsi->irq = irq;
+       ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+       if (!ccgx_client)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct gpu_i2c_dev *i2cd;
+       int status;
+
+       i2cd = devm_kzalloc(&pdev->dev, sizeof(*i2cd), GFP_KERNEL);
+       if (!i2cd)
+               return -ENOMEM;
+
+       i2cd->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, i2cd);
+
+       status = pcim_enable_device(pdev);
+       if (status < 0) {
+               dev_err(&pdev->dev, "pcim_enable_device failed %d\n", status);
+               return status;
+       }
+
+       pci_set_master(pdev);
+
+       i2cd->regs = pcim_iomap(pdev, 0, 0);
+       if (!i2cd->regs) {
+               dev_err(&pdev->dev, "pcim_iomap failed\n");
+               return -ENOMEM;
+       }
+
+       status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+       if (status < 0) {
+               dev_err(&pdev->dev, "pci_alloc_irq_vectors err %d\n", status);
+               return status;
+       }
+
+       gpu_enable_i2c_bus(i2cd);
+
+       i2c_set_adapdata(&i2cd->adapter, i2cd);
+       i2cd->adapter.owner = THIS_MODULE;
+       strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter",
+               sizeof(i2cd->adapter.name));
+       i2cd->adapter.algo = &gpu_i2c_algorithm;
+       i2cd->adapter.quirks = &gpu_i2c_quirks;
+       i2cd->adapter.dev.parent = &pdev->dev;
+       status = i2c_add_adapter(&i2cd->adapter);
+       if (status < 0)
+               goto free_irq_vectors;
+
+       status = gpu_populate_client(i2cd, pdev->irq);
+       if (status < 0) {
+               dev_err(&pdev->dev, "gpu_populate_client failed %d\n", status);
+               goto del_adapter;
+       }
+
+       return 0;
+
+del_adapter:
+       i2c_del_adapter(&i2cd->adapter);
+free_irq_vectors:
+       pci_free_irq_vectors(pdev);
+       return status;
+}
+
+static void gpu_i2c_remove(struct pci_dev *pdev)
+{
+       struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
+
+       i2c_del_adapter(&i2cd->adapter);
+       pci_free_irq_vectors(pdev);
+}
+
+static int gpu_i2c_resume(struct device *dev)
+{
+       struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
+
+       gpu_enable_i2c_bus(i2cd);
+       return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+
+static struct pci_driver gpu_i2c_driver = {
+       .name           = "nvidia-gpu",
+       .id_table       = gpu_i2c_ids,
+       .probe          = gpu_i2c_probe,
+       .remove         = gpu_i2c_remove,
+       .driver         = {
+               .pm     = &gpu_i2c_driver_pm,
+       },
+};
+
+module_pci_driver(gpu_i2c_driver);
+
+MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
+MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver");
+MODULE_LICENSE("GPL v2");
index 527f55c..db075bc 100644 (file)
@@ -571,18 +571,19 @@ static int geni_i2c_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
 
-       ret = i2c_add_adapter(&gi2c->adap);
-       if (ret) {
-               dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
-               return ret;
-       }
-
        gi2c->suspended = 1;
        pm_runtime_set_suspended(gi2c->se.dev);
        pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
        pm_runtime_use_autosuspend(gi2c->se.dev);
        pm_runtime_enable(gi2c->se.dev);
 
+       ret = i2c_add_adapter(&gi2c->adap);
+       if (ret) {
+               dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
+               pm_runtime_disable(gi2c->se.dev);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -590,8 +591,8 @@ static int geni_i2c_remove(struct platform_device *pdev)
 {
        struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
 
-       pm_runtime_disable(gi2c->se.dev);
        i2c_del_adapter(&gi2c->adap);
+       pm_runtime_disable(gi2c->se.dev);
        return 0;
 }
 
index ce7acd1..1870cf8 100644 (file)
@@ -75,8 +75,6 @@ static void pattern_trig_timer_function(struct timer_list *t)
 {
        struct pattern_trig_data *data = from_timer(data, t, timer);
 
-       mutex_lock(&data->lock);
-
        for (;;) {
                if (!data->is_indefinite && !data->repeat)
                        break;
@@ -87,9 +85,10 @@ static void pattern_trig_timer_function(struct timer_list *t)
                                           data->curr->brightness);
                        mod_timer(&data->timer,
                                  jiffies + msecs_to_jiffies(data->curr->delta_t));
-
-                       /* Skip the tuple with zero duration */
-                       pattern_trig_update_patterns(data);
+                       if (!data->next->delta_t) {
+                               /* Skip the tuple with zero duration */
+                               pattern_trig_update_patterns(data);
+                       }
                        /* Select next tuple */
                        pattern_trig_update_patterns(data);
                } else {
@@ -116,8 +115,6 @@ static void pattern_trig_timer_function(struct timer_list *t)
 
                break;
        }
-
-       mutex_unlock(&data->lock);
 }
 
 static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
@@ -176,14 +173,10 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
        if (res < -1 || res == 0)
                return -EINVAL;
 
-       /*
-        * Clear previous patterns' performence firstly, and remove the timer
-        * without mutex lock to avoid dead lock.
-        */
-       del_timer_sync(&data->timer);
-
        mutex_lock(&data->lock);
 
+       del_timer_sync(&data->timer);
+
        if (data->is_hw_pattern)
                led_cdev->pattern_clear(led_cdev);
 
@@ -234,14 +227,10 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
        struct pattern_trig_data *data = led_cdev->trigger_data;
        int ccount, cr, offset = 0, err = 0;
 
-       /*
-        * Clear previous patterns' performence firstly, and remove the timer
-        * without mutex lock to avoid dead lock.
-        */
-       del_timer_sync(&data->timer);
-
        mutex_lock(&data->lock);
 
+       del_timer_sync(&data->timer);
+
        if (data->is_hw_pattern)
                led_cdev->pattern_clear(led_cdev);
 
index e514d57..aa98342 100644 (file)
@@ -207,7 +207,7 @@ comment "Disk-On-Chip Device Drivers"
 config MTD_DOCG3
        tristate "M-Systems Disk-On-Chip G3"
        select BCH
-       select BCH_CONST_PARAMS
+       select BCH_CONST_PARAMS if !MTD_NAND_BCH
        select BITREVERSE
        help
          This provides an MTD device driver for the M-Systems DiskOnChip
index 784c6e1..fd5fe12 100644 (file)
@@ -221,7 +221,14 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
                info->mtd = info->subdev[0].mtd;
                ret = 0;
        } else if (info->num_subdev > 1) {
-               struct mtd_info *cdev[nr];
+               struct mtd_info **cdev;
+
+               cdev = kmalloc_array(nr, sizeof(*cdev), GFP_KERNEL);
+               if (!cdev) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
                /*
                 * We detected multiple devices.  Concatenate them together.
                 */
@@ -230,6 +237,7 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
 
                info->mtd = mtd_concat_create(cdev, info->num_subdev,
                                              plat->name);
+               kfree(cdev);
                if (info->mtd == NULL) {
                        ret = -ENXIO;
                        goto err;
index 05bd077..71050a0 100644 (file)
@@ -590,7 +590,6 @@ retry:
 
 /**
  * panic_nand_wait - [GENERIC] wait until the command is done
- * @mtd: MTD device structure
  * @chip: NAND chip structure
  * @timeo: timeout
  *
index e24db81..d846428 100644 (file)
@@ -996,7 +996,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
 err_unmap:
        dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE);
 
-       return 0;
+       return ret;
 }
 
 static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
index 9407ca5..3e54e31 100644 (file)
@@ -3250,12 +3250,14 @@ static int spi_nor_init_params(struct spi_nor *nor,
                memcpy(&sfdp_params, params, sizeof(sfdp_params));
                memcpy(&prev_map, &nor->erase_map, sizeof(prev_map));
 
-               if (spi_nor_parse_sfdp(nor, &sfdp_params))
+               if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
+                       nor->addr_width = 0;
                        /* restore previous erase map */
                        memcpy(&nor->erase_map, &prev_map,
                               sizeof(nor->erase_map));
-               else
+               } else {
                        memcpy(params, &sfdp_params, sizeof(*params));
+               }
        }
 
        return 0;
index 93ceea4..e294d39 100644 (file)
@@ -1072,6 +1072,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
                         * be a result of power cut during erasure.
                         */
                        ai->maybe_bad_peb_count += 1;
+               /* fall through */
        case UBI_IO_BAD_HDR:
                        /*
                         * If we're facing a bad VID header we have to drop *all*
index d2a7266..a4e3454 100644 (file)
@@ -1334,8 +1334,10 @@ static int bytes_str_to_int(const char *str)
        switch (*endp) {
        case 'G':
                result *= 1024;
+               /* fall through */
        case 'M':
                result *= 1024;
+               /* fall through */
        case 'K':
                result *= 1024;
                if (endp[1] == 'i' && endp[2] == 'B')
index ffa37ad..333387f 100644 (file)
@@ -3112,13 +3112,13 @@ static int bond_slave_netdev_event(unsigned long event,
        case NETDEV_CHANGE:
                /* For 802.3ad mode only:
                 * Getting invalid Speed/Duplex values here will put slave
-                * in weird state. So mark it as link-down for the time
+                * in weird state. So mark it as link-fail for the time
                 * being and let link-monitoring (miimon) set it right when
                 * correct speeds/duplex are available.
                 */
                if (bond_update_speed_duplex(slave) &&
                    BOND_MODE(bond) == BOND_MODE_8023AD)
-                       slave->link = BOND_LINK_DOWN;
+                       slave->link = BOND_LINK_FAIL;
 
                if (BOND_MODE(bond) == BOND_MODE_8023AD)
                        bond_3ad_adapter_speed_duplex_changed(slave);
index 54e0ca6..86b6464 100644 (file)
@@ -1117,11 +1117,6 @@ static int ksz_switch_init(struct ksz_device *dev)
 {
        int i;
 
-       mutex_init(&dev->reg_mutex);
-       mutex_init(&dev->stats_mutex);
-       mutex_init(&dev->alu_mutex);
-       mutex_init(&dev->vlan_mutex);
-
        dev->ds->ops = &ksz_switch_ops;
 
        for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
@@ -1206,6 +1201,11 @@ int ksz_switch_register(struct ksz_device *dev)
        if (dev->pdata)
                dev->chip_id = dev->pdata->chip_id;
 
+       mutex_init(&dev->reg_mutex);
+       mutex_init(&dev->stats_mutex);
+       mutex_init(&dev->alu_mutex);
+       mutex_init(&dev->vlan_mutex);
+
        if (ksz_switch_detect(dev))
                return -EINVAL;
 
index 78c5de4..9d0e74f 100644 (file)
@@ -140,6 +140,5 @@ struct alx_priv {
 };
 
 extern const struct ethtool_ops alx_ethtool_ops;
-extern const char alx_drv_name[];
 
 #endif
index 7968c64..c131cfc 100644 (file)
@@ -49,7 +49,7 @@
 #include "hw.h"
 #include "reg.h"
 
-const char alx_drv_name[] = "alx";
+static const char alx_drv_name[] = "alx";
 
 static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
 {
index 4122553..0e2d99c 100644 (file)
@@ -1902,9 +1902,6 @@ static void bcm_sysport_netif_start(struct net_device *dev)
                intrl2_1_mask_clear(priv, 0xffffffff);
        else
                intrl2_0_mask_clear(priv, INTRL2_0_TDMA_MBDONE_MASK);
-
-       /* Last call before we start the real business */
-       netif_tx_start_all_queues(dev);
 }
 
 static void rbuf_init(struct bcm_sysport_priv *priv)
@@ -2048,6 +2045,8 @@ static int bcm_sysport_open(struct net_device *dev)
 
        bcm_sysport_netif_start(dev);
 
+       netif_tx_start_all_queues(dev);
+
        return 0;
 
 out_clear_rx_int:
@@ -2071,7 +2070,7 @@ static void bcm_sysport_netif_stop(struct net_device *dev)
        struct bcm_sysport_priv *priv = netdev_priv(dev);
 
        /* stop all software from updating hardware */
-       netif_tx_stop_all_queues(dev);
+       netif_tx_disable(dev);
        napi_disable(&priv->napi);
        cancel_work_sync(&priv->dim.dim.work);
        phy_stop(dev->phydev);
@@ -2658,12 +2657,12 @@ static int __maybe_unused bcm_sysport_suspend(struct device *d)
        if (!netif_running(dev))
                return 0;
 
+       netif_device_detach(dev);
+
        bcm_sysport_netif_stop(dev);
 
        phy_suspend(dev->phydev);
 
-       netif_device_detach(dev);
-
        /* Disable UniMAC RX */
        umac_enable_set(priv, CMD_RX_EN, 0);
 
@@ -2746,8 +2745,6 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
                goto out_free_rx_ring;
        }
 
-       netif_device_attach(dev);
-
        /* RX pipe enable */
        topctrl_writel(priv, 0, RX_FLUSH_CNTL);
 
@@ -2788,6 +2785,8 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
 
        bcm_sysport_netif_start(dev);
 
+       netif_device_attach(dev);
+
        return 0;
 
 out_free_rx_ring:
index 20c1681..2d6f090 100644 (file)
@@ -2855,7 +2855,6 @@ static void bcmgenet_netif_start(struct net_device *dev)
 
        umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
 
-       netif_tx_start_all_queues(dev);
        bcmgenet_enable_tx_napi(priv);
 
        /* Monitor link interrupts now */
@@ -2937,6 +2936,8 @@ static int bcmgenet_open(struct net_device *dev)
 
        bcmgenet_netif_start(dev);
 
+       netif_tx_start_all_queues(dev);
+
        return 0;
 
 err_irq1:
@@ -2958,7 +2959,7 @@ static void bcmgenet_netif_stop(struct net_device *dev)
        struct bcmgenet_priv *priv = netdev_priv(dev);
 
        bcmgenet_disable_tx_napi(priv);
-       netif_tx_stop_all_queues(dev);
+       netif_tx_disable(dev);
 
        /* Disable MAC receive */
        umac_enable_set(priv, CMD_RX_EN, false);
@@ -3620,13 +3621,13 @@ static int bcmgenet_suspend(struct device *d)
        if (!netif_running(dev))
                return 0;
 
+       netif_device_detach(dev);
+
        bcmgenet_netif_stop(dev);
 
        if (!device_may_wakeup(d))
                phy_suspend(dev->phydev);
 
-       netif_device_detach(dev);
-
        /* Prepare the device for Wake-on-LAN and switch to the slow clock */
        if (device_may_wakeup(d) && priv->wolopts) {
                ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
@@ -3700,8 +3701,6 @@ static int bcmgenet_resume(struct device *d)
        /* Always enable ring 16 - descriptor ring */
        bcmgenet_enable_dma(priv, dma_ctrl);
 
-       netif_device_attach(dev);
-
        if (!device_may_wakeup(d))
                phy_resume(dev->phydev);
 
@@ -3710,6 +3709,8 @@ static int bcmgenet_resume(struct device *d)
 
        bcmgenet_netif_start(dev);
 
+       netif_device_attach(dev);
+
        return 0;
 
 out_clk_disable:
index aa5cb98..494e562 100644 (file)
@@ -1168,14 +1168,14 @@ static int hclge_pfc_setup_hw(struct hclge_dev *hdev)
  */
 static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc)
 {
-       struct hclge_vport *vport = hdev->vport;
-       u32 i, k, qs_bitmap;
-       int ret;
+       int i;
 
        for (i = 0; i < HCLGE_BP_GRP_NUM; i++) {
-               qs_bitmap = 0;
+               u32 qs_bitmap = 0;
+               int k, ret;
 
                for (k = 0; k < hdev->num_alloc_vport; k++) {
+                       struct hclge_vport *vport = &hdev->vport[k];
                        u16 qs_id = vport->qs_offset + tc;
                        u8 grp, sub_grp;
 
@@ -1185,8 +1185,6 @@ static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc)
                                                  HCLGE_BP_SUB_GRP_ID_S);
                        if (i == grp)
                                qs_bitmap |= (1 << sub_grp);
-
-                       vport++;
                }
 
                ret = hclge_tm_qs_bp_cfg(hdev, tc, i, qs_bitmap);
index 1857ee0..6f5153a 100644 (file)
@@ -1006,7 +1006,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                ring->packets++;
        }
        ring->bytes += tx_info->nr_bytes;
-       netdev_tx_sent_queue(ring->tx_queue, tx_info->nr_bytes);
        AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, skb->len);
 
        if (tx_info->inl)
@@ -1044,7 +1043,10 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_tx_stop_queue(ring->tx_queue);
                ring->queue_stopped++;
        }
-       send_doorbell = !skb->xmit_more || netif_xmit_stopped(ring->tx_queue);
+
+       send_doorbell = __netdev_tx_sent_queue(ring->tx_queue,
+                                              tx_info->nr_bytes,
+                                              skb->xmit_more);
 
        real_size = (real_size / 16) & 0x3f;
 
index a2df12b..9bec940 100644 (file)
@@ -3568,7 +3568,6 @@ static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
                        burst_size = 7;
                        break;
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME:
-                       is_bytes = true;
                        rate = 4 * 1024;
                        burst_size = 4;
                        break;
index f40f654..a96364d 100644 (file)
@@ -1944,9 +1944,12 @@ int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn,
                             struct qed_ptt *p_ptt, u32 *p_speed_mask)
 {
        u32 transceiver_type, transceiver_state;
+       int ret;
 
-       qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state,
-                                    &transceiver_type);
+       ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state,
+                                          &transceiver_type);
+       if (ret)
+               return ret;
 
        if (qed_is_transceiver_ready(transceiver_state, transceiver_type) ==
                                     false)
index b12023b..a5bab61 100644 (file)
@@ -71,7 +71,6 @@ static unsigned int tx_start = 10;
 static unsigned int tx_stop = 5;
 
 struct ntb_netdev {
-       struct list_head list;
        struct pci_dev *pdev;
        struct net_device *ndev;
        struct ntb_transport_qp *qp;
@@ -81,8 +80,6 @@ struct ntb_netdev {
 #define        NTB_TX_TIMEOUT_MS       1000
 #define        NTB_RXQ_SIZE            100
 
-static LIST_HEAD(dev_list);
-
 static void ntb_netdev_event_handler(void *data, int link_is_up)
 {
        struct net_device *ndev = data;
@@ -236,7 +233,7 @@ static void ntb_netdev_tx_timer(struct timer_list *t)
        struct net_device *ndev = dev->ndev;
 
        if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
-               mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time));
+               mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
        } else {
                /* Make sure anybody stopping the queue after this sees the new
                 * value of ntb_transport_tx_free_entry()
@@ -452,7 +449,7 @@ static int ntb_netdev_probe(struct device *client_dev)
        if (rc)
                goto err1;
 
-       list_add(&dev->list, &dev_list);
+       dev_set_drvdata(client_dev, ndev);
        dev_info(&pdev->dev, "%s created\n", ndev->name);
        return 0;
 
@@ -465,27 +462,8 @@ err:
 
 static void ntb_netdev_remove(struct device *client_dev)
 {
-       struct ntb_dev *ntb;
-       struct net_device *ndev;
-       struct pci_dev *pdev;
-       struct ntb_netdev *dev;
-       bool found = false;
-
-       ntb = dev_ntb(client_dev->parent);
-       pdev = ntb->pdev;
-
-       list_for_each_entry(dev, &dev_list, list) {
-               if (dev->pdev == pdev) {
-                       found = true;
-                       break;
-               }
-       }
-       if (!found)
-               return;
-
-       list_del(&dev->list);
-
-       ndev = dev->ndev;
+       struct net_device *ndev = dev_get_drvdata(client_dev);
+       struct ntb_netdev *dev = netdev_priv(ndev);
 
        unregister_netdev(ndev);
        ntb_transport_free_queue(dev->qp);
index 7fc8508..271e8ad 100644 (file)
@@ -220,7 +220,7 @@ static struct phy_driver realtek_drvs[] = {
                .flags          = PHY_HAS_INTERRUPT,
        }, {
                .phy_id         = 0x001cc816,
-               .name           = "RTL8201F 10/100Mbps Ethernet",
+               .name           = "RTL8201F Fast Ethernet",
                .phy_id_mask    = 0x001fffff,
                .features       = PHY_BASIC_FEATURES,
                .flags          = PHY_HAS_INTERRUPT,
index 262e7a3..2d17f3b 100644 (file)
@@ -1598,6 +1598,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                return ret;
        }
 
+       cancel_delayed_work_sync(&pdata->carrier_check);
+
        if (pdata->suspend_flags) {
                netdev_warn(dev->net, "error during last resume\n");
                pdata->suspend_flags = 0;
@@ -1840,6 +1842,11 @@ done:
         */
        if (ret && PMSG_IS_AUTO(message))
                usbnet_resume(intf);
+
+       if (ret)
+               schedule_delayed_work(&pdata->carrier_check,
+                                     CARRIER_CHECK_DELAY);
+
        return ret;
 }
 
index b360e56..f8948cf 100644 (file)
@@ -1,6 +1,7 @@
 config NTB_IDT
        tristate "IDT PCIe-switch Non-Transparent Bridge support"
        depends on PCI
+       select HWMON
        help
         This driver supports NTB of cappable IDT PCIe-switches.
 
@@ -23,9 +24,7 @@ config NTB_IDT
         BAR settings of peer NT-functions, the BAR setups can't be done over
         kernel PCI fixups. That's why the alternative pre-initialization
         techniques like BIOS using SMBus interface or EEPROM should be
-        utilized. Additionally if one needs to have temperature sensor
-        information printed to system log, the corresponding registers must
-        be initialized within BIOS/EEPROM as well.
+        utilized.
 
         If unsure, say N.
 
index dbe72f1..1dede87 100644 (file)
@@ -4,7 +4,7 @@
  *
  *   GPL LICENSE SUMMARY
  *
- *   Copyright (C) 2016 T-Platforms All Rights Reserved.
+ *   Copyright (C) 2016-2018 T-Platforms JSC 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,
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/aer.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/debugfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/ntb.h>
 
 #include "ntb_hw_idt.h"
@@ -1105,9 +1108,9 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port,
        }
 
        /* Allocate memory for memory window descriptors */
-       ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt,
-                               sizeof(*ret_mws), GFP_KERNEL);
-       if (IS_ERR_OR_NULL(ret_mws))
+       ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws),
+                              GFP_KERNEL);
+       if (!ret_mws)
                return ERR_PTR(-ENOMEM);
 
        /* Copy the info of detected memory windows */
@@ -1320,7 +1323,7 @@ static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
                idt_nt_write(ndev, bar->ltbase, (u32)addr);
                idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
                /* Set the custom BAR aperture limit */
-               limit = pci_resource_start(ntb->pdev, mw_cfg->bar) + size;
+               limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size;
                idt_nt_write(ndev, bar->limit, (u32)limit);
                if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
                        idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
@@ -1821,61 +1824,284 @@ static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
  *                      7. Temperature sensor operations
  *
  *    IDT PCIe-switch has an embedded temperature sensor, which can be used to
- * warn a user-space of possible chip overheating. Since workload temperature
- * can be different on different platforms, temperature thresholds as well as
- * general sensor settings must be setup in the framework of BIOS/EEPROM
- * initializations. It includes the actual sensor enabling as well.
+ * check current chip core temperature. Since a workload environment can be
+ * different on different platforms, an offset and ADC/filter settings can be
+ * specified. Although the offset configuration is only exposed to the sysfs
+ * hwmon interface at the moment. The rest of the settings can be adjusted
+ * for instance by the BIOS/EEPROM firmware.
  *=============================================================================
  */
 
 /*
+ * idt_get_deg() - convert millidegree Celsius value to just degree
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: Degree corresponding to the passed millidegree value
+ */
+static inline s8 idt_get_deg(long mdegC)
+{
+       return mdegC / 1000;
+}
+
+/*
+ * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: 0/0.5 degree fraction of the passed millidegree value
+ */
+static inline u8 idt_get_deg_frac(long mdegC)
+{
+       return (mdegC % 1000) >= 500 ? 5 : 0;
+}
+
+/*
+ * idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: 0:7:1 format acceptable by the IDT temperature sensor
+ */
+static inline u8 idt_temp_get_fmt(long mdegC)
+{
+       return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to signed millidegree Celsius
+ * @data:      IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: signed millidegree Celsius
+ */
+static inline long idt_get_temp_sval(u32 data)
+{
+       return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius
+ * @data:      IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: unsigned millidegree Celsius
+ */
+static inline long idt_get_temp_uval(u32 data)
+{
+       return (data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
+/*
  * idt_read_temp() - read temperature from chip sensor
  * @ntb:       NTB device context.
- * @val:       OUT - integer value of temperature
- * @frac:      OUT - fraction
+ * @type:      IN - type of the temperature value to read
+ * @val:       OUT - integer value of temperature in millidegree Celsius
  */
-static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
-                         unsigned char *frac)
+static void idt_read_temp(struct idt_ntb_dev *ndev,
+                         const enum idt_temp_val type, long *val)
 {
        u32 data;
 
-       /* Read the data from TEMP field of the TMPSTS register */
-       data = idt_sw_read(ndev, IDT_SW_TMPSTS);
-       data = GET_FIELD(TMPSTS_TEMP, data);
-       /* TEMP field has one fractional bit and seven integer bits */
-       *val = data >> 1;
-       *frac = ((data & 0x1) ? 5 : 0);
+       /* Alter the temperature field in accordance with the passed type */
+       switch (type) {
+       case IDT_TEMP_CUR:
+               data = GET_FIELD(TMPSTS_TEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_LOW:
+               data = GET_FIELD(TMPSTS_LTEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_HIGH:
+               data = GET_FIELD(TMPSTS_HTEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_OFFSET:
+               /* This is the only field with signed 0:7:1 format */
+               data = GET_FIELD(TMPADJ_OFFSET,
+                                idt_sw_read(ndev, IDT_SW_TMPADJ));
+               *val = idt_get_temp_sval(data);
+               return;
+       default:
+               data = GET_FIELD(TMPSTS_TEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       }
+
+       /* The rest of the fields accept unsigned 0:7:1 format */
+       *val = idt_get_temp_uval(data);
 }
 
 /*
- * idt_temp_isr() - temperature sensor alarm events ISR
- * @ndev:      IDT NTB hardware driver descriptor
- * @ntint_sts: NT-function interrupt status
+ * idt_write_temp() - write temperature to the chip sensor register
+ * @ntb:       NTB device context.
+ * @type:      IN - type of the temperature value to change
+ * @val:       IN - integer value of temperature in millidegree Celsius
+ */
+static void idt_write_temp(struct idt_ntb_dev *ndev,
+                          const enum idt_temp_val type, const long val)
+{
+       unsigned int reg;
+       u32 data;
+       u8 fmt;
+
+       /* Retrieve the properly formatted temperature value */
+       fmt = idt_temp_get_fmt(val);
+
+       mutex_lock(&ndev->hwmon_mtx);
+       switch (type) {
+       case IDT_TEMP_LOW:
+               reg = IDT_SW_TMPALARM;
+               data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) &
+                       ~IDT_TMPALARM_IRQ_MASK;
+               break;
+       case IDT_TEMP_HIGH:
+               reg = IDT_SW_TMPALARM;
+               data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) &
+                       ~IDT_TMPALARM_IRQ_MASK;
+               break;
+       case IDT_TEMP_OFFSET:
+               reg = IDT_SW_TMPADJ;
+               data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt);
+               break;
+       default:
+               goto inval_spin_unlock;
+       }
+
+       idt_sw_write(ndev, reg, data);
+
+inval_spin_unlock:
+       mutex_unlock(&ndev->hwmon_mtx);
+}
+
+/*
+ * idt_sysfs_show_temp() - printout corresponding temperature value
+ * @dev:       Pointer to the NTB device structure
+ * @da:                Sensor device attribute structure
+ * @buf:       Buffer to print temperature out
  *
- * It handles events of temperature crossing alarm thresholds. Since reading
- * of TMPALARM register clears it up, the function doesn't analyze the
- * read value, instead the current temperature value just warningly printed to
- * log.
- * The method is called from PCIe ISR bottom-half routine.
+ * Return: Number of written symbols or negative error
  */
-static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+static ssize_t idt_sysfs_show_temp(struct device *dev,
+                                  struct device_attribute *da, char *buf)
 {
-       unsigned char val, frac;
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+       enum idt_temp_val type = attr->index;
+       long mdeg;
 
-       /* Read the current temperature value */
-       idt_read_temp(ndev, &val, &frac);
+       idt_read_temp(ndev, type, &mdeg);
+       return sprintf(buf, "%ld\n", mdeg);
+}
 
-       /* Read the temperature alarm to clean the alarm status out */
-       /*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
+/*
+ * idt_sysfs_set_temp() - set corresponding temperature value
+ * @dev:       Pointer to the NTB device structure
+ * @da:                Sensor device attribute structure
+ * @buf:       Buffer to print temperature out
+ * @count:     Size of the passed buffer
+ *
+ * Return: Number of written symbols or negative error
+ */
+static ssize_t idt_sysfs_set_temp(struct device *dev,
+                                 struct device_attribute *da, const char *buf,
+                                 size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+       enum idt_temp_val type = attr->index;
+       long mdeg;
+       int ret;
 
-       /* Clean the corresponding interrupt bit */
-       idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_TMPSENSOR);
+       ret = kstrtol(buf, 10, &mdeg);
+       if (ret)
+               return ret;
+
+       /* Clamp the passed value in accordance with the type */
+       if (type == IDT_TEMP_OFFSET)
+               mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET,
+                                IDT_TEMP_MAX_OFFSET);
+       else
+               mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG);
+
+       idt_write_temp(ndev, type, mdeg);
+
+       return count;
+}
+
+/*
+ * idt_sysfs_reset_hist() - reset temperature history
+ * @dev:       Pointer to the NTB device structure
+ * @da:                Sensor device attribute structure
+ * @buf:       Buffer to print temperature out
+ * @count:     Size of the passed buffer
+ *
+ * Return: Number of written symbols or negative error
+ */
+static ssize_t idt_sysfs_reset_hist(struct device *dev,
+                                   struct device_attribute *da,
+                                   const char *buf, size_t count)
+{
+       struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+
+       /* Just set the maximal value to the lowest temperature field and
+        * minimal value to the highest temperature field
+        */
+       idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG);
+       idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG);
 
-       dev_dbg(&ndev->ntb.pdev->dev,
-               "Temp sensor IRQ detected %#08x", ntint_sts);
+       return count;
+}
+
+/*
+ * Hwmon IDT sysfs attributes
+ */
+static SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL,
+                         IDT_TEMP_CUR);
+static SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL,
+                         IDT_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL,
+                         IDT_TEMP_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp,
+                         idt_sysfs_set_temp, IDT_TEMP_OFFSET);
+static DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist);
 
-       /* Print temperature value to log */
-       dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
+/*
+ * Hwmon IDT sysfs attributes group
+ */
+static struct attribute *idt_temp_attrs[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_lowest.dev_attr.attr,
+       &sensor_dev_attr_temp1_highest.dev_attr.attr,
+       &sensor_dev_attr_temp1_offset.dev_attr.attr,
+       &dev_attr_temp1_reset_history.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(idt_temp);
+
+/*
+ * idt_init_temp() - initialize temperature sensor interface
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Simple sensor initializarion method is responsible for device switching
+ * on and resource management based hwmon interface registration. Note, that
+ * since the device is shared we won't disable it on remove, but leave it
+ * working until the system is powered off.
+ */
+static void idt_init_temp(struct idt_ntb_dev *ndev)
+{
+       struct device *hwmon;
+
+       /* Enable sensor if it hasn't been already */
+       idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0);
+
+       /* Initialize hwmon interface fields */
+       mutex_init(&ndev->hwmon_mtx);
+
+       hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev,
+               ndev->swcfg->name, ndev, idt_temp_groups);
+       if (IS_ERR(hwmon)) {
+               dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device");
+               return;
+       }
+
+       dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered");
 }
 
 /*=============================================================================
@@ -1931,7 +2157,7 @@ static int idt_init_isr(struct idt_ntb_dev *ndev)
                goto err_free_vectors;
        }
 
-       /* Unmask Message/Doorbell/SE/Temperature interrupts */
+       /* Unmask Message/Doorbell/SE interrupts */
        ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
        idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
 
@@ -1946,7 +2172,6 @@ err_free_vectors:
        return ret;
 }
 
-
 /*
  * idt_deinit_ist() - deinitialize PCIe interrupt handler
  * @ndev:      IDT NTB hardware driver descriptor
@@ -2007,12 +2232,6 @@ static irqreturn_t idt_thread_isr(int irq, void *devid)
                handled = true;
        }
 
-       /* Handle temperature sensor interrupt */
-       if (ntint_sts & IDT_NTINTSTS_TMPSENSOR) {
-               idt_temp_isr(ndev, ntint_sts);
-               handled = true;
-       }
-
        dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
 
        return handled ? IRQ_HANDLED : IRQ_NONE;
@@ -2123,9 +2342,9 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
                                   size_t count, loff_t *offp)
 {
        struct idt_ntb_dev *ndev = filp->private_data;
-       unsigned char temp, frac, idx, pidx, cnt;
+       unsigned char idx, pidx, cnt;
+       unsigned long irqflags, mdeg;
        ssize_t ret = 0, off = 0;
-       unsigned long irqflags;
        enum ntb_speed speed;
        enum ntb_width width;
        char *strbuf;
@@ -2274,9 +2493,10 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
        off += scnprintf(strbuf + off, size - off, "\n");
 
        /* Current temperature */
-       idt_read_temp(ndev, &temp, &frac);
+       idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
        off += scnprintf(strbuf + off, size - off,
-               "Switch temperature\t\t- %hhu.%hhuC\n", temp, frac);
+               "Switch temperature\t\t- %hhd.%hhuC\n",
+               idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
 
        /* Copy the buffer to the User Space */
        ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
@@ -2390,7 +2610,7 @@ static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev,
 
        /* Allocate memory for the IDT PCIe-device descriptor */
        ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL);
-       if (IS_ERR_OR_NULL(ndev)) {
+       if (!ndev) {
                dev_err(&pdev->dev, "Memory allocation failed for descriptor");
                return ERR_PTR(-ENOMEM);
        }
@@ -2571,6 +2791,9 @@ static int idt_pci_probe(struct pci_dev *pdev,
        /* Initialize Messaging subsystem */
        idt_init_msg(ndev);
 
+       /* Initialize hwmon interface */
+       idt_init_temp(ndev);
+
        /* Initialize IDT interrupts handler */
        ret = idt_init_isr(ndev);
        if (ret != 0)
index 856fd18..2f1aa12 100644 (file)
@@ -4,7 +4,7 @@
  *
  *   GPL LICENSE SUMMARY
  *
- *   Copyright (C) 2016 T-Platforms All Rights Reserved.
+ *   Copyright (C) 2016-2018 T-Platforms JSC 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,
@@ -47,9 +47,9 @@
 #include <linux/pci_ids.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/ntb.h>
 
-
 /*
  * Macro is used to create the struct pci_device_id that matches
  * the supported IDT PCIe-switches
  * @IDT_NTINTMSK_DBELL:                Doorbell interrupt mask bit
  * @IDT_NTINTMSK_SEVENT:       Switch Event interrupt mask bit
  * @IDT_NTINTMSK_TMPSENSOR:    Temperature sensor interrupt mask bit
- * @IDT_NTINTMSK_ALL:          All the useful interrupts mask
+ * @IDT_NTINTMSK_ALL:          NTB-related interrupts mask
  */
 #define IDT_NTINTMSK_MSG               0x00000001U
 #define IDT_NTINTMSK_DBELL             0x00000002U
 #define IDT_NTINTMSK_SEVENT            0x00000008U
 #define IDT_NTINTMSK_TMPSENSOR         0x00000080U
 #define IDT_NTINTMSK_ALL \
-       (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | \
-        IDT_NTINTMSK_SEVENT | IDT_NTINTMSK_TMPSENSOR)
+       (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | IDT_NTINTMSK_SEVENT)
 
 /*
  * NTGSIGNAL register fields related constants
 #define IDT_SWPxMSGCTL_PART_FLD                4
 
 /*
+ * TMPCTL register fields related constants
+ * @IDT_TMPCTL_LTH_MASK:       Low temperature threshold field mask
+ * @IDT_TMPCTL_LTH_FLD:                Low temperature threshold field offset
+ * @IDT_TMPCTL_MTH_MASK:       Middle temperature threshold field mask
+ * @IDT_TMPCTL_MTH_FLD:                Middle temperature threshold field offset
+ * @IDT_TMPCTL_HTH_MASK:       High temperature threshold field mask
+ * @IDT_TMPCTL_HTH_FLD:                High temperature threshold field offset
+ * @IDT_TMPCTL_PDOWN:          Temperature sensor power down
+ */
+#define IDT_TMPCTL_LTH_MASK            0x000000FFU
+#define IDT_TMPCTL_LTH_FLD             0
+#define IDT_TMPCTL_MTH_MASK            0x0000FF00U
+#define IDT_TMPCTL_MTH_FLD             8
+#define IDT_TMPCTL_HTH_MASK            0x00FF0000U
+#define IDT_TMPCTL_HTH_FLD             16
+#define IDT_TMPCTL_PDOWN               0x80000000U
+
+/*
  * TMPSTS register fields related constants
  * @IDT_TMPSTS_TEMP_MASK:      Current temperature field mask
  * @IDT_TMPSTS_TEMP_FLD:       Current temperature field offset
+ * @IDT_TMPSTS_LTEMP_MASK:     Lowest temperature field mask
+ * @IDT_TMPSTS_LTEMP_FLD:      Lowest temperature field offset
+ * @IDT_TMPSTS_HTEMP_MASK:     Highest temperature field mask
+ * @IDT_TMPSTS_HTEMP_FLD:      Highest temperature field offset
  */
 #define IDT_TMPSTS_TEMP_MASK           0x000000FFU
 #define IDT_TMPSTS_TEMP_FLD            0
+#define IDT_TMPSTS_LTEMP_MASK          0x0000FF00U
+#define IDT_TMPSTS_LTEMP_FLD           8
+#define IDT_TMPSTS_HTEMP_MASK          0x00FF0000U
+#define IDT_TMPSTS_HTEMP_FLD           16
+
+/*
+ * TMPALARM register fields related constants
+ * @IDT_TMPALARM_LTEMP_MASK:   Lowest temperature field mask
+ * @IDT_TMPALARM_LTEMP_FLD:    Lowest temperature field offset
+ * @IDT_TMPALARM_HTEMP_MASK:   Highest temperature field mask
+ * @IDT_TMPALARM_HTEMP_FLD:    Highest temperature field offset
+ * @IDT_TMPALARM_IRQ_MASK:     Alarm IRQ status mask
+ */
+#define IDT_TMPALARM_LTEMP_MASK                0x0000FF00U
+#define IDT_TMPALARM_LTEMP_FLD         8
+#define IDT_TMPALARM_HTEMP_MASK                0x00FF0000U
+#define IDT_TMPALARM_HTEMP_FLD         16
+#define IDT_TMPALARM_IRQ_MASK          0x3F000000U
+
+/*
+ * TMPADJ register fields related constants
+ * @IDT_TMPADJ_OFFSET_MASK:    Temperature value offset field mask
+ * @IDT_TMPADJ_OFFSET_FLD:     Temperature value offset field offset
+ */
+#define IDT_TMPADJ_OFFSET_MASK         0x000000FFU
+#define IDT_TMPADJ_OFFSET_FLD          0
 
 /*
  * Helper macro to get/set the corresponding field value
 #define IDT_DIR_SIZE_ALIGN     1
 
 /*
+ * IDT PCIe-switch temperature sensor value limits
+ * @IDT_TEMP_MIN_MDEG: Minimal integer value of temperature
+ * @IDT_TEMP_MAX_MDEG: Maximal integer value of temperature
+ * @IDT_TEMP_MIN_OFFSET:Minimal integer value of temperature offset
+ * @IDT_TEMP_MAX_OFFSET:Maximal integer value of temperature offset
+ */
+#define IDT_TEMP_MIN_MDEG      0
+#define IDT_TEMP_MAX_MDEG      127500
+#define IDT_TEMP_MIN_OFFSET    -64000
+#define IDT_TEMP_MAX_OFFSET    63500
+
+/*
+ * Temperature sensor values enumeration
+ * @IDT_TEMP_CUR:      Current temperature
+ * @IDT_TEMP_LOW:      Lowest historical temperature
+ * @IDT_TEMP_HIGH:     Highest historical temperature
+ * @IDT_TEMP_OFFSET:   Current temperature offset
+ */
+enum idt_temp_val {
+       IDT_TEMP_CUR,
+       IDT_TEMP_LOW,
+       IDT_TEMP_HIGH,
+       IDT_TEMP_OFFSET
+};
+
+/*
  * IDT Memory Windows type. Depending on the device settings, IDT supports
  * Direct Address Translation MW registers and Lookup Table registers
  * @IDT_MW_DIR:                Direct address translation
@@ -1044,6 +1117,8 @@ struct idt_ntb_peer {
  * @msg_mask_lock:     Message mask register lock
  * @gasa_lock:         GASA registers access lock
  *
+ * @hwmon_mtx:         Temperature sensor interface update mutex
+ *
  * @dbgfs_info:                DebugFS info node
  */
 struct idt_ntb_dev {
@@ -1071,6 +1146,8 @@ struct idt_ntb_dev {
        spinlock_t msg_mask_lock;
        spinlock_t gasa_lock;
 
+       struct mutex hwmon_mtx;
+
        struct dentry *dbgfs_info;
 };
 #define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)
index 6aa5732..2ad263f 100644 (file)
@@ -265,7 +265,7 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
        return 0;
 }
 
-static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
+static inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
 {
        u64 shift, mask;
 
index 9398959..3bfdb45 100644 (file)
@@ -194,6 +194,8 @@ struct ntb_transport_mw {
        void __iomem *vbase;
        size_t xlat_size;
        size_t buff_size;
+       size_t alloc_size;
+       void *alloc_addr;
        void *virt_addr;
        dma_addr_t dma_addr;
 };
@@ -672,13 +674,59 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
                return;
 
        ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
-       dma_free_coherent(&pdev->dev, mw->buff_size,
-                         mw->virt_addr, mw->dma_addr);
+       dma_free_coherent(&pdev->dev, mw->alloc_size,
+                         mw->alloc_addr, mw->dma_addr);
        mw->xlat_size = 0;
        mw->buff_size = 0;
+       mw->alloc_size = 0;
+       mw->alloc_addr = NULL;
        mw->virt_addr = NULL;
 }
 
+static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
+                              struct device *dma_dev, size_t align)
+{
+       dma_addr_t dma_addr;
+       void *alloc_addr, *virt_addr;
+       int rc;
+
+       alloc_addr = dma_alloc_coherent(dma_dev, mw->alloc_size,
+                                       &dma_addr, GFP_KERNEL);
+       if (!alloc_addr) {
+               dev_err(dma_dev, "Unable to alloc MW buff of size %zu\n",
+                       mw->alloc_size);
+               return -ENOMEM;
+       }
+       virt_addr = alloc_addr;
+
+       /*
+        * we must ensure that the memory address allocated is BAR size
+        * aligned in order for the XLAT register to take the value. This
+        * is a requirement of the hardware. It is recommended to setup CMA
+        * for BAR sizes equal or greater than 4MB.
+        */
+       if (!IS_ALIGNED(dma_addr, align)) {
+               if (mw->alloc_size > mw->buff_size) {
+                       virt_addr = PTR_ALIGN(alloc_addr, align);
+                       dma_addr = ALIGN(dma_addr, align);
+               } else {
+                       rc = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       mw->alloc_addr = alloc_addr;
+       mw->virt_addr = virt_addr;
+       mw->dma_addr = dma_addr;
+
+       return 0;
+
+err:
+       dma_free_coherent(dma_dev, mw->alloc_size, alloc_addr, dma_addr);
+
+       return rc;
+}
+
 static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
                      resource_size_t size)
 {
@@ -710,28 +758,20 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
        /* Alloc memory for receiving data.  Must be aligned */
        mw->xlat_size = xlat_size;
        mw->buff_size = buff_size;
+       mw->alloc_size = buff_size;
 
-       mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size,
-                                          &mw->dma_addr, GFP_KERNEL);
-       if (!mw->virt_addr) {
-               mw->xlat_size = 0;
-               mw->buff_size = 0;
-               dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
-                       buff_size);
-               return -ENOMEM;
-       }
-
-       /*
-        * we must ensure that the memory address allocated is BAR size
-        * aligned in order for the XLAT register to take the value. This
-        * is a requirement of the hardware. It is recommended to setup CMA
-        * for BAR sizes equal or greater than 4MB.
-        */
-       if (!IS_ALIGNED(mw->dma_addr, xlat_align)) {
-               dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
-                       &mw->dma_addr);
-               ntb_free_mw(nt, num_mw);
-               return -ENOMEM;
+       rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+       if (rc) {
+               mw->alloc_size *= 2;
+               rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+               if (rc) {
+                       dev_err(&pdev->dev,
+                               "Unable to alloc aligned MW buff\n");
+                       mw->xlat_size = 0;
+                       mw->buff_size = 0;
+                       mw->alloc_size = 0;
+                       return rc;
+               }
        }
 
        /* Notify HW the memory location of the receive buffer */
@@ -1278,6 +1318,7 @@ static void ntb_rx_copy_callback(void *data,
                case DMA_TRANS_READ_FAILED:
                case DMA_TRANS_WRITE_FAILED:
                        entry->errors++;
+                       /* fall through */
                case DMA_TRANS_ABORTED:
                {
                        struct ntb_transport_qp *qp = entry->qp;
@@ -1533,6 +1574,7 @@ static void ntb_tx_copy_callback(void *data,
                case DMA_TRANS_READ_FAILED:
                case DMA_TRANS_WRITE_FAILED:
                        entry->errors++;
+                       /* fall through */
                case DMA_TRANS_ABORTED:
                {
                        void __iomem *offset =
index 2e65be8..559d567 100644 (file)
@@ -1519,8 +1519,10 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
        if (ns->ndev)
                nvme_nvm_update_nvm_info(ns);
 #ifdef CONFIG_NVME_MULTIPATH
-       if (ns->head->disk)
+       if (ns->head->disk) {
                nvme_update_disk_info(ns->head->disk, ns, id);
+               blk_queue_stack_limits(ns->head->disk->queue, ns->queue);
+       }
 #endif
 }
 
index 5e3cc8c..9901afd 100644 (file)
@@ -285,6 +285,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
        blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
        /* set to a default value for 512 until disk is validated */
        blk_queue_logical_block_size(q, 512);
+       blk_set_stacking_limits(&q->limits);
 
        /* we need to propagate up the VMC settings */
        if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
index f4efe28..a5f9bbc 100644 (file)
@@ -420,7 +420,7 @@ static void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl,
        struct pci_dev *p2p_dev;
        int ret;
 
-       if (!ctrl->p2p_client)
+       if (!ctrl->p2p_client || !ns->use_p2pmem)
                return;
 
        if (ns->p2p_dev) {
index ddce100..3f7971d 100644 (file)
@@ -122,7 +122,6 @@ struct nvmet_rdma_device {
        int                     inline_page_count;
 };
 
-static struct workqueue_struct *nvmet_rdma_delete_wq;
 static bool nvmet_rdma_use_srq;
 module_param_named(use_srq, nvmet_rdma_use_srq, bool, 0444);
 MODULE_PARM_DESC(use_srq, "Use shared receive queue.");
@@ -1274,12 +1273,12 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
 
        if (queue->host_qid == 0) {
                /* Let inflight controller teardown complete */
-               flush_workqueue(nvmet_rdma_delete_wq);
+               flush_scheduled_work();
        }
 
        ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
        if (ret) {
-               queue_work(nvmet_rdma_delete_wq, &queue->release_work);
+               schedule_work(&queue->release_work);
                /* Destroying rdma_cm id is not needed here */
                return 0;
        }
@@ -1344,7 +1343,7 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
 
        if (disconnect) {
                rdma_disconnect(queue->cm_id);
-               queue_work(nvmet_rdma_delete_wq, &queue->release_work);
+               schedule_work(&queue->release_work);
        }
 }
 
@@ -1374,7 +1373,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
        mutex_unlock(&nvmet_rdma_queue_mutex);
 
        pr_err("failed to connect queue %d\n", queue->idx);
-       queue_work(nvmet_rdma_delete_wq, &queue->release_work);
+       schedule_work(&queue->release_work);
 }
 
 /**
@@ -1656,17 +1655,8 @@ static int __init nvmet_rdma_init(void)
        if (ret)
                goto err_ib_client;
 
-       nvmet_rdma_delete_wq = alloc_workqueue("nvmet-rdma-delete-wq",
-                       WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
-       if (!nvmet_rdma_delete_wq) {
-               ret = -ENOMEM;
-               goto err_unreg_transport;
-       }
-
        return 0;
 
-err_unreg_transport:
-       nvmet_unregister_transport(&nvmet_rdma_ops);
 err_ib_client:
        ib_unregister_client(&nvmet_rdma_ib_client);
        return ret;
@@ -1674,7 +1664,6 @@ err_ib_client:
 
 static void __exit nvmet_rdma_exit(void)
 {
-       destroy_workqueue(nvmet_rdma_delete_wq);
        nvmet_unregister_transport(&nvmet_rdma_ops);
        ib_unregister_client(&nvmet_rdma_ib_client);
        WARN_ON_ONCE(!list_empty(&nvmet_rdma_queue_list));
index 0f27fad..5592437 100644 (file)
@@ -149,9 +149,11 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
         * set by the driver.
         */
        mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1);
-       dev->bus_dma_mask = mask;
        dev->coherent_dma_mask &= mask;
        *dev->dma_mask &= mask;
+       /* ...but only set bus mask if we found valid dma-ranges earlier */
+       if (!ret)
+               dev->bus_dma_mask = mask;
 
        coherent = of_dma_is_coherent(np);
        dev_dbg(dev, "device is%sdma coherent\n",
index 35c64a4..fe6b136 100644 (file)
@@ -104,9 +104,14 @@ static int __init of_numa_parse_distance_map_v1(struct device_node *map)
                distance = of_read_number(matrix, 1);
                matrix++;
 
+               if ((nodea == nodeb && distance != LOCAL_DISTANCE) ||
+                   (nodea != nodeb && distance <= LOCAL_DISTANCE)) {
+                       pr_err("Invalid distance[node%d -> node%d] = %d\n",
+                              nodea, nodeb, distance);
+                       return -EINVAL;
+               }
+
                numa_set_distance(nodea, nodeb, distance);
-               pr_debug("distance[node%d -> node%d] = %d\n",
-                        nodea, nodeb, distance);
 
                /* Set default distance of node B->A same as A->B */
                if (nodeb > nodea)
index 6843bc7..04e294d 100644 (file)
@@ -87,6 +87,18 @@ struct qeth_dbf_info {
 #define SENSE_RESETTING_EVENT_BYTE 1
 #define SENSE_RESETTING_EVENT_FLAG 0x80
 
+static inline u32 qeth_get_device_id(struct ccw_device *cdev)
+{
+       struct ccw_dev_id dev_id;
+       u32 id;
+
+       ccw_device_get_id(cdev, &dev_id);
+       id = dev_id.devno;
+       id |= (u32) (dev_id.ssid << 16);
+
+       return id;
+}
+
 /*
  * Common IO related definitions
  */
@@ -97,7 +109,8 @@ struct qeth_dbf_info {
 #define CARD_RDEV_ID(card) dev_name(&card->read.ccwdev->dev)
 #define CARD_WDEV_ID(card) dev_name(&card->write.ccwdev->dev)
 #define CARD_DDEV_ID(card) dev_name(&card->data.ccwdev->dev)
-#define CHANNEL_ID(channel) dev_name(&channel->ccwdev->dev)
+#define CCW_DEVID(cdev)                (qeth_get_device_id(cdev))
+#define CARD_DEVID(card)       (CCW_DEVID(CARD_RDEV(card)))
 
 /**
  * card stuff
@@ -830,6 +843,11 @@ struct qeth_trap_id {
 /*some helper functions*/
 #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
 
+static inline bool qeth_netdev_is_registered(struct net_device *dev)
+{
+       return dev->netdev_ops != NULL;
+}
+
 static inline void qeth_scrub_qdio_buffer(struct qdio_buffer *buf,
                                          unsigned int elements)
 {
@@ -973,7 +991,7 @@ int qeth_wait_for_threads(struct qeth_card *, unsigned long);
 int qeth_do_run_thread(struct qeth_card *, unsigned long);
 void qeth_clear_thread_start_bit(struct qeth_card *, unsigned long);
 void qeth_clear_thread_running_bit(struct qeth_card *, unsigned long);
-int qeth_core_hardsetup_card(struct qeth_card *);
+int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok);
 void qeth_print_status_message(struct qeth_card *);
 int qeth_init_qdio_queues(struct qeth_card *);
 int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
@@ -1028,11 +1046,6 @@ int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
 int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
 void qeth_trace_features(struct qeth_card *);
 void qeth_close_dev(struct qeth_card *);
-int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
-                         long,
-                         int (*reply_cb)(struct qeth_card *,
-                                         struct qeth_reply *, unsigned long),
-                         void *);
 int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
 struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
                                                 enum qeth_ipa_funcs,
index 3274f13..4bce5ae 100644 (file)
@@ -167,6 +167,8 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
                                return "OSD_1000";
                        case QETH_LINK_TYPE_10GBIT_ETH:
                                return "OSD_10GIG";
+                       case QETH_LINK_TYPE_25GBIT_ETH:
+                               return "OSD_25GIG";
                        case QETH_LINK_TYPE_LANE_ETH100:
                                return "OSD_FE_LANE";
                        case QETH_LINK_TYPE_LANE_TR:
@@ -554,8 +556,8 @@ static int __qeth_issue_next_read(struct qeth_card *card)
        if (!iob) {
                dev_warn(&card->gdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob "
-                       "available\n", dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(2, "issue_next_read on device %x failed: no iob available\n",
+                                CARD_DEVID(card));
                return -ENOMEM;
        }
        qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data);
@@ -563,8 +565,8 @@ static int __qeth_issue_next_read(struct qeth_card *card)
        rc = ccw_device_start(channel->ccwdev, channel->ccw,
                              (addr_t) iob, 0, 0);
        if (rc) {
-               QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! "
-                       "rc=%i\n", dev_name(&card->gdev->dev), rc);
+               QETH_DBF_MESSAGE(2, "error %i on device %x when starting next read ccw!\n",
+                                rc, CARD_DEVID(card));
                atomic_set(&channel->irq_pending, 0);
                card->read_or_write_problem = 1;
                qeth_schedule_recovery(card);
@@ -613,16 +615,14 @@ static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
        const char *ipa_name;
        int com = cmd->hdr.command;
        ipa_name = qeth_get_ipa_cmd_name(com);
+
        if (rc)
-               QETH_DBF_MESSAGE(2, "IPA: %s(x%X) for %s/%s returned "
-                               "x%X \"%s\"\n",
-                               ipa_name, com, dev_name(&card->gdev->dev),
-                               QETH_CARD_IFNAME(card), rc,
-                               qeth_get_ipa_msg(rc));
+               QETH_DBF_MESSAGE(2, "IPA: %s(%#x) for device %x returned %#x \"%s\"\n",
+                                ipa_name, com, CARD_DEVID(card), rc,
+                                qeth_get_ipa_msg(rc));
        else
-               QETH_DBF_MESSAGE(5, "IPA: %s(x%X) for %s/%s succeeded\n",
-                               ipa_name, com, dev_name(&card->gdev->dev),
-                               QETH_CARD_IFNAME(card));
+               QETH_DBF_MESSAGE(5, "IPA: %s(%#x) for device %x succeeded\n",
+                                ipa_name, com, CARD_DEVID(card));
 }
 
 static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
@@ -711,7 +711,7 @@ static int qeth_check_idx_response(struct qeth_card *card,
 
        QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN);
        if ((buffer[2] & 0xc0) == 0xc0) {
-               QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#02x\n",
+               QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#04x\n",
                                 buffer[4]);
                QETH_CARD_TEXT(card, 2, "ckidxres");
                QETH_CARD_TEXT(card, 2, " idxterm");
@@ -972,8 +972,8 @@ static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev,
                QETH_CARD_TEXT(card, 2, "CGENCHK");
                dev_warn(&cdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x\n",
-                       dev_name(&cdev->dev), dstat, cstat);
+               QETH_DBF_MESSAGE(2, "check on channel %x with dstat=%#x, cstat=%#x\n",
+                                CCW_DEVID(cdev), dstat, cstat);
                print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
                                16, 1, irb, 64, 1);
                return 1;
@@ -1013,8 +1013,8 @@ static long qeth_check_irb_error(struct qeth_card *card,
 
        switch (PTR_ERR(irb)) {
        case -EIO:
-               QETH_DBF_MESSAGE(2, "%s i/o-error on device\n",
-                       dev_name(&cdev->dev));
+               QETH_DBF_MESSAGE(2, "i/o-error on channel %x\n",
+                                CCW_DEVID(cdev));
                QETH_CARD_TEXT(card, 2, "ckirberr");
                QETH_CARD_TEXT_(card, 2, "  rc%d", -EIO);
                break;
@@ -1031,8 +1031,8 @@ static long qeth_check_irb_error(struct qeth_card *card,
                }
                break;
        default:
-               QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n",
-                       dev_name(&cdev->dev), PTR_ERR(irb));
+               QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n",
+                                PTR_ERR(irb), CCW_DEVID(cdev));
                QETH_CARD_TEXT(card, 2, "ckirberr");
                QETH_CARD_TEXT(card, 2, "  rc???");
        }
@@ -1114,9 +1114,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                        dev_warn(&channel->ccwdev->dev,
                                "The qeth device driver failed to recover "
                                "an error on the device\n");
-                       QETH_DBF_MESSAGE(2, "%s sense data available. cstat "
-                               "0x%X dstat 0x%X\n",
-                               dev_name(&channel->ccwdev->dev), cstat, dstat);
+                       QETH_DBF_MESSAGE(2, "sense data available on channel %x: cstat %#X dstat %#X\n",
+                                        CCW_DEVID(channel->ccwdev), cstat,
+                                        dstat);
                        print_hex_dump(KERN_WARNING, "qeth: irb ",
                                DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1);
                        print_hex_dump(KERN_WARNING, "qeth: sense data ",
@@ -1890,8 +1890,8 @@ static int qeth_idx_activate_channel(struct qeth_card *card,
        if (channel->state != CH_STATE_ACTIVATING) {
                dev_warn(&channel->ccwdev->dev, "The qeth device driver"
                        " failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
-                       dev_name(&channel->ccwdev->dev));
+               QETH_DBF_MESSAGE(2, "IDX activate timed out on channel %x\n",
+                                CCW_DEVID(channel->ccwdev));
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
                return -ETIME;
        }
@@ -1926,17 +1926,15 @@ static void qeth_idx_write_cb(struct qeth_card *card,
                                "The adapter is used exclusively by another "
                                "host\n");
                else
-                       QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:"
-                               " negative reply\n",
-                               dev_name(&channel->ccwdev->dev));
+                       QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n",
+                                        CCW_DEVID(channel->ccwdev));
                goto out;
        }
        memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
        if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
-               QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: "
-                       "function level mismatch (sent: 0x%x, received: "
-                       "0x%x)\n", dev_name(&channel->ccwdev->dev),
-                       card->info.func_level, temp);
+               QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n",
+                                CCW_DEVID(channel->ccwdev),
+                                card->info.func_level, temp);
                goto out;
        }
        channel->state = CH_STATE_UP;
@@ -1973,9 +1971,8 @@ static void qeth_idx_read_cb(struct qeth_card *card,
                                "insufficient authorization\n");
                        break;
                default:
-                       QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
-                               " negative reply\n",
-                               dev_name(&channel->ccwdev->dev));
+                       QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n",
+                                        CCW_DEVID(channel->ccwdev));
                }
                QETH_CARD_TEXT_(card, 2, "idxread%c",
                        QETH_IDX_ACT_CAUSE_CODE(iob->data));
@@ -1984,10 +1981,9 @@ static void qeth_idx_read_cb(struct qeth_card *card,
 
        memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
        if (temp != qeth_peer_func_level(card->info.func_level)) {
-               QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function "
-                       "level mismatch (sent: 0x%x, received: 0x%x)\n",
-                       dev_name(&channel->ccwdev->dev),
-                       card->info.func_level, temp);
+               QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n",
+                                CCW_DEVID(channel->ccwdev),
+                                card->info.func_level, temp);
                goto out;
        }
        memcpy(&card->token.issuer_rm_r,
@@ -2096,9 +2092,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
                                      (addr_t) iob, 0, 0, event_timeout);
        spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
        if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
-                       "ccw_device_start rc = %i\n",
-                       dev_name(&channel->ccwdev->dev), rc);
+               QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
+                                CARD_DEVID(card), rc);
                QETH_CARD_TEXT_(card, 2, " err%d", rc);
                spin_lock_irq(&card->lock);
                list_del_init(&reply->list);
@@ -2853,8 +2848,8 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
        } else {
                dev_warn(&card->gdev->dev,
                         "The qeth driver ran out of channel command buffers\n");
-               QETH_DBF_MESSAGE(1, "%s The qeth driver ran out of channel command buffers",
-                                dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(1, "device %x ran out of channel command buffers",
+                                CARD_DEVID(card));
        }
 
        return iob;
@@ -2989,10 +2984,9 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
                return 0;
        default:
                if (cmd->hdr.return_code) {
-                       QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Unhandled "
-                                               "rc=%d\n",
-                                               dev_name(&card->gdev->dev),
-                                               cmd->hdr.return_code);
+                       QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n",
+                                        CARD_DEVID(card),
+                                        cmd->hdr.return_code);
                        return 0;
                }
        }
@@ -3004,8 +2998,8 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
                card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
                card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
        } else
-               QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Flawed LIC detected"
-                                       "\n", dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Flawed LIC detected\n",
+                                CARD_DEVID(card));
        return 0;
 }
 
@@ -4297,10 +4291,9 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                cmd->data.setadapterparms.hdr.return_code);
        if (cmd->data.setadapterparms.hdr.return_code !=
                                                SET_ACCESS_CTRL_RC_SUCCESS)
-               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
-                               card->gdev->dev.kobj.name,
-                               access_ctrl_req->subcmd_code,
-                               cmd->data.setadapterparms.hdr.return_code);
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%#x) on device %x: %#x\n",
+                                access_ctrl_req->subcmd_code, CARD_DEVID(card),
+                                cmd->data.setadapterparms.hdr.return_code);
        switch (cmd->data.setadapterparms.hdr.return_code) {
        case SET_ACCESS_CTRL_RC_SUCCESS:
                if (card->options.isolation == ISOLATION_MODE_NONE) {
@@ -4312,14 +4305,14 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                }
                break;
        case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
-               QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already "
-                               "deactivated\n", dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already deactivated\n",
+                                CARD_DEVID(card));
                if (fallback)
                        card->options.isolation = card->options.prev_isolation;
                break;
        case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
-               QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already"
-                               " activated\n", dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already activated\n",
+                                CARD_DEVID(card));
                if (fallback)
                        card->options.isolation = card->options.prev_isolation;
                break;
@@ -4405,10 +4398,8 @@ int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback)
                rc = qeth_setadpparms_set_access_ctrl(card,
                        card->options.isolation, fallback);
                if (rc) {
-                       QETH_DBF_MESSAGE(3,
-                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
-                               card->gdev->dev.kobj.name,
-                               rc);
+                       QETH_DBF_MESSAGE(3, "IPA(SET_ACCESS_CTRL(%d) on device %x: sent failed\n",
+                                        rc, CARD_DEVID(card));
                        rc = -EOPNOTSUPP;
                }
        } else if (card->options.isolation != ISOLATION_MODE_NONE) {
@@ -4443,7 +4434,8 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
                rc = BMCR_FULLDPLX;
                if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH) &&
                    (card->info.link_type != QETH_LINK_TYPE_OSN) &&
-                   (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH))
+                   (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH) &&
+                   (card->info.link_type != QETH_LINK_TYPE_25GBIT_ETH))
                        rc |= BMCR_SPEED100;
                break;
        case MII_BMSR: /* Basic mode status register */
@@ -4634,8 +4626,8 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
        rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len,
                                    qeth_snmp_command_cb, (void *)&qinfo);
        if (rc)
-               QETH_DBF_MESSAGE(2, "SNMP command failed on %s: (0x%x)\n",
-                          QETH_CARD_IFNAME(card), rc);
+               QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n",
+                                CARD_DEVID(card), rc);
        else {
                if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
                        rc = -EFAULT;
@@ -4869,8 +4861,8 @@ static void qeth_determine_capabilities(struct qeth_card *card)
 
        rc = qeth_read_conf_data(card, (void **) &prcd, &length);
        if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_MESSAGE(2, "qeth_read_conf_data on device %x returned %i\n",
+                                CARD_DEVID(card), rc);
                QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
                goto out_offline;
        }
@@ -5086,7 +5078,7 @@ static struct ccw_driver qeth_ccw_driver = {
        .remove = ccwgroup_remove_ccwdev,
 };
 
-int qeth_core_hardsetup_card(struct qeth_card *card)
+int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
 {
        int retries = 3;
        int rc;
@@ -5096,8 +5088,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
        qeth_update_from_chp_desc(card);
 retry:
        if (retries < 3)
-               QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
-                       dev_name(&card->gdev->dev));
+               QETH_DBF_MESSAGE(2, "Retrying to do IDX activates on device %x.\n",
+                                CARD_DEVID(card));
        rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
@@ -5161,13 +5153,20 @@ retriable:
                if (rc == IPA_RC_LAN_OFFLINE) {
                        dev_warn(&card->gdev->dev,
                                "The LAN is offline\n");
-                       netif_carrier_off(card->dev);
+                       *carrier_ok = false;
                } else {
                        rc = -ENODEV;
                        goto out;
                }
        } else {
-               netif_carrier_on(card->dev);
+               *carrier_ok = true;
+       }
+
+       if (qeth_netdev_is_registered(card->dev)) {
+               if (*carrier_ok)
+                       netif_carrier_on(card->dev);
+               else
+                       netif_carrier_off(card->dev);
        }
 
        card->options.ipa4.supported_funcs = 0;
@@ -5201,8 +5200,8 @@ retriable:
 out:
        dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
                "an error on the device\n");
-       QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n",
-               dev_name(&card->gdev->dev), rc);
+       QETH_DBF_MESSAGE(2, "Initialization for device %x failed in hardsetup! rc=%d\n",
+                        CARD_DEVID(card), rc);
        return rc;
 }
 EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
@@ -5481,11 +5480,12 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
 }
 EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
 
-int qeth_send_setassparms(struct qeth_card *card,
-                         struct qeth_cmd_buffer *iob, __u16 len, long data,
-                         int (*reply_cb)(struct qeth_card *,
-                                         struct qeth_reply *, unsigned long),
-                         void *reply_param)
+static int qeth_send_setassparms(struct qeth_card *card,
+                                struct qeth_cmd_buffer *iob, u16 len,
+                                long data, int (*reply_cb)(struct qeth_card *,
+                                                           struct qeth_reply *,
+                                                           unsigned long),
+                                void *reply_param)
 {
        int rc;
        struct qeth_ipa_cmd *cmd;
@@ -5501,7 +5501,6 @@ int qeth_send_setassparms(struct qeth_card *card,
        rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
        return rc;
 }
-EXPORT_SYMBOL_GPL(qeth_send_setassparms);
 
 int qeth_send_simple_setassparms_prot(struct qeth_card *card,
                                      enum qeth_ipa_funcs ipa_func,
@@ -6170,8 +6169,14 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd,
                WARN_ON_ONCE(1);
        }
 
-       /* fallthrough from high to low, to select all legal speeds: */
+       /* partially does fall through, to also select lower speeds */
        switch (maxspeed) {
+       case SPEED_25000:
+               ethtool_link_ksettings_add_link_mode(cmd, supported,
+                                                    25000baseSR_Full);
+               ethtool_link_ksettings_add_link_mode(cmd, advertising,
+                                                    25000baseSR_Full);
+               break;
        case SPEED_10000:
                ethtool_link_ksettings_add_link_mode(cmd, supported,
                                                     10000baseT_Full);
@@ -6254,6 +6259,10 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
                cmd->base.speed = SPEED_10000;
                cmd->base.port = PORT_FIBRE;
                break;
+       case QETH_LINK_TYPE_25GBIT_ETH:
+               cmd->base.speed = SPEED_25000;
+               cmd->base.port = PORT_FIBRE;
+               break;
        default:
                cmd->base.speed = SPEED_10;
                cmd->base.port = PORT_TP;
@@ -6320,6 +6329,9 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
        case CARD_INFO_PORTS_10G:
                cmd->base.speed = SPEED_10000;
                break;
+       case CARD_INFO_PORTS_25G:
+               cmd->base.speed = SPEED_25000;
+               break;
        }
 
        return 0;
index e850904..3e54be2 100644 (file)
@@ -90,6 +90,7 @@ enum qeth_link_types {
        QETH_LINK_TYPE_GBIT_ETH     = 0x03,
        QETH_LINK_TYPE_OSN          = 0x04,
        QETH_LINK_TYPE_10GBIT_ETH   = 0x10,
+       QETH_LINK_TYPE_25GBIT_ETH   = 0x12,
        QETH_LINK_TYPE_LANE_ETH100  = 0x81,
        QETH_LINK_TYPE_LANE_TR      = 0x82,
        QETH_LINK_TYPE_LANE_ETH1000 = 0x83,
@@ -347,6 +348,7 @@ enum qeth_card_info_port_speed {
        CARD_INFO_PORTS_100M            = 0x00000006,
        CARD_INFO_PORTS_1G              = 0x00000007,
        CARD_INFO_PORTS_10G             = 0x00000008,
+       CARD_INFO_PORTS_25G             = 0x0000000A,
 };
 
 /* (SET)DELIP(M) IPA stuff ***************************************************/
@@ -436,7 +438,7 @@ struct qeth_ipacmd_setassparms {
                __u32 flags_32bit;
                struct qeth_ipa_caps caps;
                struct qeth_checksum_cmd chksum;
-               struct qeth_arp_cache_entry add_arp_entry;
+               struct qeth_arp_cache_entry arp_entry;
                struct qeth_arp_query_data query_arp;
                struct qeth_tso_start_data tso;
                __u8 ip[16];
index 23aaf37..2914a1a 100644 (file)
@@ -146,11 +146,11 @@ static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
        QETH_CARD_TEXT(card, 2, "L2Wmac");
        rc = qeth_l2_send_setdelmac(card, mac, cmd);
        if (rc == -EEXIST)
-               QETH_DBF_MESSAGE(2, "MAC %pM already registered on %s\n",
-                                mac, QETH_CARD_IFNAME(card));
+               QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n",
+                                CARD_DEVID(card));
        else if (rc)
-               QETH_DBF_MESSAGE(2, "Failed to register MAC %pM on %s: %d\n",
-                                mac, QETH_CARD_IFNAME(card), rc);
+               QETH_DBF_MESSAGE(2, "Failed to register MAC on device %x: %d\n",
+                                CARD_DEVID(card), rc);
        return rc;
 }
 
@@ -163,8 +163,8 @@ static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
        QETH_CARD_TEXT(card, 2, "L2Rmac");
        rc = qeth_l2_send_setdelmac(card, mac, cmd);
        if (rc)
-               QETH_DBF_MESSAGE(2, "Failed to delete MAC %pM on %s: %d\n",
-                                mac, QETH_CARD_IFNAME(card), rc);
+               QETH_DBF_MESSAGE(2, "Failed to delete MAC on device %u: %d\n",
+                                CARD_DEVID(card), rc);
        return rc;
 }
 
@@ -260,9 +260,9 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
 
        QETH_CARD_TEXT(card, 2, "L2sdvcb");
        if (cmd->hdr.return_code) {
-               QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x.\n",
+               QETH_DBF_MESSAGE(2, "Error in processing VLAN %u on device %x: %#x.\n",
                                 cmd->data.setdelvlan.vlan_id,
-                                QETH_CARD_IFNAME(card), cmd->hdr.return_code);
+                                CARD_DEVID(card), cmd->hdr.return_code);
                QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
                QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
        }
@@ -455,8 +455,8 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
                rc = qeth_vm_request_mac(card);
                if (!rc)
                        goto out;
-               QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %s: x%x\n",
-                                CARD_BUS_ID(card), rc);
+               QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n",
+                                CARD_DEVID(card), rc);
                QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc);
                /* fall back to alternative mechanism: */
        }
@@ -468,8 +468,8 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
                rc = qeth_setadpparms_change_macaddr(card);
                if (!rc)
                        goto out;
-               QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %s: x%x\n",
-                                CARD_BUS_ID(card), rc);
+               QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
+                                CARD_DEVID(card), rc);
                QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
                /* fall back once more: */
        }
@@ -826,7 +826,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
 
        if (cgdev->state == CCWGROUP_ONLINE)
                qeth_l2_set_offline(cgdev);
-       unregister_netdev(card->dev);
+       if (qeth_netdev_is_registered(card->dev))
+               unregister_netdev(card->dev);
 }
 
 static const struct ethtool_ops qeth_l2_ethtool_ops = {
@@ -862,11 +863,11 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
        .ndo_set_features       = qeth_set_features
 };
 
-static int qeth_l2_setup_netdev(struct qeth_card *card)
+static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok)
 {
        int rc;
 
-       if (card->dev->netdev_ops)
+       if (qeth_netdev_is_registered(card->dev))
                return 0;
 
        card->dev->priv_flags |= IFF_UNICAST_FLT;
@@ -919,6 +920,9 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
        qeth_l2_request_initial_mac(card);
        netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
        rc = register_netdev(card->dev);
+       if (!rc && carrier_ok)
+               netif_carrier_on(card->dev);
+
        if (rc)
                card->dev->netdev_ops = NULL;
        return rc;
@@ -949,6 +953,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
        int rc = 0;
        enum qeth_card_states recover_flag;
+       bool carrier_ok;
 
        mutex_lock(&card->discipline_mutex);
        mutex_lock(&card->conf_mutex);
@@ -956,7 +961,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
        recover_flag = card->state;
-       rc = qeth_core_hardsetup_card(card);
+       rc = qeth_core_hardsetup_card(card, &carrier_ok);
        if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
                rc = -ENODEV;
@@ -967,7 +972,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                dev_info(&card->gdev->dev,
                "The device represents a Bridge Capable Port\n");
 
-       rc = qeth_l2_setup_netdev(card);
+       rc = qeth_l2_setup_netdev(card, carrier_ok);
        if (rc)
                goto out_remove;
 
index 0b161cc..f08b745 100644 (file)
@@ -278,9 +278,6 @@ static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover)
 
        QETH_CARD_TEXT(card, 4, "clearip");
 
-       if (recover && card->options.sniffer)
-               return;
-
        spin_lock_bh(&card->ip_lock);
 
        hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
@@ -494,9 +491,8 @@ int qeth_l3_setrouting_v4(struct qeth_card *card)
                                  QETH_PROT_IPV4);
        if (rc) {
                card->options.route4.type = NO_ROUTER;
-               QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
-                       " on %s. Type set to 'no router'.\n", rc,
-                       QETH_CARD_IFNAME(card));
+               QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
+                                rc, CARD_DEVID(card));
        }
        return rc;
 }
@@ -518,9 +514,8 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
                                  QETH_PROT_IPV6);
        if (rc) {
                card->options.route6.type = NO_ROUTER;
-               QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
-                       " on %s. Type set to 'no router'.\n", rc,
-                       QETH_CARD_IFNAME(card));
+               QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
+                                rc, CARD_DEVID(card));
        }
        return rc;
 }
@@ -663,6 +658,8 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card,
        int rc = 0;
        int cnt = 3;
 
+       if (card->options.sniffer)
+               return 0;
 
        if (addr->proto == QETH_PROT_IPV4) {
                QETH_CARD_TEXT(card, 2, "setaddr4");
@@ -697,6 +694,9 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
 {
        int rc = 0;
 
+       if (card->options.sniffer)
+               return 0;
+
        if (addr->proto == QETH_PROT_IPV4) {
                QETH_CARD_TEXT(card, 2, "deladdr4");
                QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
@@ -1070,8 +1070,8 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
                }
                break;
        default:
-               QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n",
-                       cmd->data.diagass.action, QETH_CARD_IFNAME(card));
+               QETH_DBF_MESSAGE(2, "Unknown sniffer action (%#06x) on device %x\n",
+                                cmd->data.diagass.action, CARD_DEVID(card));
        }
 
        return 0;
@@ -1517,32 +1517,25 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
        qeth_l3_handle_promisc_mode(card);
 }
 
-static const char *qeth_l3_arp_get_error_cause(int *rc)
+static int qeth_l3_arp_makerc(int rc)
 {
-       switch (*rc) {
-       case QETH_IPA_ARP_RC_FAILED:
-               *rc = -EIO;
-               return "operation failed";
+       switch (rc) {
+       case IPA_RC_SUCCESS:
+               return 0;
        case QETH_IPA_ARP_RC_NOTSUPP:
-               *rc = -EOPNOTSUPP;
-               return "operation not supported";
-       case QETH_IPA_ARP_RC_OUT_OF_RANGE:
-               *rc = -EINVAL;
-               return "argument out of range";
        case QETH_IPA_ARP_RC_Q_NOTSUPP:
-               *rc = -EOPNOTSUPP;
-               return "query operation not supported";
+               return -EOPNOTSUPP;
+       case QETH_IPA_ARP_RC_OUT_OF_RANGE:
+               return -EINVAL;
        case QETH_IPA_ARP_RC_Q_NO_DATA:
-               *rc = -ENOENT;
-               return "no query data available";
+               return -ENOENT;
        default:
-               return "unknown error";
+               return -EIO;
        }
 }
 
 static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
 {
-       int tmp;
        int rc;
 
        QETH_CARD_TEXT(card, 3, "arpstnoe");
@@ -1560,13 +1553,10 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
        rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
                                          IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
                                          no_entries);
-       if (rc) {
-               tmp = rc;
-               QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on "
-                       "%s: %s (0x%x/%d)\n", QETH_CARD_IFNAME(card),
-                       qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
-       }
-       return rc;
+       if (rc)
+               QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
+                                CARD_DEVID(card), rc);
+       return qeth_l3_arp_makerc(rc);
 }
 
 static __u32 get_arp_entry_size(struct qeth_card *card,
@@ -1716,7 +1706,6 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
 {
        struct qeth_cmd_buffer *iob;
        struct qeth_ipa_cmd *cmd;
-       int tmp;
        int rc;
 
        QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
@@ -1735,15 +1724,10 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
        rc = qeth_l3_send_ipa_arp_cmd(card, iob,
                           QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
                           qeth_l3_arp_query_cb, (void *)qinfo);
-       if (rc) {
-               tmp = rc;
-               QETH_DBF_MESSAGE(2,
-                       "Error while querying ARP cache on %s: %s "
-                       "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
-                       qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
-       }
-
-       return rc;
+       if (rc)
+               QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
+                                CARD_DEVID(card), rc);
+       return qeth_l3_arp_makerc(rc);
 }
 
 static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
@@ -1793,15 +1777,18 @@ out:
        return rc;
 }
 
-static int qeth_l3_arp_add_entry(struct qeth_card *card,
-                               struct qeth_arp_cache_entry *entry)
+static int qeth_l3_arp_modify_entry(struct qeth_card *card,
+                                   struct qeth_arp_cache_entry *entry,
+                                   enum qeth_arp_process_subcmds arp_cmd)
 {
+       struct qeth_arp_cache_entry *cmd_entry;
        struct qeth_cmd_buffer *iob;
-       char buf[16];
-       int tmp;
        int rc;
 
-       QETH_CARD_TEXT(card, 3, "arpadent");
+       if (arp_cmd == IPA_CMD_ASS_ARP_ADD_ENTRY)
+               QETH_CARD_TEXT(card, 3, "arpadd");
+       else
+               QETH_CARD_TEXT(card, 3, "arpdel");
 
        /*
         * currently GuestLAN only supports the ARP assist function
@@ -1814,71 +1801,25 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
                return -EOPNOTSUPP;
        }
 
-       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
-                                      IPA_CMD_ASS_ARP_ADD_ENTRY,
-                                      sizeof(struct qeth_arp_cache_entry),
-                                      QETH_PROT_IPV4);
+       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
+                                      sizeof(*cmd_entry), QETH_PROT_IPV4);
        if (!iob)
                return -ENOMEM;
-       rc = qeth_send_setassparms(card, iob,
-                                  sizeof(struct qeth_arp_cache_entry),
-                                  (unsigned long) entry,
-                                  qeth_setassparms_cb, NULL);
-       if (rc) {
-               tmp = rc;
-               qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
-               QETH_DBF_MESSAGE(2, "Could not add ARP entry for address %s "
-                       "on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
-                       qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
-       }
-       return rc;
-}
-
-static int qeth_l3_arp_remove_entry(struct qeth_card *card,
-                               struct qeth_arp_cache_entry *entry)
-{
-       struct qeth_cmd_buffer *iob;
-       char buf[16] = {0, };
-       int tmp;
-       int rc;
 
-       QETH_CARD_TEXT(card, 3, "arprment");
+       cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
+       ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
+       memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
+       if (rc)
+               QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
+                                arp_cmd, CARD_DEVID(card), rc);
 
-       /*
-        * currently GuestLAN only supports the ARP assist function
-        * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY;
-        * thus we say EOPNOTSUPP for this ARP function
-        */
-       if (card->info.guestlan)
-               return -EOPNOTSUPP;
-       if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
-               return -EOPNOTSUPP;
-       }
-       memcpy(buf, entry, 12);
-       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
-                                      IPA_CMD_ASS_ARP_REMOVE_ENTRY,
-                                      12,
-                                      QETH_PROT_IPV4);
-       if (!iob)
-               return -ENOMEM;
-       rc = qeth_send_setassparms(card, iob,
-                                  12, (unsigned long)buf,
-                                  qeth_setassparms_cb, NULL);
-       if (rc) {
-               tmp = rc;
-               memset(buf, 0, 16);
-               qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
-               QETH_DBF_MESSAGE(2, "Could not delete ARP entry for address %s"
-                       " on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
-                       qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
-       }
-       return rc;
+       return qeth_l3_arp_makerc(rc);
 }
 
 static int qeth_l3_arp_flush_cache(struct qeth_card *card)
 {
        int rc;
-       int tmp;
 
        QETH_CARD_TEXT(card, 3, "arpflush");
 
@@ -1894,19 +1835,17 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
        }
        rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
                                          IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
-       if (rc) {
-               tmp = rc;
-               QETH_DBF_MESSAGE(2, "Could not flush ARP cache on %s: %s "
-                       "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
-                       qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
-       }
-       return rc;
+       if (rc)
+               QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
+                                CARD_DEVID(card), rc);
+       return qeth_l3_arp_makerc(rc);
 }
 
 static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct qeth_card *card = dev->ml_priv;
        struct qeth_arp_cache_entry arp_entry;
+       enum qeth_arp_process_subcmds arp_cmd;
        int rc = 0;
 
        switch (cmd) {
@@ -1925,27 +1864,16 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
                break;
        case SIOC_QETH_ARP_ADD_ENTRY:
-               if (!capable(CAP_NET_ADMIN)) {
-                       rc = -EPERM;
-                       break;
-               }
-               if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
-                                  sizeof(struct qeth_arp_cache_entry)))
-                       rc = -EFAULT;
-               else
-                       rc = qeth_l3_arp_add_entry(card, &arp_entry);
-               break;
        case SIOC_QETH_ARP_REMOVE_ENTRY:
-               if (!capable(CAP_NET_ADMIN)) {
-                       rc = -EPERM;
-                       break;
-               }
-               if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
-                                  sizeof(struct qeth_arp_cache_entry)))
-                       rc = -EFAULT;
-               else
-                       rc = qeth_l3_arp_remove_entry(card, &arp_entry);
-               break;
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (copy_from_user(&arp_entry, rq->ifr_data, sizeof(arp_entry)))
+                       return -EFAULT;
+
+               arp_cmd = (cmd == SIOC_QETH_ARP_ADD_ENTRY) ?
+                               IPA_CMD_ASS_ARP_ADD_ENTRY :
+                               IPA_CMD_ASS_ARP_REMOVE_ENTRY;
+               return qeth_l3_arp_modify_entry(card, &arp_entry, arp_cmd);
        case SIOC_QETH_ARP_FLUSH_CACHE:
                if (!capable(CAP_NET_ADMIN)) {
                        rc = -EPERM;
@@ -2383,12 +2311,12 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
        .ndo_neigh_setup        = qeth_l3_neigh_setup,
 };
 
-static int qeth_l3_setup_netdev(struct qeth_card *card)
+static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
 {
        unsigned int headroom;
        int rc;
 
-       if (card->dev->netdev_ops)
+       if (qeth_netdev_is_registered(card->dev))
                return 0;
 
        if (card->info.type == QETH_CARD_TYPE_OSD ||
@@ -2457,6 +2385,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
 
        netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
        rc = register_netdev(card->dev);
+       if (!rc && carrier_ok)
+               netif_carrier_on(card->dev);
+
 out:
        if (rc)
                card->dev->netdev_ops = NULL;
@@ -2497,7 +2428,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
        if (cgdev->state == CCWGROUP_ONLINE)
                qeth_l3_set_offline(cgdev);
 
-       unregister_netdev(card->dev);
+       if (qeth_netdev_is_registered(card->dev))
+               unregister_netdev(card->dev);
        qeth_l3_clear_ip_htable(card, 0);
        qeth_l3_clear_ipato_list(card);
 }
@@ -2507,6 +2439,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
        int rc = 0;
        enum qeth_card_states recover_flag;
+       bool carrier_ok;
 
        mutex_lock(&card->discipline_mutex);
        mutex_lock(&card->conf_mutex);
@@ -2514,14 +2447,14 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
        recover_flag = card->state;
-       rc = qeth_core_hardsetup_card(card);
+       rc = qeth_core_hardsetup_card(card, &carrier_ok);
        if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
                rc = -ENODEV;
                goto out_remove;
        }
 
-       rc = qeth_l3_setup_netdev(card);
+       rc = qeth_l3_setup_netdev(card, carrier_ok);
        if (rc)
                goto out_remove;
 
index ff6ba6d..cc56cb3 100644 (file)
@@ -1614,10 +1614,10 @@ static void sci_request_dma(struct uart_port *port)
                hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                s->rx_timer.function = rx_timer_fn;
 
+               s->chan_rx_saved = s->chan_rx = chan;
+
                if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
                        sci_submit_rx(s);
-
-               s->chan_rx_saved = s->chan_rx = chan;
        }
 }
 
@@ -3102,6 +3102,7 @@ static struct uart_driver sci_uart_driver = {
 static int sci_remove(struct platform_device *dev)
 {
        struct sci_port *port = platform_get_drvdata(dev);
+       unsigned int type = port->port.type;    /* uart_remove_... clears it */
 
        sci_ports_in_use &= ~BIT(port->port.line);
        uart_remove_one_port(&sci_uart_driver, &port->port);
@@ -3112,8 +3113,7 @@ static int sci_remove(struct platform_device *dev)
                sysfs_remove_file(&dev->dev.kobj,
                                  &dev_attr_rx_fifo_trigger.attr);
        }
-       if (port->port.type == PORT_SCIFA || port->port.type == PORT_SCIFB ||
-           port->port.type == PORT_HSCIF) {
+       if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) {
                sysfs_remove_file(&dev->dev.kobj,
                                  &dev_attr_rx_fifo_timeout.attr);
        }
index 7576cea..f438eaa 100644 (file)
@@ -77,7 +77,7 @@ speed_t tty_termios_baud_rate(struct ktermios *termios)
                else
                        cbaud += 15;
        }
-       return baud_table[cbaud];
+       return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
 }
 EXPORT_SYMBOL(tty_termios_baud_rate);
 
@@ -113,7 +113,7 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
                else
                        cbaud += 15;
        }
-       return baud_table[cbaud];
+       return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
 #else  /* IBSHIFT */
        return tty_termios_baud_rate(termios);
 #endif /* IBSHIFT */
index 55370e6..41ec8e5 100644 (file)
@@ -1548,7 +1548,7 @@ static void csi_K(struct vc_data *vc, int vpar)
        scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
        vc->vc_need_wrap = 0;
        if (con_should_update(vc))
-               do_update_region(vc, (unsigned long) start, count);
+               do_update_region(vc, (unsigned long)(start + offset), count);
 }
 
 static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
index e36d6c7..7811888 100644 (file)
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+       tristate "UCSI Interface Driver for Cypress CCGx"
+       depends on I2C
+       help
+         This driver enables UCSI support on platforms that expose a
+         Cypress CCGx Type-C controller over I2C interface.
+
+         To compile the driver as a module, choose M here: the module will be
+         called ucsi_ccg.
+
 config UCSI_ACPI
        tristate "UCSI ACPI Interface Driver"
        depends on ACPI
index 7afbea5..2f4900b 100644 (file)
@@ -8,3 +8,5 @@ typec_ucsi-y                    := ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)                += ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG)         += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644 (file)
index 0000000..de8a43b
--- /dev/null
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta <ajayg@nvidia.com>
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/unaligned.h>
+#include "ucsi.h"
+
+struct ucsi_ccg {
+       struct device *dev;
+       struct ucsi *ucsi;
+       struct ucsi_ppm ppm;
+       struct i2c_client *client;
+};
+
+#define CCGX_RAB_INTR_REG                      0x06
+#define CCGX_RAB_UCSI_CONTROL                  0x39
+#define CCGX_RAB_UCSI_CONTROL_START            BIT(0)
+#define CCGX_RAB_UCSI_CONTROL_STOP             BIT(1)
+#define CCGX_RAB_UCSI_DATA_BLOCK(offset)       (0xf000 | ((offset) & 0xff))
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+       struct i2c_client *client = uc->client;
+       const struct i2c_adapter_quirks *quirks = client->adapter->quirks;
+       unsigned char buf[2];
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = client->addr,
+                       .flags  = 0x0,
+                       .len    = sizeof(buf),
+                       .buf    = buf,
+               },
+               {
+                       .addr   = client->addr,
+                       .flags  = I2C_M_RD,
+                       .buf    = data,
+               },
+       };
+       u32 rlen, rem_len = len, max_read_len = len;
+       int status;
+
+       /* check any max_read_len limitation on i2c adapter */
+       if (quirks && quirks->max_read_len)
+               max_read_len = quirks->max_read_len;
+
+       while (rem_len > 0) {
+               msgs[1].buf = &data[len - rem_len];
+               rlen = min_t(u16, rem_len, max_read_len);
+               msgs[1].len = rlen;
+               put_unaligned_le16(rab, buf);
+               status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+               if (status < 0) {
+                       dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+                       return status;
+               }
+               rab += rlen;
+               rem_len -= rlen;
+       }
+
+       return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+       struct i2c_client *client = uc->client;
+       unsigned char *buf;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = client->addr,
+                       .flags  = 0x0,
+               }
+       };
+       int status;
+
+       buf = kzalloc(len + sizeof(rab), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       put_unaligned_le16(rab, buf);
+       memcpy(buf + sizeof(rab), data, len);
+
+       msgs[0].len = len + sizeof(rab);
+       msgs[0].buf = buf;
+
+       status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (status < 0) {
+               dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+               kfree(buf);
+               return status;
+       }
+
+       kfree(buf);
+       return 0;
+}
+
+static int ucsi_ccg_init(struct ucsi_ccg *uc)
+{
+       unsigned int count = 10;
+       u8 data;
+       int status;
+
+       data = CCGX_RAB_UCSI_CONTROL_STOP;
+       status = ccg_write(uc, CCGX_RAB_UCSI_CONTROL, &data, sizeof(data));
+       if (status < 0)
+               return status;
+
+       data = CCGX_RAB_UCSI_CONTROL_START;
+       status = ccg_write(uc, CCGX_RAB_UCSI_CONTROL, &data, sizeof(data));
+       if (status < 0)
+               return status;
+
+       /*
+        * Flush CCGx RESPONSE queue by acking interrupts. Above ucsi control
+        * register write will push response which must be cleared.
+        */
+       do {
+               status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+               if (status < 0)
+                       return status;
+
+               if (!data)
+                       return 0;
+
+               status = ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+               if (status < 0)
+                       return status;
+
+               usleep_range(10000, 11000);
+       } while (--count);
+
+       return -ETIMEDOUT;
+}
+
+static int ucsi_ccg_send_data(struct ucsi_ccg *uc)
+{
+       u8 *ppm = (u8 *)uc->ppm.data;
+       int status;
+       u16 rab;
+
+       rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_out));
+       status = ccg_write(uc, rab, ppm +
+                          offsetof(struct ucsi_data, message_out),
+                          sizeof(uc->ppm.data->message_out));
+       if (status < 0)
+               return status;
+
+       rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, ctrl));
+       return ccg_write(uc, rab, ppm + offsetof(struct ucsi_data, ctrl),
+                        sizeof(uc->ppm.data->ctrl));
+}
+
+static int ucsi_ccg_recv_data(struct ucsi_ccg *uc)
+{
+       u8 *ppm = (u8 *)uc->ppm.data;
+       int status;
+       u16 rab;
+
+       rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, cci));
+       status = ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, cci),
+                         sizeof(uc->ppm.data->cci));
+       if (status < 0)
+               return status;
+
+       rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_in));
+       return ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, message_in),
+                       sizeof(uc->ppm.data->message_in));
+}
+
+static int ucsi_ccg_ack_interrupt(struct ucsi_ccg *uc)
+{
+       int status;
+       unsigned char data;
+
+       status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+       if (status < 0)
+               return status;
+
+       return ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+}
+
+static int ucsi_ccg_sync(struct ucsi_ppm *ppm)
+{
+       struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
+       int status;
+
+       status = ucsi_ccg_recv_data(uc);
+       if (status < 0)
+               return status;
+
+       /* ack interrupt to allow next command to run */
+       return ucsi_ccg_ack_interrupt(uc);
+}
+
+static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl)
+{
+       struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
+
+       ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
+       return ucsi_ccg_send_data(uc);
+}
+
+static irqreturn_t ccg_irq_handler(int irq, void *data)
+{
+       struct ucsi_ccg *uc = data;
+
+       ucsi_notify(uc->ucsi);
+
+       return IRQ_HANDLED;
+}
+
+static int ucsi_ccg_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct ucsi_ccg *uc;
+       int status;
+       u16 rab;
+
+       uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL);
+       if (!uc)
+               return -ENOMEM;
+
+       uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data), GFP_KERNEL);
+       if (!uc->ppm.data)
+               return -ENOMEM;
+
+       uc->ppm.cmd = ucsi_ccg_cmd;
+       uc->ppm.sync = ucsi_ccg_sync;
+       uc->dev = dev;
+       uc->client = client;
+
+       /* reset ccg device and initialize ucsi */
+       status = ucsi_ccg_init(uc);
+       if (status < 0) {
+               dev_err(uc->dev, "ucsi_ccg_init failed - %d\n", status);
+               return status;
+       }
+
+       status = devm_request_threaded_irq(dev, client->irq, NULL,
+                                          ccg_irq_handler,
+                                          IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+                                          dev_name(dev), uc);
+       if (status < 0) {
+               dev_err(uc->dev, "request_threaded_irq failed - %d\n", status);
+               return status;
+       }
+
+       uc->ucsi = ucsi_register_ppm(dev, &uc->ppm);
+       if (IS_ERR(uc->ucsi)) {
+               dev_err(uc->dev, "ucsi_register_ppm failed\n");
+               return PTR_ERR(uc->ucsi);
+       }
+
+       rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, version));
+       status = ccg_read(uc, rab, (u8 *)(uc->ppm.data) +
+                         offsetof(struct ucsi_data, version),
+                         sizeof(uc->ppm.data->version));
+       if (status < 0) {
+               ucsi_unregister_ppm(uc->ucsi);
+               return status;
+       }
+
+       i2c_set_clientdata(client, uc);
+       return 0;
+}
+
+static int ucsi_ccg_remove(struct i2c_client *client)
+{
+       struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+       ucsi_unregister_ppm(uc->ucsi);
+
+       return 0;
+}
+
+static const struct i2c_device_id ucsi_ccg_device_id[] = {
+       {"ccgx-ucsi", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
+
+static struct i2c_driver ucsi_ccg_driver = {
+       .driver = {
+               .name = "ucsi_ccg",
+       },
+       .probe = ucsi_ccg_probe,
+       .remove = ucsi_ccg_remove,
+       .id_table = ucsi_ccg_device_id,
+};
+
+module_i2c_driver(ucsi_ccg_driver);
+
+MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
+MODULE_DESCRIPTION("UCSI driver for Cypress CCGx Type-C controller");
+MODULE_LICENSE("GPL v2");
index f15f89d..7ea6fb6 100644 (file)
@@ -914,7 +914,7 @@ int gnttab_dma_free_pages(struct gnttab_dma_alloc_args *args)
 
        ret = xenmem_reservation_increase(args->nr_pages, args->frames);
        if (ret != args->nr_pages) {
-               pr_debug("Failed to decrease reservation for DMA buffer\n");
+               pr_debug("Failed to increase reservation for DMA buffer\n");
                ret = -EFAULT;
        } else {
                ret = 0;
index df1ed37..de01a6d 100644 (file)
 
 MODULE_LICENSE("GPL");
 
-static unsigned int limit = 64;
-module_param(limit, uint, 0644);
-MODULE_PARM_DESC(limit, "Maximum number of pages that may be allocated by "
-                       "the privcmd-buf device per open file");
-
 struct privcmd_buf_private {
        struct mutex lock;
        struct list_head list;
-       unsigned int allocated;
 };
 
 struct privcmd_buf_vma_private {
@@ -60,13 +54,10 @@ static void privcmd_buf_vmapriv_free(struct privcmd_buf_vma_private *vma_priv)
 {
        unsigned int i;
 
-       vma_priv->file_priv->allocated -= vma_priv->n_pages;
-
        list_del(&vma_priv->list);
 
        for (i = 0; i < vma_priv->n_pages; i++)
-               if (vma_priv->pages[i])
-                       __free_page(vma_priv->pages[i]);
+               __free_page(vma_priv->pages[i]);
 
        kfree(vma_priv);
 }
@@ -146,8 +137,7 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
        unsigned int i;
        int ret = 0;
 
-       if (!(vma->vm_flags & VM_SHARED) || count > limit ||
-           file_priv->allocated + count > limit)
+       if (!(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
        vma_priv = kzalloc(sizeof(*vma_priv) + count * sizeof(void *),
@@ -155,19 +145,15 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
        if (!vma_priv)
                return -ENOMEM;
 
-       vma_priv->n_pages = count;
-       count = 0;
-       for (i = 0; i < vma_priv->n_pages; i++) {
+       for (i = 0; i < count; i++) {
                vma_priv->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
                if (!vma_priv->pages[i])
                        break;
-               count++;
+               vma_priv->n_pages++;
        }
 
        mutex_lock(&file_priv->lock);
 
-       file_priv->allocated += count;
-
        vma_priv->file_priv = file_priv;
        vma_priv->users = 1;
 
index 27cad84..189df66 100644 (file)
@@ -1931,10 +1931,17 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
        if (!prealloc_cf)
                return -ENOMEM;
 
-       /* Start by sync'ing the source file */
+       /* Start by sync'ing the source and destination files */
        ret = file_write_and_wait_range(src_file, src_off, (src_off + len));
-       if (ret < 0)
+       if (ret < 0) {
+               dout("failed to write src file (%zd)\n", ret);
+               goto out;
+       }
+       ret = file_write_and_wait_range(dst_file, dst_off, (dst_off + len));
+       if (ret < 0) {
+               dout("failed to write dst file (%zd)\n", ret);
                goto out;
+       }
 
        /*
         * We need FILE_WR caps for dst_ci and FILE_RD for src_ci as other
index 67a9aeb..bd13a32 100644 (file)
@@ -80,12 +80,8 @@ static int parse_reply_info_in(void **p, void *end,
        info->symlink = *p;
        *p += info->symlink_len;
 
-       if (features & CEPH_FEATURE_DIRLAYOUTHASH)
-               ceph_decode_copy_safe(p, end, &info->dir_layout,
-                                     sizeof(info->dir_layout), bad);
-       else
-               memset(&info->dir_layout, 0, sizeof(info->dir_layout));
-
+       ceph_decode_copy_safe(p, end, &info->dir_layout,
+                             sizeof(info->dir_layout), bad);
        ceph_decode_32_safe(p, end, info->xattr_len, bad);
        ceph_decode_need(p, end, info->xattr_len, bad);
        info->xattr_data = *p;
@@ -3182,10 +3178,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
        recon_state.pagelist = pagelist;
        if (session->s_con.peer_features & CEPH_FEATURE_MDSENC)
                recon_state.msg_version = 3;
-       else if (session->s_con.peer_features & CEPH_FEATURE_FLOCK)
-               recon_state.msg_version = 2;
        else
-               recon_state.msg_version = 1;
+               recon_state.msg_version = 2;
        err = iterate_session_caps(session, encode_caps_cb, &recon_state);
        if (err < 0)
                goto fail;
index 32d4f13..03f4d24 100644 (file)
@@ -237,7 +237,8 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
                ceph_put_snap_realm(mdsc, realm);
                realm = next;
        }
-       ceph_put_snap_realm(mdsc, realm);
+       if (realm)
+               ceph_put_snap_realm(mdsc, realm);
        up_read(&mdsc->snap_rwsem);
 
        return exceeded;
index 98d27da..74f6429 100644 (file)
@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags)
 
        namespace_lock();
        lock_mount_hash();
-       event++;
 
+       /* Recheck MNT_LOCKED with the locks held */
+       retval = -EINVAL;
+       if (mnt->mnt.mnt_flags & MNT_LOCKED)
+               goto out;
+
+       event++;
        if (flags & MNT_DETACH) {
                if (!list_empty(&mnt->mnt_list))
                        umount_tree(mnt, UMOUNT_PROPAGATE);
@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags)
                        retval = 0;
                }
        }
+out:
        unlock_mount_hash();
        namespace_unlock();
        return retval;
@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags)
                goto dput_and_out;
        if (!check_mnt(mnt))
                goto dput_and_out;
-       if (mnt->mnt.mnt_flags & MNT_LOCKED)
+       if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
                goto dput_and_out;
        retval = -EPERM;
        if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
                for (s = r; s; s = next_mnt(s, r)) {
                        if (!(flag & CL_COPY_UNBINDABLE) &&
                            IS_MNT_UNBINDABLE(s)) {
-                               s = skip_mnt_tree(s);
-                               continue;
+                               if (s->mnt.mnt_flags & MNT_LOCKED) {
+                                       /* Both unbindable and locked. */
+                                       q = ERR_PTR(-EPERM);
+                                       goto out;
+                               } else {
+                                       s = skip_mnt_tree(s);
+                                       continue;
+                               }
                        }
                        if (!(flag & CL_COPY_MNT_NS_FILE) &&
                            is_mnt_ns_file(s->mnt.mnt_root)) {
@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
 {
        namespace_lock();
        lock_mount_hash();
-       umount_tree(real_mount(mnt), UMOUNT_SYNC);
+       umount_tree(real_mount(mnt), 0);
        unlock_mount_hash();
        namespace_unlock();
 }
index db84b4a..867457d 100644 (file)
@@ -3788,7 +3788,7 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        }
 
        /*
-        * -EACCESS could mean that the user doesn't have correct permissions
+        * -EACCES could mean that the user doesn't have correct permissions
         * to access the mount.  It could also mean that we tried to mount
         * with a gss auth flavor, but rpc.gssd isn't running.  Either way,
         * existing mount programs don't handle -EACCES very well so it should
index bbc7854..529856f 100644 (file)
@@ -7,6 +7,7 @@ config UBIFS_FS
        select CRYPTO if UBIFS_FS_ZLIB
        select CRYPTO_LZO if UBIFS_FS_LZO
        select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
+       select CRYPTO_HASH_INFO
        depends on MTD_UBI
        help
          UBIFS is a file system for flash devices which works on top of UBI.
@@ -85,3 +86,13 @@ config UBIFS_FS_SECURITY
          the extended attribute support in advance.
 
          If you are not using a security module, say N.
+
+config UBIFS_FS_AUTHENTICATION
+       bool "UBIFS authentication support"
+       select CRYPTO_HMAC
+       help
+         Enable authentication support for UBIFS. This feature offers protection
+         against offline changes for both data and metadata of the filesystem.
+         If you say yes here you should also select a hashing algorithm such as
+         sha256, these are not selected automatically since there are many
+         different options.
index 6197d7e..5f83831 100644 (file)
@@ -8,3 +8,4 @@ ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o
 ubifs-y += misc.o
 ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o
 ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
+ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o
diff --git a/fs/ubifs/auth.c b/fs/ubifs/auth.c
new file mode 100644 (file)
index 0000000..124e965
--- /dev/null
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2018 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ */
+
+/*
+ * This file implements various helper functions for UBIFS authentication support
+ */
+
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <keys/user-type.h>
+
+#include "ubifs.h"
+
+/**
+ * ubifs_node_calc_hash - calculate the hash of a UBIFS node
+ * @c: UBIFS file-system description object
+ * @node: the node to calculate a hash for
+ * @hash: the returned hash
+ *
+ * Returns 0 for success or a negative error code otherwise.
+ */
+int __ubifs_node_calc_hash(const struct ubifs_info *c, const void *node,
+                           u8 *hash)
+{
+       const struct ubifs_ch *ch = node;
+       SHASH_DESC_ON_STACK(shash, c->hash_tfm);
+       int err;
+
+       shash->tfm = c->hash_tfm;
+       shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_shash_digest(shash, node, le32_to_cpu(ch->len), hash);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/**
+ * ubifs_hash_calc_hmac - calculate a HMAC from a hash
+ * @c: UBIFS file-system description object
+ * @hash: the node to calculate a HMAC for
+ * @hmac: the returned HMAC
+ *
+ * Returns 0 for success or a negative error code otherwise.
+ */
+static int ubifs_hash_calc_hmac(const struct ubifs_info *c, const u8 *hash,
+                                u8 *hmac)
+{
+       SHASH_DESC_ON_STACK(shash, c->hmac_tfm);
+       int err;
+
+       shash->tfm = c->hmac_tfm;
+       shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_shash_digest(shash, hash, c->hash_len, hmac);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/**
+ * ubifs_prepare_auth_node - Prepare an authentication node
+ * @c: UBIFS file-system description object
+ * @node: the node to calculate a hash for
+ * @hash: input hash of previous nodes
+ *
+ * This function prepares an authentication node for writing onto flash.
+ * It creates a HMAC from the given input hash and writes it to the node.
+ *
+ * Returns 0 for success or a negative error code otherwise.
+ */
+int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
+                            struct shash_desc *inhash)
+{
+       SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
+       struct ubifs_auth_node *auth = node;
+       u8 *hash;
+       int err;
+
+       hash = kmalloc(crypto_shash_descsize(c->hash_tfm), GFP_NOFS);
+       if (!hash)
+               return -ENOMEM;
+
+       hash_desc->tfm = c->hash_tfm;
+       hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+       ubifs_shash_copy_state(c, inhash, hash_desc);
+
+       err = crypto_shash_final(hash_desc, hash);
+       if (err)
+               goto out;
+
+       err = ubifs_hash_calc_hmac(c, hash, auth->hmac);
+       if (err)
+               goto out;
+
+       auth->ch.node_type = UBIFS_AUTH_NODE;
+       ubifs_prepare_node(c, auth, ubifs_auth_node_sz(c), 0);
+
+       err = 0;
+out:
+       kfree(hash);
+
+       return err;
+}
+
+static struct shash_desc *ubifs_get_desc(const struct ubifs_info *c,
+                                        struct crypto_shash *tfm)
+{
+       struct shash_desc *desc;
+       int err;
+
+       if (!ubifs_authenticated(c))
+               return NULL;
+
+       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+       if (!desc)
+               return ERR_PTR(-ENOMEM);
+
+       desc->tfm = tfm;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_shash_init(desc);
+       if (err) {
+               kfree(desc);
+               return ERR_PTR(err);
+       }
+
+       return desc;
+}
+
+/**
+ * __ubifs_hash_get_desc - get a descriptor suitable for hashing a node
+ * @c: UBIFS file-system description object
+ *
+ * This function returns a descriptor suitable for hashing a node. Free after use
+ * with kfree.
+ */
+struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c)
+{
+       return ubifs_get_desc(c, c->hash_tfm);
+}
+
+/**
+ * __ubifs_shash_final - finalize shash
+ * @c: UBIFS file-system description object
+ * @desc: the descriptor
+ * @out: the output hash
+ *
+ * Simple wrapper around crypto_shash_final(), safe to be called with
+ * disabled authentication.
+ */
+int __ubifs_shash_final(const struct ubifs_info *c, struct shash_desc *desc,
+                       u8 *out)
+{
+       if (ubifs_authenticated(c))
+               return crypto_shash_final(desc, out);
+
+       return 0;
+}
+
+/**
+ * ubifs_bad_hash - Report hash mismatches
+ * @c: UBIFS file-system description object
+ * @node: the node
+ * @hash: the expected hash
+ * @lnum: the LEB @node was read from
+ * @offs: offset in LEB @node was read from
+ *
+ * This function reports a hash mismatch when a node has a different hash than
+ * expected.
+ */
+void ubifs_bad_hash(const struct ubifs_info *c, const void *node, const u8 *hash,
+                   int lnum, int offs)
+{
+       int len = min(c->hash_len, 20);
+       int cropped = len != c->hash_len;
+       const char *cont = cropped ? "..." : "";
+
+       u8 calc[UBIFS_HASH_ARR_SZ];
+
+       __ubifs_node_calc_hash(c, node, calc);
+
+       ubifs_err(c, "hash mismatch on node at LEB %d:%d", lnum, offs);
+       ubifs_err(c, "hash expected:   %*ph%s", len, hash, cont);
+       ubifs_err(c, "hash calculated: %*ph%s", len, calc, cont);
+}
+
+/**
+ * __ubifs_node_check_hash - check the hash of a node against given hash
+ * @c: UBIFS file-system description object
+ * @node: the node
+ * @expected: the expected hash
+ *
+ * This function calculates a hash over a node and compares it to the given hash.
+ * Returns 0 if both hashes are equal or authentication is disabled, otherwise a
+ * negative error code is returned.
+ */
+int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node,
+                           const u8 *expected)
+{
+       u8 calc[UBIFS_HASH_ARR_SZ];
+       int err;
+
+       err = __ubifs_node_calc_hash(c, node, calc);
+       if (err)
+               return err;
+
+       if (ubifs_check_hash(c, expected, calc))
+               return -EPERM;
+
+       return 0;
+}
+
+/**
+ * ubifs_init_authentication - initialize UBIFS authentication support
+ * @c: UBIFS file-system description object
+ *
+ * This function returns 0 for success or a negative error code otherwise.
+ */
+int ubifs_init_authentication(struct ubifs_info *c)
+{
+       struct key *keyring_key;
+       const struct user_key_payload *ukp;
+       int err;
+       char hmac_name[CRYPTO_MAX_ALG_NAME];
+
+       if (!c->auth_hash_name) {
+               ubifs_err(c, "authentication hash name needed with authentication");
+               return -EINVAL;
+       }
+
+       c->auth_hash_algo = match_string(hash_algo_name, HASH_ALGO__LAST,
+                                        c->auth_hash_name);
+       if ((int)c->auth_hash_algo < 0) {
+               ubifs_err(c, "Unknown hash algo %s specified",
+                         c->auth_hash_name);
+               return -EINVAL;
+       }
+
+       snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
+                c->auth_hash_name);
+
+       keyring_key = request_key(&key_type_logon, c->auth_key_name, NULL);
+
+       if (IS_ERR(keyring_key)) {
+               ubifs_err(c, "Failed to request key: %ld",
+                         PTR_ERR(keyring_key));
+               return PTR_ERR(keyring_key);
+       }
+
+       down_read(&keyring_key->sem);
+
+       if (keyring_key->type != &key_type_logon) {
+               ubifs_err(c, "key type must be logon");
+               err = -ENOKEY;
+               goto out;
+       }
+
+       ukp = user_key_payload_locked(keyring_key);
+       if (!ukp) {
+               /* key was revoked before we acquired its semaphore */
+               err = -EKEYREVOKED;
+               goto out;
+       }
+
+       c->hash_tfm = crypto_alloc_shash(c->auth_hash_name, 0,
+                                        CRYPTO_ALG_ASYNC);
+       if (IS_ERR(c->hash_tfm)) {
+               err = PTR_ERR(c->hash_tfm);
+               ubifs_err(c, "Can not allocate %s: %d",
+                         c->auth_hash_name, err);
+               goto out;
+       }
+
+       c->hash_len = crypto_shash_digestsize(c->hash_tfm);
+       if (c->hash_len > UBIFS_HASH_ARR_SZ) {
+               ubifs_err(c, "hash %s is bigger than maximum allowed hash size (%d > %d)",
+                         c->auth_hash_name, c->hash_len, UBIFS_HASH_ARR_SZ);
+               err = -EINVAL;
+               goto out_free_hash;
+       }
+
+       c->hmac_tfm = crypto_alloc_shash(hmac_name, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(c->hmac_tfm)) {
+               err = PTR_ERR(c->hmac_tfm);
+               ubifs_err(c, "Can not allocate %s: %d", hmac_name, err);
+               goto out_free_hash;
+       }
+
+       c->hmac_desc_len = crypto_shash_digestsize(c->hmac_tfm);
+       if (c->hmac_desc_len > UBIFS_HMAC_ARR_SZ) {
+               ubifs_err(c, "hmac %s is bigger than maximum allowed hmac size (%d > %d)",
+                         hmac_name, c->hmac_desc_len, UBIFS_HMAC_ARR_SZ);
+               err = -EINVAL;
+               goto out_free_hash;
+       }
+
+       err = crypto_shash_setkey(c->hmac_tfm, ukp->data, ukp->datalen);
+       if (err)
+               goto out_free_hmac;
+
+       c->authenticated = true;
+
+       c->log_hash = ubifs_hash_get_desc(c);
+       if (IS_ERR(c->log_hash))
+               goto out_free_hmac;
+
+       err = 0;
+
+out_free_hmac:
+       if (err)
+               crypto_free_shash(c->hmac_tfm);
+out_free_hash:
+       if (err)
+               crypto_free_shash(c->hash_tfm);
+out:
+       up_read(&keyring_key->sem);
+       key_put(keyring_key);
+
+       return err;
+}
+
+/**
+ * __ubifs_exit_authentication - release resource
+ * @c: UBIFS file-system description object
+ *
+ * This function releases the authentication related resources.
+ */
+void __ubifs_exit_authentication(struct ubifs_info *c)
+{
+       if (!ubifs_authenticated(c))
+               return;
+
+       crypto_free_shash(c->hmac_tfm);
+       crypto_free_shash(c->hash_tfm);
+       kfree(c->log_hash);
+}
+
+/**
+ * ubifs_node_calc_hmac - calculate the HMAC of a UBIFS node
+ * @c: UBIFS file-system description object
+ * @node: the node to insert a HMAC into.
+ * @len: the length of the node
+ * @ofs_hmac: the offset in the node where the HMAC is inserted
+ * @hmac: returned HMAC
+ *
+ * This function calculates a HMAC of a UBIFS node. The HMAC is expected to be
+ * embedded into the node, so this area is not covered by the HMAC. Also not
+ * covered is the UBIFS_NODE_MAGIC and the CRC of the node.
+ */
+static int ubifs_node_calc_hmac(const struct ubifs_info *c, const void *node,
+                               int len, int ofs_hmac, void *hmac)
+{
+       SHASH_DESC_ON_STACK(shash, c->hmac_tfm);
+       int hmac_len = c->hmac_desc_len;
+       int err;
+
+       ubifs_assert(c, ofs_hmac > 8);
+       ubifs_assert(c, ofs_hmac + hmac_len < len);
+
+       shash->tfm = c->hmac_tfm;
+       shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_shash_init(shash);
+       if (err)
+               return err;
+
+       /* behind common node header CRC up to HMAC begin */
+       err = crypto_shash_update(shash, node + 8, ofs_hmac - 8);
+       if (err < 0)
+               return err;
+
+       /* behind HMAC, if any */
+       if (len - ofs_hmac - hmac_len > 0) {
+               err = crypto_shash_update(shash, node + ofs_hmac + hmac_len,
+                           len - ofs_hmac - hmac_len);
+               if (err < 0)
+                       return err;
+       }
+
+       return crypto_shash_final(shash, hmac);
+}
+
+/**
+ * __ubifs_node_insert_hmac - insert a HMAC into a UBIFS node
+ * @c: UBIFS file-system description object
+ * @node: the node to insert a HMAC into.
+ * @len: the length of the node
+ * @ofs_hmac: the offset in the node where the HMAC is inserted
+ *
+ * This function inserts a HMAC at offset @ofs_hmac into the node given in
+ * @node.
+ *
+ * This function returns 0 for success or a negative error code otherwise.
+ */
+int __ubifs_node_insert_hmac(const struct ubifs_info *c, void *node, int len,
+                           int ofs_hmac)
+{
+       return ubifs_node_calc_hmac(c, node, len, ofs_hmac, node + ofs_hmac);
+}
+
+/**
+ * __ubifs_node_verify_hmac - verify the HMAC of UBIFS node
+ * @c: UBIFS file-system description object
+ * @node: the node to insert a HMAC into.
+ * @len: the length of the node
+ * @ofs_hmac: the offset in the node where the HMAC is inserted
+ *
+ * This function verifies the HMAC at offset @ofs_hmac of the node given in
+ * @node. Returns 0 if successful or a negative error code otherwise.
+ */
+int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *node,
+                            int len, int ofs_hmac)
+{
+       int hmac_len = c->hmac_desc_len;
+       u8 *hmac;
+       int err;
+
+       hmac = kmalloc(hmac_len, GFP_NOFS);
+       if (!hmac)
+               return -ENOMEM;
+
+       err = ubifs_node_calc_hmac(c, node, len, ofs_hmac, hmac);
+       if (err)
+               return err;
+
+       err = crypto_memneq(hmac, node + ofs_hmac, hmac_len);
+
+       kfree(hmac);
+
+       if (!err)
+               return 0;
+
+       return -EPERM;
+}
+
+int __ubifs_shash_copy_state(const struct ubifs_info *c, struct shash_desc *src,
+                            struct shash_desc *target)
+{
+       u8 *state;
+       int err;
+
+       state = kmalloc(crypto_shash_descsize(src->tfm), GFP_NOFS);
+       if (!state)
+               return -ENOMEM;
+
+       err = crypto_shash_export(src, state);
+       if (err)
+               goto out;
+
+       err = crypto_shash_import(target, state);
+
+out:
+       kfree(state);
+
+       return err;
+}
+
+/**
+ * ubifs_hmac_wkm - Create a HMAC of the well known message
+ * @c: UBIFS file-system description object
+ * @hmac: The HMAC of the well known message
+ *
+ * This function creates a HMAC of a well known message. This is used
+ * to check if the provided key is suitable to authenticate a UBIFS
+ * image. This is only a convenience to the user to provide a better
+ * error message when the wrong key is provided.
+ *
+ * This function returns 0 for success or a negative error code otherwise.
+ */
+int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac)
+{
+       SHASH_DESC_ON_STACK(shash, c->hmac_tfm);
+       int err;
+       const char well_known_message[] = "UBIFS";
+
+       if (!ubifs_authenticated(c))
+               return 0;
+
+       shash->tfm = c->hmac_tfm;
+       shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_shash_init(shash);
+       if (err)
+               return err;
+
+       err = crypto_shash_update(shash, well_known_message,
+                                 sizeof(well_known_message) - 1);
+       if (err < 0)
+               return err;
+
+       err = crypto_shash_final(shash, hmac);
+       if (err)
+               return err;
+       return 0;
+}
index 564e330..c49ff50 100644 (file)
@@ -165,6 +165,8 @@ const char *dbg_ntype(int type)
                return "commit start node";
        case UBIFS_ORPH_NODE:
                return "orphan node";
+       case UBIFS_AUTH_NODE:
+               return "auth node";
        default:
                return "unknown node";
        }
@@ -542,6 +544,10 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
                               (unsigned long long)le64_to_cpu(orph->inos[i]));
                break;
        }
+       case UBIFS_AUTH_NODE:
+       {
+               break;
+       }
        default:
                pr_err("node type %d was not recognized\n",
                       (int)ch->node_type);
index d2680e0..bf75fdc 100644 (file)
@@ -254,7 +254,8 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                             snod->type == UBIFS_DATA_NODE ||
                             snod->type == UBIFS_DENT_NODE ||
                             snod->type == UBIFS_XENT_NODE ||
-                            snod->type == UBIFS_TRUN_NODE);
+                            snod->type == UBIFS_TRUN_NODE ||
+                            snod->type == UBIFS_AUTH_NODE);
 
                if (snod->type != UBIFS_INO_NODE  &&
                    snod->type != UBIFS_DATA_NODE &&
@@ -364,12 +365,13 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
 
        /* Write nodes to their new location. Use the first-fit strategy */
        while (1) {
-               int avail;
+               int avail, moved = 0;
                struct ubifs_scan_node *snod, *tmp;
 
                /* Move data nodes */
                list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
-                       avail = c->leb_size - wbuf->offs - wbuf->used;
+                       avail = c->leb_size - wbuf->offs - wbuf->used -
+                                       ubifs_auth_node_sz(c);
                        if  (snod->len > avail)
                                /*
                                 * Do not skip data nodes in order to optimize
@@ -377,14 +379,21 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
                                 */
                                break;
 
+                       err = ubifs_shash_update(c, c->jheads[GCHD].log_hash,
+                                                snod->node, snod->len);
+                       if (err)
+                               goto out;
+
                        err = move_node(c, sleb, snod, wbuf);
                        if (err)
                                goto out;
+                       moved = 1;
                }
 
                /* Move non-data nodes */
                list_for_each_entry_safe(snod, tmp, &nondata, list) {
-                       avail = c->leb_size - wbuf->offs - wbuf->used;
+                       avail = c->leb_size - wbuf->offs - wbuf->used -
+                                       ubifs_auth_node_sz(c);
                        if (avail < min)
                                break;
 
@@ -402,9 +411,41 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
                                continue;
                        }
 
+                       err = ubifs_shash_update(c, c->jheads[GCHD].log_hash,
+                                                snod->node, snod->len);
+                       if (err)
+                               goto out;
+
                        err = move_node(c, sleb, snod, wbuf);
                        if (err)
                                goto out;
+                       moved = 1;
+               }
+
+               if (ubifs_authenticated(c) && moved) {
+                       struct ubifs_auth_node *auth;
+
+                       auth = kmalloc(ubifs_auth_node_sz(c), GFP_NOFS);
+                       if (!auth) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+
+                       err = ubifs_prepare_auth_node(c, auth,
+                                               c->jheads[GCHD].log_hash);
+                       if (err) {
+                               kfree(auth);
+                               goto out;
+                       }
+
+                       err = ubifs_wbuf_write_nolock(wbuf, auth,
+                                                     ubifs_auth_node_sz(c));
+                       if (err) {
+                               kfree(auth);
+                               goto out;
+                       }
+
+                       ubifs_add_dirt(c, wbuf->lnum, ubifs_auth_node_sz(c));
                }
 
                if (list_empty(&sleb->nodes) && list_empty(&nondata))
index 099bec9..d124117 100644 (file)
@@ -365,20 +365,8 @@ static unsigned long long next_sqnum(struct ubifs_info *c)
        return sqnum;
 }
 
-/**
- * ubifs_prepare_node - prepare node to be written to flash.
- * @c: UBIFS file-system description object
- * @node: the node to pad
- * @len: node length
- * @pad: if the buffer has to be padded
- *
- * This function prepares node at @node to be written to the media - it
- * calculates node CRC, fills the common header, and adds proper padding up to
- * the next minimum I/O unit if @pad is not zero.
- */
-void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
+void ubifs_init_node(struct ubifs_info *c, void *node, int len, int pad)
 {
-       uint32_t crc;
        struct ubifs_ch *ch = node;
        unsigned long long sqnum = next_sqnum(c);
 
@@ -389,8 +377,6 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
        ch->group_type = UBIFS_NO_NODE_GROUP;
        ch->sqnum = cpu_to_le64(sqnum);
        ch->padding[0] = ch->padding[1] = 0;
-       crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
-       ch->crc = cpu_to_le32(crc);
 
        if (pad) {
                len = ALIGN(len, 8);
@@ -399,6 +385,68 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
        }
 }
 
+void ubifs_crc_node(struct ubifs_info *c, void *node, int len)
+{
+       struct ubifs_ch *ch = node;
+       uint32_t crc;
+
+       crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+       ch->crc = cpu_to_le32(crc);
+}
+
+/**
+ * ubifs_prepare_node_hmac - prepare node to be written to flash.
+ * @c: UBIFS file-system description object
+ * @node: the node to pad
+ * @len: node length
+ * @hmac_offs: offset of the HMAC in the node
+ * @pad: if the buffer has to be padded
+ *
+ * This function prepares node at @node to be written to the media - it
+ * calculates node CRC, fills the common header, and adds proper padding up to
+ * the next minimum I/O unit if @pad is not zero. if @hmac_offs is positive then
+ * a HMAC is inserted into the node at the given offset.
+ *
+ * This function returns 0 for success or a negative error code otherwise.
+ */
+int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len,
+                           int hmac_offs, int pad)
+{
+       int err;
+
+       ubifs_init_node(c, node, len, pad);
+
+       if (hmac_offs > 0) {
+               err = ubifs_node_insert_hmac(c, node, len, hmac_offs);
+               if (err)
+                       return err;
+       }
+
+       ubifs_crc_node(c, node, len);
+
+       return 0;
+}
+
+/**
+ * ubifs_prepare_node - prepare node to be written to flash.
+ * @c: UBIFS file-system description object
+ * @node: the node to pad
+ * @len: node length
+ * @pad: if the buffer has to be padded
+ *
+ * This function prepares node at @node to be written to the media - it
+ * calculates node CRC, fills the common header, and adds proper padding up to
+ * the next minimum I/O unit if @pad is not zero.
+ */
+void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
+{
+       /*
+        * Deliberately ignore return value since this function can only fail
+        * when a hmac offset is given.
+        */
+       ubifs_prepare_node_hmac(c, node, len, 0, pad);
+}
+
 /**
  * ubifs_prep_grp_node - prepare node of a group to be written to flash.
  * @c: UBIFS file-system description object
@@ -849,12 +897,13 @@ out:
 }
 
 /**
- * ubifs_write_node - write node to the media.
+ * ubifs_write_node_hmac - write node to the media.
  * @c: UBIFS file-system description object
  * @buf: the node to write
  * @len: node length
  * @lnum: logical eraseblock number
  * @offs: offset within the logical eraseblock
+ * @hmac_offs: offset of the HMAC within the node
  *
  * This function automatically fills node magic number, assigns sequence
  * number, and calculates node CRC checksum. The length of the @buf buffer has
@@ -862,8 +911,8 @@ out:
  * appends padding node and padding bytes if needed. Returns zero in case of
  * success and a negative error code in case of failure.
  */
-int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
-                    int offs)
+int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum,
+                         int offs, int hmac_offs)
 {
        int err, buf_len = ALIGN(len, c->min_io_size);
 
@@ -878,7 +927,10 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
        if (c->ro_error)
                return -EROFS;
 
-       ubifs_prepare_node(c, buf, len, 1);
+       err = ubifs_prepare_node_hmac(c, buf, len, hmac_offs, 1);
+       if (err)
+               return err;
+
        err = ubifs_leb_write(c, lnum, buf, offs, buf_len);
        if (err)
                ubifs_dump_node(c, buf);
@@ -887,6 +939,26 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
 }
 
 /**
+ * ubifs_write_node - write node to the media.
+ * @c: UBIFS file-system description object
+ * @buf: the node to write
+ * @len: node length
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ *
+ * This function automatically fills node magic number, assigns sequence
+ * number, and calculates node CRC checksum. The length of the @buf buffer has
+ * to be aligned to the minimal I/O unit size. This function automatically
+ * appends padding node and padding bytes if needed. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
+                    int offs)
+{
+       return ubifs_write_node_hmac(c, buf, len, lnum, offs, -1);
+}
+
+/**
  * ubifs_read_node_wbuf - read node from the media or write-buffer.
  * @wbuf: wbuf to check for un-written data
  * @buf: buffer to read to
index 802565a..729dc76 100644 (file)
@@ -90,6 +90,12 @@ static inline void zero_trun_node_unused(struct ubifs_trun_node *trun)
        memset(trun->padding, 0, 12);
 }
 
+static void ubifs_add_auth_dirt(struct ubifs_info *c, int lnum)
+{
+       if (ubifs_authenticated(c))
+               ubifs_add_dirt(c, lnum, ubifs_auth_node_sz(c));
+}
+
 /**
  * reserve_space - reserve space in the journal.
  * @c: UBIFS file-system description object
@@ -228,34 +234,33 @@ out_return:
        return err;
 }
 
-/**
- * write_node - write node to a journal head.
- * @c: UBIFS file-system description object
- * @jhead: journal head
- * @node: node to write
- * @len: node length
- * @lnum: LEB number written is returned here
- * @offs: offset written is returned here
- *
- * This function writes a node to reserved space of journal head @jhead.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-static int write_node(struct ubifs_info *c, int jhead, void *node, int len,
-                     int *lnum, int *offs)
+static int ubifs_hash_nodes(struct ubifs_info *c, void *node,
+                            int len, struct shash_desc *hash)
 {
-       struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf;
+       int auth_node_size = ubifs_auth_node_sz(c);
+       int err;
 
-       ubifs_assert(c, jhead != GCHD);
+       while (1) {
+               const struct ubifs_ch *ch = node;
+               int nodelen = le32_to_cpu(ch->len);
 
-       *lnum = c->jheads[jhead].wbuf.lnum;
-       *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used;
+               ubifs_assert(c, len >= auth_node_size);
 
-       dbg_jnl("jhead %s, LEB %d:%d, len %d",
-               dbg_jhead(jhead), *lnum, *offs, len);
-       ubifs_prepare_node(c, node, len, 0);
+               if (len == auth_node_size)
+                       break;
+
+               ubifs_assert(c, len > nodelen);
+               ubifs_assert(c, ch->magic == cpu_to_le32(UBIFS_NODE_MAGIC));
 
-       return ubifs_wbuf_write_nolock(wbuf, node, len);
+               err = ubifs_shash_update(c, hash, (void *)node, nodelen);
+               if (err)
+                       return err;
+
+               node += ALIGN(nodelen, 8);
+               len -= ALIGN(nodelen, 8);
+       }
+
+       return ubifs_prepare_auth_node(c, node, hash);
 }
 
 /**
@@ -268,9 +273,9 @@ static int write_node(struct ubifs_info *c, int jhead, void *node, int len,
  * @offs: offset written is returned here
  * @sync: non-zero if the write-buffer has to by synchronized
  *
- * This function is the same as 'write_node()' but it does not assume the
- * buffer it is writing is a node, so it does not prepare it (which means
- * initializing common header and calculating CRC).
+ * This function writes data to the reserved space of journal head @jhead.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
  */
 static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
                      int *lnum, int *offs, int sync)
@@ -285,6 +290,12 @@ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
        dbg_jnl("jhead %s, LEB %d:%d, len %d",
                dbg_jhead(jhead), *lnum, *offs, len);
 
+       if (ubifs_authenticated(c)) {
+               err = ubifs_hash_nodes(c, buf, len, c->jheads[jhead].log_hash);
+               if (err)
+                       return err;
+       }
+
        err = ubifs_wbuf_write_nolock(wbuf, buf, len);
        if (err)
                return err;
@@ -548,6 +559,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        struct ubifs_dent_node *dent;
        struct ubifs_ino_node *ino;
        union ubifs_key dent_key, ino_key;
+       u8 hash_dent[UBIFS_HASH_ARR_SZ];
+       u8 hash_ino[UBIFS_HASH_ARR_SZ];
+       u8 hash_ino_host[UBIFS_HASH_ARR_SZ];
 
        ubifs_assert(c, mutex_is_locked(&host_ui->ui_mutex));
 
@@ -570,7 +584,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 
        len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
        /* Make sure to also account for extended attributes */
-       len += host_ui->data_len;
+       if (ubifs_authenticated(c))
+               len += ALIGN(host_ui->data_len, 8) + ubifs_auth_node_sz(c);
+       else
+               len += host_ui->data_len;
 
        dent = kzalloc(len, GFP_NOFS);
        if (!dent)
@@ -602,11 +619,21 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 
        zero_dent_node_unused(dent);
        ubifs_prep_grp_node(c, dent, dlen, 0);
+       err = ubifs_node_calc_hash(c, dent, hash_dent);
+       if (err)
+               goto out_release;
 
        ino = (void *)dent + aligned_dlen;
        pack_inode(c, ino, inode, 0);
+       err = ubifs_node_calc_hash(c, ino, hash_ino);
+       if (err)
+               goto out_release;
+
        ino = (void *)ino + aligned_ilen;
        pack_inode(c, ino, dir, 1);
+       err = ubifs_node_calc_hash(c, ino, hash_ino_host);
+       if (err)
+               goto out_release;
 
        if (last_reference) {
                err = ubifs_add_orphan(c, inode->i_ino);
@@ -628,6 +655,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        }
        release_head(c, BASEHD);
        kfree(dent);
+       ubifs_add_auth_dirt(c, lnum);
 
        if (deletion) {
                if (nm->hash)
@@ -638,7 +666,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
                        goto out_ro;
                err = ubifs_add_dirt(c, lnum, dlen);
        } else
-               err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm);
+               err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen,
+                                      hash_dent, nm);
        if (err)
                goto out_ro;
 
@@ -650,14 +679,14 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
         */
        ino_key_init(c, &ino_key, inode->i_ino);
        ino_offs = dent_offs + aligned_dlen;
-       err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen);
+       err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen, hash_ino);
        if (err)
                goto out_ro;
 
        ino_key_init(c, &ino_key, dir->i_ino);
        ino_offs += aligned_ilen;
        err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs,
-                           UBIFS_INO_NODE_SZ + host_ui->data_len);
+                           UBIFS_INO_NODE_SZ + host_ui->data_len, hash_ino_host);
        if (err)
                goto out_ro;
 
@@ -706,10 +735,12 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
                         const union ubifs_key *key, const void *buf, int len)
 {
        struct ubifs_data_node *data;
-       int err, lnum, offs, compr_type, out_len, compr_len;
+       int err, lnum, offs, compr_type, out_len, compr_len, auth_len;
        int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
+       int write_len;
        struct ubifs_inode *ui = ubifs_inode(inode);
        bool encrypted = ubifs_crypt_is_encrypted(inode);
+       u8 hash[UBIFS_HASH_ARR_SZ];
 
        dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
                (unsigned long)key_inum(c, key), key_block(c, key), len);
@@ -718,7 +749,9 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
        if (encrypted)
                dlen += UBIFS_CIPHER_BLOCK_SIZE;
 
-       data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
+       auth_len = ubifs_auth_node_sz(c);
+
+       data = kmalloc(dlen + auth_len, GFP_NOFS | __GFP_NOWARN);
        if (!data) {
                /*
                 * Fall-back to the write reserve buffer. Note, we might be
@@ -757,20 +790,33 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
        }
 
        dlen = UBIFS_DATA_NODE_SZ + out_len;
+       if (ubifs_authenticated(c))
+               write_len = ALIGN(dlen, 8) + auth_len;
+       else
+               write_len = dlen;
+
        data->compr_type = cpu_to_le16(compr_type);
 
        /* Make reservation before allocating sequence numbers */
-       err = make_reservation(c, DATAHD, dlen);
+       err = make_reservation(c, DATAHD, write_len);
        if (err)
                goto out_free;
 
-       err = write_node(c, DATAHD, data, dlen, &lnum, &offs);
+       ubifs_prepare_node(c, data, dlen, 0);
+       err = write_head(c, DATAHD, data, write_len, &lnum, &offs, 0);
+       if (err)
+               goto out_release;
+
+       err = ubifs_node_calc_hash(c, data, hash);
        if (err)
                goto out_release;
+
        ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, key_inum(c, key));
        release_head(c, DATAHD);
 
-       err = ubifs_tnc_add(c, key, lnum, offs, dlen);
+       ubifs_add_auth_dirt(c, lnum);
+
+       err = ubifs_tnc_add(c, key, lnum, offs, dlen, hash);
        if (err)
                goto out_ro;
 
@@ -808,7 +854,9 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
        int err, lnum, offs;
        struct ubifs_ino_node *ino;
        struct ubifs_inode *ui = ubifs_inode(inode);
-       int sync = 0, len = UBIFS_INO_NODE_SZ, last_reference = !inode->i_nlink;
+       int sync = 0, write_len, ilen = UBIFS_INO_NODE_SZ;
+       int last_reference = !inode->i_nlink;
+       u8 hash[UBIFS_HASH_ARR_SZ];
 
        dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
 
@@ -817,20 +865,30 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
         * need to synchronize the write-buffer either.
         */
        if (!last_reference) {
-               len += ui->data_len;
+               ilen += ui->data_len;
                sync = IS_SYNC(inode);
        }
-       ino = kmalloc(len, GFP_NOFS);
+
+       if (ubifs_authenticated(c))
+               write_len = ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
+       else
+               write_len = ilen;
+
+       ino = kmalloc(write_len, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
 
        /* Make reservation before allocating sequence numbers */
-       err = make_reservation(c, BASEHD, len);
+       err = make_reservation(c, BASEHD, write_len);
        if (err)
                goto out_free;
 
        pack_inode(c, ino, inode, 1);
-       err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
+       err = ubifs_node_calc_hash(c, ino, hash);
+       if (err)
+               goto out_release;
+
+       err = write_head(c, BASEHD, ino, write_len, &lnum, &offs, sync);
        if (err)
                goto out_release;
        if (!sync)
@@ -838,17 +896,19 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
                                          inode->i_ino);
        release_head(c, BASEHD);
 
+       ubifs_add_auth_dirt(c, lnum);
+
        if (last_reference) {
                err = ubifs_tnc_remove_ino(c, inode->i_ino);
                if (err)
                        goto out_ro;
                ubifs_delete_orphan(c, inode->i_ino);
-               err = ubifs_add_dirt(c, lnum, len);
+               err = ubifs_add_dirt(c, lnum, ilen);
        } else {
                union ubifs_key key;
 
                ino_key_init(c, &key, inode->i_ino);
-               err = ubifs_tnc_add(c, &key, lnum, offs, len);
+               err = ubifs_tnc_add(c, &key, lnum, offs, ilen, hash);
        }
        if (err)
                goto out_ro;
@@ -958,6 +1018,10 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        int aligned_dlen1, aligned_dlen2;
        int twoparents = (fst_dir != snd_dir);
        void *p;
+       u8 hash_dent1[UBIFS_HASH_ARR_SZ];
+       u8 hash_dent2[UBIFS_HASH_ARR_SZ];
+       u8 hash_p1[UBIFS_HASH_ARR_SZ];
+       u8 hash_p2[UBIFS_HASH_ARR_SZ];
 
        ubifs_assert(c, ubifs_inode(fst_dir)->data_len == 0);
        ubifs_assert(c, ubifs_inode(snd_dir)->data_len == 0);
@@ -973,6 +1037,8 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        if (twoparents)
                len += plen;
 
+       len += ubifs_auth_node_sz(c);
+
        dent1 = kzalloc(len, GFP_NOFS);
        if (!dent1)
                return -ENOMEM;
@@ -993,6 +1059,9 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        set_dent_cookie(c, dent1);
        zero_dent_node_unused(dent1);
        ubifs_prep_grp_node(c, dent1, dlen1, 0);
+       err = ubifs_node_calc_hash(c, dent1, hash_dent1);
+       if (err)
+               goto out_release;
 
        /* Make new dent for 2nd entry */
        dent2 = (void *)dent1 + aligned_dlen1;
@@ -1006,14 +1075,26 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        set_dent_cookie(c, dent2);
        zero_dent_node_unused(dent2);
        ubifs_prep_grp_node(c, dent2, dlen2, 0);
+       err = ubifs_node_calc_hash(c, dent2, hash_dent2);
+       if (err)
+               goto out_release;
 
        p = (void *)dent2 + aligned_dlen2;
-       if (!twoparents)
+       if (!twoparents) {
                pack_inode(c, p, fst_dir, 1);
-       else {
+               err = ubifs_node_calc_hash(c, p, hash_p1);
+               if (err)
+                       goto out_release;
+       } else {
                pack_inode(c, p, fst_dir, 0);
+               err = ubifs_node_calc_hash(c, p, hash_p1);
+               if (err)
+                       goto out_release;
                p += ALIGN(plen, 8);
                pack_inode(c, p, snd_dir, 1);
+               err = ubifs_node_calc_hash(c, p, hash_p2);
+               if (err)
+                       goto out_release;
        }
 
        err = write_head(c, BASEHD, dent1, len, &lnum, &offs, sync);
@@ -1027,28 +1108,30 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        }
        release_head(c, BASEHD);
 
+       ubifs_add_auth_dirt(c, lnum);
+
        dent_key_init(c, &key, snd_dir->i_ino, snd_nm);
-       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, snd_nm);
+       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, snd_nm);
        if (err)
                goto out_ro;
 
        offs += aligned_dlen1;
        dent_key_init(c, &key, fst_dir->i_ino, fst_nm);
-       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, fst_nm);
+       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, hash_dent2, fst_nm);
        if (err)
                goto out_ro;
 
        offs += aligned_dlen2;
 
        ino_key_init(c, &key, fst_dir->i_ino);
-       err = ubifs_tnc_add(c, &key, lnum, offs, plen);
+       err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_p1);
        if (err)
                goto out_ro;
 
        if (twoparents) {
                offs += ALIGN(plen, 8);
                ino_key_init(c, &key, snd_dir->i_ino);
-               err = ubifs_tnc_add(c, &key, lnum, offs, plen);
+               err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_p2);
                if (err)
                        goto out_ro;
        }
@@ -1101,6 +1184,11 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        int last_reference = !!(new_inode && new_inode->i_nlink == 0);
        int move = (old_dir != new_dir);
        struct ubifs_inode *uninitialized_var(new_ui);
+       u8 hash_old_dir[UBIFS_HASH_ARR_SZ];
+       u8 hash_new_dir[UBIFS_HASH_ARR_SZ];
+       u8 hash_new_inode[UBIFS_HASH_ARR_SZ];
+       u8 hash_dent1[UBIFS_HASH_ARR_SZ];
+       u8 hash_dent2[UBIFS_HASH_ARR_SZ];
 
        ubifs_assert(c, ubifs_inode(old_dir)->data_len == 0);
        ubifs_assert(c, ubifs_inode(new_dir)->data_len == 0);
@@ -1123,6 +1211,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
        if (move)
                len += plen;
+
+       len += ubifs_auth_node_sz(c);
+
        dent = kzalloc(len, GFP_NOFS);
        if (!dent)
                return -ENOMEM;
@@ -1143,6 +1234,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        set_dent_cookie(c, dent);
        zero_dent_node_unused(dent);
        ubifs_prep_grp_node(c, dent, dlen1, 0);
+       err = ubifs_node_calc_hash(c, dent, hash_dent1);
+       if (err)
+               goto out_release;
 
        dent2 = (void *)dent + aligned_dlen1;
        dent2->ch.node_type = UBIFS_DENT_NODE;
@@ -1162,19 +1256,36 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        set_dent_cookie(c, dent2);
        zero_dent_node_unused(dent2);
        ubifs_prep_grp_node(c, dent2, dlen2, 0);
+       err = ubifs_node_calc_hash(c, dent2, hash_dent2);
+       if (err)
+               goto out_release;
 
        p = (void *)dent2 + aligned_dlen2;
        if (new_inode) {
                pack_inode(c, p, new_inode, 0);
+               err = ubifs_node_calc_hash(c, p, hash_new_inode);
+               if (err)
+                       goto out_release;
+
                p += ALIGN(ilen, 8);
        }
 
-       if (!move)
+       if (!move) {
                pack_inode(c, p, old_dir, 1);
-       else {
+               err = ubifs_node_calc_hash(c, p, hash_old_dir);
+               if (err)
+                       goto out_release;
+       } else {
                pack_inode(c, p, old_dir, 0);
+               err = ubifs_node_calc_hash(c, p, hash_old_dir);
+               if (err)
+                       goto out_release;
+
                p += ALIGN(plen, 8);
                pack_inode(c, p, new_dir, 1);
+               err = ubifs_node_calc_hash(c, p, hash_new_dir);
+               if (err)
+                       goto out_release;
        }
 
        if (last_reference) {
@@ -1200,15 +1311,17 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        }
        release_head(c, BASEHD);
 
+       ubifs_add_auth_dirt(c, lnum);
+
        dent_key_init(c, &key, new_dir->i_ino, new_nm);
-       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, new_nm);
+       err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, new_nm);
        if (err)
                goto out_ro;
 
        offs += aligned_dlen1;
        if (whiteout) {
                dent_key_init(c, &key, old_dir->i_ino, old_nm);
-               err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, old_nm);
+               err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, hash_dent2, old_nm);
                if (err)
                        goto out_ro;
 
@@ -1227,21 +1340,21 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        offs += aligned_dlen2;
        if (new_inode) {
                ino_key_init(c, &key, new_inode->i_ino);
-               err = ubifs_tnc_add(c, &key, lnum, offs, ilen);
+               err = ubifs_tnc_add(c, &key, lnum, offs, ilen, hash_new_inode);
                if (err)
                        goto out_ro;
                offs += ALIGN(ilen, 8);
        }
 
        ino_key_init(c, &key, old_dir->i_ino);
-       err = ubifs_tnc_add(c, &key, lnum, offs, plen);
+       err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_old_dir);
        if (err)
                goto out_ro;
 
        if (move) {
                offs += ALIGN(plen, 8);
                ino_key_init(c, &key, new_dir->i_ino);
-               err = ubifs_tnc_add(c, &key, lnum, offs, plen);
+               err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_new_dir);
                if (err)
                        goto out_ro;
        }
@@ -1360,6 +1473,8 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
        struct ubifs_inode *ui = ubifs_inode(inode);
        ino_t inum = inode->i_ino;
        unsigned int blk;
+       u8 hash_ino[UBIFS_HASH_ARR_SZ];
+       u8 hash_dn[UBIFS_HASH_ARR_SZ];
 
        dbg_jnl("ino %lu, size %lld -> %lld",
                (unsigned long)inum, old_size, new_size);
@@ -1369,6 +1484,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
 
        sz = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ +
             UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR;
+
+       sz += ubifs_auth_node_sz(c);
+
        ino = kmalloc(sz, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
@@ -1414,16 +1532,28 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
 
        /* Must make reservation before allocating sequence numbers */
        len = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ;
-       if (dlen)
+
+       if (ubifs_authenticated(c))
+               len += ALIGN(dlen, 8) + ubifs_auth_node_sz(c);
+       else
                len += dlen;
+
        err = make_reservation(c, BASEHD, len);
        if (err)
                goto out_free;
 
        pack_inode(c, ino, inode, 0);
+       err = ubifs_node_calc_hash(c, ino, hash_ino);
+       if (err)
+               goto out_release;
+
        ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1);
-       if (dlen)
+       if (dlen) {
                ubifs_prep_grp_node(c, dn, dlen, 1);
+               err = ubifs_node_calc_hash(c, dn, hash_dn);
+               if (err)
+                       goto out_release;
+       }
 
        err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
        if (err)
@@ -1432,15 +1562,17 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
                ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum);
        release_head(c, BASEHD);
 
+       ubifs_add_auth_dirt(c, lnum);
+
        if (dlen) {
                sz = offs + UBIFS_INO_NODE_SZ + UBIFS_TRUN_NODE_SZ;
-               err = ubifs_tnc_add(c, &key, lnum, sz, dlen);
+               err = ubifs_tnc_add(c, &key, lnum, sz, dlen, hash_dn);
                if (err)
                        goto out_ro;
        }
 
        ino_key_init(c, &key, inum);
-       err = ubifs_tnc_add(c, &key, lnum, offs, UBIFS_INO_NODE_SZ);
+       err = ubifs_tnc_add(c, &key, lnum, offs, UBIFS_INO_NODE_SZ, hash_ino);
        if (err)
                goto out_ro;
 
@@ -1495,12 +1627,13 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
                           const struct inode *inode,
                           const struct fscrypt_name *nm)
 {
-       int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
+       int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen, write_len;
        struct ubifs_dent_node *xent;
        struct ubifs_ino_node *ino;
        union ubifs_key xent_key, key1, key2;
        int sync = IS_DIRSYNC(host);
        struct ubifs_inode *host_ui = ubifs_inode(host);
+       u8 hash[UBIFS_HASH_ARR_SZ];
 
        ubifs_assert(c, inode->i_nlink == 0);
        ubifs_assert(c, mutex_is_locked(&host_ui->ui_mutex));
@@ -1514,12 +1647,14 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
        len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
 
-       xent = kzalloc(len, GFP_NOFS);
+       write_len = len + ubifs_auth_node_sz(c);
+
+       xent = kzalloc(write_len, GFP_NOFS);
        if (!xent)
                return -ENOMEM;
 
        /* Make reservation before allocating sequence numbers */
-       err = make_reservation(c, BASEHD, len);
+       err = make_reservation(c, BASEHD, write_len);
        if (err) {
                kfree(xent);
                return err;
@@ -1540,11 +1675,16 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        pack_inode(c, ino, inode, 0);
        ino = (void *)ino + UBIFS_INO_NODE_SZ;
        pack_inode(c, ino, host, 1);
+       err = ubifs_node_calc_hash(c, ino, hash);
+       if (err)
+               goto out_release;
 
-       err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync);
+       err = write_head(c, BASEHD, xent, write_len, &lnum, &xent_offs, sync);
        if (!sync && !err)
                ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino);
        release_head(c, BASEHD);
+
+       ubifs_add_auth_dirt(c, lnum);
        kfree(xent);
        if (err)
                goto out_ro;
@@ -1572,7 +1712,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
 
        /* And update TNC with the new host inode position */
        ino_key_init(c, &key1, host->i_ino);
-       err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen);
+       err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen, hash);
        if (err)
                goto out_ro;
 
@@ -1583,6 +1723,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        mark_inode_clean(c, host_ui);
        return 0;
 
+out_release:
+       kfree(xent);
+       release_head(c, BASEHD);
 out_ro:
        ubifs_ro_mode(c, err);
        finish_reservation(c);
@@ -1610,6 +1753,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        struct ubifs_ino_node *ino;
        union ubifs_key key;
        int sync = IS_DIRSYNC(host);
+       u8 hash_host[UBIFS_HASH_ARR_SZ];
+       u8 hash[UBIFS_HASH_ARR_SZ];
 
        dbg_jnl("ino %lu, ino %lu", host->i_ino, inode->i_ino);
        ubifs_assert(c, host->i_nlink > 0);
@@ -1621,6 +1766,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        aligned_len1 = ALIGN(len1, 8);
        aligned_len = aligned_len1 + ALIGN(len2, 8);
 
+       aligned_len += ubifs_auth_node_sz(c);
+
        ino = kzalloc(aligned_len, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
@@ -1631,7 +1778,13 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
                goto out_free;
 
        pack_inode(c, ino, host, 0);
+       err = ubifs_node_calc_hash(c, ino, hash_host);
+       if (err)
+               goto out_release;
        pack_inode(c, (void *)ino + aligned_len1, inode, 1);
+       err = ubifs_node_calc_hash(c, (void *)ino + aligned_len1, hash);
+       if (err)
+               goto out_release;
 
        err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0);
        if (!sync && !err) {
@@ -1644,13 +1797,15 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        if (err)
                goto out_ro;
 
+       ubifs_add_auth_dirt(c, lnum);
+
        ino_key_init(c, &key, host->i_ino);
-       err = ubifs_tnc_add(c, &key, lnum, offs, len1);
+       err = ubifs_tnc_add(c, &key, lnum, offs, len1, hash_host);
        if (err)
                goto out_ro;
 
        ino_key_init(c, &key, inode->i_ino);
-       err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2);
+       err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2, hash);
        if (err)
                goto out_ro;
 
@@ -1662,6 +1817,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        kfree(ino);
        return 0;
 
+out_release:
+       release_head(c, BASEHD);
 out_ro:
        ubifs_ro_mode(c, err);
        finish_reservation(c);
index 86b0828..15fd854 100644 (file)
@@ -236,6 +236,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
        bud->lnum = lnum;
        bud->start = offs;
        bud->jhead = jhead;
+       bud->log_hash = NULL;
 
        ref->ch.node_type = UBIFS_REF_NODE;
        ref->lnum = cpu_to_le32(bud->lnum);
@@ -275,6 +276,14 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
        if (err)
                goto out_unlock;
 
+       err = ubifs_shash_update(c, c->log_hash, ref, UBIFS_REF_NODE_SZ);
+       if (err)
+               goto out_unlock;
+
+       err = ubifs_shash_copy_state(c, c->log_hash, c->jheads[jhead].log_hash);
+       if (err)
+               goto out_unlock;
+
        c->lhead_offs += c->ref_node_alsz;
 
        ubifs_add_bud(c, bud);
@@ -377,6 +386,14 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
        cs->cmt_no = cpu_to_le64(c->cmt_no);
        ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
 
+       err = ubifs_shash_init(c, c->log_hash);
+       if (err)
+               goto out;
+
+       err = ubifs_shash_update(c, c->log_hash, cs, UBIFS_CS_NODE_SZ);
+       if (err < 0)
+               goto out;
+
        /*
         * Note, we do not lock 'c->log_mutex' because this is the commit start
         * phase and we are exclusively using the log. And we do not lock
@@ -402,6 +419,12 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
                ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0);
                len += UBIFS_REF_NODE_SZ;
+
+               err = ubifs_shash_update(c, c->log_hash, ref,
+                                        UBIFS_REF_NODE_SZ);
+               if (err)
+                       goto out;
+               ubifs_shash_copy_state(c, c->log_hash, c->jheads[i].log_hash);
        }
 
        ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len);
@@ -516,6 +539,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
                if (err)
                        return err;
                list_del(&bud->list);
+               kfree(bud->log_hash);
                kfree(bud);
        }
        mutex_lock(&c->log_mutex);
index 3139337..d1d5e96 100644 (file)
@@ -604,11 +604,12 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c,
  * @lpt_first: LEB number of first LPT LEB
  * @lpt_lebs: number of LEBs for LPT is passed and returned here
  * @big_lpt: use big LPT model is passed and returned here
+ * @hash: hash of the LPT is returned here
  *
  * This function returns %0 on success and a negative error code on failure.
  */
 int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
-                         int *lpt_lebs, int *big_lpt)
+                         int *lpt_lebs, int *big_lpt, u8 *hash)
 {
        int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
        int blnum, boffs, bsz, bcnt;
@@ -617,6 +618,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
        void *buf = NULL, *p;
        struct ubifs_lpt_lprops *ltab = NULL;
        int *lsave = NULL;
+       struct shash_desc *desc;
 
        err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
        if (err)
@@ -630,6 +632,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
        /* Needed by 'ubifs_pack_lsave()' */
        c->main_first = c->leb_cnt - *main_lebs;
 
+       desc = ubifs_hash_get_desc(c);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
        lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL);
        pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
        nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
@@ -677,6 +683,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
 
        /* Add first pnode */
        ubifs_pack_pnode(c, p, pnode);
+       err = ubifs_shash_update(c, desc, p, c->pnode_sz);
+       if (err)
+               goto out;
+
        p += c->pnode_sz;
        len = c->pnode_sz;
        pnode->num += 1;
@@ -711,6 +721,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
                        len = 0;
                }
                ubifs_pack_pnode(c, p, pnode);
+               err = ubifs_shash_update(c, desc, p, c->pnode_sz);
+               if (err)
+                       goto out;
+
                p += c->pnode_sz;
                len += c->pnode_sz;
                /*
@@ -830,6 +844,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
        if (err)
                goto out;
 
+       err = ubifs_shash_final(c, desc, hash);
+       if (err)
+               goto out;
+
        c->nhead_lnum = lnum;
        c->nhead_offs = ALIGN(len, c->min_io_size);
 
@@ -853,6 +871,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
                dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
 out:
        c->ltab = NULL;
+       kfree(desc);
        kfree(lsave);
        vfree(ltab);
        vfree(buf);
@@ -1439,26 +1458,25 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
 }
 
 /**
- * ubifs_lpt_lookup - lookup LEB properties in the LPT.
+ * ubifs_pnode_lookup - lookup a pnode in the LPT.
  * @c: UBIFS file-system description object
- * @lnum: LEB number to lookup
+ * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)
  *
- * This function returns a pointer to the LEB properties on success or a
- * negative error code on failure.
+ * This function returns a pointer to the pnode on success or a negative
+ * error code on failure.
  */
-struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
+struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i)
 {
-       int err, i, h, iip, shft;
+       int err, h, iip, shft;
        struct ubifs_nnode *nnode;
-       struct ubifs_pnode *pnode;
 
        if (!c->nroot) {
                err = ubifs_read_nnode(c, NULL, 0);
                if (err)
                        return ERR_PTR(err);
        }
+       i <<= UBIFS_LPT_FANOUT_SHIFT;
        nnode = c->nroot;
-       i = lnum - c->main_first;
        shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
        for (h = 1; h < c->lpt_hght; h++) {
                iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
@@ -1468,7 +1486,24 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
                        return ERR_CAST(nnode);
        }
        iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-       pnode = ubifs_get_pnode(c, nnode, iip);
+       return ubifs_get_pnode(c, nnode, iip);
+}
+
+/**
+ * ubifs_lpt_lookup - lookup LEB properties in the LPT.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to lookup
+ *
+ * This function returns a pointer to the LEB properties on success or a
+ * negative error code on failure.
+ */
+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
+{
+       int i, iip;
+       struct ubifs_pnode *pnode;
+
+       i = lnum - c->main_first;
+       pnode = ubifs_pnode_lookup(c, i >> UBIFS_LPT_FANOUT_SHIFT);
        if (IS_ERR(pnode))
                return ERR_CAST(pnode);
        iip = (i & (UBIFS_LPT_FANOUT - 1));
@@ -1620,6 +1655,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
 }
 
 /**
+ * ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes
+ * @c: UBIFS file-system description object
+ * @hash: the returned hash of the LPT pnodes
+ *
+ * This function iterates over the LPT pnodes and creates a hash over them.
+ * Returns 0 for success or a negative error code otherwise.
+ */
+int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)
+{
+       struct ubifs_nnode *nnode, *nn;
+       struct ubifs_cnode *cnode;
+       struct shash_desc *desc;
+       int iip = 0, i;
+       int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz);
+       void *buf;
+       int err;
+
+       if (!ubifs_authenticated(c))
+               return 0;
+
+       desc = ubifs_hash_get_desc(c);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       buf = kmalloc(bufsiz, GFP_NOFS);
+       if (!buf) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       if (!c->nroot) {
+               err = ubifs_read_nnode(c, NULL, 0);
+               if (err)
+                       return err;
+       }
+
+       cnode = (struct ubifs_cnode *)c->nroot;
+
+       while (cnode) {
+               nnode = cnode->parent;
+               nn = (struct ubifs_nnode *)cnode;
+               if (cnode->level > 1) {
+                       while (iip < UBIFS_LPT_FANOUT) {
+                               if (nn->nbranch[iip].lnum == 0) {
+                                       /* Go right */
+                                       iip++;
+                                       continue;
+                               }
+
+                               nnode = ubifs_get_nnode(c, nn, iip);
+                               if (IS_ERR(nnode)) {
+                                       err = PTR_ERR(nnode);
+                                       goto out;
+                               }
+
+                               /* Go down */
+                               iip = 0;
+                               cnode = (struct ubifs_cnode *)nnode;
+                               break;
+                       }
+                       if (iip < UBIFS_LPT_FANOUT)
+                               continue;
+               } else {
+                       struct ubifs_pnode *pnode;
+
+                       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+                               if (nn->nbranch[i].lnum == 0)
+                                       continue;
+                               pnode = ubifs_get_pnode(c, nn, i);
+                               if (IS_ERR(pnode)) {
+                                       err = PTR_ERR(pnode);
+                                       goto out;
+                               }
+
+                               ubifs_pack_pnode(c, buf, pnode);
+                               err = ubifs_shash_update(c, desc, buf,
+                                                        c->pnode_sz);
+                               if (err)
+                                       goto out;
+                       }
+               }
+               /* Go up and to the right */
+               iip = cnode->iip + 1;
+               cnode = (struct ubifs_cnode *)nnode;
+       }
+
+       err = ubifs_shash_final(c, desc, hash);
+out:
+       kfree(desc);
+       kfree(buf);
+
+       return err;
+}
+
+/**
+ * lpt_check_hash - check the hash of the LPT.
+ * @c: UBIFS file-system description object
+ *
+ * This function calculates a hash over all pnodes in the LPT and compares it with
+ * the hash stored in the master node. Returns %0 on success and a negative error
+ * code on failure.
+ */
+static int lpt_check_hash(struct ubifs_info *c)
+{
+       int err;
+       u8 hash[UBIFS_HASH_ARR_SZ];
+
+       if (!ubifs_authenticated(c))
+               return 0;
+
+       err = ubifs_lpt_calc_hash(c, hash);
+       if (err)
+               return err;
+
+       if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) {
+               err = -EPERM;
+               ubifs_err(c, "Failed to authenticate LPT");
+       } else {
+               err = 0;
+       }
+
+       return err;
+}
+
+/**
  * lpt_init_rd - initialize the LPT for reading.
  * @c: UBIFS file-system description object
  *
@@ -1660,6 +1820,10 @@ static int lpt_init_rd(struct ubifs_info *c)
        if (err)
                return err;
 
+       err = lpt_check_hash(c);
+       if (err)
+               return err;
+
        dbg_lp("space_bits %d", c->space_bits);
        dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
        dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
index 7ce3099..1f88caf 100644 (file)
@@ -619,38 +619,6 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
 }
 
 /**
- * pnode_lookup - lookup a pnode in the LPT.
- * @c: UBIFS file-system description object
- * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT))
- *
- * This function returns a pointer to the pnode on success or a negative
- * error code on failure.
- */
-static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
-{
-       int err, h, iip, shft;
-       struct ubifs_nnode *nnode;
-
-       if (!c->nroot) {
-               err = ubifs_read_nnode(c, NULL, 0);
-               if (err)
-                       return ERR_PTR(err);
-       }
-       i <<= UBIFS_LPT_FANOUT_SHIFT;
-       nnode = c->nroot;
-       shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
-       for (h = 1; h < c->lpt_hght; h++) {
-               iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-               shft -= UBIFS_LPT_FANOUT_SHIFT;
-               nnode = ubifs_get_nnode(c, nnode, iip);
-               if (IS_ERR(nnode))
-                       return ERR_CAST(nnode);
-       }
-       iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-       return ubifs_get_pnode(c, nnode, iip);
-}
-
-/**
  * add_pnode_dirt - add dirty space to LPT LEB properties.
  * @c: UBIFS file-system description object
  * @pnode: pnode for which to add dirt
@@ -702,7 +670,7 @@ static int make_tree_dirty(struct ubifs_info *c)
 {
        struct ubifs_pnode *pnode;
 
-       pnode = pnode_lookup(c, 0);
+       pnode = ubifs_pnode_lookup(c, 0);
        if (IS_ERR(pnode))
                return PTR_ERR(pnode);
 
@@ -956,7 +924,7 @@ static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum,
        struct ubifs_pnode *pnode;
        struct ubifs_nbranch *branch;
 
-       pnode = pnode_lookup(c, node_num);
+       pnode = ubifs_pnode_lookup(c, node_num);
        if (IS_ERR(pnode))
                return PTR_ERR(pnode);
        branch = &pnode->parent->nbranch[pnode->iip];
@@ -1279,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c)
        if (err)
                goto out;
 
+       err = ubifs_lpt_calc_hash(c, c->mst_node->hash_lpt);
+       if (err)
+               goto out;
+
        /* Copy the LPT's own lprops for end commit to write */
        memcpy(c->ltab_cmt, c->ltab,
               sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
@@ -1558,7 +1530,7 @@ static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
                struct ubifs_nbranch *branch;
 
                cond_resched();
-               pnode = pnode_lookup(c, i);
+               pnode = ubifs_pnode_lookup(c, i);
                if (IS_ERR(pnode))
                        return PTR_ERR(pnode);
                branch = &pnode->parent->nbranch[pnode->iip];
@@ -1710,7 +1682,7 @@ int dbg_check_ltab(struct ubifs_info *c)
        for (i = 0; i < cnt; i++) {
                struct ubifs_pnode *pnode;
 
-               pnode = pnode_lookup(c, i);
+               pnode = ubifs_pnode_lookup(c, i);
                if (IS_ERR(pnode))
                        return PTR_ERR(pnode);
                cond_resched();
index 9df4a41..5ea51bb 100644 (file)
 #include "ubifs.h"
 
 /**
+ * ubifs_compare_master_node - compare two UBIFS master nodes
+ * @c: UBIFS file-system description object
+ * @m1: the first node
+ * @m2: the second node
+ *
+ * This function compares two UBIFS master nodes. Returns 0 if they are equal
+ * and nonzero if not.
+ */
+int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
+{
+       int ret;
+       int behind;
+       int hmac_offs = offsetof(struct ubifs_mst_node, hmac);
+
+       /*
+        * Do not compare the common node header since the sequence number and
+        * hence the CRC are different.
+        */
+       ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,
+                    hmac_offs - UBIFS_CH_SZ);
+       if (ret)
+               return ret;
+
+       /*
+        * Do not compare the embedded HMAC aswell which also must be different
+        * due to the different common node header.
+        */
+       behind = hmac_offs + UBIFS_MAX_HMAC_LEN;
+
+       if (UBIFS_MST_NODE_SZ > behind)
+               return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);
+
+       return 0;
+}
+
+/**
  * scan_for_master - search the valid master node.
  * @c: UBIFS file-system description object
  *
@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c)
 {
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
-       int lnum, offs = 0, nodes_cnt;
+       int lnum, offs = 0, nodes_cnt, err;
 
        lnum = UBIFS_MST_LNUM;
 
@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c)
                goto out_dump;
        if (snod->offs != offs)
                goto out;
-       if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
-                  (void *)snod->node + UBIFS_CH_SZ,
-                  UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+       if (ubifs_compare_master_node(c, c->mst_node, snod->node))
                goto out;
+
        c->mst_offs = offs;
        ubifs_scan_destroy(sleb);
+
+       if (!ubifs_authenticated(c))
+               return 0;
+
+       err = ubifs_node_verify_hmac(c, c->mst_node,
+                                    sizeof(struct ubifs_mst_node),
+                                    offsetof(struct ubifs_mst_node, hmac));
+       if (err) {
+               ubifs_err(c, "Failed to verify master node HMAC");
+               return -EPERM;
+       }
+
        return 0;
 
 out:
@@ -305,6 +352,8 @@ int ubifs_read_master(struct ubifs_info *c)
        c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
        c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
 
+       ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
+
        c->calc_idx_sz = c->bi.old_idx_sz;
 
        if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
@@ -378,7 +427,9 @@ int ubifs_write_master(struct ubifs_info *c)
        c->mst_offs = offs;
        c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
 
-       err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
+       ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
+       err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
+                                   offsetof(struct ubifs_mst_node, hmac));
        if (err)
                return err;
 
@@ -389,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c)
                if (err)
                        return err;
        }
-       err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
+       err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
+                                   offsetof(struct ubifs_mst_node, hmac));
 
        return err;
 }
index 21d35d7..6f87237 100644 (file)
@@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
  */
 static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
 {
-       return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+       return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len + c->hash_len)
+                                  * child_cnt;
 }
 
 /**
@@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
                                      int bnum)
 {
        return (struct ubifs_branch *)((void *)idx->branches +
-                                      (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+                       (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) * bnum);
 }
 
 /**
index 984e30e..8526b7e 100644 (file)
@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
        save_flags = mst->flags;
        mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
 
-       ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+       err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
+                                     offsetof(struct ubifs_mst_node, hmac), 1);
+       if (err)
+               goto out;
        err = ubifs_leb_change(c, lnum, mst, sz);
        if (err)
                goto out;
@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
                        offs2 = (void *)mst2 - buf2;
                        if (offs1 == offs2) {
                                /* Same offset, so must be the same */
-                               if (memcmp((void *)mst1 + UBIFS_CH_SZ,
-                                          (void *)mst2 + UBIFS_CH_SZ,
-                                          UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+                               if (ubifs_compare_master_node(c, mst1, mst2))
                                        goto out_err;
                                mst = mst1;
                        } else if (offs2 + sz == offs1) {
@@ -1462,15 +1463,81 @@ out:
 }
 
 /**
+ * inode_fix_size - fix inode size
+ * @c: UBIFS file-system description object
+ * @e: inode size information for recovery
+ */
+static int inode_fix_size(struct ubifs_info *c, struct size_entry *e)
+{
+       struct inode *inode;
+       struct ubifs_inode *ui;
+       int err;
+
+       if (c->ro_mount)
+               ubifs_assert(c, !e->inode);
+
+       if (e->inode) {
+               /* Remounting rw, pick up inode we stored earlier */
+               inode = e->inode;
+       } else {
+               inode = ubifs_iget(c->vfs_sb, e->inum);
+               if (IS_ERR(inode))
+                       return PTR_ERR(inode);
+
+               if (inode->i_size >= e->d_size) {
+                       /*
+                        * The original inode in the index already has a size
+                        * big enough, nothing to do
+                        */
+                       iput(inode);
+                       return 0;
+               }
+
+               dbg_rcvry("ino %lu size %lld -> %lld",
+                         (unsigned long)e->inum,
+                         inode->i_size, e->d_size);
+
+               ui = ubifs_inode(inode);
+
+               inode->i_size = e->d_size;
+               ui->ui_size = e->d_size;
+               ui->synced_i_size = e->d_size;
+
+               e->inode = inode;
+       }
+
+       /*
+        * In readonly mode just keep the inode pinned in memory until we go
+        * readwrite. In readwrite mode write the inode to the journal with the
+        * fixed size.
+        */
+       if (c->ro_mount)
+               return 0;
+
+       err = ubifs_jnl_write_inode(c, inode);
+
+       iput(inode);
+
+       if (err)
+               return err;
+
+       rb_erase(&e->rb, &c->size_tree);
+       kfree(e);
+
+       return 0;
+}
+
+/**
  * ubifs_recover_size - recover inode size.
  * @c: UBIFS file-system description object
+ * @in_place: If true, do a in-place size fixup
  *
  * This function attempts to fix inode size discrepancies identified by the
  * 'ubifs_recover_size_accum()' function.
  *
  * This functions returns %0 on success and a negative error code on failure.
  */
-int ubifs_recover_size(struct ubifs_info *c)
+int ubifs_recover_size(struct ubifs_info *c, bool in_place)
 {
        struct rb_node *this = rb_first(&c->size_tree);
 
@@ -1479,6 +1546,9 @@ int ubifs_recover_size(struct ubifs_info *c)
                int err;
 
                e = rb_entry(this, struct size_entry, rb);
+
+               this = rb_next(this);
+
                if (!e->exists) {
                        union ubifs_key key;
 
@@ -1502,40 +1572,26 @@ int ubifs_recover_size(struct ubifs_info *c)
                }
 
                if (e->exists && e->i_size < e->d_size) {
-                       if (c->ro_mount) {
-                               /* Fix the inode size and pin it in memory */
-                               struct inode *inode;
-                               struct ubifs_inode *ui;
-
-                               ubifs_assert(c, !e->inode);
-
-                               inode = ubifs_iget(c->vfs_sb, e->inum);
-                               if (IS_ERR(inode))
-                                       return PTR_ERR(inode);
-
-                               ui = ubifs_inode(inode);
-                               if (inode->i_size < e->d_size) {
-                                       dbg_rcvry("ino %lu size %lld -> %lld",
-                                                 (unsigned long)e->inum,
-                                                 inode->i_size, e->d_size);
-                                       inode->i_size = e->d_size;
-                                       ui->ui_size = e->d_size;
-                                       ui->synced_i_size = e->d_size;
-                                       e->inode = inode;
-                                       this = rb_next(this);
-                                       continue;
-                               }
-                               iput(inode);
-                       } else {
-                               /* Fix the size in place */
+                       ubifs_assert(c, !(c->ro_mount && in_place));
+
+                       /*
+                        * We found data that is outside the found inode size,
+                        * fixup the inode size
+                        */
+
+                       if (in_place) {
                                err = fix_size_in_place(c, e);
                                if (err)
                                        return err;
                                iput(e->inode);
+                       } else {
+                               err = inode_fix_size(c, e);
+                               if (err)
+                                       return err;
+                               continue;
                        }
                }
 
-               this = rb_next(this);
                rb_erase(&e->rb, &c->size_tree);
                kfree(e);
        }
index 4844538..75f961c 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "ubifs.h"
 #include <linux/list_sort.h>
+#include <crypto/hash.h>
+#include <crypto/algapi.h>
 
 /**
  * struct replay_entry - replay list entry.
@@ -56,6 +58,7 @@ struct replay_entry {
        int lnum;
        int offs;
        int len;
+       u8 hash[UBIFS_HASH_ARR_SZ];
        unsigned int deletion:1;
        unsigned long long sqnum;
        struct list_head list;
@@ -228,7 +231,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
                        err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
                else
                        err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
-                                              r->len, &r->nm);
+                                              r->len, r->hash, &r->nm);
        } else {
                if (r->deletion)
                        switch (key_type(c, &r->key)) {
@@ -248,7 +251,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
                        }
                else
                        err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
-                                           r->len);
+                                           r->len, r->hash);
                if (err)
                        return err;
 
@@ -352,9 +355,9 @@ static void destroy_replay_list(struct ubifs_info *c)
  * in case of success and a negative error code in case of failure.
  */
 static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
-                      union ubifs_key *key, unsigned long long sqnum,
-                      int deletion, int *used, loff_t old_size,
-                      loff_t new_size)
+                      const u8 *hash, union ubifs_key *key,
+                      unsigned long long sqnum, int deletion, int *used,
+                      loff_t old_size, loff_t new_size)
 {
        struct replay_entry *r;
 
@@ -372,6 +375,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       ubifs_copy_hash(c, hash, r->hash);
        r->deletion = !!deletion;
        r->sqnum = sqnum;
        key_copy(c, key, &r->key);
@@ -400,8 +404,9 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
  * negative error code in case of failure.
  */
 static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
-                      union ubifs_key *key, const char *name, int nlen,
-                      unsigned long long sqnum, int deletion, int *used)
+                      const u8 *hash, union ubifs_key *key,
+                      const char *name, int nlen, unsigned long long sqnum,
+                      int deletion, int *used)
 {
        struct replay_entry *r;
        char *nbuf;
@@ -425,6 +430,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       ubifs_copy_hash(c, hash, r->hash);
        r->deletion = !!deletion;
        r->sqnum = sqnum;
        key_copy(c, key, &r->key);
@@ -528,6 +534,105 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
 }
 
 /**
+ * authenticate_sleb - authenticate one scan LEB
+ * @c: UBIFS file-system description object
+ * @sleb: the scan LEB to authenticate
+ * @log_hash:
+ * @is_last: if true, this is is the last LEB
+ *
+ * This function iterates over the buds of a single LEB authenticating all buds
+ * with the authentication nodes on this LEB. Authentication nodes are written
+ * after some buds and contain a HMAC covering the authentication node itself
+ * and the buds between the last authentication node and the current
+ * authentication node. It can happen that the last buds cannot be authenticated
+ * because a powercut happened when some nodes were written but not the
+ * corresponding authentication node. This function returns the number of nodes
+ * that could be authenticated or a negative error code.
+ */
+static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                            struct shash_desc *log_hash, int is_last)
+{
+       int n_not_auth = 0;
+       struct ubifs_scan_node *snod;
+       int n_nodes = 0;
+       int err;
+       u8 *hash, *hmac;
+
+       if (!ubifs_authenticated(c))
+               return sleb->nodes_cnt;
+
+       hash = kmalloc(crypto_shash_descsize(c->hash_tfm), GFP_NOFS);
+       hmac = kmalloc(c->hmac_desc_len, GFP_NOFS);
+       if (!hash || !hmac) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       list_for_each_entry(snod, &sleb->nodes, list) {
+
+               n_nodes++;
+
+               if (snod->type == UBIFS_AUTH_NODE) {
+                       struct ubifs_auth_node *auth = snod->node;
+                       SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
+                       SHASH_DESC_ON_STACK(hmac_desc, c->hmac_tfm);
+
+                       hash_desc->tfm = c->hash_tfm;
+                       hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+                       ubifs_shash_copy_state(c, log_hash, hash_desc);
+                       err = crypto_shash_final(hash_desc, hash);
+                       if (err)
+                               goto out;
+
+                       hmac_desc->tfm = c->hmac_tfm;
+                       hmac_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+                       err = crypto_shash_digest(hmac_desc, hash, c->hash_len,
+                                                 hmac);
+                       if (err)
+                               goto out;
+
+                       err = ubifs_check_hmac(c, auth->hmac, hmac);
+                       if (err) {
+                               err = -EPERM;
+                               goto out;
+                       }
+                       n_not_auth = 0;
+               } else {
+                       err = crypto_shash_update(log_hash, snod->node,
+                                                 snod->len);
+                       if (err)
+                               goto out;
+                       n_not_auth++;
+               }
+       }
+
+       /*
+        * A powercut can happen when some nodes were written, but not yet
+        * the corresponding authentication node. This may only happen on
+        * the last bud though.
+        */
+       if (n_not_auth) {
+               if (is_last) {
+                       dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them",
+                               n_not_auth, sleb->lnum);
+                       err = 0;
+               } else {
+                       dbg_mnt("%d unauthenticated nodes found on non-last LEB %d",
+                               n_not_auth, sleb->lnum);
+                       err = -EPERM;
+               }
+       } else {
+               err = 0;
+       }
+out:
+       kfree(hash);
+       kfree(hmac);
+
+       return err ? err : n_nodes - n_not_auth;
+}
+
+/**
  * replay_bud - replay a bud logical eraseblock.
  * @c: UBIFS file-system description object
  * @b: bud entry which describes the bud
@@ -540,6 +645,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 {
        int is_last = is_last_bud(c, b->bud);
        int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
+       int n_nodes, n = 0;
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
 
@@ -559,6 +665,15 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
        if (IS_ERR(sleb))
                return PTR_ERR(sleb);
 
+       n_nodes = authenticate_sleb(c, sleb, b->bud->log_hash, is_last);
+       if (n_nodes < 0) {
+               err = n_nodes;
+               goto out;
+       }
+
+       ubifs_shash_copy_state(c, b->bud->log_hash,
+                              c->jheads[b->bud->jhead].log_hash);
+
        /*
         * The bud does not have to start from offset zero - the beginning of
         * the 'lnum' LEB may contain previously committed data. One of the
@@ -582,6 +697,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
         */
 
        list_for_each_entry(snod, &sleb->nodes, list) {
+               u8 hash[UBIFS_HASH_ARR_SZ];
                int deletion = 0;
 
                cond_resched();
@@ -591,6 +707,8 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                        goto out_dump;
                }
 
+               ubifs_node_calc_hash(c, snod->node, hash);
+
                if (snod->sqnum > c->max_sqnum)
                        c->max_sqnum = snod->sqnum;
 
@@ -602,7 +720,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 
                        if (le32_to_cpu(ino->nlink) == 0)
                                deletion = 1;
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, snod->sqnum, deletion,
                                          &used, 0, new_size);
                        break;
@@ -614,7 +732,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                                          key_block(c, &snod->key) *
                                          UBIFS_BLOCK_SIZE;
 
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, snod->sqnum, deletion,
                                          &used, 0, new_size);
                        break;
@@ -628,7 +746,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                        if (err)
                                goto out_dump;
 
-                       err = insert_dent(c, lnum, snod->offs, snod->len,
+                       err = insert_dent(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, dent->name,
                                          le16_to_cpu(dent->nlen), snod->sqnum,
                                          !le64_to_cpu(dent->inum), &used);
@@ -654,11 +772,13 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                         * functions which expect nodes to have keys.
                         */
                        trun_key_init(c, &key, le32_to_cpu(trun->inum));
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &key, snod->sqnum, 1, &used,
                                          old_size, new_size);
                        break;
                }
+               case UBIFS_AUTH_NODE:
+                       break;
                default:
                        ubifs_err(c, "unexpected node type %d in bud LEB %d:%d",
                                  snod->type, lnum, snod->offs);
@@ -667,6 +787,10 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                }
                if (err)
                        goto out;
+
+               n++;
+               if (n == n_nodes)
+                       break;
        }
 
        ubifs_assert(c, ubifs_search_bud(c, lnum));
@@ -745,6 +869,7 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
 {
        struct ubifs_bud *bud;
        struct bud_entry *b;
+       int err;
 
        dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
 
@@ -754,13 +879,21 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
 
        b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
        if (!b) {
-               kfree(bud);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out;
        }
 
        bud->lnum = lnum;
        bud->start = offs;
        bud->jhead = jhead;
+       bud->log_hash = ubifs_hash_get_desc(c);
+       if (IS_ERR(bud->log_hash)) {
+               err = PTR_ERR(bud->log_hash);
+               goto out;
+       }
+
+       ubifs_shash_copy_state(c, c->log_hash, bud->log_hash);
+
        ubifs_add_bud(c, bud);
 
        b->bud = bud;
@@ -768,6 +901,11 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
        list_add_tail(&b->list, &c->replay_buds);
 
        return 0;
+out:
+       kfree(bud);
+       kfree(b);
+
+       return err;
 }
 
 /**
@@ -873,6 +1011,14 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
 
                c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
                dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
+
+               err = ubifs_shash_init(c, c->log_hash);
+               if (err)
+                       goto out;
+
+               err = ubifs_shash_update(c, c->log_hash, node, UBIFS_CS_NODE_SZ);
+               if (err < 0)
+                       goto out;
        }
 
        if (snod->sqnum < c->cs_sqnum) {
@@ -920,6 +1066,11 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
                        if (err)
                                goto out_dump;
 
+                       err = ubifs_shash_update(c, c->log_hash, ref,
+                                                UBIFS_REF_NODE_SZ);
+                       if (err)
+                               goto out;
+
                        err = add_replay_bud(c, le32_to_cpu(ref->lnum),
                                             le32_to_cpu(ref->offs),
                                             le32_to_cpu(ref->jhead),
index bf17f58..75a69dd 100644 (file)
@@ -82,10 +82,13 @@ static int create_default_filesystem(struct ubifs_info *c)
        int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
        int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
        int min_leb_cnt = UBIFS_MIN_LEB_CNT;
+       int idx_node_size;
        long long tmp64, main_bytes;
        __le64 tmp_le64;
        __le32 tmp_le32;
        struct timespec64 ts;
+       u8 hash[UBIFS_HASH_ARR_SZ];
+       u8 hash_lpt[UBIFS_HASH_ARR_SZ];
 
        /* Some functions called from here depend on the @c->key_len filed */
        c->key_len = UBIFS_SK_LEN;
@@ -147,7 +150,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        c->lsave_cnt = DEFAULT_LSAVE_CNT;
        c->max_leb_cnt = c->leb_cnt;
        err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs,
-                                   &big_lpt);
+                                   &big_lpt, hash_lpt);
        if (err)
                return err;
 
@@ -156,17 +159,35 @@ static int create_default_filesystem(struct ubifs_info *c)
 
        main_first = c->leb_cnt - main_lebs;
 
+       sup = kzalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_KERNEL);
+       mst = kzalloc(c->mst_node_alsz, GFP_KERNEL);
+       idx_node_size = ubifs_idx_node_sz(c, 1);
+       idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL);
+       ino = kzalloc(ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size), GFP_KERNEL);
+       cs = kzalloc(ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size), GFP_KERNEL);
+
+       if (!sup || !mst || !idx || !ino || !cs) {
+               err = -ENOMEM;
+               goto out;
+       }
+
        /* Create default superblock */
-       tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
-       sup = kzalloc(tmp, GFP_KERNEL);
-       if (!sup)
-               return -ENOMEM;
 
        tmp64 = (long long)max_buds * c->leb_size;
        if (big_lpt)
                sup_flags |= UBIFS_FLG_BIGLPT;
        sup_flags |= UBIFS_FLG_DOUBLE_HASH;
 
+       if (ubifs_authenticated(c)) {
+               sup_flags |= UBIFS_FLG_AUTHENTICATION;
+               sup->hash_algo = cpu_to_le16(c->auth_hash_algo);
+               err = ubifs_hmac_wkm(c, sup->hmac_wkm);
+               if (err)
+                       goto out;
+       } else {
+               sup->hash_algo = 0xffff;
+       }
+
        sup->ch.node_type  = UBIFS_SB_NODE;
        sup->key_hash      = UBIFS_KEY_HASH_R5;
        sup->flags         = cpu_to_le32(sup_flags);
@@ -197,17 +218,9 @@ static int create_default_filesystem(struct ubifs_info *c)
        sup->rp_size = cpu_to_le64(tmp64);
        sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION);
 
-       err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0);
-       kfree(sup);
-       if (err)
-               return err;
-
        dbg_gen("default superblock created at LEB 0:0");
 
        /* Create default master node */
-       mst = kzalloc(c->mst_node_alsz, GFP_KERNEL);
-       if (!mst)
-               return -ENOMEM;
 
        mst->ch.node_type = UBIFS_MST_NODE;
        mst->log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
@@ -233,6 +246,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        mst->empty_lebs   = cpu_to_le32(main_lebs - 2);
        mst->idx_lebs     = cpu_to_le32(1);
        mst->leb_cnt      = cpu_to_le32(c->leb_cnt);
+       ubifs_copy_hash(c, hash_lpt, mst->hash_lpt);
 
        /* Calculate lprops statistics */
        tmp64 = main_bytes;
@@ -253,24 +267,9 @@ static int create_default_filesystem(struct ubifs_info *c)
 
        mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
 
-       err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0);
-       if (err) {
-               kfree(mst);
-               return err;
-       }
-       err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
-                              0);
-       kfree(mst);
-       if (err)
-               return err;
-
        dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM);
 
        /* Create the root indexing node */
-       tmp = ubifs_idx_node_sz(c, 1);
-       idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL);
-       if (!idx)
-               return -ENOMEM;
 
        c->key_fmt = UBIFS_SIMPLE_KEY_FMT;
        c->key_hash = key_r5_hash;
@@ -282,19 +281,11 @@ static int create_default_filesystem(struct ubifs_info *c)
        key_write_idx(c, &key, &br->key);
        br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
        br->len  = cpu_to_le32(UBIFS_INO_NODE_SZ);
-       err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0);
-       kfree(idx);
-       if (err)
-               return err;
 
        dbg_gen("default root indexing node created LEB %d:0",
                main_first + DEFAULT_IDX_LEB);
 
        /* Create default root inode */
-       tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size);
-       ino = kzalloc(tmp, GFP_KERNEL);
-       if (!ino)
-               return -ENOMEM;
 
        ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO);
        ino->ch.node_type = UBIFS_INO_NODE;
@@ -317,12 +308,6 @@ static int create_default_filesystem(struct ubifs_info *c)
        /* Set compression enabled by default */
        ino->flags = cpu_to_le32(UBIFS_COMPR_FL);
 
-       err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
-                              main_first + DEFAULT_DATA_LEB, 0);
-       kfree(ino);
-       if (err)
-               return err;
-
        dbg_gen("root inode created at LEB %d:0",
                main_first + DEFAULT_DATA_LEB);
 
@@ -331,19 +316,54 @@ static int create_default_filesystem(struct ubifs_info *c)
         * always the case during normal file-system operation. Write a fake
         * commit start node to the log.
         */
-       tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size);
-       cs = kzalloc(tmp, GFP_KERNEL);
-       if (!cs)
-               return -ENOMEM;
 
        cs->ch.node_type = UBIFS_CS_NODE;
+
+       err = ubifs_write_node_hmac(c, sup, UBIFS_SB_NODE_SZ, 0, 0,
+                                   offsetof(struct ubifs_sb_node, hmac));
+       if (err)
+               goto out;
+
+       err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
+                              main_first + DEFAULT_DATA_LEB, 0);
+       if (err)
+               goto out;
+
+       ubifs_node_calc_hash(c, ino, hash);
+       ubifs_copy_hash(c, hash, ubifs_branch_hash(c, br));
+
+       err = ubifs_write_node(c, idx, idx_node_size, main_first + DEFAULT_IDX_LEB, 0);
+       if (err)
+               goto out;
+
+       ubifs_node_calc_hash(c, idx, hash);
+       ubifs_copy_hash(c, hash, mst->hash_root_idx);
+
+       err = ubifs_write_node_hmac(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0,
+               offsetof(struct ubifs_mst_node, hmac));
+       if (err)
+               goto out;
+
+       err = ubifs_write_node_hmac(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
+                              0, offsetof(struct ubifs_mst_node, hmac));
+       if (err)
+               goto out;
+
        err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0);
-       kfree(cs);
        if (err)
-               return err;
+               goto out;
 
        ubifs_msg(c, "default file-system created");
-       return 0;
+
+       err = 0;
+out:
+       kfree(sup);
+       kfree(mst);
+       kfree(idx);
+       kfree(ino);
+       kfree(cs);
+
+       return err;
 }
 
 /**
@@ -498,7 +518,7 @@ failed:
  * code. Note, the user of this function is responsible of kfree()'ing the
  * returned superblock buffer.
  */
-struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+static struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 {
        struct ubifs_sb_node *sup;
        int err;
@@ -517,6 +537,65 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
        return sup;
 }
 
+static int authenticate_sb_node(struct ubifs_info *c,
+                               const struct ubifs_sb_node *sup)
+{
+       unsigned int sup_flags = le32_to_cpu(sup->flags);
+       u8 hmac_wkm[UBIFS_HMAC_ARR_SZ];
+       int authenticated = !!(sup_flags & UBIFS_FLG_AUTHENTICATION);
+       int hash_algo;
+       int err;
+
+       if (c->authenticated && !authenticated) {
+               ubifs_err(c, "authenticated FS forced, but found FS without authentication");
+               return -EINVAL;
+       }
+
+       if (!c->authenticated && authenticated) {
+               ubifs_err(c, "authenticated FS found, but no key given");
+               return -EINVAL;
+       }
+
+       ubifs_msg(c, "Mounting in %sauthenticated mode",
+                 c->authenticated ? "" : "un");
+
+       if (!c->authenticated)
+               return 0;
+
+       if (!IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION))
+               return -EOPNOTSUPP;
+
+       hash_algo = le16_to_cpu(sup->hash_algo);
+       if (hash_algo >= HASH_ALGO__LAST) {
+               ubifs_err(c, "superblock uses unknown hash algo %d",
+                         hash_algo);
+               return -EINVAL;
+       }
+
+       if (strcmp(hash_algo_name[hash_algo], c->auth_hash_name)) {
+               ubifs_err(c, "This filesystem uses %s for hashing,"
+                            " but %s is specified", hash_algo_name[hash_algo],
+                            c->auth_hash_name);
+               return -EINVAL;
+       }
+
+       err = ubifs_hmac_wkm(c, hmac_wkm);
+       if (err)
+               return err;
+
+       if (ubifs_check_hmac(c, hmac_wkm, sup->hmac_wkm)) {
+               ubifs_err(c, "provided key does not fit");
+               return -ENOKEY;
+       }
+
+       err = ubifs_node_verify_hmac(c, sup, sizeof(*sup),
+                                    offsetof(struct ubifs_sb_node, hmac));
+       if (err)
+               ubifs_err(c, "Failed to authenticate superblock: %d", err);
+
+       return err;
+}
+
 /**
  * ubifs_write_sb_node - write superblock node.
  * @c: UBIFS file-system description object
@@ -527,8 +606,13 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
 {
        int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
+       int err;
+
+       err = ubifs_prepare_node_hmac(c, sup, UBIFS_SB_NODE_SZ,
+                                     offsetof(struct ubifs_sb_node, hmac), 1);
+       if (err)
+               return err;
 
-       ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
        return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len);
 }
 
@@ -555,6 +639,8 @@ int ubifs_read_superblock(struct ubifs_info *c)
        if (IS_ERR(sup))
                return PTR_ERR(sup);
 
+       c->sup_node = sup;
+
        c->fmt_version = le32_to_cpu(sup->fmt_version);
        c->ro_compat_version = le32_to_cpu(sup->ro_compat_version);
 
@@ -603,7 +689,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
                c->key_hash = key_test_hash;
                c->key_hash_type = UBIFS_KEY_HASH_TEST;
                break;
-       };
+       }
 
        c->key_fmt = sup->key_fmt;
 
@@ -640,6 +726,10 @@ int ubifs_read_superblock(struct ubifs_info *c)
        c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
        c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
 
+       err = authenticate_sb_node(c, sup);
+       if (err)
+               goto out;
+
        if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
                ubifs_err(c, "Unknown feature flags found: %#x",
                          sup_flags & ~UBIFS_FLG_MASK);
@@ -686,7 +776,6 @@ int ubifs_read_superblock(struct ubifs_info *c)
 
        err = validate_sb(c, sup);
 out:
-       kfree(sup);
        return err;
 }
 
@@ -815,7 +904,7 @@ out:
 int ubifs_fixup_free_space(struct ubifs_info *c)
 {
        int err;
-       struct ubifs_sb_node *sup;
+       struct ubifs_sb_node *sup = c->sup_node;
 
        ubifs_assert(c, c->space_fixup);
        ubifs_assert(c, !c->ro_mount);
@@ -826,16 +915,11 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
        if (err)
                return err;
 
-       sup = ubifs_read_sb_node(c);
-       if (IS_ERR(sup))
-               return PTR_ERR(sup);
-
        /* Free-space fixup is no longer required */
        c->space_fixup = 0;
        sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
 
        err = ubifs_write_sb_node(c, sup);
-       kfree(sup);
        if (err)
                return err;
 
@@ -846,7 +930,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
 int ubifs_enable_encryption(struct ubifs_info *c)
 {
        int err;
-       struct ubifs_sb_node *sup;
+       struct ubifs_sb_node *sup = c->sup_node;
 
        if (c->encrypted)
                return 0;
@@ -859,16 +943,11 @@ int ubifs_enable_encryption(struct ubifs_info *c)
                return -EINVAL;
        }
 
-       sup = ubifs_read_sb_node(c);
-       if (IS_ERR(sup))
-               return PTR_ERR(sup);
-
        sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
 
        err = ubifs_write_sb_node(c, sup);
        if (!err)
                c->encrypted = 1;
-       kfree(sup);
 
        return err;
 }
index fec62e9..1fac113 100644 (file)
@@ -579,6 +579,9 @@ static int init_constants_early(struct ubifs_info *c)
        c->ranges[UBIFS_REF_NODE].len  = UBIFS_REF_NODE_SZ;
        c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
        c->ranges[UBIFS_CS_NODE].len   = UBIFS_CS_NODE_SZ;
+       c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ;
+       c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ +
+                               UBIFS_MAX_HMAC_LEN;
 
        c->ranges[UBIFS_INO_NODE].min_len  = UBIFS_INO_NODE_SZ;
        c->ranges[UBIFS_INO_NODE].max_len  = UBIFS_MAX_INO_NODE_SZ;
@@ -816,6 +819,9 @@ static int alloc_wbufs(struct ubifs_info *c)
                c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
                c->jheads[i].wbuf.jhead = i;
                c->jheads[i].grouped = 1;
+               c->jheads[i].log_hash = ubifs_hash_get_desc(c);
+               if (IS_ERR(c->jheads[i].log_hash))
+                       goto out;
        }
 
        /*
@@ -826,6 +832,12 @@ static int alloc_wbufs(struct ubifs_info *c)
        c->jheads[GCHD].grouped = 0;
 
        return 0;
+
+out:
+       while (i--)
+               kfree(c->jheads[i].log_hash);
+
+       return err;
 }
 
 /**
@@ -840,6 +852,7 @@ static void free_wbufs(struct ubifs_info *c)
                for (i = 0; i < c->jhead_cnt; i++) {
                        kfree(c->jheads[i].wbuf.buf);
                        kfree(c->jheads[i].wbuf.inodes);
+                       kfree(c->jheads[i].log_hash);
                }
                kfree(c->jheads);
                c->jheads = NULL;
@@ -924,6 +937,8 @@ static int check_volume_empty(struct ubifs_info *c)
  * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
  * Opt_override_compr: override default compressor
  * Opt_assert: set ubifs_assert() action
+ * Opt_auth_key: The key name used for authentication
+ * Opt_auth_hash_name: The hash type used for authentication
  * Opt_err: just end of array marker
  */
 enum {
@@ -935,6 +950,8 @@ enum {
        Opt_no_chk_data_crc,
        Opt_override_compr,
        Opt_assert,
+       Opt_auth_key,
+       Opt_auth_hash_name,
        Opt_ignore,
        Opt_err,
 };
@@ -947,6 +964,8 @@ static const match_table_t tokens = {
        {Opt_chk_data_crc, "chk_data_crc"},
        {Opt_no_chk_data_crc, "no_chk_data_crc"},
        {Opt_override_compr, "compr=%s"},
+       {Opt_auth_key, "auth_key=%s"},
+       {Opt_auth_hash_name, "auth_hash_name=%s"},
        {Opt_ignore, "ubi=%s"},
        {Opt_ignore, "vol=%s"},
        {Opt_assert, "assert=%s"},
@@ -1070,6 +1089,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                        kfree(act);
                        break;
                }
+               case Opt_auth_key:
+                       c->auth_key_name = kstrdup(args[0].from, GFP_KERNEL);
+                       if (!c->auth_key_name)
+                               return -ENOMEM;
+                       break;
+               case Opt_auth_hash_name:
+                       c->auth_hash_name = kstrdup(args[0].from, GFP_KERNEL);
+                       if (!c->auth_hash_name)
+                               return -ENOMEM;
+                       break;
                case Opt_ignore:
                        break;
                default:
@@ -1249,6 +1278,19 @@ static int mount_ubifs(struct ubifs_info *c)
 
        c->mounting = 1;
 
+       if (c->auth_key_name) {
+               if (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) {
+                       err = ubifs_init_authentication(c);
+                       if (err)
+                               goto out_free;
+               } else {
+                       ubifs_err(c, "auth_key_name, but UBIFS is built without"
+                                 " authentication support");
+                       err = -EINVAL;
+                       goto out_free;
+               }
+       }
+
        err = ubifs_read_superblock(c);
        if (err)
                goto out_free;
@@ -1367,12 +1409,21 @@ static int mount_ubifs(struct ubifs_info *c)
                }
 
                if (c->need_recovery) {
-                       err = ubifs_recover_size(c);
-                       if (err)
-                               goto out_orphans;
+                       if (!ubifs_authenticated(c)) {
+                               err = ubifs_recover_size(c, true);
+                               if (err)
+                                       goto out_orphans;
+                       }
+
                        err = ubifs_rcvry_gc_commit(c);
                        if (err)
                                goto out_orphans;
+
+                       if (ubifs_authenticated(c)) {
+                               err = ubifs_recover_size(c, false);
+                               if (err)
+                                       goto out_orphans;
+                       }
                } else {
                        err = take_gc_lnum(c);
                        if (err)
@@ -1391,7 +1442,7 @@ static int mount_ubifs(struct ubifs_info *c)
                if (err)
                        goto out_orphans;
        } else if (c->need_recovery) {
-               err = ubifs_recover_size(c);
+               err = ubifs_recover_size(c, false);
                if (err)
                        goto out_orphans;
        } else {
@@ -1557,7 +1608,10 @@ static void ubifs_umount(struct ubifs_info *c)
        free_wbufs(c);
        free_orphans(c);
        ubifs_lpt_free(c, 0);
+       ubifs_exit_authentication(c);
 
+       kfree(c->auth_key_name);
+       kfree(c->auth_hash_name);
        kfree(c->cbuf);
        kfree(c->rcvrd_mst_node);
        kfree(c->mst_node);
@@ -1605,16 +1659,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                goto out;
 
        if (c->old_leb_cnt != c->leb_cnt) {
-               struct ubifs_sb_node *sup;
+               struct ubifs_sb_node *sup = c->sup_node;
 
-               sup = ubifs_read_sb_node(c);
-               if (IS_ERR(sup)) {
-                       err = PTR_ERR(sup);
-                       goto out;
-               }
                sup->leb_cnt = cpu_to_le32(c->leb_cnt);
                err = ubifs_write_sb_node(c, sup);
-               kfree(sup);
                if (err)
                        goto out;
        }
@@ -1624,9 +1672,11 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                err = ubifs_write_rcvrd_mst_node(c);
                if (err)
                        goto out;
-               err = ubifs_recover_size(c);
-               if (err)
-                       goto out;
+               if (!ubifs_authenticated(c)) {
+                       err = ubifs_recover_size(c, true);
+                       if (err)
+                               goto out;
+               }
                err = ubifs_clean_lebs(c, c->sbuf);
                if (err)
                        goto out;
@@ -1692,10 +1742,19 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                        goto out;
        }
 
-       if (c->need_recovery)
+       if (c->need_recovery) {
                err = ubifs_rcvry_gc_commit(c);
-       else
+               if (err)
+                       goto out;
+
+               if (ubifs_authenticated(c)) {
+                       err = ubifs_recover_size(c, false);
+                       if (err)
+                               goto out;
+               }
+       } else {
                err = ubifs_leb_unmap(c, c->gc_lnum);
+       }
        if (err)
                goto out;
 
index bf416e5..25572ff 100644 (file)
@@ -35,7 +35,7 @@
 #include "ubifs.h"
 
 static int try_read_node(const struct ubifs_info *c, void *buf, int type,
-                        int len, int lnum, int offs);
+                        struct ubifs_zbranch *zbr);
 static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
                              struct ubifs_zbranch *zbr, void *node);
 
@@ -433,9 +433,7 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
  * @c: UBIFS file-system description object
  * @buf: buffer to read to
  * @type: node type
- * @len: node length (not aligned)
- * @lnum: LEB number of node to read
- * @offs: offset of node to read
+ * @zbr: the zbranch describing the node to read
  *
  * This function tries to read a node of known type and length, checks it and
  * stores it in @buf. This function returns %1 if a node is present and %0 if
@@ -453,8 +451,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
  * journal nodes may potentially be corrupted, so checking is required.
  */
 static int try_read_node(const struct ubifs_info *c, void *buf, int type,
-                        int len, int lnum, int offs)
+                        struct ubifs_zbranch *zbr)
 {
+       int len = zbr->len;
+       int lnum = zbr->lnum;
+       int offs = zbr->offs;
        int err, node_len;
        struct ubifs_ch *ch = buf;
        uint32_t crc, node_crc;
@@ -487,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
        if (crc != node_crc)
                return 0;
 
+       err = ubifs_node_check_hash(c, buf, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, buf, zbr->hash, lnum, offs);
+               return 0;
+       }
+
        return 1;
 }
 
@@ -507,8 +514,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
 
        dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
 
-       ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
-                           zbr->offs);
+       ret = try_read_node(c, node, key_type(c, key), zbr);
        if (ret == 1) {
                union ubifs_key node_key;
                struct ubifs_dent_node *dent = node;
@@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
                goto out;
        }
 
+       err = ubifs_node_check_hash(c, buf, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs);
+               return err;
+       }
+
        len = le32_to_cpu(ch->len);
        if (len != zbr->len) {
                ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
@@ -2260,13 +2272,14 @@ do_split:
  * @lnum: LEB number of node
  * @offs: node offset
  * @len: node length
+ * @hash: The hash over the node
  *
  * This function adds a node with key @key to TNC. The node may be new or it may
  * obsolete some existing one. Returns %0 on success or negative error code on
  * failure.
  */
 int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
-                 int offs, int len)
+                 int offs, int len, const u8 *hash)
 {
        int found, n, err = 0;
        struct ubifs_znode *znode;
@@ -2281,6 +2294,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
                zbr.lnum = lnum;
                zbr.offs = offs;
                zbr.len = len;
+               ubifs_copy_hash(c, hash, zbr.hash);
                key_copy(c, key, &zbr.key);
                err = tnc_insert(c, znode, &zbr, n + 1);
        } else if (found == 1) {
@@ -2291,6 +2305,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
                zbr->lnum = lnum;
                zbr->offs = offs;
                zbr->len = len;
+               ubifs_copy_hash(c, hash, zbr->hash);
        } else
                err = found;
        if (!err)
@@ -2392,13 +2407,14 @@ out_unlock:
  * @lnum: LEB number of node
  * @offs: node offset
  * @len: node length
+ * @hash: The hash over the node
  * @nm: node name
  *
  * This is the same as 'ubifs_tnc_add()' but it should be used with keys which
  * may have collisions, like directory entry keys.
  */
 int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
-                    int lnum, int offs, int len,
+                    int lnum, int offs, int len, const u8 *hash,
                     const struct fscrypt_name *nm)
 {
        int found, n, err = 0;
@@ -2441,6 +2457,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
                        zbr->lnum = lnum;
                        zbr->offs = offs;
                        zbr->len = len;
+                       ubifs_copy_hash(c, hash, zbr->hash);
                        goto out_unlock;
                }
        }
@@ -2452,6 +2469,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
                zbr.lnum = lnum;
                zbr.offs = offs;
                zbr.len = len;
+               ubifs_copy_hash(c, hash, zbr.hash);
                key_copy(c, key, &zbr.key);
                err = tnc_insert(c, znode, &zbr, n + 1);
                if (err)
index dba87d0..dbcd2c3 100644 (file)
@@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
                         struct ubifs_znode *znode, int lnum, int offs, int len)
 {
        struct ubifs_znode *zp;
+       u8 hash[UBIFS_HASH_ARR_SZ];
        int i, err;
 
        /* Make index node */
@@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
                br->lnum = cpu_to_le32(zbr->lnum);
                br->offs = cpu_to_le32(zbr->offs);
                br->len = cpu_to_le32(zbr->len);
+               ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
                if (!zbr->lnum || !zbr->len) {
                        ubifs_err(c, "bad ref in znode");
                        ubifs_dump_znode(c, znode);
@@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
                }
        }
        ubifs_prepare_node(c, idx, len, 0);
+       ubifs_node_calc_hash(c, idx, hash);
 
        znode->lnum = lnum;
        znode->offs = offs;
@@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
                zbr->lnum = lnum;
                zbr->offs = offs;
                zbr->len = len;
+               ubifs_copy_hash(c, hash, zbr->hash);
        } else {
                c->zroot.lnum = lnum;
                c->zroot.offs = offs;
                c->zroot.len = len;
+               ubifs_copy_hash(c, hash, c->zroot.hash);
        }
        c->calc_idx_sz += ALIGN(len, 8);
 
@@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c)
                        znode->cnext = c->cnext;
                        break;
                }
+               znode->cparent = znode->parent;
+               znode->ciip = znode->iip;
                znode->cnext = cnext;
                znode = cnext;
                cnt += 1;
@@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c)
        }
 
        while (1) {
+               u8 hash[UBIFS_HASH_ARR_SZ];
+
                cond_resched();
 
                znode = cnext;
@@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c)
                        br->lnum = cpu_to_le32(zbr->lnum);
                        br->offs = cpu_to_le32(zbr->offs);
                        br->len = cpu_to_le32(zbr->len);
+                       ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
                        if (!zbr->lnum || !zbr->len) {
                                ubifs_err(c, "bad ref in znode");
                                ubifs_dump_znode(c, znode);
@@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c)
                }
                len = ubifs_idx_node_sz(c, znode->child_cnt);
                ubifs_prepare_node(c, idx, len, 0);
+               ubifs_node_calc_hash(c, idx, hash);
+
+               mutex_lock(&c->tnc_mutex);
+
+               if (znode->cparent)
+                       ubifs_copy_hash(c, hash,
+                                       znode->cparent->zbranch[znode->ciip].hash);
+
+               if (znode->parent) {
+                       if (!ubifs_zn_obsolete(znode))
+                               ubifs_copy_hash(c, hash,
+                                       znode->parent->zbranch[znode->iip].hash);
+               } else {
+                       ubifs_copy_hash(c, hash, c->zroot.hash);
+               }
+
+               mutex_unlock(&c->tnc_mutex);
 
                /* Determine the index node position */
                if (lnum == -1) {
index d90ee01..d1815e9 100644 (file)
@@ -265,9 +265,7 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
 /**
  * read_znode - read an indexing node from flash and fill znode.
  * @c: UBIFS file-system description object
- * @lnum: LEB of the indexing node to read
- * @offs: node offset
- * @len: node length
+ * @zzbr: the zbranch describing the node to read
  * @znode: znode to read to
  *
  * This function reads an indexing node from the flash media and fills znode
@@ -276,9 +274,12 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
  * is wrong with it, this function prints complaint messages and returns
  * %-EINVAL.
  */
-static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
                      struct ubifs_znode *znode)
 {
+       int lnum = zzbr->lnum;
+       int offs = zzbr->offs;
+       int len = zzbr->len;
        int i, err, type, cmp;
        struct ubifs_idx_node *idx;
 
@@ -292,6 +293,12 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
                return err;
        }
 
+       err = ubifs_node_check_hash(c, idx, zzbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
+               return err;
+       }
+
        znode->child_cnt = le16_to_cpu(idx->child_cnt);
        znode->level = le16_to_cpu(idx->level);
 
@@ -308,13 +315,14 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
        }
 
        for (i = 0; i < znode->child_cnt; i++) {
-               const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+               struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
                struct ubifs_zbranch *zbr = &znode->zbranch[i];
 
                key_read(c, &br->key, &zbr->key);
                zbr->lnum = le32_to_cpu(br->lnum);
                zbr->offs = le32_to_cpu(br->offs);
                zbr->len  = le32_to_cpu(br->len);
+               ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash);
                zbr->znode = NULL;
 
                /* Validate branch */
@@ -425,7 +433,7 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
        if (!znode)
                return ERR_PTR(-ENOMEM);
 
-       err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);
+       err = read_znode(c, zbr, znode);
        if (err)
                goto out;
 
@@ -496,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                return -EINVAL;
        }
 
+       err = ubifs_node_check_hash(c, node, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, node, zbr->hash, zbr->lnum, zbr->offs);
+               return err;
+       }
+
        return 0;
 }
index e8c23c9..8b7c184 100644 (file)
@@ -286,6 +286,7 @@ enum {
 #define UBIFS_IDX_NODE_SZ  sizeof(struct ubifs_idx_node)
 #define UBIFS_CS_NODE_SZ   sizeof(struct ubifs_cs_node)
 #define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
+#define UBIFS_AUTH_NODE_SZ sizeof(struct ubifs_auth_node)
 /* Extended attribute entry nodes are identical to directory entry nodes */
 #define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
 /* Only this does not have to be multiple of 8 bytes */
@@ -300,6 +301,12 @@ enum {
 /* The largest UBIFS node */
 #define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
 
+/* The maxmimum size of a hash, enough for sha512 */
+#define UBIFS_MAX_HASH_LEN 64
+
+/* The maxmimum size of a hmac, enough for hmac(sha512) */
+#define UBIFS_MAX_HMAC_LEN 64
+
 /*
  * xattr name of UBIFS encryption context, we don't use a prefix
  * nor a long name to not waste space on the flash.
@@ -365,6 +372,7 @@ enum {
  * UBIFS_IDX_NODE: index node
  * UBIFS_CS_NODE: commit start node
  * UBIFS_ORPH_NODE: orphan node
+ * UBIFS_AUTH_NODE: authentication node
  * UBIFS_NODE_TYPES_CNT: count of supported node types
  *
  * Note, we index arrays by these numbers, so keep them low and contiguous.
@@ -384,6 +392,7 @@ enum {
        UBIFS_IDX_NODE,
        UBIFS_CS_NODE,
        UBIFS_ORPH_NODE,
+       UBIFS_AUTH_NODE,
        UBIFS_NODE_TYPES_CNT,
 };
 
@@ -421,15 +430,19 @@ enum {
  * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
  *                       support 64bit cookies for lookups by hash
  * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
+ * UBIFS_FLG_AUTHENTICATION: this filesystem contains hashes for authentication
  */
 enum {
        UBIFS_FLG_BIGLPT = 0x02,
        UBIFS_FLG_SPACE_FIXUP = 0x04,
        UBIFS_FLG_DOUBLE_HASH = 0x08,
        UBIFS_FLG_ENCRYPTION = 0x10,
+       UBIFS_FLG_AUTHENTICATION = 0x20,
 };
 
-#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
+#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT | UBIFS_FLG_SPACE_FIXUP | \
+               UBIFS_FLG_DOUBLE_HASH | UBIFS_FLG_ENCRYPTION | \
+               UBIFS_FLG_AUTHENTICATION)
 
 /**
  * struct ubifs_ch - common header node.
@@ -633,6 +646,10 @@ struct ubifs_pad_node {
  * @time_gran: time granularity in nanoseconds
  * @uuid: UUID generated when the file system image was created
  * @ro_compat_version: UBIFS R/O compatibility version
+ * @hmac: HMAC to authenticate the superblock node
+ * @hmac_wkm: HMAC of a well known message (the string "UBIFS") as a convenience
+ *            to the user to check if the correct key is passed.
+ * @hash_algo: The hash algo used for this filesystem (one of enum hash_algo)
  */
 struct ubifs_sb_node {
        struct ubifs_ch ch;
@@ -660,7 +677,10 @@ struct ubifs_sb_node {
        __le32 time_gran;
        __u8 uuid[16];
        __le32 ro_compat_version;
-       __u8 padding2[3968];
+       __u8 hmac[UBIFS_MAX_HMAC_LEN];
+       __u8 hmac_wkm[UBIFS_MAX_HMAC_LEN];
+       __le16 hash_algo;
+       __u8 padding2[3838];
 } __packed;
 
 /**
@@ -695,6 +715,9 @@ struct ubifs_sb_node {
  * @empty_lebs: number of empty logical eraseblocks
  * @idx_lebs: number of indexing logical eraseblocks
  * @leb_cnt: count of LEBs used by file-system
+ * @hash_root_idx: the hash of the root index node
+ * @hash_lpt: the hash of the LPT
+ * @hmac: HMAC to authenticate the master node
  * @padding: reserved for future, zeroes
  */
 struct ubifs_mst_node {
@@ -727,7 +750,10 @@ struct ubifs_mst_node {
        __le32 empty_lebs;
        __le32 idx_lebs;
        __le32 leb_cnt;
-       __u8 padding[344];
+       __u8 hash_root_idx[UBIFS_MAX_HASH_LEN];
+       __u8 hash_lpt[UBIFS_MAX_HASH_LEN];
+       __u8 hmac[UBIFS_MAX_HMAC_LEN];
+       __u8 padding[152];
 } __packed;
 
 /**
@@ -747,11 +773,25 @@ struct ubifs_ref_node {
 } __packed;
 
 /**
+ * struct ubifs_auth_node - node for authenticating other nodes
+ * @ch: common header
+ * @hmac: The HMAC
+ */
+struct ubifs_auth_node {
+       struct ubifs_ch ch;
+       __u8 hmac[];
+} __packed;
+
+/**
  * struct ubifs_branch - key/reference/length branch
  * @lnum: LEB number of the target node
  * @offs: offset within @lnum
  * @len: target node length
  * @key: key
+ *
+ * In an authenticated UBIFS we have the hash of the referenced node after @key.
+ * This can't be added to the struct type definition because @key is a
+ * dynamically sized element already.
  */
 struct ubifs_branch {
        __le32 lnum;
index 4368cde..38401ad 100644 (file)
@@ -39,6 +39,9 @@
 #include <linux/security.h>
 #include <linux/xattr.h>
 #include <linux/random.h>
+#include <crypto/hash_info.h>
+#include <crypto/hash.h>
+#include <crypto/algapi.h>
 
 #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION)
 #include <linux/fscrypt.h>
 /* Maximum number of data nodes to bulk-read */
 #define UBIFS_MAX_BULK_READ 32
 
+#ifdef CONFIG_UBIFS_FS_AUTHENTICATION
+#define UBIFS_HASH_ARR_SZ UBIFS_MAX_HASH_LEN
+#define UBIFS_HMAC_ARR_SZ UBIFS_MAX_HMAC_LEN
+#else
+#define UBIFS_HASH_ARR_SZ 0
+#define UBIFS_HMAC_ARR_SZ 0
+#endif
+
 /*
  * Lockdep classes for UBIFS inode @ui_mutex.
  */
@@ -706,6 +717,7 @@ struct ubifs_wbuf {
  * @jhead: journal head number this bud belongs to
  * @list: link in the list buds belonging to the same journal head
  * @rb: link in the tree of all buds
+ * @log_hash: the log hash from the commit start node up to this bud
  */
 struct ubifs_bud {
        int lnum;
@@ -713,6 +725,7 @@ struct ubifs_bud {
        int jhead;
        struct list_head list;
        struct rb_node rb;
+       struct shash_desc *log_hash;
 };
 
 /**
@@ -720,6 +733,7 @@ struct ubifs_bud {
  * @wbuf: head's write-buffer
  * @buds_list: list of bud LEBs belonging to this journal head
  * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
+ * @log_hash: the log hash from the commit start node up to this journal head
  *
  * Note, the @buds list is protected by the @c->buds_lock.
  */
@@ -727,6 +741,7 @@ struct ubifs_jhead {
        struct ubifs_wbuf wbuf;
        struct list_head buds_list;
        unsigned int grouped:1;
+       struct shash_desc *log_hash;
 };
 
 /**
@@ -736,6 +751,7 @@ struct ubifs_jhead {
  * @lnum: LEB number of the target node (indexing node or data node)
  * @offs: target node offset within @lnum
  * @len: target node length
+ * @hash: the hash of the target node
  */
 struct ubifs_zbranch {
        union ubifs_key key;
@@ -746,12 +762,15 @@ struct ubifs_zbranch {
        int lnum;
        int offs;
        int len;
+       u8 hash[UBIFS_HASH_ARR_SZ];
 };
 
 /**
  * struct ubifs_znode - in-memory representation of an indexing node.
  * @parent: parent znode or NULL if it is the root
  * @cnext: next znode to commit
+ * @cparent: parent node for this commit
+ * @ciip: index in cparent's zbranch array
  * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
  * @time: last access time (seconds)
  * @level: level of the entry in the TNC tree
@@ -769,6 +788,8 @@ struct ubifs_zbranch {
 struct ubifs_znode {
        struct ubifs_znode *parent;
        struct ubifs_znode *cnext;
+       struct ubifs_znode *cparent;
+       int ciip;
        unsigned long flags;
        time64_t time;
        int level;
@@ -983,6 +1004,7 @@ struct ubifs_debug_info;
  * struct ubifs_info - UBIFS file-system description data structure
  * (per-superblock).
  * @vfs_sb: VFS @struct super_block object
+ * @sup_node: The super block node as read from the device
  *
  * @highest_inum: highest used inode number
  * @max_sqnum: current global sequence number
@@ -1028,6 +1050,7 @@ struct ubifs_debug_info;
  * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
  * @rw_incompat: the media is not R/W compatible
  * @assert_action: action to take when a ubifs_assert() fails
+ * @authenticated: flag indigating the FS is mounted in authenticated mode
  *
  * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
  *             @calc_idx_sz
@@ -1075,6 +1098,7 @@ struct ubifs_debug_info;
  * @key_hash: direntry key hash function
  * @key_fmt: key format
  * @key_len: key length
+ * @hash_len: The length of the index node hashes
  * @fanout: fanout of the index tree (number of links per indexing node)
  *
  * @min_io_size: minimal input/output unit size
@@ -1210,6 +1234,15 @@ struct ubifs_debug_info;
  * @rp_uid: reserved pool user ID
  * @rp_gid: reserved pool group ID
  *
+ * @hash_tfm: the hash transformation used for hashing nodes
+ * @hmac_tfm: the HMAC transformation for this filesystem
+ * @hmac_desc_len: length of the HMAC used for authentication
+ * @auth_key_name: the authentication key name
+ * @auth_hash_name: the name of the hash algorithm used for authentication
+ * @auth_hash_algo: the authentication hash used for this fs
+ * @log_hash: the log hash from the commit start node up to the latest reference
+ *            node.
+ *
  * @empty: %1 if the UBI device is empty
  * @need_recovery: %1 if the file-system needs recovery
  * @replaying: %1 during journal replay
@@ -1230,6 +1263,7 @@ struct ubifs_debug_info;
  */
 struct ubifs_info {
        struct super_block *vfs_sb;
+       struct ubifs_sb_node *sup_node;
 
        ino_t highest_inum;
        unsigned long long max_sqnum;
@@ -1270,6 +1304,7 @@ struct ubifs_info {
        unsigned int default_compr:2;
        unsigned int rw_incompat:1;
        unsigned int assert_action:2;
+       unsigned int authenticated:1;
 
        struct mutex tnc_mutex;
        struct ubifs_zbranch zroot;
@@ -1314,6 +1349,7 @@ struct ubifs_info {
        uint32_t (*key_hash)(const char *str, int len);
        int key_fmt;
        int key_len;
+       int hash_len;
        int fanout;
 
        int min_io_size;
@@ -1441,6 +1477,15 @@ struct ubifs_info {
        kuid_t rp_uid;
        kgid_t rp_gid;
 
+       struct crypto_shash *hash_tfm;
+       struct crypto_shash *hmac_tfm;
+       int hmac_desc_len;
+       char *auth_key_name;
+       char *auth_hash_name;
+       enum hash_algo auth_hash_algo;
+
+       struct shash_desc *log_hash;
+
        /* The below fields are used only during mounting and re-mounting */
        unsigned int empty:1;
        unsigned int need_recovery:1;
@@ -1471,6 +1516,195 @@ extern const struct inode_operations ubifs_dir_inode_operations;
 extern const struct inode_operations ubifs_symlink_inode_operations;
 extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
 
+/* auth.c */
+static inline int ubifs_authenticated(const struct ubifs_info *c)
+{
+       return (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) && c->authenticated;
+}
+
+struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c);
+static inline struct shash_desc *ubifs_hash_get_desc(const struct ubifs_info *c)
+{
+       return ubifs_authenticated(c) ? __ubifs_hash_get_desc(c) : NULL;
+}
+
+static inline int ubifs_shash_init(const struct ubifs_info *c,
+                                  struct shash_desc *desc)
+{
+       if (ubifs_authenticated(c))
+               return crypto_shash_init(desc);
+       else
+               return 0;
+}
+
+static inline int ubifs_shash_update(const struct ubifs_info *c,
+                                     struct shash_desc *desc, const void *buf,
+                                     unsigned int len)
+{
+       int err = 0;
+
+       if (ubifs_authenticated(c)) {
+               err = crypto_shash_update(desc, buf, len);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static inline int ubifs_shash_final(const struct ubifs_info *c,
+                                   struct shash_desc *desc, u8 *out)
+{
+       return ubifs_authenticated(c) ? crypto_shash_final(desc, out) : 0;
+}
+
+int __ubifs_node_calc_hash(const struct ubifs_info *c, const void *buf,
+                         u8 *hash);
+static inline int ubifs_node_calc_hash(const struct ubifs_info *c,
+                                       const void *buf, u8 *hash)
+{
+       if (ubifs_authenticated(c))
+               return __ubifs_node_calc_hash(c, buf, hash);
+       else
+               return 0;
+}
+
+int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
+                            struct shash_desc *inhash);
+
+/**
+ * ubifs_check_hash - compare two hashes
+ * @c: UBIFS file-system description object
+ * @expected: first hash
+ * @got: second hash
+ *
+ * Compare two hashes @expected and @got. Returns 0 when they are equal, a
+ * negative error code otherwise.
+ */
+static inline int ubifs_check_hash(const struct ubifs_info *c,
+                                  const u8 *expected, const u8 *got)
+{
+       return crypto_memneq(expected, got, c->hash_len);
+}
+
+/**
+ * ubifs_check_hmac - compare two HMACs
+ * @c: UBIFS file-system description object
+ * @expected: first HMAC
+ * @got: second HMAC
+ *
+ * Compare two hashes @expected and @got. Returns 0 when they are equal, a
+ * negative error code otherwise.
+ */
+static inline int ubifs_check_hmac(const struct ubifs_info *c,
+                                  const u8 *expected, const u8 *got)
+{
+       return crypto_memneq(expected, got, c->hmac_desc_len);
+}
+
+void ubifs_bad_hash(const struct ubifs_info *c, const void *node,
+                   const u8 *hash, int lnum, int offs);
+
+int __ubifs_node_check_hash(const struct ubifs_info *c, const void *buf,
+                         const u8 *expected);
+static inline int ubifs_node_check_hash(const struct ubifs_info *c,
+                                       const void *buf, const u8 *expected)
+{
+       if (ubifs_authenticated(c))
+               return __ubifs_node_check_hash(c, buf, expected);
+       else
+               return 0;
+}
+
+int ubifs_init_authentication(struct ubifs_info *c);
+void __ubifs_exit_authentication(struct ubifs_info *c);
+static inline void ubifs_exit_authentication(struct ubifs_info *c)
+{
+       if (ubifs_authenticated(c))
+               __ubifs_exit_authentication(c);
+}
+
+/**
+ * ubifs_branch_hash - returns a pointer to the hash of a branch
+ * @c: UBIFS file-system description object
+ * @br: branch to get the hash from
+ *
+ * This returns a pointer to the hash of a branch. Since the key already is a
+ * dynamically sized object we cannot use a struct member here.
+ */
+static inline u8 *ubifs_branch_hash(struct ubifs_info *c,
+                                   struct ubifs_branch *br)
+{
+       return (void *)br + sizeof(*br) + c->key_len;
+}
+
+/**
+ * ubifs_copy_hash - copy a hash
+ * @c: UBIFS file-system description object
+ * @from: source hash
+ * @to: destination hash
+ *
+ * With authentication this copies a hash, otherwise does nothing.
+ */
+static inline void ubifs_copy_hash(const struct ubifs_info *c, const u8 *from,
+                                  u8 *to)
+{
+       if (ubifs_authenticated(c))
+               memcpy(to, from, c->hash_len);
+}
+
+int __ubifs_node_insert_hmac(const struct ubifs_info *c, void *buf,
+                             int len, int ofs_hmac);
+static inline int ubifs_node_insert_hmac(const struct ubifs_info *c, void *buf,
+                                         int len, int ofs_hmac)
+{
+       if (ubifs_authenticated(c))
+               return __ubifs_node_insert_hmac(c, buf, len, ofs_hmac);
+       else
+               return 0;
+}
+
+int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *buf,
+                            int len, int ofs_hmac);
+static inline int ubifs_node_verify_hmac(const struct ubifs_info *c,
+                                        const void *buf, int len, int ofs_hmac)
+{
+       if (ubifs_authenticated(c))
+               return __ubifs_node_verify_hmac(c, buf, len, ofs_hmac);
+       else
+               return 0;
+}
+
+/**
+ * ubifs_auth_node_sz - returns the size of an authentication node
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the size of an authentication node which can
+ * be 0 for unauthenticated filesystems or the real size of an auth node
+ * authentication is enabled.
+ */
+static inline int ubifs_auth_node_sz(const struct ubifs_info *c)
+{
+       if (ubifs_authenticated(c))
+               return sizeof(struct ubifs_auth_node) + c->hmac_desc_len;
+       else
+               return 0;
+}
+
+int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac);
+
+int __ubifs_shash_copy_state(const struct ubifs_info *c, struct shash_desc *src,
+                            struct shash_desc *target);
+static inline int ubifs_shash_copy_state(const struct ubifs_info *c,
+                                          struct shash_desc *src,
+                                          struct shash_desc *target)
+{
+       if (ubifs_authenticated(c))
+               return __ubifs_shash_copy_state(c, src, target);
+       else
+               return 0;
+}
+
 /* io.c */
 void ubifs_ro_mode(struct ubifs_info *c, int err);
 int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
@@ -1490,9 +1724,15 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
                         int lnum, int offs);
 int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
                     int offs);
+int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum,
+                         int offs, int hmac_offs);
 int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
                     int offs, int quiet, int must_chk_crc);
+void ubifs_init_node(struct ubifs_info *c, void *buf, int len, int pad);
+void ubifs_crc_node(struct ubifs_info *c, void *buf, int len);
 void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
+int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len,
+                           int hmac_offs, int pad);
 void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
 int ubifs_io_init(struct ubifs_info *c);
 void ubifs_pad(const struct ubifs_info *c, void *buf, int pad);
@@ -1592,11 +1832,12 @@ int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
                     void *node, int *lnum, int *offs);
 int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
-                 int offs, int len);
+                 int offs, int len, const u8 *hash);
 int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
                      int old_lnum, int old_offs, int lnum, int offs, int len);
 int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
-                    int lnum, int offs, int len, const struct fscrypt_name *nm);
+                    int lnum, int offs, int len, const u8 *hash,
+                    const struct fscrypt_name *nm);
 int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
 int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
                        const struct fscrypt_name *nm);
@@ -1659,12 +1900,12 @@ int ubifs_gc_should_commit(struct ubifs_info *c);
 void ubifs_wait_for_commit(struct ubifs_info *c);
 
 /* master.c */
+int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2);
 int ubifs_read_master(struct ubifs_info *c);
 int ubifs_write_master(struct ubifs_info *c);
 
 /* sb.c */
 int ubifs_read_superblock(struct ubifs_info *c);
-struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
 int ubifs_fixup_free_space(struct ubifs_info *c);
 int ubifs_enable_encryption(struct ubifs_info *c);
@@ -1693,7 +1934,7 @@ int ubifs_clear_orphans(struct ubifs_info *c);
 /* lpt.c */
 int ubifs_calc_lpt_geom(struct ubifs_info *c);
 int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
-                         int *lpt_lebs, int *big_lpt);
+                         int *lpt_lebs, int *big_lpt, u8 *hash);
 int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr);
 struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum);
 struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum);
@@ -1712,6 +1953,7 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
                                    struct ubifs_nnode *parent, int iip);
 struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
                                    struct ubifs_nnode *parent, int iip);
+struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i);
 int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
 void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
 void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
@@ -1720,6 +1962,7 @@ struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
 /* Needed only in debugging code in lpt_commit.c */
 int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
                       struct ubifs_nnode *nnode);
+int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash);
 
 /* lpt_commit.c */
 int ubifs_lpt_start_commit(struct ubifs_info *c);
@@ -1807,7 +2050,7 @@ int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
 int ubifs_rcvry_gc_commit(struct ubifs_info *c);
 int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
                             int deletion, loff_t new_size);
-int ubifs_recover_size(struct ubifs_info *c);
+int ubifs_recover_size(struct ubifs_info *c, bool in_place);
 void ubifs_destroy_size_tree(struct ubifs_info *c);
 
 /* ioctl.c */
index 6fc5425..2652d00 100644 (file)
@@ -243,7 +243,7 @@ xfs_attr3_leaf_verify(
        struct xfs_mount                *mp = bp->b_target->bt_mount;
        struct xfs_attr_leafblock       *leaf = bp->b_addr;
        struct xfs_attr_leaf_entry      *entries;
-       uint16_t                        end;
+       uint32_t                        end;    /* must be 32bit - see below */
        int                             i;
 
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
@@ -293,6 +293,11 @@ xfs_attr3_leaf_verify(
        /*
         * Quickly check the freemap information.  Attribute data has to be
         * aligned to 4-byte boundaries, and likewise for the free space.
+        *
+        * Note that for 64k block size filesystems, the freemap entries cannot
+        * overflow as they are only be16 fields. However, when checking end
+        * pointer of the freemap, we have to be careful to detect overflows and
+        * so use uint32_t for those checks.
         */
        for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
                if (ichdr.freemap[i].base > mp->m_attr_geo->blksize)
@@ -303,7 +308,9 @@ xfs_attr3_leaf_verify(
                        return __this_address;
                if (ichdr.freemap[i].size & 0x3)
                        return __this_address;
-               end = ichdr.freemap[i].base + ichdr.freemap[i].size;
+
+               /* be care of 16 bit overflows here */
+               end = (uint32_t)ichdr.freemap[i].base + ichdr.freemap[i].size;
                if (end < ichdr.freemap[i].base)
                        return __this_address;
                if (end > mp->m_attr_geo->blksize)
index 6e2c08f..6ecdbb3 100644 (file)
@@ -1608,7 +1608,7 @@ xfs_ioc_getbmap(
        error = 0;
 out_free_buf:
        kmem_free(buf);
-       return 0;
+       return error;
 }
 
 struct getfsmap_info {
index 576c375..6b736ea 100644 (file)
@@ -107,5 +107,5 @@ assfail(char *expr, char *file, int line)
 void
 xfs_hex_dump(void *p, int length)
 {
-       print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1);
+       print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1);
 }
index 89f3b03..e3667c9 100644 (file)
@@ -3,7 +3,7 @@
 #define _4LEVEL_FIXUP_H
 
 #define __ARCH_HAS_4LEVEL_HACK
-#define __PAGETABLE_PUD_FOLDED
+#define __PAGETABLE_PUD_FOLDED 1
 
 #define PUD_SHIFT                      PGDIR_SHIFT
 #define PUD_SIZE                       PGDIR_SIZE
index 9c2e070..73474bb 100644 (file)
@@ -3,7 +3,7 @@
 #define _5LEVEL_FIXUP_H
 
 #define __ARCH_HAS_5LEVEL_HACK
-#define __PAGETABLE_P4D_FOLDED
+#define __PAGETABLE_P4D_FOLDED 1
 
 #define P4D_SHIFT                      PGDIR_SHIFT
 #define P4D_SIZE                       PGDIR_SIZE
index 0c34215..1d6dd38 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef __ASSEMBLY__
 #include <asm-generic/5level-fixup.h>
 
-#define __PAGETABLE_PUD_FOLDED
+#define __PAGETABLE_PUD_FOLDED 1
 
 /*
  * Having the pud type consist of a pgd gets the size right, and allows
index 1a29b2a..04cb913 100644 (file)
@@ -4,7 +4,7 @@
 
 #ifndef __ASSEMBLY__
 
-#define __PAGETABLE_P4D_FOLDED
+#define __PAGETABLE_P4D_FOLDED 1
 
 typedef struct { pgd_t pgd; } p4d_t;
 
index f35f6e8..b85b827 100644 (file)
@@ -8,7 +8,7 @@
 
 struct mm_struct;
 
-#define __PAGETABLE_PMD_FOLDED
+#define __PAGETABLE_PMD_FOLDED 1
 
 /*
  * Having the pmd type consist of a pud gets the size right, and allows
index e950b9c..9bef475 100644 (file)
@@ -9,7 +9,7 @@
 #else
 #include <asm-generic/pgtable-nop4d.h>
 
-#define __PAGETABLE_PUD_FOLDED
+#define __PAGETABLE_PUD_FOLDED 1
 
 /*
  * Having the pud type consist of a p4d gets the size right, and allows
index 5657a20..359fb93 100644 (file)
@@ -1127,4 +1127,20 @@ static inline bool arch_has_pfn_modify_check(void)
 #endif
 #endif
 
+/*
+ * On some architectures it depends on the mm if the p4d/pud or pmd
+ * layer of the page table hierarchy is folded or not.
+ */
+#ifndef mm_p4d_folded
+#define mm_p4d_folded(mm)      __is_defined(__PAGETABLE_P4D_FOLDED)
+#endif
+
+#ifndef mm_pud_folded
+#define mm_pud_folded(mm)      __is_defined(__PAGETABLE_PUD_FOLDED)
+#endif
+
+#ifndef mm_pmd_folded
+#define mm_pmd_folded(mm)      __is_defined(__PAGETABLE_PMD_FOLDED)
+#endif
+
 #endif /* _ASM_GENERIC_PGTABLE_H */
index 6b92b33..65a38c4 100644 (file)
@@ -213,12 +213,6 @@ DEFINE_CEPH_FEATURE_DEPRECATED(63, 1, RESERVED_BROKEN, LUMINOUS) // client-facin
         CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING | \
         CEPH_FEATURE_CEPHX_V2)
 
-#define CEPH_FEATURES_REQUIRED_DEFAULT   \
-       (CEPH_FEATURE_NOSRCADDR |        \
-        CEPH_FEATURE_SUBSCRIBE2 |       \
-        CEPH_FEATURE_RECONNECT_SEQ |    \
-        CEPH_FEATURE_PGID64 |           \
-        CEPH_FEATURE_PGPOOL3 |          \
-        CEPH_FEATURE_OSDENC)
+#define CEPH_FEATURES_REQUIRED_DEFAULT 0
 
 #endif
index c0f5db3..2010493 100644 (file)
 #define KASAN_ABI_VERSION 3
 #endif
 
-/*
- * Because __no_sanitize_address conflicts with inlining:
- *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
- * we do one or the other. 
- */
-#ifdef CONFIG_KASAN
-#define __no_sanitize_address_or_inline                                        \
-       __no_sanitize_address __maybe_unused notrace
-#else
-#define __no_sanitize_address_or_inline inline
-#endif
-
 #if GCC_VERSION >= 50100
 #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
 #endif
index 18c80cf..06396c1 100644 (file)
@@ -189,7 +189,7 @@ void __read_once_size(const volatile void *p, void *res, int size)
  *     https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
  * '__maybe_unused' allows us to avoid defined-but-not-used warnings.
  */
-# define __no_kasan_or_inline __no_sanitize_address __maybe_unused
+# define __no_kasan_or_inline __no_sanitize_address notrace __maybe_unused
 #else
 # define __no_kasan_or_inline __always_inline
 #endif
index 6b28c1b..f8c400b 100644 (file)
@@ -4,22 +4,26 @@
 
 /*
  * The attributes in this file are unconditionally defined and they directly
- * map to compiler attribute(s) -- except those that are optional.
+ * map to compiler attribute(s), unless one of the compilers does not support
+ * the attribute. In that case, __has_attribute is used to check for support
+ * and the reason is stated in its comment ("Optional: ...").
  *
  * Any other "attributes" (i.e. those that depend on a configuration option,
  * on a compiler, on an architecture, on plugins, on other attributes...)
  * should be defined elsewhere (e.g. compiler_types.h or compiler-*.h).
+ * The intention is to keep this file as simple as possible, as well as
+ * compiler- and version-agnostic (e.g. avoiding GCC_VERSION checks).
  *
  * This file is meant to be sorted (by actual attribute name,
  * not by #define identifier). Use the __attribute__((__name__)) syntax
  * (i.e. with underscores) to avoid future collisions with other macros.
- * If an attribute is optional, state the reason in the comment.
+ * Provide links to the documentation of each supported compiler, if it exists.
  */
 
 /*
- * To check for optional attributes, we use __has_attribute, which is supported
- * on gcc >= 5, clang >= 2.9 and icc >= 17. In the meantime, to support
- * 4.6 <= gcc < 5, we implement __has_attribute by hand.
+ * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
+ * In the meantime, to support 4.6 <= gcc < 5, we implement __has_attribute
+ * by hand.
  *
  * sparse does not support __has_attribute (yet) and defines __GNUC_MINOR__
  * depending on the compiler used to build it; however, these attributes have
index 3439d7d..4a3f9c0 100644 (file)
@@ -130,6 +130,10 @@ struct ftrace_likely_data {
 # define randomized_struct_fields_end
 #endif
 
+#ifndef asm_volatile_goto
+#define asm_volatile_goto(x...) asm goto(x)
+#endif
+
 /* Are two types/vars the same type (ignoring qualifiers)? */
 #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
 
index caf40ad..e0cd2ba 100644 (file)
@@ -126,6 +126,7 @@ enum cpuhp_state {
        CPUHP_AP_MIPS_GIC_TIMER_STARTING,
        CPUHP_AP_ARC_TIMER_STARTING,
        CPUHP_AP_RISCV_TIMER_STARTING,
+       CPUHP_AP_CSKY_TIMER_STARTING,
        CPUHP_AP_KVM_STARTING,
        CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
        CPUHP_AP_KVM_ARM_VGIC_STARTING,
index 2827b87..387c70d 100644 (file)
@@ -722,8 +722,8 @@ struct hid_usage_id {
  * input will not be passed to raw_event unless hid_device_io_start is
  * called.
  *
- * raw_event and event should return 0 on no action performed, 1 when no
- * further processing should be done and negative on error
+ * raw_event and event should return negative on error, any other value will
+ * pass the event on to .event() typically return 0 for success.
  *
  * input_mapping shall return a negative value to completely ignore this usage
  * (e.g. doubled or invalid usage), zero to continue with parsing of this
index fcf9cc9..5411de9 100644 (file)
@@ -1744,11 +1744,15 @@ int __pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address);
 
 static inline void mm_inc_nr_puds(struct mm_struct *mm)
 {
+       if (mm_pud_folded(mm))
+               return;
        atomic_long_add(PTRS_PER_PUD * sizeof(pud_t), &mm->pgtables_bytes);
 }
 
 static inline void mm_dec_nr_puds(struct mm_struct *mm)
 {
+       if (mm_pud_folded(mm))
+               return;
        atomic_long_sub(PTRS_PER_PUD * sizeof(pud_t), &mm->pgtables_bytes);
 }
 #endif
@@ -1768,11 +1772,15 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address);
 
 static inline void mm_inc_nr_pmds(struct mm_struct *mm)
 {
+       if (mm_pmd_folded(mm))
+               return;
        atomic_long_add(PTRS_PER_PMD * sizeof(pmd_t), &mm->pgtables_bytes);
 }
 
 static inline void mm_dec_nr_pmds(struct mm_struct *mm)
 {
+       if (mm_pmd_folded(mm))
+               return;
        atomic_long_sub(PTRS_PER_PMD * sizeof(pmd_t), &mm->pgtables_bytes);
 }
 #endif
index abe975c..7f53ece 100644 (file)
@@ -324,9 +324,8 @@ static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
  */
 static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand)
 {
-       return (u64)nand->memorg.luns_per_target *
-              nand->memorg.eraseblocks_per_lun *
-              nand->memorg.pages_per_eraseblock;
+       return nand->memorg.ntargets * nand->memorg.luns_per_target *
+              nand->memorg.eraseblocks_per_lun;
 }
 
 /**
@@ -569,7 +568,7 @@ static inline void nanddev_pos_next_eraseblock(struct nand_device *nand,
 }
 
 /**
- * nanddev_pos_next_eraseblock() - Move a position to the next page
+ * nanddev_pos_next_page() - Move a position to the next page
  * @nand: NAND device
  * @pos: the position to update
  *
index dc1d9ed..857f8ab 100644 (file)
@@ -3190,6 +3190,26 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
 #endif
 }
 
+/* Variant of netdev_tx_sent_queue() for drivers that are aware
+ * that they should not test BQL status themselves.
+ * We do want to change __QUEUE_STATE_STACK_XOFF only for the last
+ * skb of a batch.
+ * Returns true if the doorbell must be used to kick the NIC.
+ */
+static inline bool __netdev_tx_sent_queue(struct netdev_queue *dev_queue,
+                                         unsigned int bytes,
+                                         bool xmit_more)
+{
+       if (xmit_more) {
+#ifdef CONFIG_BQL
+               dql_queued(&dev_queue->dql, bytes);
+#endif
+               return netif_tx_queue_stopped(dev_queue);
+       }
+       netdev_tx_sent_queue(dev_queue, bytes);
+       return true;
+}
+
 /**
  *     netdev_sent_queue - report the number of bytes queued to hardware
  *     @dev: network device
index 34fc80f..1d100ef 100644 (file)
@@ -314,7 +314,7 @@ enum {
 extern ip_set_id_t ip_set_get_byname(struct net *net,
                                     const char *name, struct ip_set **set);
 extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
-extern const char *ip_set_name_byindex(struct net *net, ip_set_id_t index);
+extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
 extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
 extern void ip_set_nfnl_put(struct net *net, ip_set_id_t index);
 
index 8e2bab1..70877f8 100644 (file)
@@ -43,11 +43,11 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
        rcu_assign_pointer(comment->c, c);
 }
 
-/* Used only when dumping a set, protected by rcu_read_lock_bh() */
+/* Used only when dumping a set, protected by rcu_read_lock() */
 static inline int
 ip_set_put_comment(struct sk_buff *skb, const struct ip_set_comment *comment)
 {
-       struct ip_set_comment_rcu *c = rcu_dereference_bh(comment->c);
+       struct ip_set_comment_rcu *c = rcu_dereference(comment->c);
 
        if (!c)
                return 0;
index 08f9247..9003e29 100644 (file)
@@ -119,6 +119,8 @@ static inline int hardlockup_detector_perf_init(void) { return 0; }
 void watchdog_nmi_stop(void);
 void watchdog_nmi_start(void);
 int watchdog_nmi_probe(void);
+int watchdog_nmi_enable(unsigned int cpu);
+void watchdog_nmi_disable(unsigned int cpu);
 
 /**
  * touch_nmi_watchdog - restart NMI watchdog timeout.
index 131424c..02c0412 100644 (file)
@@ -107,8 +107,8 @@ struct krb5_ctx {
        u8                      Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */
        u8                      cksum[GSS_KRB5_MAX_KEYLEN];
        s32                     endtime;
-       u32                     seq_send;
-       u64                     seq_send64;
+       atomic_t                seq_send;
+       atomic64_t              seq_send64;
        struct xdr_netobj       mech_used;
        u8                      initiator_sign[GSS_KRB5_MAX_KEYLEN];
        u8                      acceptor_sign[GSS_KRB5_MAX_KEYLEN];
@@ -118,9 +118,6 @@ struct krb5_ctx {
        u8                      acceptor_integ[GSS_KRB5_MAX_KEYLEN];
 };
 
-extern u32 gss_seq_send_fetch_and_inc(struct krb5_ctx *ctx);
-extern u64 gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx);
-
 /* The length of the Kerberos GSS token header */
 #define GSS_KRB5_TOK_HDR_LEN   (16)
 
index 14b789a..1656c59 100644 (file)
@@ -317,6 +317,8 @@ bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
                         const struct in6_addr *addr);
 bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev,
                             const struct in6_addr *addr);
+int ipv6_anycast_init(void);
+void ipv6_anycast_cleanup(void);
 
 /* Device notifier */
 int register_inet6addr_notifier(struct notifier_block *nb);
index d7578cf..c9c78c1 100644 (file)
@@ -146,10 +146,12 @@ struct ifacaddr6 {
        struct in6_addr         aca_addr;
        struct fib6_info        *aca_rt;
        struct ifacaddr6        *aca_next;
+       struct hlist_node       aca_addr_lst;
        int                     aca_users;
        refcount_t              aca_refcnt;
        unsigned long           aca_cstamp;
        unsigned long           aca_tstamp;
+       struct rcu_head         rcu;
 };
 
 #define        IFA_HOST        IPV6_ADDR_LOOPBACK
index eed04af..ae7b86f 100644 (file)
@@ -153,4 +153,43 @@ void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
                               const char *fmt, ...) { }
 #endif /* CONFIG_SYSCTL */
 
+static inline struct nf_generic_net *nf_generic_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.generic;
+}
+
+static inline struct nf_tcp_net *nf_tcp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.tcp;
+}
+
+static inline struct nf_udp_net *nf_udp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.udp;
+}
+
+static inline struct nf_icmp_net *nf_icmp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.icmp;
+}
+
+static inline struct nf_icmp_net *nf_icmpv6_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.icmpv6;
+}
+
+#ifdef CONFIG_NF_CT_PROTO_DCCP
+static inline struct nf_dccp_net *nf_dccp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.dccp;
+}
+#endif
+
+#ifdef CONFIG_NF_CT_PROTO_SCTP
+static inline struct nf_sctp_net *nf_sctp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.sctp;
+}
+#endif
+
 #endif /*_NF_CONNTRACK_PROTOCOL_H*/
index f5ff8a7..b01eb50 100644 (file)
@@ -83,11 +83,11 @@ struct kfd_ioctl_set_cu_mask_args {
 };
 
 struct kfd_ioctl_get_queue_wave_state_args {
-       uint64_t ctl_stack_address;     /* to KFD */
-       uint32_t ctl_stack_used_size;   /* from KFD */
-       uint32_t save_area_used_size;   /* from KFD */
-       uint32_t queue_id;              /* to KFD */
-       uint32_t pad;
+       __u64 ctl_stack_address;        /* to KFD */
+       __u32 ctl_stack_used_size;      /* from KFD */
+       __u32 save_area_used_size;      /* from KFD */
+       __u32 queue_id;                 /* to KFD */
+       __u32 pad;
 };
 
 /* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */
@@ -255,10 +255,10 @@ struct kfd_hsa_memory_exception_data {
 
 /* hw exception data */
 struct kfd_hsa_hw_exception_data {
-       uint32_t reset_type;
-       uint32_t reset_cause;
-       uint32_t memory_lost;
-       uint32_t gpu_id;
+       __u32 reset_type;
+       __u32 reset_cause;
+       __u32 memory_lost;
+       __u32 gpu_id;
 };
 
 /* Event data */
index 579974b..7de4f1b 100644 (file)
@@ -1635,8 +1635,8 @@ enum nft_ng_attributes {
        NFTA_NG_MODULUS,
        NFTA_NG_TYPE,
        NFTA_NG_OFFSET,
-       NFTA_NG_SET_NAME,
-       NFTA_NG_SET_ID,
+       NFTA_NG_SET_NAME,       /* deprecated */
+       NFTA_NG_SET_ID,         /* deprecated */
        __NFTA_NG_MAX
 };
 #define NFTA_NG_MAX    (__NFTA_NG_MAX - 1)
index 156ccd0..1610fdb 100644 (file)
 #include <linux/if_vlan.h>
 #include <linux/if_pppox.h>
 
+#ifndef __KERNEL__
+#include <limits.h> /* for INT_MIN, INT_MAX */
+#endif
+
 /* Bridge Hooks */
 /* After promisc drops, checksum checks. */
 #define NF_BR_PRE_ROUTING      0
index 34dd3d4..c81feb3 100644 (file)
@@ -568,6 +568,8 @@ struct sctp_assoc_reset_event {
 
 #define SCTP_ASSOC_CHANGE_DENIED       0x0004
 #define SCTP_ASSOC_CHANGE_FAILED       0x0008
+#define SCTP_STREAM_CHANGE_DENIED      SCTP_ASSOC_CHANGE_DENIED
+#define SCTP_STREAM_CHANGE_FAILED      SCTP_ASSOC_CHANGE_FAILED
 struct sctp_stream_change_event {
        __u16 strchange_type;
        __u16 strchange_flags;
@@ -1151,6 +1153,7 @@ struct sctp_add_streams {
 /* SCTP Stream schedulers */
 enum sctp_sched_type {
        SCTP_SS_FCFS,
+       SCTP_SS_DEFAULT = SCTP_SS_FCFS,
        SCTP_SS_PRIO,
        SCTP_SS_RR,
        SCTP_SS_MAX = SCTP_SS_RR
index 18803ff..4969817 100644 (file)
@@ -42,16 +42,12 @@ int xen_setup_shutdown_event(void);
 
 extern unsigned long *xen_contiguous_bitmap;
 
-#ifdef CONFIG_XEN_PV
+#if defined(CONFIG_XEN_PV) || defined(CONFIG_ARM) || defined(CONFIG_ARM64)
 int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
                                unsigned int address_bits,
                                dma_addr_t *dma_handle);
 
 void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order);
-
-int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
-                 xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
-                 unsigned int domid, bool no_translate, struct page **pages);
 #else
 static inline int xen_create_contiguous_region(phys_addr_t pstart,
                                               unsigned int order,
@@ -63,7 +59,13 @@ static inline int xen_create_contiguous_region(phys_addr_t pstart,
 
 static inline void xen_destroy_contiguous_region(phys_addr_t pstart,
                                                 unsigned int order) { }
+#endif
 
+#if defined(CONFIG_XEN_PV)
+int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
+                 xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
+                 unsigned int domid, bool no_translate, struct page **pages);
+#else
 static inline int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
                                xen_pfn_t *pfn, int nr, int *err_ptr,
                                pgprot_t prot,  unsigned int domid,
index 6377225..1a796e0 100644 (file)
@@ -553,7 +553,6 @@ bool is_bpf_text_address(unsigned long addr)
 int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                    char *sym)
 {
-       unsigned long symbol_start, symbol_end;
        struct bpf_prog_aux *aux;
        unsigned int it = 0;
        int ret = -ERANGE;
@@ -566,10 +565,9 @@ int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                if (it++ != symnum)
                        continue;
 
-               bpf_get_prog_addr_region(aux->prog, &symbol_start, &symbol_end);
                bpf_get_prog_name(aux->prog, sym);
 
-               *value = symbol_start;
+               *value = (unsigned long)aux->prog->bpf_func;
                *type  = BPF_SYM_ELF_TYPE;
 
                ret = 0;
index ccb9327..cf5040f 100644 (file)
@@ -2078,6 +2078,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                info.jited_prog_len = 0;
                info.xlated_prog_len = 0;
                info.nr_jited_ksyms = 0;
+               info.nr_jited_func_lens = 0;
                goto done;
        }
 
@@ -2158,11 +2159,11 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
        }
 
        ulen = info.nr_jited_ksyms;
-       info.nr_jited_ksyms = prog->aux->func_cnt;
+       info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
        if (info.nr_jited_ksyms && ulen) {
                if (bpf_dump_raw_ok()) {
+                       unsigned long ksym_addr;
                        u64 __user *user_ksyms;
-                       ulong ksym_addr;
                        u32 i;
 
                        /* copy the address of the kernel symbol
@@ -2170,10 +2171,17 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                         */
                        ulen = min_t(u32, info.nr_jited_ksyms, ulen);
                        user_ksyms = u64_to_user_ptr(info.jited_ksyms);
-                       for (i = 0; i < ulen; i++) {
-                               ksym_addr = (ulong) prog->aux->func[i]->bpf_func;
-                               ksym_addr &= PAGE_MASK;
-                               if (put_user((u64) ksym_addr, &user_ksyms[i]))
+                       if (prog->aux->func_cnt) {
+                               for (i = 0; i < ulen; i++) {
+                                       ksym_addr = (unsigned long)
+                                               prog->aux->func[i]->bpf_func;
+                                       if (put_user((u64) ksym_addr,
+                                                    &user_ksyms[i]))
+                                               return -EFAULT;
+                               }
+                       } else {
+                               ksym_addr = (unsigned long) prog->bpf_func;
+                               if (put_user((u64) ksym_addr, &user_ksyms[0]))
                                        return -EFAULT;
                        }
                } else {
@@ -2182,7 +2190,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
        }
 
        ulen = info.nr_jited_func_lens;
-       info.nr_jited_func_lens = prog->aux->func_cnt;
+       info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
        if (info.nr_jited_func_lens && ulen) {
                if (bpf_dump_raw_ok()) {
                        u32 __user *user_lens;
@@ -2191,9 +2199,16 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                        /* copy the JITed image lengths for each function */
                        ulen = min_t(u32, info.nr_jited_func_lens, ulen);
                        user_lens = u64_to_user_ptr(info.jited_func_lens);
-                       for (i = 0; i < ulen; i++) {
-                               func_len = prog->aux->func[i]->jited_len;
-                               if (put_user(func_len, &user_lens[i]))
+                       if (prog->aux->func_cnt) {
+                               for (i = 0; i < ulen; i++) {
+                                       func_len =
+                                               prog->aux->func[i]->jited_len;
+                                       if (put_user(func_len, &user_lens[i]))
+                                               return -EFAULT;
+                               }
+                       } else {
+                               func_len = prog->jited_len;
+                               if (put_user(func_len, &user_lens[0]))
                                        return -EFAULT;
                        }
                } else {
index b3a3a1f..b0fbf68 100644 (file)
@@ -319,16 +319,23 @@ int release_resource(struct resource *old)
 EXPORT_SYMBOL(release_resource);
 
 /**
- * Finds the lowest iomem resource that covers part of [start..end].  The
- * caller must specify start, end, flags, and desc (which may be
+ * Finds the lowest iomem resource that covers part of [@start..@end].  The
+ * caller must specify @start, @end, @flags, and @desc (which may be
  * IORES_DESC_NONE).
  *
- * If a resource is found, returns 0 and *res is overwritten with the part
- * of the resource that's within [start..end]; if none is found, returns
- * -1.
+ * If a resource is found, returns 0 and @*res is overwritten with the part
+ * of the resource that's within [@start..@end]; if none is found, returns
+ * -1 or -EINVAL for other invalid parameters.
  *
  * This function walks the whole tree and not just first level children
  * unless @first_lvl is true.
+ *
+ * @start:     start address of the resource searched for
+ * @end:       end address of same resource
+ * @flags:     flags which the resource must have
+ * @desc:      descriptor the resource must have
+ * @first_lvl: walk only the first level children, if set
+ * @res:       return ptr, if resource found
  */
 static int find_next_iomem_res(resource_size_t start, resource_size_t end,
                               unsigned long flags, unsigned long desc,
@@ -399,6 +406,8 @@ static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end,
  * @flags: I/O resource flags
  * @start: start addr
  * @end: end addr
+ * @arg: function argument for the callback @func
+ * @func: callback function that is called for each qualifying resource area
  *
  * NOTE: For a new descriptor search, define a new IORES_DESC in
  * <linux/ioport.h> and set it in 'desc' of a target resource entry.
index f12225f..091e089 100644 (file)
@@ -5851,11 +5851,14 @@ void __init sched_init_smp(void)
        /*
         * There's no userspace yet to cause hotplug operations; hence all the
         * CPU masks are stable and all blatant races in the below code cannot
-        * happen.
+        * happen. The hotplug lock is nevertheless taken to satisfy lockdep,
+        * but there won't be any contention on it.
         */
+       cpus_read_lock();
        mutex_lock(&sched_domains_mutex);
        sched_init_domains(cpu_active_mask);
        mutex_unlock(&sched_domains_mutex);
+       cpus_read_unlock();
 
        /* Move init over to a non-isolated CPU */
        if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0)
index ee271bb..3648d03 100644 (file)
@@ -2400,8 +2400,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
                local = 1;
 
        /*
-        * Retry task to preferred node migration periodically, in case it
-        * case it previously failed, or the scheduler moved us.
+        * Retry to migrate task to preferred node periodically, in case it
+        * previously failed, or the scheduler moved us.
         */
        if (time_after(jiffies, p->numa_migrate_retry)) {
                task_numa_placement(p);
index ce32cf7..8f0644a 100644 (file)
@@ -917,9 +917,6 @@ static void check_process_timers(struct task_struct *tsk,
        struct task_cputime cputime;
        unsigned long soft;
 
-       if (dl_task(tsk))
-               check_dl_overrun(tsk);
-
        /*
         * If cputimer is not running, then there are no active
         * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU).
index 3ef15a6..bd30e93 100644 (file)
@@ -535,7 +535,7 @@ int traceprobe_update_arg(struct probe_arg *arg)
                        if (code[1].op != FETCH_OP_IMM)
                                return -EINVAL;
 
-                       tmp = strpbrk("+-", code->data);
+                       tmp = strpbrk(code->data, "+-");
                        if (tmp)
                                c = *tmp;
                        ret = traceprobe_split_symbol_offset(code->data,
index e5222b5..923414a 100644 (file)
@@ -974,10 +974,6 @@ static ssize_t map_write(struct file *file, const char __user *buf,
        if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
                goto out;
 
-       ret = sort_idmaps(&new_map);
-       if (ret < 0)
-               goto out;
-
        ret = -EPERM;
        /* Map the lower ids from the parent user namespace to the
         * kernel global id space.
@@ -1004,6 +1000,14 @@ static ssize_t map_write(struct file *file, const char __user *buf,
                e->lower_first = lower_first;
        }
 
+       /*
+        * If we want to use binary search for lookup, this clones the extent
+        * array and sorts both copies.
+        */
+       ret = sort_idmaps(&new_map);
+       if (ret < 0)
+               goto out;
+
        /* Install the map */
        if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) {
                memcpy(map->extent, new_map.extent,
index 5d73f5c..7977764 100644 (file)
@@ -27,7 +27,7 @@ ifeq ($(ARCH),arm)
         CFLAGS += -I../../../arch/arm/include -mfpu=neon
         HAS_NEON = yes
 endif
-ifeq ($(ARCH),arm64)
+ifeq ($(ARCH),aarch64)
         CFLAGS += -I../../../arch/arm64/include
         HAS_NEON = yes
 endif
@@ -41,7 +41,7 @@ ifeq ($(IS_X86),yes)
                    gcc -c -x assembler - >&/dev/null &&        \
                    rm ./-.o && echo -DCONFIG_AS_AVX512=1)
 else ifeq ($(HAS_NEON),yes)
-        OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o
+        OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o
         CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
 else
         HAS_ALTIVEC := $(shell printf '\#include <altivec.h>\nvector int a;\n' |\
index 77d43ae..0ffcbdd 100644 (file)
@@ -3272,7 +3272,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *de
                }
 
                skb = next;
-               if (netif_xmit_stopped(txq) && skb) {
+               if (netif_tx_queue_stopped(txq) && skb) {
                        rc = NETDEV_TX_BUSY;
                        break;
                }
index 5da9552..2b9fdbc 100644 (file)
@@ -717,7 +717,8 @@ int netpoll_setup(struct netpoll *np)
 
                                read_lock_bh(&idev->lock);
                                list_for_each_entry(ifp, &idev->addr_list, if_list) {
-                                       if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
+                                       if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
+                                           !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
                                                continue;
                                        np->local_ip.in6 = ifp->addr;
                                        err = 0;
index e01274b..33d9227 100644 (file)
@@ -3367,7 +3367,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
                        cb->seq = 0;
                }
                ret = dumpit(skb, cb);
-               if (ret < 0)
+               if (ret)
                        break;
        }
        cb->family = idx;
index 946de0e..b4ee5c8 100644 (file)
@@ -4944,6 +4944,8 @@ static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
  *
  * This is a helper to do that correctly considering GSO_BY_FRAGS.
  *
+ * @skb: GSO skb
+ *
  * @seg_len: The segmented length (from skb_gso_*_seglen). In the
  *           GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
  *
index 6fcc4bc..080a880 100644 (file)
@@ -3279,6 +3279,7 @@ int sock_load_diag_module(int family, int protocol)
 
 #ifdef CONFIG_INET
        if (family == AF_INET &&
+           protocol != IPPROTO_RAW &&
            !rcu_access_pointer(inet_protos[protocol]))
                return -ENOENT;
 #endif
index 9b0158f..d6ee343 100644 (file)
@@ -722,10 +722,14 @@ struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user)
        if (ip_is_fragment(&iph)) {
                skb = skb_share_check(skb, GFP_ATOMIC);
                if (skb) {
-                       if (!pskb_may_pull(skb, netoff + iph.ihl * 4))
-                               return skb;
-                       if (pskb_trim_rcsum(skb, netoff + len))
-                               return skb;
+                       if (!pskb_may_pull(skb, netoff + iph.ihl * 4)) {
+                               kfree_skb(skb);
+                               return NULL;
+                       }
+                       if (pskb_trim_rcsum(skb, netoff + len)) {
+                               kfree_skb(skb);
+                               return NULL;
+                       }
                        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
                        if (ip_defrag(net, skb, user))
                                return NULL;
index 26c36cc..fffcc13 100644 (file)
@@ -1246,7 +1246,7 @@ int ip_setsockopt(struct sock *sk, int level,
                return -ENOPROTOOPT;
 
        err = do_ip_setsockopt(sk, level, optname, optval, optlen);
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
        if (optname >= BPFILTER_IPT_SO_SET_REPLACE &&
            optname < BPFILTER_IPT_SET_MAX)
                err = bpfilter_ip_set_sockopt(sk, optname, optval, optlen);
@@ -1559,7 +1559,7 @@ int ip_getsockopt(struct sock *sk, int level,
        int err;
 
        err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
        if (optname >= BPFILTER_IPT_SO_GET_INFO &&
            optname < BPFILTER_IPT_GET_MAX)
                err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
@@ -1596,7 +1596,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
        err = do_ip_getsockopt(sk, level, optname, optval, optlen,
                MSG_CMSG_COMPAT);
 
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
        if (optname >= BPFILTER_IPT_SO_GET_INFO &&
            optname < BPFILTER_IPT_GET_MAX)
                err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
index 3f4d610..f0cd291 100644 (file)
@@ -1001,6 +1001,9 @@ static int __init inet6_init(void)
        err = ip6_flowlabel_init();
        if (err)
                goto ip6_flowlabel_fail;
+       err = ipv6_anycast_init();
+       if (err)
+               goto ipv6_anycast_fail;
        err = addrconf_init();
        if (err)
                goto addrconf_fail;
@@ -1091,6 +1094,8 @@ ipv6_frag_fail:
 ipv6_exthdrs_fail:
        addrconf_cleanup();
 addrconf_fail:
+       ipv6_anycast_cleanup();
+ipv6_anycast_fail:
        ip6_flowlabel_cleanup();
 ip6_flowlabel_fail:
        ndisc_late_cleanup();
index 4e0ff70..9499905 100644 (file)
 
 #include <net/checksum.h>
 
+#define IN6_ADDR_HSIZE_SHIFT   8
+#define IN6_ADDR_HSIZE         BIT(IN6_ADDR_HSIZE_SHIFT)
+/*     anycast address hash table
+ */
+static struct hlist_head inet6_acaddr_lst[IN6_ADDR_HSIZE];
+static DEFINE_SPINLOCK(acaddr_hash_lock);
+
 static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr);
 
+static u32 inet6_acaddr_hash(struct net *net, const struct in6_addr *addr)
+{
+       u32 val = ipv6_addr_hash(addr) ^ net_hash_mix(net);
+
+       return hash_32(val, IN6_ADDR_HSIZE_SHIFT);
+}
+
 /*
  *     socket join an anycast group
  */
@@ -204,16 +218,39 @@ void ipv6_sock_ac_close(struct sock *sk)
        rtnl_unlock();
 }
 
+static void ipv6_add_acaddr_hash(struct net *net, struct ifacaddr6 *aca)
+{
+       unsigned int hash = inet6_acaddr_hash(net, &aca->aca_addr);
+
+       spin_lock(&acaddr_hash_lock);
+       hlist_add_head_rcu(&aca->aca_addr_lst, &inet6_acaddr_lst[hash]);
+       spin_unlock(&acaddr_hash_lock);
+}
+
+static void ipv6_del_acaddr_hash(struct ifacaddr6 *aca)
+{
+       spin_lock(&acaddr_hash_lock);
+       hlist_del_init_rcu(&aca->aca_addr_lst);
+       spin_unlock(&acaddr_hash_lock);
+}
+
 static void aca_get(struct ifacaddr6 *aca)
 {
        refcount_inc(&aca->aca_refcnt);
 }
 
+static void aca_free_rcu(struct rcu_head *h)
+{
+       struct ifacaddr6 *aca = container_of(h, struct ifacaddr6, rcu);
+
+       fib6_info_release(aca->aca_rt);
+       kfree(aca);
+}
+
 static void aca_put(struct ifacaddr6 *ac)
 {
        if (refcount_dec_and_test(&ac->aca_refcnt)) {
-               fib6_info_release(ac->aca_rt);
-               kfree(ac);
+               call_rcu(&ac->rcu, aca_free_rcu);
        }
 }
 
@@ -229,6 +266,7 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *f6i,
        aca->aca_addr = *addr;
        fib6_info_hold(f6i);
        aca->aca_rt = f6i;
+       INIT_HLIST_NODE(&aca->aca_addr_lst);
        aca->aca_users = 1;
        /* aca_tstamp should be updated upon changes */
        aca->aca_cstamp = aca->aca_tstamp = jiffies;
@@ -285,6 +323,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
        aca_get(aca);
        write_unlock_bh(&idev->lock);
 
+       ipv6_add_acaddr_hash(net, aca);
+
        ip6_ins_rt(net, f6i);
 
        addrconf_join_solict(idev->dev, &aca->aca_addr);
@@ -325,6 +365,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
        else
                idev->ac_list = aca->aca_next;
        write_unlock_bh(&idev->lock);
+       ipv6_del_acaddr_hash(aca);
        addrconf_leave_solict(idev, &aca->aca_addr);
 
        ip6_del_rt(dev_net(idev->dev), aca->aca_rt);
@@ -352,6 +393,8 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev)
                idev->ac_list = aca->aca_next;
                write_unlock_bh(&idev->lock);
 
+               ipv6_del_acaddr_hash(aca);
+
                addrconf_leave_solict(idev, &aca->aca_addr);
 
                ip6_del_rt(dev_net(idev->dev), aca->aca_rt);
@@ -390,17 +433,25 @@ static bool ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *ad
 bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
                         const struct in6_addr *addr)
 {
+       unsigned int hash = inet6_acaddr_hash(net, addr);
+       struct net_device *nh_dev;
+       struct ifacaddr6 *aca;
        bool found = false;
 
        rcu_read_lock();
        if (dev)
                found = ipv6_chk_acast_dev(dev, addr);
        else
-               for_each_netdev_rcu(net, dev)
-                       if (ipv6_chk_acast_dev(dev, addr)) {
+               hlist_for_each_entry_rcu(aca, &inet6_acaddr_lst[hash],
+                                        aca_addr_lst) {
+                       nh_dev = fib6_info_nh_dev(aca->aca_rt);
+                       if (!nh_dev || !net_eq(dev_net(nh_dev), net))
+                               continue;
+                       if (ipv6_addr_equal(&aca->aca_addr, addr)) {
                                found = true;
                                break;
                        }
+               }
        rcu_read_unlock();
        return found;
 }
@@ -540,3 +591,24 @@ void ac6_proc_exit(struct net *net)
        remove_proc_entry("anycast6", net->proc_net);
 }
 #endif
+
+/*     Init / cleanup code
+ */
+int __init ipv6_anycast_init(void)
+{
+       int i;
+
+       for (i = 0; i < IN6_ADDR_HSIZE; i++)
+               INIT_HLIST_HEAD(&inet6_acaddr_lst[i]);
+       return 0;
+}
+
+void ipv6_anycast_cleanup(void)
+{
+       int i;
+
+       spin_lock(&acaddr_hash_lock);
+       for (i = 0; i < IN6_ADDR_HSIZE; i++)
+               WARN_ON(!hlist_empty(&inet6_acaddr_lst[i]));
+       spin_unlock(&acaddr_hash_lock);
+}
index 1b8bc00..ae37861 100644 (file)
@@ -591,7 +591,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
        /* fib entries are never clones */
        if (arg.filter.flags & RTM_F_CLONED)
-               return skb->len;
+               goto out;
 
        w = (void *)cb->args[2];
        if (!w) {
@@ -621,7 +621,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
                tb = fib6_get_table(net, arg.filter.table_id);
                if (!tb) {
                        if (arg.filter.dump_all_families)
-                               return skb->len;
+                               goto out;
 
                        NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist");
                        return -ENOENT;
index b8ac369..d219979 100644 (file)
@@ -587,11 +587,16 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
         */
        ret = -EINPROGRESS;
        if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           fq->q.meat == fq->q.len &&
-           nf_ct_frag6_reasm(fq, skb, dev))
-               ret = 0;
-       else
+           fq->q.meat == fq->q.len) {
+               unsigned long orefdst = skb->_skb_refdst;
+
+               skb->_skb_refdst = 0UL;
+               if (nf_ct_frag6_reasm(fq, skb, dev))
+                       ret = 0;
+               skb->_skb_refdst = orefdst;
+       } else {
                skb_dst_drop(skb);
+       }
 
 out_unlock:
        spin_unlock_bh(&fq->q.lock);
index bc4bd24..1577f2f 100644 (file)
@@ -55,11 +55,15 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 MODULE_DESCRIPTION("core IP set support");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
 
-/* When the nfnl mutex is held: */
+/* When the nfnl mutex or ip_set_ref_lock is held: */
 #define ip_set_dereference(p)          \
-       rcu_dereference_protected(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
+       rcu_dereference_protected(p,    \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET) || \
+               lockdep_is_held(&ip_set_ref_lock))
 #define ip_set(inst, id)               \
        ip_set_dereference((inst)->ip_set_list)[id]
+#define ip_set_ref_netlink(inst,id)    \
+       rcu_dereference_raw((inst)->ip_set_list)[id]
 
 /* The set types are implemented in modules and registered set types
  * can be found in ip_set_type_list. Adding/deleting types is
@@ -693,21 +697,20 @@ ip_set_put_byindex(struct net *net, ip_set_id_t index)
 EXPORT_SYMBOL_GPL(ip_set_put_byindex);
 
 /* Get the name of a set behind a set index.
- * We assume the set is referenced, so it does exist and
- * can't be destroyed. The set cannot be renamed due to
- * the referencing either.
- *
+ * Set itself is protected by RCU, but its name isn't: to protect against
+ * renaming, grab ip_set_ref_lock as reader (see ip_set_rename()) and copy the
+ * name.
  */
-const char *
-ip_set_name_byindex(struct net *net, ip_set_id_t index)
+void
+ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name)
 {
-       const struct ip_set *set = ip_set_rcu_get(net, index);
+       struct ip_set *set = ip_set_rcu_get(net, index);
 
        BUG_ON(!set);
-       BUG_ON(set->ref == 0);
 
-       /* Referenced, so it's safe */
-       return set->name;
+       read_lock_bh(&ip_set_ref_lock);
+       strncpy(name, set->name, IPSET_MAXNAMELEN);
+       read_unlock_bh(&ip_set_ref_lock);
 }
 EXPORT_SYMBOL_GPL(ip_set_name_byindex);
 
@@ -961,7 +964,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
                        /* Wraparound */
                        goto cleanup;
 
-               list = kcalloc(i, sizeof(struct ip_set *), GFP_KERNEL);
+               list = kvcalloc(i, sizeof(struct ip_set *), GFP_KERNEL);
                if (!list)
                        goto cleanup;
                /* nfnl mutex is held, both lists are valid */
@@ -973,7 +976,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
                /* Use new list */
                index = inst->ip_set_max;
                inst->ip_set_max = i;
-               kfree(tmp);
+               kvfree(tmp);
                ret = 0;
        } else if (ret) {
                goto cleanup;
@@ -1153,7 +1156,7 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
        if (!set)
                return -ENOENT;
 
-       read_lock_bh(&ip_set_ref_lock);
+       write_lock_bh(&ip_set_ref_lock);
        if (set->ref != 0) {
                ret = -IPSET_ERR_REFERENCED;
                goto out;
@@ -1170,7 +1173,7 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
        strncpy(set->name, name2, IPSET_MAXNAMELEN);
 
 out:
-       read_unlock_bh(&ip_set_ref_lock);
+       write_unlock_bh(&ip_set_ref_lock);
        return ret;
 }
 
@@ -1252,7 +1255,7 @@ ip_set_dump_done(struct netlink_callback *cb)
                struct ip_set_net *inst =
                        (struct ip_set_net *)cb->args[IPSET_CB_NET];
                ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX];
-               struct ip_set *set = ip_set(inst, index);
+               struct ip_set *set = ip_set_ref_netlink(inst, index);
 
                if (set->variant->uref)
                        set->variant->uref(set, cb, false);
@@ -1441,7 +1444,7 @@ next_set:
 release_refcount:
        /* If there was an error or set is done, release set */
        if (ret || !cb->args[IPSET_CB_ARG0]) {
-               set = ip_set(inst, index);
+               set = ip_set_ref_netlink(inst, index);
                if (set->variant->uref)
                        set->variant->uref(set, cb, false);
                pr_debug("release set %s\n", set->name);
@@ -2059,7 +2062,7 @@ ip_set_net_init(struct net *net)
        if (inst->ip_set_max >= IPSET_INVALID_ID)
                inst->ip_set_max = IPSET_INVALID_ID - 1;
 
-       list = kcalloc(inst->ip_set_max, sizeof(struct ip_set *), GFP_KERNEL);
+       list = kvcalloc(inst->ip_set_max, sizeof(struct ip_set *), GFP_KERNEL);
        if (!list)
                return -ENOMEM;
        inst->is_deleted = false;
@@ -2087,7 +2090,7 @@ ip_set_net_exit(struct net *net)
                }
        }
        nfnl_unlock(NFNL_SUBSYS_IPSET);
-       kfree(rcu_dereference_protected(inst->ip_set_list, 1));
+       kvfree(rcu_dereference_protected(inst->ip_set_list, 1));
 }
 
 static struct pernet_operations ip_set_net_ops = {
index d391485..613e18e 100644 (file)
@@ -213,13 +213,13 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_CIDR]) {
                e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-               if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
+               if (e.cidr[0] > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
        if (tb[IPSET_ATTR_CIDR2]) {
                e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-               if (!e.cidr[1] || e.cidr[1] > HOST_MASK)
+               if (e.cidr[1] > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
@@ -493,13 +493,13 @@ hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_CIDR]) {
                e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-               if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
+               if (e.cidr[0] > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
        if (tb[IPSET_ATTR_CIDR2]) {
                e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-               if (!e.cidr[1] || e.cidr[1] > HOST_MASK)
+               if (e.cidr[1] > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
index 072a658..4eef55d 100644 (file)
@@ -148,9 +148,7 @@ __list_set_del_rcu(struct rcu_head * rcu)
 {
        struct set_elem *e = container_of(rcu, struct set_elem, rcu);
        struct ip_set *set = e->set;
-       struct list_set *map = set->data;
 
-       ip_set_put_byindex(map->net, e->id);
        ip_set_ext_destroy(set, e);
        kfree(e);
 }
@@ -158,15 +156,21 @@ __list_set_del_rcu(struct rcu_head * rcu)
 static inline void
 list_set_del(struct ip_set *set, struct set_elem *e)
 {
+       struct list_set *map = set->data;
+
        set->elements--;
        list_del_rcu(&e->list);
+       ip_set_put_byindex(map->net, e->id);
        call_rcu(&e->rcu, __list_set_del_rcu);
 }
 
 static inline void
-list_set_replace(struct set_elem *e, struct set_elem *old)
+list_set_replace(struct ip_set *set, struct set_elem *e, struct set_elem *old)
 {
+       struct list_set *map = set->data;
+
        list_replace_rcu(&old->list, &e->list);
+       ip_set_put_byindex(map->net, old->id);
        call_rcu(&old->rcu, __list_set_del_rcu);
 }
 
@@ -298,7 +302,7 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        INIT_LIST_HEAD(&e->list);
        list_set_init_extensions(set, ext, e);
        if (n)
-               list_set_replace(e, n);
+               list_set_replace(set, e, n);
        else if (next)
                list_add_tail_rcu(&e->list, &next->list);
        else if (prev)
@@ -486,6 +490,7 @@ list_set_list(const struct ip_set *set,
        const struct list_set *map = set->data;
        struct nlattr *atd, *nested;
        u32 i = 0, first = cb->args[IPSET_CB_ARG0];
+       char name[IPSET_MAXNAMELEN];
        struct set_elem *e;
        int ret = 0;
 
@@ -504,8 +509,8 @@ list_set_list(const struct ip_set *set,
                nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
                if (!nested)
                        goto nla_put_failure;
-               if (nla_put_string(skb, IPSET_ATTR_NAME,
-                                  ip_set_name_byindex(map->net, e->id)))
+               ip_set_name_byindex(map->net, e->id, name);
+               if (nla_put_string(skb, IPSET_ATTR_NAME, name))
                        goto nla_put_failure;
                if (ip_set_put_extensions(skb, set, e, true))
                        goto nla_put_failure;
index ca1168d..e92e749 100644 (file)
@@ -1073,19 +1073,22 @@ static unsigned int early_drop_list(struct net *net,
        return drops;
 }
 
-static noinline int early_drop(struct net *net, unsigned int _hash)
+static noinline int early_drop(struct net *net, unsigned int hash)
 {
-       unsigned int i;
+       unsigned int i, bucket;
 
        for (i = 0; i < NF_CT_EVICTION_RANGE; i++) {
                struct hlist_nulls_head *ct_hash;
-               unsigned int hash, hsize, drops;
+               unsigned int hsize, drops;
 
                rcu_read_lock();
                nf_conntrack_get_ht(&ct_hash, &hsize);
-               hash = reciprocal_scale(_hash++, hsize);
+               if (!i)
+                       bucket = reciprocal_scale(hash, hsize);
+               else
+                       bucket = (bucket + 1) % hsize;
 
-               drops = early_drop_list(net, &ct_hash[hash]);
+               drops = early_drop_list(net, &ct_hash[bucket]);
                rcu_read_unlock();
 
                if (drops) {
index 171e9e1..023c144 100644 (file)
@@ -384,11 +384,6 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
        },
 };
 
-static inline struct nf_dccp_net *dccp_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.dccp;
-}
-
 static noinline bool
 dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
         const struct dccp_hdr *dh)
@@ -401,7 +396,7 @@ dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
        state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
        switch (state) {
        default:
-               dn = dccp_pernet(net);
+               dn = nf_dccp_pernet(net);
                if (dn->dccp_loose == 0) {
                        msg = "not picking up existing connection ";
                        goto out_invalid;
@@ -568,7 +563,7 @@ static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
 
        timeouts = nf_ct_timeout_lookup(ct);
        if (!timeouts)
-               timeouts = dccp_pernet(nf_ct_net(ct))->dccp_timeout;
+               timeouts = nf_dccp_pernet(nf_ct_net(ct))->dccp_timeout;
        nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
 
        return NF_ACCEPT;
@@ -681,7 +676,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
 static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
                                      struct net *net, void *data)
 {
-       struct nf_dccp_net *dn = dccp_pernet(net);
+       struct nf_dccp_net *dn = nf_dccp_pernet(net);
        unsigned int *timeouts = data;
        int i;
 
@@ -814,7 +809,7 @@ static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn,
 
 static int dccp_init_net(struct net *net)
 {
-       struct nf_dccp_net *dn = dccp_pernet(net);
+       struct nf_dccp_net *dn = nf_dccp_pernet(net);
        struct nf_proto_net *pn = &dn->pn;
 
        if (!pn->users) {
index e10e867..5da19d5 100644 (file)
@@ -27,11 +27,6 @@ static bool nf_generic_should_process(u8 proto)
        }
 }
 
-static inline struct nf_generic_net *generic_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.generic;
-}
-
 static bool generic_pkt_to_tuple(const struct sk_buff *skb,
                                 unsigned int dataoff,
                                 struct net *net, struct nf_conntrack_tuple *tuple)
@@ -58,7 +53,7 @@ static int generic_packet(struct nf_conn *ct,
        }
 
        if (!timeout)
-               timeout = &generic_pernet(nf_ct_net(ct))->timeout;
+               timeout = &nf_generic_pernet(nf_ct_net(ct))->timeout;
 
        nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
        return NF_ACCEPT;
@@ -72,7 +67,7 @@ static int generic_packet(struct nf_conn *ct,
 static int generic_timeout_nlattr_to_obj(struct nlattr *tb[],
                                         struct net *net, void *data)
 {
-       struct nf_generic_net *gn = generic_pernet(net);
+       struct nf_generic_net *gn = nf_generic_pernet(net);
        unsigned int *timeout = data;
 
        if (!timeout)
@@ -138,7 +133,7 @@ static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int generic_init_net(struct net *net)
 {
-       struct nf_generic_net *gn = generic_pernet(net);
+       struct nf_generic_net *gn = nf_generic_pernet(net);
        struct nf_proto_net *pn = &gn->pn;
 
        gn->timeout = nf_ct_generic_timeout;
index 3598520..de64d8a 100644 (file)
 
 static const unsigned int nf_ct_icmp_timeout = 30*HZ;
 
-static inline struct nf_icmp_net *icmp_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.icmp;
-}
-
 static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                              struct net *net, struct nf_conntrack_tuple *tuple)
 {
@@ -103,7 +98,7 @@ static int icmp_packet(struct nf_conn *ct,
        }
 
        if (!timeout)
-               timeout = &icmp_pernet(nf_ct_net(ct))->timeout;
+               timeout = &nf_icmp_pernet(nf_ct_net(ct))->timeout;
 
        nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
        return NF_ACCEPT;
@@ -275,7 +270,7 @@ static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[],
                                      struct net *net, void *data)
 {
        unsigned int *timeout = data;
-       struct nf_icmp_net *in = icmp_pernet(net);
+       struct nf_icmp_net *in = nf_icmp_pernet(net);
 
        if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
                if (!timeout)
@@ -337,7 +332,7 @@ static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int icmp_init_net(struct net *net)
 {
-       struct nf_icmp_net *in = icmp_pernet(net);
+       struct nf_icmp_net *in = nf_icmp_pernet(net);
        struct nf_proto_net *pn = &in->pn;
 
        in->timeout = nf_ct_icmp_timeout;
index 378618f..a15eefb 100644 (file)
 
 static const unsigned int nf_ct_icmpv6_timeout = 30*HZ;
 
-static inline struct nf_icmp_net *icmpv6_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.icmpv6;
-}
-
 static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb,
                                unsigned int dataoff,
                                struct net *net,
@@ -87,7 +82,7 @@ static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
 
 static unsigned int *icmpv6_get_timeouts(struct net *net)
 {
-       return &icmpv6_pernet(net)->timeout;
+       return &nf_icmpv6_pernet(net)->timeout;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -286,7 +281,7 @@ static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[],
                                        struct net *net, void *data)
 {
        unsigned int *timeout = data;
-       struct nf_icmp_net *in = icmpv6_pernet(net);
+       struct nf_icmp_net *in = nf_icmpv6_pernet(net);
 
        if (!timeout)
                timeout = icmpv6_get_timeouts(net);
@@ -348,7 +343,7 @@ static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int icmpv6_init_net(struct net *net)
 {
-       struct nf_icmp_net *in = icmpv6_pernet(net);
+       struct nf_icmp_net *in = nf_icmpv6_pernet(net);
        struct nf_proto_net *pn = &in->pn;
 
        in->timeout = nf_ct_icmpv6_timeout;
index 3d719d3..d53e3e7 100644 (file)
@@ -146,11 +146,6 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = {
        }
 };
 
-static inline struct nf_sctp_net *sctp_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.sctp;
-}
-
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
 /* Print out the private part of the conntrack. */
 static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
@@ -480,7 +475,7 @@ static int sctp_packet(struct nf_conn *ct,
 
        timeouts = nf_ct_timeout_lookup(ct);
        if (!timeouts)
-               timeouts = sctp_pernet(nf_ct_net(ct))->timeouts;
+               timeouts = nf_sctp_pernet(nf_ct_net(ct))->timeouts;
 
        nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
 
@@ -599,7 +594,7 @@ static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[],
                                      struct net *net, void *data)
 {
        unsigned int *timeouts = data;
-       struct nf_sctp_net *sn = sctp_pernet(net);
+       struct nf_sctp_net *sn = nf_sctp_pernet(net);
        int i;
 
        /* set default SCTP timeouts. */
@@ -736,7 +731,7 @@ static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int sctp_init_net(struct net *net)
 {
-       struct nf_sctp_net *sn = sctp_pernet(net);
+       struct nf_sctp_net *sn = nf_sctp_pernet(net);
        struct nf_proto_net *pn = &sn->pn;
 
        if (!pn->users) {
index 1bcf998..4dcbd51 100644 (file)
@@ -272,11 +272,6 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
        }
 };
 
-static inline struct nf_tcp_net *tcp_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.tcp;
-}
-
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
 /* Print out the private part of the conntrack. */
 static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
@@ -475,7 +470,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
                          const struct tcphdr *tcph)
 {
        struct net *net = nf_ct_net(ct);
-       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_tcp_net *tn = nf_tcp_pernet(net);
        struct ip_ct_tcp_state *sender = &state->seen[dir];
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
        const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
@@ -767,7 +762,7 @@ static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
 {
        enum tcp_conntrack new_state;
        struct net *net = nf_ct_net(ct);
-       const struct nf_tcp_net *tn = tcp_pernet(net);
+       const struct nf_tcp_net *tn = nf_tcp_pernet(net);
        const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
        const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
@@ -841,7 +836,7 @@ static int tcp_packet(struct nf_conn *ct,
                      const struct nf_hook_state *state)
 {
        struct net *net = nf_ct_net(ct);
-       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_tcp_net *tn = nf_tcp_pernet(net);
        struct nf_conntrack_tuple *tuple;
        enum tcp_conntrack new_state, old_state;
        unsigned int index, *timeouts;
@@ -1283,7 +1278,7 @@ static unsigned int tcp_nlattr_tuple_size(void)
 static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[],
                                     struct net *net, void *data)
 {
-       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_tcp_net *tn = nf_tcp_pernet(net);
        unsigned int *timeouts = data;
        int i;
 
@@ -1508,7 +1503,7 @@ static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int tcp_init_net(struct net *net)
 {
-       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_tcp_net *tn = nf_tcp_pernet(net);
        struct nf_proto_net *pn = &tn->pn;
 
        if (!pn->users) {
index a7aa703..c879d8d 100644 (file)
@@ -32,14 +32,9 @@ static const unsigned int udp_timeouts[UDP_CT_MAX] = {
        [UDP_CT_REPLIED]        = 180*HZ,
 };
 
-static inline struct nf_udp_net *udp_pernet(struct net *net)
-{
-       return &net->ct.nf_ct_proto.udp;
-}
-
 static unsigned int *udp_get_timeouts(struct net *net)
 {
-       return udp_pernet(net)->timeouts;
+       return nf_udp_pernet(net)->timeouts;
 }
 
 static void udp_error_log(const struct sk_buff *skb,
@@ -212,7 +207,7 @@ static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
                                     struct net *net, void *data)
 {
        unsigned int *timeouts = data;
-       struct nf_udp_net *un = udp_pernet(net);
+       struct nf_udp_net *un = nf_udp_pernet(net);
 
        if (!timeouts)
                timeouts = un->timeouts;
@@ -292,7 +287,7 @@ static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 
 static int udp_init_net(struct net *net)
 {
-       struct nf_udp_net *un = udp_pernet(net);
+       struct nf_udp_net *un = nf_udp_pernet(net);
        struct nf_proto_net *pn = &un->pn;
 
        if (!pn->users) {
index e7a50af..a518eb1 100644 (file)
@@ -382,7 +382,8 @@ err:
 static int
 cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
                            u32 seq, u32 type, int event, u16 l3num,
-                           const struct nf_conntrack_l4proto *l4proto)
+                           const struct nf_conntrack_l4proto *l4proto,
+                           const unsigned int *timeouts)
 {
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
@@ -408,7 +409,7 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
        if (!nest_parms)
                goto nla_put_failure;
 
-       ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, NULL);
+       ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
        if (ret < 0)
                goto nla_put_failure;
 
@@ -430,6 +431,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
                                 struct netlink_ext_ack *extack)
 {
        const struct nf_conntrack_l4proto *l4proto;
+       unsigned int *timeouts = NULL;
        struct sk_buff *skb2;
        int ret, err;
        __u16 l3num;
@@ -442,12 +444,44 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
        l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
        l4proto = nf_ct_l4proto_find_get(l4num);
 
-       /* This protocol is not supported, skip. */
-       if (l4proto->l4proto != l4num) {
-               err = -EOPNOTSUPP;
+       err = -EOPNOTSUPP;
+       if (l4proto->l4proto != l4num)
                goto err;
+
+       switch (l4proto->l4proto) {
+       case IPPROTO_ICMP:
+               timeouts = &nf_icmp_pernet(net)->timeout;
+               break;
+       case IPPROTO_TCP:
+               timeouts = nf_tcp_pernet(net)->timeouts;
+               break;
+       case IPPROTO_UDP:
+               timeouts = nf_udp_pernet(net)->timeouts;
+               break;
+       case IPPROTO_DCCP:
+#ifdef CONFIG_NF_CT_PROTO_DCCP
+               timeouts = nf_dccp_pernet(net)->dccp_timeout;
+#endif
+               break;
+       case IPPROTO_ICMPV6:
+               timeouts = &nf_icmpv6_pernet(net)->timeout;
+               break;
+       case IPPROTO_SCTP:
+#ifdef CONFIG_NF_CT_PROTO_SCTP
+               timeouts = nf_sctp_pernet(net)->timeouts;
+#endif
+               break;
+       case 255:
+               timeouts = &nf_generic_pernet(net)->timeout;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
        }
 
+       if (!timeouts)
+               goto err;
+
        skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (skb2 == NULL) {
                err = -ENOMEM;
@@ -458,8 +492,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
                                          nlh->nlmsg_seq,
                                          NFNL_MSG_TYPE(nlh->nlmsg_type),
                                          IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
-                                         l3num,
-                                         l4proto);
+                                         l3num, l4proto, timeouts);
        if (ret <= 0) {
                kfree_skb(skb2);
                err = -ENOMEM;
index 768292e..9d0ede4 100644 (file)
@@ -54,9 +54,11 @@ static bool nft_xt_put(struct nft_xt *xt)
        return false;
 }
 
-static int nft_compat_chain_validate_dependency(const char *tablename,
-                                               const struct nft_chain *chain)
+static int nft_compat_chain_validate_dependency(const struct nft_ctx *ctx,
+                                               const char *tablename)
 {
+       enum nft_chain_types type = NFT_CHAIN_T_DEFAULT;
+       const struct nft_chain *chain = ctx->chain;
        const struct nft_base_chain *basechain;
 
        if (!tablename ||
@@ -64,9 +66,12 @@ static int nft_compat_chain_validate_dependency(const char *tablename,
                return 0;
 
        basechain = nft_base_chain(chain);
-       if (strcmp(tablename, "nat") == 0 &&
-           basechain->type->type != NFT_CHAIN_T_NAT)
-               return -EINVAL;
+       if (strcmp(tablename, "nat") == 0) {
+               if (ctx->family != NFPROTO_BRIDGE)
+                       type = NFT_CHAIN_T_NAT;
+               if (basechain->type->type != type)
+                       return -EINVAL;
+       }
 
        return 0;
 }
@@ -342,8 +347,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
                if (target->hooks && !(hook_mask & target->hooks))
                        return -EINVAL;
 
-               ret = nft_compat_chain_validate_dependency(target->table,
-                                                          ctx->chain);
+               ret = nft_compat_chain_validate_dependency(ctx, target->table);
                if (ret < 0)
                        return ret;
        }
@@ -590,8 +594,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
                if (match->hooks && !(hook_mask & match->hooks))
                        return -EINVAL;
 
-               ret = nft_compat_chain_validate_dependency(match->table,
-                                                          ctx->chain);
+               ret = nft_compat_chain_validate_dependency(ctx, match->table);
                if (ret < 0)
                        return ret;
        }
index 649d170..3cc1b3d 100644 (file)
@@ -24,7 +24,6 @@ struct nft_ng_inc {
        u32                     modulus;
        atomic_t                counter;
        u32                     offset;
-       struct nft_set          *map;
 };
 
 static u32 nft_ng_inc_gen(struct nft_ng_inc *priv)
@@ -48,34 +47,11 @@ static void nft_ng_inc_eval(const struct nft_expr *expr,
        regs->data[priv->dreg] = nft_ng_inc_gen(priv);
 }
 
-static void nft_ng_inc_map_eval(const struct nft_expr *expr,
-                               struct nft_regs *regs,
-                               const struct nft_pktinfo *pkt)
-{
-       struct nft_ng_inc *priv = nft_expr_priv(expr);
-       const struct nft_set *map = priv->map;
-       const struct nft_set_ext *ext;
-       u32 result;
-       bool found;
-
-       result = nft_ng_inc_gen(priv);
-       found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
-
-       if (!found)
-               return;
-
-       nft_data_copy(&regs->data[priv->dreg],
-                     nft_set_ext_data(ext), map->dlen);
-}
-
 static const struct nla_policy nft_ng_policy[NFTA_NG_MAX + 1] = {
        [NFTA_NG_DREG]          = { .type = NLA_U32 },
        [NFTA_NG_MODULUS]       = { .type = NLA_U32 },
        [NFTA_NG_TYPE]          = { .type = NLA_U32 },
        [NFTA_NG_OFFSET]        = { .type = NLA_U32 },
-       [NFTA_NG_SET_NAME]      = { .type = NLA_STRING,
-                                   .len = NFT_SET_MAXNAMELEN - 1 },
-       [NFTA_NG_SET_ID]        = { .type = NLA_U32 },
 };
 
 static int nft_ng_inc_init(const struct nft_ctx *ctx,
@@ -101,22 +77,6 @@ static int nft_ng_inc_init(const struct nft_ctx *ctx,
                                           NFT_DATA_VALUE, sizeof(u32));
 }
 
-static int nft_ng_inc_map_init(const struct nft_ctx *ctx,
-                              const struct nft_expr *expr,
-                              const struct nlattr * const tb[])
-{
-       struct nft_ng_inc *priv = nft_expr_priv(expr);
-       u8 genmask = nft_genmask_next(ctx->net);
-
-       nft_ng_inc_init(ctx, expr, tb);
-
-       priv->map = nft_set_lookup_global(ctx->net, ctx->table,
-                                         tb[NFTA_NG_SET_NAME],
-                                         tb[NFTA_NG_SET_ID], genmask);
-
-       return PTR_ERR_OR_ZERO(priv->map);
-}
-
 static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg,
                       u32 modulus, enum nft_ng_types type, u32 offset)
 {
@@ -143,27 +103,10 @@ static int nft_ng_inc_dump(struct sk_buff *skb, const struct nft_expr *expr)
                           priv->offset);
 }
 
-static int nft_ng_inc_map_dump(struct sk_buff *skb,
-                              const struct nft_expr *expr)
-{
-       const struct nft_ng_inc *priv = nft_expr_priv(expr);
-
-       if (nft_ng_dump(skb, priv->dreg, priv->modulus,
-                       NFT_NG_INCREMENTAL, priv->offset) ||
-           nla_put_string(skb, NFTA_NG_SET_NAME, priv->map->name))
-               goto nla_put_failure;
-
-       return 0;
-
-nla_put_failure:
-       return -1;
-}
-
 struct nft_ng_random {
        enum nft_registers      dreg:8;
        u32                     modulus;
        u32                     offset;
-       struct nft_set          *map;
 };
 
 static u32 nft_ng_random_gen(struct nft_ng_random *priv)
@@ -183,25 +126,6 @@ static void nft_ng_random_eval(const struct nft_expr *expr,
        regs->data[priv->dreg] = nft_ng_random_gen(priv);
 }
 
-static void nft_ng_random_map_eval(const struct nft_expr *expr,
-                                  struct nft_regs *regs,
-                                  const struct nft_pktinfo *pkt)
-{
-       struct nft_ng_random *priv = nft_expr_priv(expr);
-       const struct nft_set *map = priv->map;
-       const struct nft_set_ext *ext;
-       u32 result;
-       bool found;
-
-       result = nft_ng_random_gen(priv);
-       found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
-       if (!found)
-               return;
-
-       nft_data_copy(&regs->data[priv->dreg],
-                     nft_set_ext_data(ext), map->dlen);
-}
-
 static int nft_ng_random_init(const struct nft_ctx *ctx,
                              const struct nft_expr *expr,
                              const struct nlattr * const tb[])
@@ -226,21 +150,6 @@ static int nft_ng_random_init(const struct nft_ctx *ctx,
                                           NFT_DATA_VALUE, sizeof(u32));
 }
 
-static int nft_ng_random_map_init(const struct nft_ctx *ctx,
-                                 const struct nft_expr *expr,
-                                 const struct nlattr * const tb[])
-{
-       struct nft_ng_random *priv = nft_expr_priv(expr);
-       u8 genmask = nft_genmask_next(ctx->net);
-
-       nft_ng_random_init(ctx, expr, tb);
-       priv->map = nft_set_lookup_global(ctx->net, ctx->table,
-                                         tb[NFTA_NG_SET_NAME],
-                                         tb[NFTA_NG_SET_ID], genmask);
-
-       return PTR_ERR_OR_ZERO(priv->map);
-}
-
 static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_ng_random *priv = nft_expr_priv(expr);
@@ -249,22 +158,6 @@ static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr)
                           priv->offset);
 }
 
-static int nft_ng_random_map_dump(struct sk_buff *skb,
-                                 const struct nft_expr *expr)
-{
-       const struct nft_ng_random *priv = nft_expr_priv(expr);
-
-       if (nft_ng_dump(skb, priv->dreg, priv->modulus,
-                       NFT_NG_RANDOM, priv->offset) ||
-           nla_put_string(skb, NFTA_NG_SET_NAME, priv->map->name))
-               goto nla_put_failure;
-
-       return 0;
-
-nla_put_failure:
-       return -1;
-}
-
 static struct nft_expr_type nft_ng_type;
 static const struct nft_expr_ops nft_ng_inc_ops = {
        .type           = &nft_ng_type,
@@ -274,14 +167,6 @@ static const struct nft_expr_ops nft_ng_inc_ops = {
        .dump           = nft_ng_inc_dump,
 };
 
-static const struct nft_expr_ops nft_ng_inc_map_ops = {
-       .type           = &nft_ng_type,
-       .size           = NFT_EXPR_SIZE(sizeof(struct nft_ng_inc)),
-       .eval           = nft_ng_inc_map_eval,
-       .init           = nft_ng_inc_map_init,
-       .dump           = nft_ng_inc_map_dump,
-};
-
 static const struct nft_expr_ops nft_ng_random_ops = {
        .type           = &nft_ng_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ng_random)),
@@ -290,14 +175,6 @@ static const struct nft_expr_ops nft_ng_random_ops = {
        .dump           = nft_ng_random_dump,
 };
 
-static const struct nft_expr_ops nft_ng_random_map_ops = {
-       .type           = &nft_ng_type,
-       .size           = NFT_EXPR_SIZE(sizeof(struct nft_ng_random)),
-       .eval           = nft_ng_random_map_eval,
-       .init           = nft_ng_random_map_init,
-       .dump           = nft_ng_random_map_dump,
-};
-
 static const struct nft_expr_ops *
 nft_ng_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
 {
@@ -312,12 +189,8 @@ nft_ng_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
 
        switch (type) {
        case NFT_NG_INCREMENTAL:
-               if (tb[NFTA_NG_SET_NAME])
-                       return &nft_ng_inc_map_ops;
                return &nft_ng_inc_ops;
        case NFT_NG_RANDOM:
-               if (tb[NFTA_NG_SET_NAME])
-                       return &nft_ng_random_map_ops;
                return &nft_ng_random_ops;
        }
 
index ca5e5d8..b13618c 100644 (file)
@@ -50,7 +50,7 @@ static int nft_osf_init(const struct nft_ctx *ctx,
        int err;
        u8 ttl;
 
-       if (nla_get_u8(tb[NFTA_OSF_TTL])) {
+       if (tb[NFTA_OSF_TTL]) {
                ttl = nla_get_u8(tb[NFTA_OSF_TTL]);
                if (ttl > 2)
                        return -EINVAL;
index c6acfc2..eb4cbd2 100644 (file)
@@ -114,6 +114,22 @@ static void idletimer_tg_expired(struct timer_list *t)
        schedule_work(&timer->work);
 }
 
+static int idletimer_check_sysfs_name(const char *name, unsigned int size)
+{
+       int ret;
+
+       ret = xt_check_proc_name(name, size);
+       if (ret < 0)
+               return ret;
+
+       if (!strcmp(name, "power") ||
+           !strcmp(name, "subsystem") ||
+           !strcmp(name, "uevent"))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int idletimer_tg_create(struct idletimer_tg_info *info)
 {
        int ret;
@@ -124,6 +140,10 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
                goto out;
        }
 
+       ret = idletimer_check_sysfs_name(info->label, sizeof(info->label));
+       if (ret < 0)
+               goto out_free_timer;
+
        sysfs_attr_init(&info->timer->attr.attr);
        info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
        if (!info->timer->attr.attr.name) {
index 6bec37a..a4660c4 100644 (file)
@@ -1203,7 +1203,8 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
                                         &info->labels.mask);
                if (err)
                        return err;
-       } else if (labels_nonzero(&info->labels.mask)) {
+       } else if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
+                  labels_nonzero(&info->labels.mask)) {
                err = ovs_ct_set_labels(ct, key, &info->labels.value,
                                        &info->labels.mask);
                if (err)
index 382196e..bc628ac 100644 (file)
@@ -611,6 +611,7 @@ struct rxrpc_call {
                                                 * not hard-ACK'd packet follows this.
                                                 */
        rxrpc_seq_t             tx_top;         /* Highest Tx slot allocated. */
+       u16                     tx_backoff;     /* Delay to insert due to Tx failure */
 
        /* TCP-style slow-start congestion control [RFC5681].  Since the SMSS
         * is fixed, we keep these numbers in terms of segments (ie. DATA
index 8e7434e..468efc3 100644 (file)
@@ -123,6 +123,7 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                else
                        ack_at = expiry;
 
+               ack_at += READ_ONCE(call->tx_backoff);
                ack_at += now;
                if (time_before(ack_at, call->ack_at)) {
                        WRITE_ONCE(call->ack_at, ack_at);
@@ -311,6 +312,7 @@ void rxrpc_process_call(struct work_struct *work)
                container_of(work, struct rxrpc_call, processor);
        rxrpc_serial_t *send_ack;
        unsigned long now, next, t;
+       unsigned int iterations = 0;
 
        rxrpc_see_call(call);
 
@@ -319,6 +321,11 @@ void rxrpc_process_call(struct work_struct *work)
               call->debug_id, rxrpc_call_states[call->state], call->events);
 
 recheck_state:
+       /* Limit the number of times we do this before returning to the manager */
+       iterations++;
+       if (iterations > 5)
+               goto requeue;
+
        if (test_and_clear_bit(RXRPC_CALL_EV_ABORT, &call->events)) {
                rxrpc_send_abort_packet(call);
                goto recheck_state;
@@ -447,13 +454,16 @@ recheck_state:
        rxrpc_reduce_call_timer(call, next, now, rxrpc_timer_restart);
 
        /* other events may have been raised since we started checking */
-       if (call->events && call->state < RXRPC_CALL_COMPLETE) {
-               __rxrpc_queue_call(call);
-               goto out;
-       }
+       if (call->events && call->state < RXRPC_CALL_COMPLETE)
+               goto requeue;
 
 out_put:
        rxrpc_put_call(call, rxrpc_call_put);
 out:
        _leave("");
+       return;
+
+requeue:
+       __rxrpc_queue_call(call);
+       goto out;
 }
index 1894188..736aa92 100644 (file)
@@ -35,6 +35,21 @@ struct rxrpc_abort_buffer {
 static const char rxrpc_keepalive_string[] = "";
 
 /*
+ * Increase Tx backoff on transmission failure and clear it on success.
+ */
+static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret)
+{
+       if (ret < 0) {
+               u16 tx_backoff = READ_ONCE(call->tx_backoff);
+
+               if (tx_backoff < HZ)
+                       WRITE_ONCE(call->tx_backoff, tx_backoff + 1);
+       } else {
+               WRITE_ONCE(call->tx_backoff, 0);
+       }
+}
+
+/*
  * Arrange for a keepalive ping a certain time after we last transmitted.  This
  * lets the far side know we're still interested in this call and helps keep
  * the route through any intervening firewall open.
@@ -210,6 +225,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
        else
                trace_rxrpc_tx_packet(call->debug_id, &pkt->whdr,
                                      rxrpc_tx_point_call_ack);
+       rxrpc_tx_backoff(call, ret);
 
        if (call->state < RXRPC_CALL_COMPLETE) {
                if (ret < 0) {
@@ -218,7 +234,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
                        rxrpc_propose_ACK(call, pkt->ack.reason,
                                          ntohs(pkt->ack.maxSkew),
                                          ntohl(pkt->ack.serial),
-                                         true, true,
+                                         false, true,
                                          rxrpc_propose_ack_retry_tx);
                } else {
                        spin_lock_bh(&call->lock);
@@ -300,7 +316,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
        else
                trace_rxrpc_tx_packet(call->debug_id, &pkt.whdr,
                                      rxrpc_tx_point_call_abort);
-
+       rxrpc_tx_backoff(call, ret);
 
        rxrpc_put_connection(conn);
        return ret;
@@ -413,6 +429,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        else
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_nofrag);
+       rxrpc_tx_backoff(call, ret);
        if (ret == -EMSGSIZE)
                goto send_fragmentable;
 
@@ -445,9 +462,18 @@ done:
                        rxrpc_reduce_call_timer(call, expect_rx_by, nowj,
                                                rxrpc_timer_set_for_normal);
                }
-       }
 
-       rxrpc_set_keepalive(call);
+               rxrpc_set_keepalive(call);
+       } else {
+               /* Cancel the call if the initial transmission fails,
+                * particularly if that's due to network routing issues that
+                * aren't going away anytime soon.  The layer above can arrange
+                * the retransmission.
+                */
+               if (!test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags))
+                       rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
+                                                 RX_USER_ABORT, ret);
+       }
 
        _leave(" = %d [%u]", ret, call->peer->maxdata);
        return ret;
@@ -506,6 +532,7 @@ send_fragmentable:
        else
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_frag);
+       rxrpc_tx_backoff(call, ret);
 
        up_write(&conn->params.local->defrag_sem);
        goto done;
index 9cb854b..c37e1c2 100644 (file)
@@ -212,7 +212,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
        INIT_LIST_HEAD(&q->retransmit);
        INIT_LIST_HEAD(&q->sacked);
        INIT_LIST_HEAD(&q->abandoned);
-       sctp_sched_set_sched(asoc, SCTP_SS_FCFS);
+       sctp_sched_set_sched(asoc, SCTP_SS_DEFAULT);
 }
 
 /* Free the outqueue structure and any related pending chunks.
index 7f0424d..eab71fc 100644 (file)
@@ -274,6 +274,7 @@ out_err:
 static int
 gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
 {
+       u32 seq_send;
        int tmp;
 
        p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
@@ -315,9 +316,10 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
        p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
        if (IS_ERR(p))
                goto out_err;
-       p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send));
+       p = simple_get_bytes(p, end, &seq_send, sizeof(seq_send));
        if (IS_ERR(p))
                goto out_err;
+       atomic_set(&ctx->seq_send, seq_send);
        p = simple_get_netobj(p, end, &ctx->mech_used);
        if (IS_ERR(p))
                goto out_err;
@@ -607,6 +609,7 @@ static int
 gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
                gfp_t gfp_mask)
 {
+       u64 seq_send64;
        int keylen;
 
        p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
@@ -617,14 +620,15 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
        p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
        if (IS_ERR(p))
                goto out_err;
-       p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64));
+       p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64));
        if (IS_ERR(p))
                goto out_err;
+       atomic64_set(&ctx->seq_send64, seq_send64);
        /* set seq_send for use by "older" enctypes */
-       ctx->seq_send = ctx->seq_send64;
-       if (ctx->seq_send64 != ctx->seq_send) {
-               dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
-                       (unsigned long)ctx->seq_send64, ctx->seq_send);
+       atomic_set(&ctx->seq_send, seq_send64);
+       if (seq_send64 != atomic_read(&ctx->seq_send)) {
+               dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__,
+                       seq_send64, atomic_read(&ctx->seq_send));
                p = ERR_PTR(-EINVAL);
                goto out_err;
        }
index b4adeb0..48fe4a5 100644 (file)
@@ -123,30 +123,6 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
        return krb5_hdr;
 }
 
-u32
-gss_seq_send_fetch_and_inc(struct krb5_ctx *ctx)
-{
-       u32 old, seq_send = READ_ONCE(ctx->seq_send);
-
-       do {
-               old = seq_send;
-               seq_send = cmpxchg(&ctx->seq_send, old, old + 1);
-       } while (old != seq_send);
-       return seq_send;
-}
-
-u64
-gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx)
-{
-       u64 old, seq_send = READ_ONCE(ctx->seq_send);
-
-       do {
-               old = seq_send;
-               seq_send = cmpxchg64(&ctx->seq_send64, old, old + 1);
-       } while (old != seq_send);
-       return seq_send;
-}
-
 static u32
 gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
                struct xdr_netobj *token)
@@ -177,7 +153,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
 
        memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
 
-       seq_send = gss_seq_send_fetch_and_inc(ctx);
+       seq_send = atomic_fetch_inc(&ctx->seq_send);
 
        if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff,
                              seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))
@@ -205,7 +181,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 
        /* Set up the sequence number. Now 64-bits in clear
         * text and w/o direction indicator */
-       seq_send_be64 = cpu_to_be64(gss_seq_send64_fetch_and_inc(ctx));
+       seq_send_be64 = cpu_to_be64(atomic64_fetch_inc(&ctx->seq_send64));
        memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8);
 
        if (ctx->initiate) {
index 962fa84..5cdde6c 100644 (file)
@@ -228,7 +228,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
 
        memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
 
-       seq_send = gss_seq_send_fetch_and_inc(kctx);
+       seq_send = atomic_fetch_inc(&kctx->seq_send);
 
        /* XXX would probably be more efficient to compute checksum
         * and encrypt at the same time: */
@@ -475,7 +475,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
        *be16ptr++ = 0;
 
        be64ptr = (__be64 *)be16ptr;
-       *be64ptr = cpu_to_be64(gss_seq_send64_fetch_and_inc(kctx));
+       *be64ptr = cpu_to_be64(atomic64_fetch_inc(&kctx->seq_send64));
 
        err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages);
        if (err)
index 97f49b7..568575b 100644 (file)
@@ -58,8 +58,8 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                        removefunc = false;
                }
                if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
-                   snd_hda_gen_add_micmute_led(codec,
-                                               update_tpacpi_micmute) > 0)
+                   !snd_hda_gen_add_micmute_led(codec,
+                                                update_tpacpi_micmute))
                        removefunc = false;
        }
 
index 12835ea..378c051 100644 (file)
 #define wmb()          asm volatile("dmb ishst" ::: "memory")
 #define rmb()          asm volatile("dmb ishld" ::: "memory")
 
-#define smp_store_release(p, v)                                        \
-do {                                                           \
-       union { typeof(*p) __val; char __c[1]; } __u =          \
-               { .__val = (__force typeof(*p)) (v) };          \
-                                                               \
-       switch (sizeof(*p)) {                                   \
-       case 1:                                                 \
-               asm volatile ("stlrb %w1, %0"                   \
-                               : "=Q" (*p)                     \
-                               : "r" (*(__u8 *)__u.__c)        \
-                               : "memory");                    \
-               break;                                          \
-       case 2:                                                 \
-               asm volatile ("stlrh %w1, %0"                   \
-                               : "=Q" (*p)                     \
-                               : "r" (*(__u16 *)__u.__c)       \
-                               : "memory");                    \
-               break;                                          \
-       case 4:                                                 \
-               asm volatile ("stlr %w1, %0"                    \
-                               : "=Q" (*p)                     \
-                               : "r" (*(__u32 *)__u.__c)       \
-                               : "memory");                    \
-               break;                                          \
-       case 8:                                                 \
-               asm volatile ("stlr %1, %0"                     \
-                               : "=Q" (*p)                     \
-                               : "r" (*(__u64 *)__u.__c)       \
-                               : "memory");                    \
-               break;                                          \
-       default:                                                \
-               /* Only to shut up gcc ... */                   \
-               mb();                                           \
-               break;                                          \
-       }                                                       \
+#define smp_store_release(p, v)                                                \
+do {                                                                   \
+       union { typeof(*p) __val; char __c[1]; } __u =                  \
+               { .__val = (v) };                                       \
+                                                                       \
+       switch (sizeof(*p)) {                                           \
+       case 1:                                                         \
+               asm volatile ("stlrb %w1, %0"                           \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u8_alias_t *)__u.__c)        \
+                               : "memory");                            \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile ("stlrh %w1, %0"                           \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u16_alias_t *)__u.__c)       \
+                               : "memory");                            \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile ("stlr %w1, %0"                            \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u32_alias_t *)__u.__c)       \
+                               : "memory");                            \
+               break;                                                  \
+       case 8:                                                         \
+               asm volatile ("stlr %1, %0"                             \
+                               : "=Q" (*p)                             \
+                               : "r" (*(__u64_alias_t *)__u.__c)       \
+                               : "memory");                            \
+               break;                                                  \
+       default:                                                        \
+               /* Only to shut up gcc ... */                           \
+               mb();                                                   \
+               break;                                                  \
+       }                                                               \
 } while (0)
 
-#define smp_load_acquire(p)                                    \
-({                                                             \
-       union { typeof(*p) __val; char __c[1]; } __u;           \
-                                                               \
-       switch (sizeof(*p)) {                                   \
-       case 1:                                                 \
-               asm volatile ("ldarb %w0, %1"                   \
-                       : "=r" (*(__u8 *)__u.__c)               \
-                       : "Q" (*p) : "memory");                 \
-               break;                                          \
-       case 2:                                                 \
-               asm volatile ("ldarh %w0, %1"                   \
-                       : "=r" (*(__u16 *)__u.__c)              \
-                       : "Q" (*p) : "memory");                 \
-               break;                                          \
-       case 4:                                                 \
-               asm volatile ("ldar %w0, %1"                    \
-                       : "=r" (*(__u32 *)__u.__c)              \
-                       : "Q" (*p) : "memory");                 \
-               break;                                          \
-       case 8:                                                 \
-               asm volatile ("ldar %0, %1"                     \
-                       : "=r" (*(__u64 *)__u.__c)              \
-                       : "Q" (*p) : "memory");                 \
-               break;                                          \
-       default:                                                \
-               /* Only to shut up gcc ... */                   \
-               mb();                                           \
-               break;                                          \
-       }                                                       \
-       __u.__val;                                              \
+#define smp_load_acquire(p)                                            \
+({                                                                     \
+       union { typeof(*p) __val; char __c[1]; } __u =                  \
+               { .__c = { 0 } };                                       \
+                                                                       \
+       switch (sizeof(*p)) {                                           \
+       case 1:                                                         \
+               asm volatile ("ldarb %w0, %1"                           \
+                       : "=r" (*(__u8_alias_t *)__u.__c)               \
+                       : "Q" (*p) : "memory");                         \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile ("ldarh %w0, %1"                           \
+                       : "=r" (*(__u16_alias_t *)__u.__c)              \
+                       : "Q" (*p) : "memory");                         \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile ("ldar %w0, %1"                            \
+                       : "=r" (*(__u32_alias_t *)__u.__c)              \
+                       : "Q" (*p) : "memory");                         \
+               break;                                                  \
+       case 8:                                                         \
+               asm volatile ("ldar %0, %1"                             \
+                       : "=r" (*(__u64_alias_t *)__u.__c)              \
+                       : "Q" (*p) : "memory");                         \
+               break;                                                  \
+       default:                                                        \
+               /* Only to shut up gcc ... */                           \
+               mb();                                                   \
+               break;                                                  \
+       }                                                               \
+       __u.__val;                                                      \
 })
 
 #endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */
index 236b9b9..667c14e 100644 (file)
@@ -55,7 +55,6 @@ counted. The following modifiers exist:
  S - read sample value (PERF_SAMPLE_READ)
  D - pin the event to the PMU
  W - group is weak and will fallback to non-group if not schedulable,
-     only supported in 'perf stat' for now.
 
 The 'p' modifier can be used for specifying how precise the instruction
 address should be. The 'p' modifier can be specified multiple times:
index 3ccb4f0..d956554 100644 (file)
@@ -387,7 +387,7 @@ SHELL = $(SHELL_PATH)
 
 linux_uapi_dir := $(srctree)/tools/include/uapi/linux
 asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic
-arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/
+arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/
 
 beauty_outdir := $(OUTPUT)trace/beauty/generated
 beauty_ioctl_outdir := $(beauty_outdir)/ioctl
index 10cf889..488779b 100644 (file)
@@ -391,7 +391,12 @@ try_again:
                                        ui__warning("%s\n", msg);
                                goto try_again;
                        }
-
+                       if ((errno == EINVAL || errno == EBADF) &&
+                           pos->leader != pos &&
+                           pos->weak_group) {
+                               pos = perf_evlist__reset_weak_group(evlist, pos);
+                               goto try_again;
+                       }
                        rc = -errno;
                        perf_evsel__open_strerror(pos, &opts->target,
                                                  errno, msg, sizeof(msg));
index d1028d7..a635abf 100644 (file)
@@ -383,32 +383,6 @@ static bool perf_evsel__should_store_id(struct perf_evsel *counter)
        return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID;
 }
 
-static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
-{
-       struct perf_evsel *c2, *leader;
-       bool is_open = true;
-
-       leader = evsel->leader;
-       pr_debug("Weak group for %s/%d failed\n",
-                       leader->name, leader->nr_members);
-
-       /*
-        * for_each_group_member doesn't work here because it doesn't
-        * include the first entry.
-        */
-       evlist__for_each_entry(evsel_list, c2) {
-               if (c2 == evsel)
-                       is_open = false;
-               if (c2->leader == leader) {
-                       if (is_open)
-                               perf_evsel__close(c2);
-                       c2->leader = c2;
-                       c2->nr_members = 0;
-               }
-       }
-       return leader;
-}
-
 static bool is_target_alive(struct target *_target,
                            struct thread_map *threads)
 {
@@ -477,7 +451,7 @@ try_again:
                        if ((errno == EINVAL || errno == EBADF) &&
                            counter->leader != counter &&
                            counter->weak_group) {
-                               counter = perf_evsel__reset_weak_group(counter);
+                               counter = perf_evlist__reset_weak_group(evsel_list, counter);
                                goto try_again;
                        }
 
index b2838de..aa0c73e 100644 (file)
@@ -1429,6 +1429,9 @@ int cmd_top(int argc, const char **argv)
                }
        }
 
+       if (opts->branch_stack && callchain_param.enabled)
+               symbol_conf.show_branchflag_count = true;
+
        sort__mode = SORT_MODE__TOP;
        /* display thread wants entries to be collapsed in a different tree */
        perf_hpp_list.need_collapse = 1;
index dc8a6c4..8356194 100644 (file)
@@ -108,6 +108,7 @@ struct trace {
        } stats;
        unsigned int            max_stack;
        unsigned int            min_stack;
+       bool                    raw_augmented_syscalls;
        bool                    not_ev_qualifier;
        bool                    live;
        bool                    full_time;
@@ -1724,13 +1725,28 @@ static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
        return printed;
 }
 
-static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size)
+static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented)
 {
        void *augmented_args = NULL;
+       /*
+        * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
+        * and there we get all 6 syscall args plus the tracepoint common
+        * fields (sizeof(long)) and the syscall_nr (another long). So we check
+        * if that is the case and if so don't look after the sc->args_size,
+        * but always after the full raw_syscalls:sys_enter payload, which is
+        * fixed.
+        *
+        * We'll revisit this later to pass s->args_size to the BPF augmenter
+        * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
+        * copies only what we need for each syscall, like what happens when we
+        * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
+        * traffic to just what is needed for each syscall.
+        */
+       int args_size = raw_augmented ? (8 * (int)sizeof(long)) : sc->args_size;
 
-       *augmented_args_size = sample->raw_size - sc->args_size;
+       *augmented_args_size = sample->raw_size - args_size;
        if (*augmented_args_size > 0)
-               augmented_args = sample->raw_data + sc->args_size;
+               augmented_args = sample->raw_data + args_size;
 
        return augmented_args;
 }
@@ -1780,7 +1796,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
         * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
         */
        if (evsel != trace->syscalls.events.sys_enter)
-               augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size);
+               augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
        ttrace->entry_time = sample->time;
        msg = ttrace->entry_str;
        printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
@@ -1833,7 +1849,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
                goto out_put;
 
        args = perf_evsel__sc_tp_ptr(evsel, args, sample);
-       augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size);
+       augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
        syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
        fprintf(trace->output, "%s", msg);
        err = 0;
@@ -3501,7 +3517,15 @@ int cmd_trace(int argc, const char **argv)
                evsel->handler = trace__sys_enter;
 
                evlist__for_each_entry(trace.evlist, evsel) {
+                       bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
+
+                       if (raw_syscalls_sys_exit) {
+                               trace.raw_augmented_syscalls = true;
+                               goto init_augmented_syscall_tp;
+                       }
+
                        if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
+init_augmented_syscall_tp:
                                perf_evsel__init_augmented_syscall_tp(evsel);
                                perf_evsel__init_augmented_syscall_tp_ret(evsel);
                                evsel->handler = trace__sys_exit;
diff --git a/tools/perf/examples/bpf/augmented_raw_syscalls.c b/tools/perf/examples/bpf/augmented_raw_syscalls.c
new file mode 100644 (file)
index 0000000..90a1933
--- /dev/null
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Augment the raw_syscalls tracepoints with the contents of the pointer arguments.
+ *
+ * Test it with:
+ *
+ * perf trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c cat /etc/passwd > /dev/null
+ *
+ * This exactly matches what is marshalled into the raw_syscall:sys_enter
+ * payload expected by the 'perf trace' beautifiers.
+ *
+ * For now it just uses the existing tracepoint augmentation code in 'perf
+ * trace', in the next csets we'll hook up these with the sys_enter/sys_exit
+ * code that will combine entry/exit in a strace like way.
+ */
+
+#include <stdio.h>
+#include <linux/socket.h>
+
+/* bpf-output associated map */
+struct bpf_map SEC("maps") __augmented_syscalls__ = {
+       .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+       .key_size = sizeof(int),
+       .value_size = sizeof(u32),
+       .max_entries = __NR_CPUS__,
+};
+
+struct syscall_enter_args {
+       unsigned long long common_tp_fields;
+       long               syscall_nr;
+       unsigned long      args[6];
+};
+
+struct syscall_exit_args {
+       unsigned long long common_tp_fields;
+       long               syscall_nr;
+       long               ret;
+};
+
+struct augmented_filename {
+       unsigned int    size;
+       int             reserved;
+       char            value[256];
+};
+
+#define SYS_OPEN 2
+#define SYS_OPENAT 257
+
+SEC("raw_syscalls:sys_enter")
+int sys_enter(struct syscall_enter_args *args)
+{
+       struct {
+               struct syscall_enter_args args;
+               struct augmented_filename filename;
+       } augmented_args;
+       unsigned int len = sizeof(augmented_args);
+       const void *filename_arg = NULL;
+
+       probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
+       /*
+        * Yonghong and Edward Cree sayz:
+        *
+        * https://www.spinics.net/lists/netdev/msg531645.html
+        *
+        * >>   R0=inv(id=0) R1=inv2 R6=ctx(id=0,off=0,imm=0) R7=inv64 R10=fp0,call_-1
+        * >> 10: (bf) r1 = r6
+        * >> 11: (07) r1 += 16
+        * >> 12: (05) goto pc+2
+        * >> 15: (79) r3 = *(u64 *)(r1 +0)
+        * >> dereference of modified ctx ptr R1 off=16 disallowed
+        * > Aha, we at least got a different error message this time.
+        * > And indeed llvm has done that optimisation, rather than the more obvious
+        * > 11: r3 = *(u64 *)(r1 +16)
+        * > because it wants to have lots of reads share a single insn.  You may be able
+        * > to defeat that optimisation by adding compiler barriers, idk.  Maybe someone
+        * > with llvm knowledge can figure out how to stop it (ideally, llvm would know
+        * > when it's generating for bpf backend and not do that).  -O0?  Â¯\_(ツ)_/¯
+        *
+        * The optimization mostly likes below:
+        *
+        *      br1:
+        *      ...
+        *      r1 += 16
+        *      goto merge
+        *      br2:
+        *      ...
+        *      r1 += 20
+        *      goto merge
+        *      merge:
+        *      *(u64 *)(r1 + 0)
+        *
+        * The compiler tries to merge common loads. There is no easy way to
+        * stop this compiler optimization without turning off a lot of other
+        * optimizations. The easiest way is to add barriers:
+        *
+        *       __asm__ __volatile__("": : :"memory")
+        *
+        *       after the ctx memory access to prevent their down stream merging.
+        */
+       switch (augmented_args.args.syscall_nr) {
+       case SYS_OPEN:   filename_arg = (const void *)args->args[0];
+                       __asm__ __volatile__("": : :"memory");
+                        break;
+       case SYS_OPENAT: filename_arg = (const void *)args->args[1];
+                        break;
+       }
+
+       if (filename_arg != NULL) {
+               augmented_args.filename.reserved = 0;
+               augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
+                                                             sizeof(augmented_args.filename.value),
+                                                             filename_arg);
+               if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
+                       len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
+                       len &= sizeof(augmented_args.filename.value) - 1;
+               }
+       } else {
+               len = sizeof(augmented_args.args);
+       }
+
+       perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
+       return 0;
+}
+
+SEC("raw_syscalls:sys_exit")
+int sys_exit(struct syscall_exit_args *args)
+{
+       return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */
+}
+
+license(GPL);
index ac1bcdc..f7eb63c 100644 (file)
@@ -125,7 +125,7 @@ perf_get_timestamp(void)
 }
 
 static int
-debug_cache_init(void)
+create_jit_cache_dir(void)
 {
        char str[32];
        char *base, *p;
@@ -144,8 +144,13 @@ debug_cache_init(void)
 
        strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
 
-       snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
-
+       ret = snprintf(jit_path, PATH_MAX, "%s/.debug/", base);
+       if (ret >= PATH_MAX) {
+               warnx("jvmti: cannot generate jit cache dir because %s/.debug/"
+                       " is too long, please check the cwd, JITDUMPDIR, and"
+                       " HOME variables", base);
+               return -1;
+       }
        ret = mkdir(jit_path, 0755);
        if (ret == -1) {
                if (errno != EEXIST) {
@@ -154,20 +159,32 @@ debug_cache_init(void)
                }
        }
 
-       snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
+       ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit", base);
+       if (ret >= PATH_MAX) {
+               warnx("jvmti: cannot generate jit cache dir because"
+                       " %s/.debug/jit is too long, please check the cwd,"
+                       " JITDUMPDIR, and HOME variables", base);
+               return -1;
+       }
        ret = mkdir(jit_path, 0755);
        if (ret == -1) {
                if (errno != EEXIST) {
-                       warn("cannot create jit cache dir %s", jit_path);
+                       warn("jvmti: cannot create jit cache dir %s", jit_path);
                        return -1;
                }
        }
 
-       snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
-
+       ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit/%s.XXXXXXXX", base, str);
+       if (ret >= PATH_MAX) {
+               warnx("jvmti: cannot generate jit cache dir because"
+                       " %s/.debug/jit/%s.XXXXXXXX is too long, please check"
+                       " the cwd, JITDUMPDIR, and HOME variables",
+                       base, str);
+               return -1;
+       }
        p = mkdtemp(jit_path);
        if (p != jit_path) {
-               warn("cannot create jit cache dir %s", jit_path);
+               warn("jvmti: cannot create jit cache dir %s", jit_path);
                return -1;
        }
 
@@ -228,7 +245,7 @@ void *jvmti_open(void)
 {
        char dump_path[PATH_MAX];
        struct jitheader header;
-       int fd;
+       int fd, ret;
        FILE *fp;
 
        init_arch_timestamp();
@@ -245,12 +262,22 @@ void *jvmti_open(void)
 
        memset(&header, 0, sizeof(header));
 
-       debug_cache_init();
+       /*
+        * jitdump file dir
+        */
+       if (create_jit_cache_dir() < 0)
+               return NULL;
 
        /*
         * jitdump file name
         */
-       scnprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
+       ret = snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
+       if (ret >= PATH_MAX) {
+               warnx("jvmti: cannot generate jitdump file full path because"
+                       " %s/jit-%i.dump is too long, please check the cwd,"
+                       " JITDUMPDIR, and HOME variables", jit_path, getpid());
+               return NULL;
+       }
 
        fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
        if (fd == -1)
index 24cb0bd..f278ce5 100755 (executable)
@@ -119,6 +119,14 @@ def dsoname(name):
                return "[kernel]"
        return name
 
+def findnth(s, sub, n, offs=0):
+       pos = s.find(sub)
+       if pos < 0:
+               return pos
+       if n <= 1:
+               return offs + pos
+       return findnth(s[pos + 1:], sub, n - 1, offs + pos + 1)
+
 # Percent to one decimal place
 
 def PercentToOneDP(n, d):
@@ -1464,6 +1472,317 @@ class BranchWindow(QMdiSubWindow):
                else:
                        self.find_bar.NotFound()
 
+# Dialog data item converted and validated using a SQL table
+
+class SQLTableDialogDataItem():
+
+       def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):
+               self.glb = glb
+               self.label = label
+               self.placeholder_text = placeholder_text
+               self.table_name = table_name
+               self.match_column = match_column
+               self.column_name1 = column_name1
+               self.column_name2 = column_name2
+               self.parent = parent
+
+               self.value = ""
+
+               self.widget = QLineEdit()
+               self.widget.editingFinished.connect(self.Validate)
+               self.widget.textChanged.connect(self.Invalidate)
+               self.red = False
+               self.error = ""
+               self.validated = True
+
+               self.last_id = 0
+               self.first_time = 0
+               self.last_time = 2 ** 64
+               if self.table_name == "<timeranges>":
+                       query = QSqlQuery(self.glb.db)
+                       QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")
+                       if query.next():
+                               self.last_id = int(query.value(0))
+                               self.last_time = int(query.value(1))
+                       QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")
+                       if query.next():
+                               self.first_time = int(query.value(0))
+                       if placeholder_text:
+                               placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time)
+
+               if placeholder_text:
+                       self.widget.setPlaceholderText(placeholder_text)
+
+       def ValueToIds(self, value):
+               ids = []
+               query = QSqlQuery(self.glb.db)
+               stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'"
+               ret = query.exec_(stmt)
+               if ret:
+                       while query.next():
+                               ids.append(str(query.value(0)))
+               return ids
+
+       def IdBetween(self, query, lower_id, higher_id, order):
+               QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1")
+               if query.next():
+                       return True, int(query.value(0))
+               else:
+                       return False, 0
+
+       def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor):
+               query = QSqlQuery(self.glb.db)
+               while True:
+                       next_id = int((lower_id + higher_id) / 2)
+                       QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
+                       if not query.next():
+                               ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC")
+                               if not ok:
+                                       ok, dbid = self.IdBetween(query, next_id, higher_id, "")
+                                       if not ok:
+                                               return str(higher_id)
+                               next_id = dbid
+                               QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
+                       next_time = int(query.value(0))
+                       if get_floor:
+                               if target_time > next_time:
+                                       lower_id = next_id
+                               else:
+                                       higher_id = next_id
+                               if higher_id <= lower_id + 1:
+                                       return str(higher_id)
+                       else:
+                               if target_time >= next_time:
+                                       lower_id = next_id
+                               else:
+                                       higher_id = next_id
+                               if higher_id <= lower_id + 1:
+                                       return str(lower_id)
+
+       def ConvertRelativeTime(self, val):
+               print "val ", val
+               mult = 1
+               suffix = val[-2:]
+               if suffix == "ms":
+                       mult = 1000000
+               elif suffix == "us":
+                       mult = 1000
+               elif suffix == "ns":
+                       mult = 1
+               else:
+                       return val
+               val = val[:-2].strip()
+               if not self.IsNumber(val):
+                       return val
+               val = int(val) * mult
+               if val >= 0:
+                       val += self.first_time
+               else:
+                       val += self.last_time
+               return str(val)
+
+       def ConvertTimeRange(self, vrange):
+               print "vrange ", vrange
+               if vrange[0] == "":
+                       vrange[0] = str(self.first_time)
+               if vrange[1] == "":
+                       vrange[1] = str(self.last_time)
+               vrange[0] = self.ConvertRelativeTime(vrange[0])
+               vrange[1] = self.ConvertRelativeTime(vrange[1])
+               print "vrange2 ", vrange
+               if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
+                       return False
+               print "ok1"
+               beg_range = max(int(vrange[0]), self.first_time)
+               end_range = min(int(vrange[1]), self.last_time)
+               if beg_range > self.last_time or end_range < self.first_time:
+                       return False
+               print "ok2"
+               vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True)
+               vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False)
+               print "vrange3 ", vrange
+               return True
+
+       def AddTimeRange(self, value, ranges):
+               print "value ", value
+               n = value.count("-")
+               if n == 1:
+                       pass
+               elif n == 2:
+                       if value.split("-")[1].strip() == "":
+                               n = 1
+               elif n == 3:
+                       n = 2
+               else:
+                       return False
+               pos = findnth(value, "-", n)
+               vrange = [value[:pos].strip() ,value[pos+1:].strip()]
+               if self.ConvertTimeRange(vrange):
+                       ranges.append(vrange)
+                       return True
+               return False
+
+       def InvalidValue(self, value):
+               self.value = ""
+               palette = QPalette()
+               palette.setColor(QPalette.Text,Qt.red)
+               self.widget.setPalette(palette)
+               self.red = True
+               self.error = self.label + " invalid value '" + value + "'"
+               self.parent.ShowMessage(self.error)
+
+       def IsNumber(self, value):
+               try:
+                       x = int(value)
+               except:
+                       x = 0
+               return str(x) == value
+
+       def Invalidate(self):
+               self.validated = False
+
+       def Validate(self):
+               input_string = self.widget.text()
+               self.validated = True
+               if self.red:
+                       palette = QPalette()
+                       self.widget.setPalette(palette)
+                       self.red = False
+               if not len(input_string.strip()):
+                       self.error = ""
+                       self.value = ""
+                       return
+               if self.table_name == "<timeranges>":
+                       ranges = []
+                       for value in [x.strip() for x in input_string.split(",")]:
+                               if not self.AddTimeRange(value, ranges):
+                                       return self.InvalidValue(value)
+                       ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
+                       self.value = " OR ".join(ranges)
+               elif self.table_name == "<ranges>":
+                       singles = []
+                       ranges = []
+                       for value in [x.strip() for x in input_string.split(",")]:
+                               if "-" in value:
+                                       vrange = value.split("-")
+                                       if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
+                                               return self.InvalidValue(value)
+                                       ranges.append(vrange)
+                               else:
+                                       if not self.IsNumber(value):
+                                               return self.InvalidValue(value)
+                                       singles.append(value)
+                       ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
+                       if len(singles):
+                               ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")")
+                       self.value = " OR ".join(ranges)
+               elif self.table_name:
+                       all_ids = []
+                       for value in [x.strip() for x in input_string.split(",")]:
+                               ids = self.ValueToIds(value)
+                               if len(ids):
+                                       all_ids.extend(ids)
+                               else:
+                                       return self.InvalidValue(value)
+                       self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"
+                       if self.column_name2:
+                               self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )"
+               else:
+                       self.value = input_string.strip()
+               self.error = ""
+               self.parent.ClearMessage()
+
+       def IsValid(self):
+               if not self.validated:
+                       self.Validate()
+               if len(self.error):
+                       self.parent.ShowMessage(self.error)
+                       return False
+               return True
+
+# Selected branch report creation dialog
+
+class SelectedBranchDialog(QDialog):
+
+       def __init__(self, glb, parent=None):
+               super(SelectedBranchDialog, self).__init__(parent)
+
+               self.glb = glb
+
+               self.name = ""
+               self.where_clause = ""
+
+               self.setWindowTitle("Selected Branches")
+               self.setMinimumWidth(600)
+
+               items = (
+                       ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""),
+                       ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""),
+                       ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""),
+                       ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""),
+                       ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""),
+                       ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""),
+                       ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"),
+                       ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"),
+                       ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""),
+                       )
+               self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items]
+
+               self.grid = QGridLayout()
+
+               for row in xrange(len(self.data_items)):
+                       self.grid.addWidget(QLabel(self.data_items[row].label), row, 0)
+                       self.grid.addWidget(self.data_items[row].widget, row, 1)
+
+               self.status = QLabel()
+
+               self.ok_button = QPushButton("Ok", self)
+               self.ok_button.setDefault(True)
+               self.ok_button.released.connect(self.Ok)
+               self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+
+               self.cancel_button = QPushButton("Cancel", self)
+               self.cancel_button.released.connect(self.reject)
+               self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+
+               self.hbox = QHBoxLayout()
+               #self.hbox.addStretch()
+               self.hbox.addWidget(self.status)
+               self.hbox.addWidget(self.ok_button)
+               self.hbox.addWidget(self.cancel_button)
+
+               self.vbox = QVBoxLayout()
+               self.vbox.addLayout(self.grid)
+               self.vbox.addLayout(self.hbox)
+
+               self.setLayout(self.vbox);
+
+       def Ok(self):
+               self.name = self.data_items[0].value
+               if not self.name:
+                       self.ShowMessage("Report name is required")
+                       return
+               for d in self.data_items:
+                       if not d.IsValid():
+                               return
+               for d in self.data_items[1:]:
+                       if len(d.value):
+                               if len(self.where_clause):
+                                       self.where_clause += " AND "
+                               self.where_clause += d.value
+               if len(self.where_clause):
+                       self.where_clause = " AND ( " + self.where_clause + " ) "
+               else:
+                       self.ShowMessage("No selection")
+                       return
+               self.accept()
+
+       def ShowMessage(self, msg):
+               self.status.setText("<font color=#FF0000>" + msg)
+
+       def ClearMessage(self):
+               self.status.setText("")
+
 # Event list
 
 def GetEventList(db):
@@ -1656,7 +1975,7 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
        def FindDone(self, row):
                self.find_bar.Idle()
                if row >= 0:
-                       self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex()))
+                       self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex())))
                else:
                        self.find_bar.NotFound()
 
@@ -1765,6 +2084,149 @@ class WindowMenu():
        def setActiveSubWindow(self, nr):
                self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1])
 
+# Help text
+
+glb_help_text = """
+<h1>Contents</h1>
+<style>
+p.c1 {
+    text-indent: 40px;
+}
+p.c2 {
+    text-indent: 80px;
+}
+}
+</style>
+<p class=c1><a href=#reports>1. Reports</a></p>
+<p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p>
+<p class=c2><a href=#allbranches>1.2 All branches</a></p>
+<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p>
+<p class=c1><a href=#tables>2. Tables</a></p>
+<h1 id=reports>1. Reports</h1>
+<h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2>
+The result is a GUI window with a tree representing a context-sensitive
+call-graph. Expanding a couple of levels of the tree and adjusting column
+widths to suit will display something like:
+<pre>
+                                         Call Graph: pt_example
+Call Path                          Object      Count   Time(ns)  Time(%)  Branch Count   Branch Count(%)
+v- ls
+    v- 2638:2638
+        v- _start                  ld-2.19.so    1     10074071   100.0         211135            100.0
+          |- unknown               unknown       1        13198     0.1              1              0.0
+          >- _dl_start             ld-2.19.so    1      1400980    13.9          19637              9.3
+          >- _d_linit_internal     ld-2.19.so    1       448152     4.4          11094              5.3
+          v-__libc_start_main@plt  ls            1      8211741    81.5         180397             85.4
+             >- _dl_fixup          ld-2.19.so    1         7607     0.1            108              0.1
+             >- __cxa_atexit       libc-2.19.so  1        11737     0.1             10              0.0
+             >- __libc_csu_init    ls            1        10354     0.1             10              0.0
+             |- _setjmp            libc-2.19.so  1            0     0.0              4              0.0
+             v- main               ls            1      8182043    99.6         180254             99.9
+</pre>
+<h3>Points to note:</h3>
+<ul>
+<li>The top level is a command name (comm)</li>
+<li>The next level is a thread (pid:tid)</li>
+<li>Subsequent levels are functions</li>
+<li>'Count' is the number of calls</li>
+<li>'Time' is the elapsed time until the function returns</li>
+<li>Percentages are relative to the level above</li>
+<li>'Branch Count' is the total number of branches for that function and all functions that it calls
+</ul>
+<h3>Find</h3>
+Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match.
+The pattern matching symbols are ? for any character and * for zero or more characters.
+<h2 id=allbranches>1.2 All branches</h2>
+The All branches report displays all branches in chronological order.
+Not all data is fetched immediately. More records can be fetched using the Fetch bar provided.
+<h3>Disassembly</h3>
+Open a branch to display disassembly. This only works if:
+<ol>
+<li>The disassembler is available. Currently, only Intel XED is supported - see <a href=#xed>Intel XED Setup</a></li>
+<li>The object code is available. Currently, only the perf build ID cache is searched for object code.
+The default directory ~/.debug can be overridden by setting environment variable PERF_BUILDID_DIR.
+One exception is kcore where the DSO long name is used (refer dsos_view on the Tables menu),
+or alternatively, set environment variable PERF_KCORE to the kcore file name.</li>
+</ol>
+<h4 id=xed>Intel XED Setup</h4>
+To use Intel XED, libxed.so must be present.  To build and install libxed.so:
+<pre>
+git clone https://github.com/intelxed/mbuild.git mbuild
+git clone https://github.com/intelxed/xed
+cd xed
+./mfile.py --share
+sudo ./mfile.py --prefix=/usr/local install
+sudo ldconfig
+</pre>
+<h3>Find</h3>
+Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
+Refer to Python documentation for the regular expression syntax.
+All columns are searched, but only currently fetched rows are searched.
+<h2 id=selectedbranches>1.3 Selected branches</h2>
+This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced
+by various selection criteria. A dialog box displays available criteria which are AND'ed together.
+<h3>1.3.1 Time ranges</h3>
+The time ranges hint text shows the total time range. Relative time ranges can also be entered in
+ms, us or ns. Also, negative values are relative to the end of trace.  Examples:
+<pre>
+       81073085947329-81073085958238   From 81073085947329 to 81073085958238
+       100us-200us             From 100us to 200us
+       10ms-                   From 10ms to the end
+       -100ns                  The first 100ns
+       -10ms-                  The last 10ms
+</pre>
+N.B. Due to the granularity of timestamps, there could be no branches in any given time range.
+<h1 id=tables>2. Tables</h1>
+The Tables menu shows all tables and views in the database. Most tables have an associated view
+which displays the information in a more friendly way. Not all data for large tables is fetched
+immediately. More records can be fetched using the Fetch bar provided. Columns can be sorted,
+but that can be slow for large tables.
+<p>There are also tables of database meta-information.
+For SQLite3 databases, the sqlite_master table is included.
+For PostgreSQL databases, information_schema.tables/views/columns are included.
+<h3>Find</h3>
+Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
+Refer to Python documentation for the regular expression syntax.
+All columns are searched, but only currently fetched rows are searched.
+<p>N.B. Results are found in id order, so if the table is re-ordered, find-next and find-previous
+will go to the next/previous result in id order, instead of display order.
+"""
+
+# Help window
+
+class HelpWindow(QMdiSubWindow):
+
+       def __init__(self, glb, parent=None):
+               super(HelpWindow, self).__init__(parent)
+
+               self.text = QTextBrowser()
+               self.text.setHtml(glb_help_text)
+               self.text.setReadOnly(True)
+               self.text.setOpenExternalLinks(True)
+
+               self.setWidget(self.text)
+
+               AddSubWindow(glb.mainwindow.mdi_area, self, "Exported SQL Viewer Help")
+
+# Main window that only displays the help text
+
+class HelpOnlyWindow(QMainWindow):
+
+       def __init__(self, parent=None):
+               super(HelpOnlyWindow, self).__init__(parent)
+
+               self.setMinimumSize(200, 100)
+               self.resize(800, 600)
+               self.setWindowTitle("Exported SQL Viewer Help")
+               self.setWindowIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation))
+
+               self.text = QTextBrowser()
+               self.text.setHtml(glb_help_text)
+               self.text.setReadOnly(True)
+               self.text.setOpenExternalLinks(True)
+
+               self.setCentralWidget(self.text)
+
 # Font resize
 
 def ResizeFont(widget, diff):
@@ -1851,6 +2313,9 @@ class MainWindow(QMainWindow):
 
                self.window_menu = WindowMenu(self.mdi_area, menu)
 
+               help_menu = menu.addMenu("&Help")
+               help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
+
        def Find(self):
                win = self.mdi_area.activeSubWindow()
                if win:
@@ -1888,6 +2353,8 @@ class MainWindow(QMainWindow):
                        if event == "branches":
                                label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
                                reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self))
+                               label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")"
+                               reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self))
 
        def TableMenu(self, tables, menu):
                table_menu = menu.addMenu("&Tables")
@@ -1900,9 +2367,18 @@ class MainWindow(QMainWindow):
        def NewBranchView(self, event_id):
                BranchWindow(self.glb, event_id, "", "", self)
 
+       def NewSelectedBranchView(self, event_id):
+               dialog = SelectedBranchDialog(self.glb, self)
+               ret = dialog.exec_()
+               if ret:
+                       BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self)
+
        def NewTableView(self, table_name):
                TableWindow(self.glb, table_name, self)
 
+       def Help(self):
+               HelpWindow(self.glb, self)
+
 # XED Disassembler
 
 class xed_state_t(Structure):
@@ -1929,7 +2405,12 @@ class XEDInstruction():
 class LibXED():
 
        def __init__(self):
-               self.libxed = CDLL("libxed.so")
+               try:
+                       self.libxed = CDLL("libxed.so")
+               except:
+                       self.libxed = None
+               if not self.libxed:
+                       self.libxed = CDLL("/usr/local/lib/libxed.so")
 
                self.xed_tables_init = self.libxed.xed_tables_init
                self.xed_tables_init.restype = None
@@ -2097,10 +2578,16 @@ class DBRef():
 
 def Main():
        if (len(sys.argv) < 2):
-               print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>"
+               print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}"
                raise Exception("Too few arguments")
 
        dbname = sys.argv[1]
+       if dbname == "--help-only":
+               app = QApplication(sys.argv)
+               mainwindow = HelpOnlyWindow()
+               mainwindow.show()
+               err = app.exec_()
+               sys.exit(err)
 
        is_sqlite3 = False
        try:
index e88e6f9..668d2a9 100644 (file)
@@ -1810,3 +1810,30 @@ void perf_evlist__force_leader(struct perf_evlist *evlist)
                leader->forced_leader = true;
        }
 }
+
+struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
+                                                struct perf_evsel *evsel)
+{
+       struct perf_evsel *c2, *leader;
+       bool is_open = true;
+
+       leader = evsel->leader;
+       pr_debug("Weak group for %s/%d failed\n",
+                       leader->name, leader->nr_members);
+
+       /*
+        * for_each_group_member doesn't work here because it doesn't
+        * include the first entry.
+        */
+       evlist__for_each_entry(evsel_list, c2) {
+               if (c2 == evsel)
+                       is_open = false;
+               if (c2->leader == leader) {
+                       if (is_open)
+                               perf_evsel__close(c2);
+                       c2->leader = c2;
+                       c2->nr_members = 0;
+               }
+       }
+       return leader;
+}
index dc66436..9919eed 100644 (file)
@@ -312,4 +312,7 @@ bool perf_evlist__exclude_kernel(struct perf_evlist *evlist);
 
 void perf_evlist__force_leader(struct perf_evlist *evlist);
 
+struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
+                                                struct perf_evsel *evsel);
+
 #endif /* __PERF_EVLIST_H */
index 6d18705..d37bb15 100644 (file)
@@ -956,7 +956,6 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
                attr->sample_freq    = 0;
                attr->sample_period  = 0;
                attr->write_backward = 0;
-               attr->sample_id_all  = 0;
        }
 
        if (opts->no_samples)
index 58f6a9c..4503f3c 100644 (file)
@@ -1474,6 +1474,8 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
                decoder->have_calc_cyc_to_tsc = false;
                intel_pt_calc_cyc_to_tsc(decoder, true);
        }
+
+       intel_pt_log_to("Setting timestamp", decoder->timestamp);
 }
 
 static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder)
@@ -1514,6 +1516,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
                decoder->timestamp = timestamp;
 
        decoder->timestamp_insn_cnt = 0;
+
+       intel_pt_log_to("Setting timestamp", decoder->timestamp);
 }
 
 /* Walk PSB+ packets when already in sync. */
index e02bc7b..5e64da2 100644 (file)
@@ -31,6 +31,11 @@ static FILE *f;
 static char log_name[MAX_LOG_NAME];
 bool intel_pt_enable_logging;
 
+void *intel_pt_log_fp(void)
+{
+       return f;
+}
+
 void intel_pt_log_enable(void)
 {
        intel_pt_enable_logging = true;
index 45b64f9..cc08493 100644 (file)
@@ -22,6 +22,7 @@
 
 struct intel_pt_pkt;
 
+void *intel_pt_log_fp(void);
 void intel_pt_log_enable(void);
 void intel_pt_log_disable(void);
 void intel_pt_log_set_name(const char *name);
index 86cc9a6..149ff36 100644 (file)
@@ -206,6 +206,16 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf,
        intel_pt_dump(pt, buf, len);
 }
 
+static void intel_pt_log_event(union perf_event *event)
+{
+       FILE *f = intel_pt_log_fp();
+
+       if (!intel_pt_enable_logging || !f)
+               return;
+
+       perf_event__fprintf(event, f);
+}
+
 static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
                                   struct auxtrace_buffer *b)
 {
@@ -2010,9 +2020,9 @@ static int intel_pt_process_event(struct perf_session *session,
                 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
                err = intel_pt_context_switch(pt, event, sample);
 
-       intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n",
-                    perf_event__name(event->header.type), event->header.type,
-                    sample->cpu, sample->time, timestamp);
+       intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ",
+                    event->header.type, sample->cpu, sample->time, timestamp);
+       intel_pt_log_event(event);
 
        return err;
 }
index 7799788..7e49baa 100644 (file)
@@ -773,7 +773,7 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 
                if (!is_arm_pmu_core(name)) {
                        pname = pe->pmu ? pe->pmu : "cpu";
-                       if (strncmp(pname, name, strlen(pname)))
+                       if (strcmp(pname, name))
                                continue;
                }