Merge tag 'kbuild-v4.21-3' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 Jan 2019 00:33:10 +0000 (16:33 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 Jan 2019 00:33:10 +0000 (16:33 -0800)
Pull more Kbuild updates from Masahiro Yamada:

 - improve boolinit.cocci and use_after_iter.cocci semantic patches

 - fix alignment for kallsyms

 - move 'asm goto' compiler test to Kconfig and clean up jump_label
   CONFIG option

 - generate asm-generic wrappers automatically if arch does not
   implement mandatory UAPI headers

 - remove redundant generic-y defines

 - misc cleanups

* tag 'kbuild-v4.21-3' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild:
  kconfig: rename generated .*conf-cfg to *conf-cfg
  kbuild: remove unnecessary stubs for archheader and archscripts
  kbuild: use assignment instead of define ... endef for filechk_* rules
  arch: remove redundant UAPI generic-y defines
  kbuild: generate asm-generic wrappers if mandatory headers are missing
  arch: remove stale comments "UAPI Header export list"
  riscv: remove redundant kernel-space generic-y
  kbuild: change filechk to surround the given command with { }
  kbuild: remove redundant target cleaning on failure
  kbuild: clean up rule_dtc_dt_yaml
  kbuild: remove UIMAGE_IN and UIMAGE_OUT
  jump_label: move 'asm goto' support test to Kconfig
  kallsyms: lower alignment on ARM
  scripts: coccinelle: boolinit: drop warnings on named constants
  scripts: coccinelle: check for redeclaration
  kconfig: remove unused "file" field of yylval union
  nds32: remove redundant kernel-space generic-y
  nios2: remove unneeded HAS_DMA define

218 files changed:
CREDITS
Documentation/admin-guide/reporting-bugs.rst
Documentation/core-api/kernel-api.rst
Documentation/devicetree/bindings/eeprom/at24.txt
Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-at91.txt
Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
Documentation/devicetree/bindings/i2c/i2c-owl.txt
Documentation/devicetree/bindings/i2c/i2c-rcar.txt
Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
Documentation/devicetree/bindings/i2c/i2c-stm32.txt
Documentation/devicetree/bindings/i2c/nxp,pca9541.txt
Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
Documentation/devicetree/bindings/pci/mediatek-pcie.txt
Documentation/devicetree/bindings/pci/uniphier-pcie.txt [new file with mode: 0644]
Documentation/driver-api/pci/p2pdma.rst
Documentation/driver-model/devres.txt
Documentation/filesystems/dax.txt
Documentation/filesystems/ext2.txt
Documentation/filesystems/fscrypt.rst
Documentation/hid/uhid.txt
Documentation/input/event-codes.rst
MAINTAINERS
arch/alpha/include/asm/uaccess.h
arch/arm/boot/dts/mt7623.dtsi
arch/arm64/boot/dts/mediatek/mt7622.dtsi
arch/s390/pci/pci.c
arch/sh/include/asm/uaccess.h
arch/x86/kernel/amd_gart_64.c
arch/x86/pci/broadcom_bus.c
drivers/block/sunvdc.c
drivers/firewire/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h
drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c
drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
drivers/gpu/drm/amd/amdgpu/soc15_common.h
drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdkfd/kfd_chardev.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/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc_helper.c
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
drivers/gpu/drm/amd/display/include/bios_parser_types.h
drivers/gpu/drm/amd/display/include/dal_types.h
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/drm_atomic_state_helper.c
drivers/gpu/drm/drm_damage_helper.c
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/gvt/gvt.c
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/interrupt.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/ttm/ttm_bo.c
drivers/hid/hid-asus.c
drivers/hid/hid-core.c
drivers/hid/hid-cougar.c
drivers/hid/hid-debug.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lenovo.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hidraw.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/intel-ish-hid/ishtp-hid.c
drivers/hwspinlock/Kconfig
drivers/hwspinlock/Makefile
drivers/hwspinlock/stm32_hwspinlock.c [new file with mode: 0644]
drivers/i2c/busses/i2c-axxia.c
drivers/i2c/busses/i2c-bcm2835.c
drivers/i2c/busses/i2c-cros-ec-tunnel.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-owl.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-stm32f7.c
drivers/i2c/busses/i2c-tegra.c
drivers/infiniband/core/device.c
drivers/infiniband/hw/bnxt_re/qplib_sp.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/qedr/qedr_iw_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/md/md.c
drivers/md/raid10.c
drivers/misc/eeprom/Kconfig
drivers/misc/eeprom/at24.c
drivers/pci/Kconfig
drivers/pci/controller/dwc/Kconfig
drivers/pci/controller/dwc/Makefile
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pci-layerscape.c
drivers/pci/controller/dwc/pci-meson.c [new file with mode: 0644]
drivers/pci/controller/dwc/pcie-armada8k.c
drivers/pci/controller/dwc/pcie-designware-ep.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-designware.h
drivers/pci/controller/dwc/pcie-histb.c
drivers/pci/controller/dwc/pcie-uniphier.c [new file with mode: 0644]
drivers/pci/controller/pcie-mediatek.c
drivers/pci/iov.c
drivers/pci/p2pdma.c
drivers/pci/pci-driver.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv.h
drivers/pci/quirks.c
drivers/pci/switch/switchtec.c
drivers/platform/chrome/cros_ec_proto.c
drivers/usb/dwc3/dwc3-haps.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/clps711x-fb.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/fbsysfs.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/omap2/omapfb/dss/core.c
drivers/video/fbdev/pxa168fb.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/udlfb.c
drivers/video/fbdev/uvesafb.c
drivers/video/logo/Kconfig
fs/crypto/crypto.c
fs/crypto/fname.c
fs/crypto/fscrypt_private.h
fs/crypto/keyinfo.c
fs/crypto/policy.c
fs/ext4/fsync.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/super.c
include/linux/dma-debug.h
include/linux/dma-mapping.h
include/linux/fb.h
include/linux/hid.h
include/linux/mfd/cros_ec.h
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/raid/pq.h
include/linux/switchtec.h
include/uapi/linux/fb.h
include/uapi/linux/fs.h
include/uapi/linux/input-event-codes.h
kernel/dma/coherent.c
kernel/dma/debug.c
kernel/dma/mapping.c
kernel/dma/remap.c
lib/Kconfig
lib/raid6/algos.c
lib/raid6/test/Makefile
mm/mincore.c
samples/hidraw/hid-example.c
samples/livepatch/livepatch-shadow-fix1.c
samples/livepatch/livepatch-shadow-mod.c
tools/build/Makefile.feature
tools/build/feature/Makefile
tools/gpio/Makefile
tools/include/uapi/linux/usbdevice_fs.h [new file with mode: 0644]
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/builtin-c2c.c
tools/perf/builtin-script.c
tools/perf/builtin-trace.c
tools/perf/check-headers.sh
tools/perf/trace/beauty/beauty.h
tools/perf/trace/beauty/ioctl.c
tools/perf/trace/beauty/mmap.c
tools/perf/trace/beauty/seccomp.c
tools/perf/trace/beauty/usbdevfs_ioctl.sh [new file with mode: 0755]
tools/perf/util/dump-insn.c
tools/perf/util/dump-insn.h
tools/perf/util/intel-bts.c
tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
tools/perf/util/intel-pt.c
tools/perf/util/python.c
tools/perf/util/session.c
tools/perf/util/thread-stack.c
tools/perf/util/thread-stack.h
tools/power/x86/turbostat/Makefile
tools/power/x86/x86_energy_perf_policy/Makefile
tools/thermal/tmon/Makefile

diff --git a/CREDITS b/CREDITS
index 7d397ee675242954fa00269477522cdfdd885068..e818eb6a3e71a485ad709a7e351dee9d763f35df 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2208,6 +2208,12 @@ N: Christopher Li
 E: sparse@chrisli.org
 D: Sparse maintainer 2009 - 2018
 
+N: Shaohua Li
+D: Worked on many parts of the kernel, from core x86, ACPI, PCI, KVM, MM,
+D: and much more. He was the maintainer of MD from 2016 to 2018. Shaohua
+D: passed away late 2018, he will be greatly missed.
+W: https://www.spinics.net/lists/raid/msg61993.html
+
 N: Stephan Linz
 E: linz@mazet.de
 E: Stephan.Linz@gmx.de
index 4650edb8840a96b7a6bda742b466e039b9a0dd41..49ac8dc3594d66dbcbc604b7e5b3608b610814be 100644 (file)
@@ -67,7 +67,7 @@ If you can't figure out which subsystem caused the issue, you should file
 a bug in kernel.org bugzilla and send email to
 linux-kernel@vger.kernel.org, referencing the bugzilla URL.  (For more
 information on the linux-kernel mailing list see
-http://www.tux.org/lkml/).
+http://vger.kernel.org/lkml/).
 
 
 Tips for reporting bugs
index 3431337ee4e62909fa03722de7d346c4d2a79c9f..cdd24943fbcc3119e4105191786023ac1c47c969 100644 (file)
@@ -291,12 +291,6 @@ Block Devices
 .. kernel-doc:: block/blk-lib.c
    :export:
 
-.. kernel-doc:: block/blk-tag.c
-   :export:
-
-.. kernel-doc:: block/blk-tag.c
-   :internal:
-
 .. kernel-doc:: block/blk-integrity.c
    :export:
 
index aededdbc262b241304a0651be8d418c061f89e05..f9a7c984274ce739c392a3af08c0775199d6e32e 100644 (file)
@@ -27,6 +27,7 @@ Required properties:
                 "atmel,24c256",
                 "atmel,24c512",
                 "atmel,24c1024",
+                "atmel,24c2048",
 
                 If <manufacturer> is not "atmel", then a fallback must be used
                 with the same <model> and "atmel" as manufacturer.
diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt
new file mode 100644 (file)
index 0000000..adf4f00
--- /dev/null
@@ -0,0 +1,23 @@
+STM32 Hardware Spinlock Device Binding
+-------------------------------------
+
+Required properties :
+- compatible : should be "st,stm32-hwspinlock".
+- reg : the register address of hwspinlock.
+- #hwlock-cells : hwlock users only use the hwlock id to represent a specific
+       hwlock, so the number of cells should be <1> here.
+- clock-names : Must contain "hsem".
+- clocks : Must contain a phandle entry for the clock in clock-names, see the
+       common clock bindings.
+
+Please look at the generic hwlock binding for usage information for consumers,
+"Documentation/devicetree/bindings/hwlock/hwlock.txt"
+
+Example of hwlock provider:
+       hwspinlock@4c000000 {
+               compatible = "st,stm32-hwspinlock";
+               #hwlock-cells = <1>;
+               reg = <0x4c000000 0x400>;
+               clocks = <&rcc HSEM>;
+               clock-names = "hsem";
+       };
index ef973a0343c7b48a95cd18c3cc44b48b0ae08e62..b7cec17c3daf2b91fbb8afcbc303f60482fa8503 100644 (file)
@@ -33,7 +33,7 @@ i2c0: i2c@fff84000 {
        clock-frequency = <400000>;
 
        24c512@50 {
-               compatible = "24c512";
+               compatible = "atmel,24c512";
                reg = <0x50>;
                pagesize = <128>;
        }
index 1e98c6b3a721bfe6b92386678027a38641865ab8..8b1e49cdce3f9b2a3f2df640489314710e51e618 100644 (file)
@@ -43,7 +43,7 @@ Example:
                        reg = <0>;
 
                        eeprom@50 {
-                               compatible = "at,24c02";
+                               compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
                };
@@ -54,7 +54,7 @@ Example:
                        reg = <1>;
 
                        eeprom@50 {
-                               compatible = "at,24c02";
+                               compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
                };
index ccf6c86ed076dd843e7cac6f7459b2e520f73054..30ac6a60f041952719310cac6097870478ce0c3b 100644 (file)
@@ -54,7 +54,7 @@ Example:
                        reg = <2>;
 
                        eeprom@54 {
-                               compatible = "at,24c08";
+                               compatible = "atmel,24c08";
                                reg = <0x54>;
                        };
                };
index b743fe444e9f6096e2f16ca74bdb5386c8e0e1ec..54c05dbdb2e47d31ce3a0de1263519592131d5cc 100644 (file)
@@ -2,7 +2,9 @@ Actions Semiconductor Owl I2C controller
 
 Required properties:
 
-- compatible        : Should be "actions,s900-i2c".
+- compatible        : Should be one of the following:
+                     - "actions,s700-i2c" for S700 SoC
+                     - "actions,s900-i2c" for S900 SoC
 - reg               : Offset and length of the register set for the device.
 - #address-cells    : Should be 1.
 - #size-cells       : Should be 0.
index 30c0485b167b4d9db9a240423d04ab004005ab91..3ee5e8f6ee013987bf95640964da7a11fea060fe 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
        "renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
        "renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
        "renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
+       "renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
        "renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
        "renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
        "renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
index d81b626436550e48129bb964bda0c141be99e1ee..202602e6e837ffc12660064c57b4417cc4a13931 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
                        - "renesas,iic-r8a7744" (RZ/G1N)
                        - "renesas,iic-r8a7745" (RZ/G1E)
                        - "renesas,iic-r8a774a1" (RZ/G2M)
+                       - "renesas,iic-r8a774c0" (RZ/G2E)
                        - "renesas,iic-r8a7790" (R-Car H2)
                        - "renesas,iic-r8a7791" (R-Car M2-W)
                        - "renesas,iic-r8a7792" (R-Car V2H)
@@ -16,6 +17,7 @@ Required properties:
                        - "renesas,iic-r8a7795" (R-Car H3)
                        - "renesas,iic-r8a7796" (R-Car M3-W)
                        - "renesas,iic-r8a77965" (R-Car M3-N)
+                       - "renesas,iic-r8a77990" (R-Car E3)
                        - "renesas,iic-sh73a0" (SH-Mobile AG5)
                        - "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
                                                        compatible device)
@@ -28,7 +30,13 @@ Required properties:
                        the platform first followed by the generic R-Car
                        version.
 
-                       renesas,rmobile-iic must always follow.
+                       When compatible with "renesas,rmobile-iic" it should
+                       be the last compatibility string listed.
+
+                       The r8a77990 (R-Car E3) and r8a774c0 (RZ/G2E)
+                       controllers are not considered compatible with
+                       "renesas,rcar-gen3-iic" or "renesas,rmobile-iic"
+                       due to the absence of automatic transmission registers.
 
 - reg             : address start and address range size of device
 - interrupts      : interrupt of device
index 3b54899666342b8e5a114bc0842e193871139d5e..69240e189b01e61d44e2d588aab0e8fe3db579fa 100644 (file)
@@ -26,6 +26,11 @@ Optional properties :
 - i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board
   (default: 10)
   I2C Timings are derived from these 2 values
+- st,syscfg-fmp:  Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG
+  whether Fast Mode Plus speed is selected by slave.
+       1st cell : phandle to syscfg
+       2nd cell : register offset within SYSCFG
+       3rd cell : register bitmask for FMP bit
 
 Example :
 
@@ -53,4 +58,5 @@ Example :
                clocks = <&rcc 1 CLK_I2C1>;
                pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
                pinctrl-names = "default";
+               st,syscfg-fmp = <&syscfg 0x4 0x1>;
        };
index 0fbbc6970ec524fcacd68ab29b77473e7183ec54..42bfc09c8918dfcf5800fba7d03bc2360257fd72 100644 (file)
@@ -22,7 +22,7 @@ Example:
                        #size-cells = <0>;
 
                        eeprom@54 {
-                               compatible = "at,24c08";
+                               compatible = "atmel,24c08";
                                reg = <0x54>;
                        };
                };
diff --git a/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt b/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
new file mode 100644 (file)
index 0000000..12b18f8
--- /dev/null
@@ -0,0 +1,70 @@
+Amlogic Meson AXG DWC PCIE SoC controller
+
+Amlogic Meson PCIe host controller is based on the Synopsys DesignWare PCI core.
+It shares common functions with the PCIe DesignWare core driver and
+inherits common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt.
+
+Additional properties are described here:
+
+Required properties:
+- compatible:
+       should contain "amlogic,axg-pcie" to identify the core.
+- reg:
+       should contain the configuration address space.
+- reg-names: Must be
+       - "elbi"        External local bus interface registers
+       - "cfg"         Meson specific registers
+       - "phy"         Meson PCIE PHY registers
+       - "config"      PCIe configuration space
+- reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Must include the following entries:
+       - "pclk"       PCIe GEN 100M PLL clock
+       - "port"       PCIe_x(A or B) RC clock gate
+       - "general"    PCIe Phy clock
+       - "mipi"       PCIe_x(A or B) 100M ref clock gate
+- resets: phandle to the reset lines.
+- reset-names: must contain "phy" "port" and "apb"
+       - "phy"         Share PHY reset
+       - "port"        Port A or B reset
+       - "apb"         Share APB reset
+- device_type:
+       should be "pci". As specified in designware-pcie.txt
+
+
+Example configuration:
+
+       pcie: pcie@f9800000 {
+                       compatible = "amlogic,axg-pcie", "snps,dw-pcie";
+                       reg = <0x0 0xf9800000 0x0 0x400000
+                                       0x0 0xff646000 0x0 0x2000
+                                       0x0 0xff644000 0x0 0x2000
+                                       0x0 0xf9f00000 0x0 0x100000>;
+                       reg-names = "elbi", "cfg", "phy", "config";
+                       reset-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
+                       interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 179 IRQ_TYPE_EDGE_RISING>;
+                       bus-range = <0x0 0xff>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       ranges = <0x82000000 0 0 0x0 0xf9c00000 0 0x00300000>;
+
+                       clocks = <&clkc CLKID_USB
+                                       &clkc CLKID_MIPI_ENABLE
+                                       &clkc CLKID_PCIE_A
+                                       &clkc CLKID_PCIE_CML_EN0>;
+                       clock-names = "general",
+                                       "mipi",
+                                       "pclk",
+                                       "port";
+                       resets = <&reset RESET_PCIE_PHY>,
+                               <&reset RESET_PCIE_A>,
+                               <&reset RESET_PCIE_APB>;
+                       reset-names = "phy",
+                                       "port",
+                                       "apb";
+       };
index f37494d5a7bed50069a9aef7e646661da0c59e12..d514c1f2365f59ab04c586b4cd69f52349c80cbe 100644 (file)
@@ -41,7 +41,9 @@ Optional properties:
 Additional required properties for imx6sx-pcie:
 - clock names: Must include the following additional entries:
        - "pcie_inbound_axi"
-- power-domains: Must be set to a phandle pointing to the PCIE_PHY power domain
+- power-domains: Must be set to phandles pointing to the DISPLAY and
+  PCIE_PHY power domains
+- power-domain-names: Must be "pcie", "pcie_phy"
 
 Additional required properties for imx7d-pcie:
 - power-domains: Must be set to a phandle pointing to PCIE_PHY power domain
index 20227a875ac8f253adf2e91b5d795bf5db793bf5..92437a366e5f651224d0fa672738874f3e3e45a9 100644 (file)
@@ -65,7 +65,6 @@ Required properties:
   explanation.
 - ranges: Sub-ranges distributed from the PCIe controller node. An empty
   property is sufficient.
-- num-lanes: Number of lanes to use for this port.
 
 Examples for MT7623:
 
@@ -118,7 +117,6 @@ Examples for MT7623:
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                };
 
                pcie@1,0 {
@@ -129,7 +127,6 @@ Examples for MT7623:
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                };
 
                pcie@2,0 {
@@ -140,7 +137,6 @@ Examples for MT7623:
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                };
        };
 
@@ -172,7 +168,6 @@ Examples for MT2712:
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc0 0>,
                                        <0 0 0 2 &pcie_intc0 1>,
@@ -191,7 +186,6 @@ Examples for MT2712:
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc1 0>,
                                        <0 0 0 2 &pcie_intc1 1>,
@@ -245,7 +239,6 @@ Examples for MT7622:
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc0 0>,
                                        <0 0 0 2 &pcie_intc0 1>,
@@ -264,7 +257,6 @@ Examples for MT7622:
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc1 0>,
                                        <0 0 0 2 &pcie_intc1 1>,
diff --git a/Documentation/devicetree/bindings/pci/uniphier-pcie.txt b/Documentation/devicetree/bindings/pci/uniphier-pcie.txt
new file mode 100644 (file)
index 0000000..1fa2c59
--- /dev/null
@@ -0,0 +1,81 @@
+Socionext UniPhier PCIe host controller bindings
+
+This describes the devicetree bindings for PCIe host controller implemented
+on Socionext UniPhier SoCs.
+
+UniPhier PCIe host controller is based on the Synopsys DesignWare PCI core.
+It shares common functions with the PCIe DesignWare core driver and inherits
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pcie.txt.
+
+Required properties:
+- compatible: Should be "socionext,uniphier-pcie".
+- reg: Specifies offset and length of the register set for the device.
+       According to the reg-names, appropriate register sets are required.
+- reg-names: Must include the following entries:
+    "dbi"    - controller configuration registers
+    "link"   - SoC-specific glue layer registers
+    "config" - PCIe configuration space
+- clocks: A phandle to the clock gate for PCIe glue layer including
+       the host controller.
+- resets: A phandle to the reset line for PCIe glue layer including
+       the host controller.
+- interrupts: A list of interrupt specifiers. According to the
+       interrupt-names, appropriate interrupts are required.
+- interrupt-names: Must include the following entries:
+    "dma" - DMA interrupt
+    "msi" - MSI interrupt
+
+Optional properties:
+- phys: A phandle to generic PCIe PHY. According to the phy-names, appropriate
+       phys are required.
+- phy-names: Must be "pcie-phy".
+
+Required sub-node:
+- legacy-interrupt-controller: Specifies interrupt controller for legacy PCI
+       interrupts.
+
+Required properties for legacy-interrupt-controller:
+- interrupt-controller: identifies the node as an interrupt controller.
+- #interrupt-cells: specifies the number of cells needed to encode an
+       interrupt source. The value must be 1.
+- interrupt-parent: Phandle to the parent interrupt controller.
+- interrupts: An interrupt specifier for legacy interrupt.
+
+Example:
+
+       pcie: pcie@66000000 {
+               compatible = "socionext,uniphier-pcie", "snps,dw-pcie";
+               status = "disabled";
+               reg-names = "dbi", "link", "config";
+               reg = <0x66000000 0x1000>, <0x66010000 0x10000>,
+                     <0x2fff0000 0x10000>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               clocks = <&sys_clk 24>;
+               resets = <&sys_rst 24>;
+               num-lanes = <1>;
+               num-viewport = <1>;
+               bus-range = <0x0 0xff>;
+               device_type = "pci";
+               ranges =
+               /* downstream I/O */
+                       <0x81000000 0 0x00000000  0x2ffe0000  0 0x00010000
+               /* non-prefetchable memory */
+                        0x82000000 0 0x00000000  0x20000000  0 0x0ffe0000>;
+               #interrupt-cells = <1>;
+               interrupt-names = "dma", "msi";
+               interrupts = <0 224 4>, <0 225 4>;
+               interrupt-map-mask = <0 0 0  7>;
+               interrupt-map = <0 0 0  1  &pcie_intc 0>,       /* INTA */
+                               <0 0 0  2  &pcie_intc 1>,       /* INTB */
+                               <0 0 0  3  &pcie_intc 2>,       /* INTC */
+                               <0 0 0  4  &pcie_intc 3>;       /* INTD */
+
+               pcie_intc: legacy-interrupt-controller {
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 226 4>;
+               };
+       };
index 4c577fa7bef9176edb173e97f3297dc1957f0912..6d85b5a2598db0fc1f957fe77fe6ebff42030560 100644 (file)
@@ -49,7 +49,7 @@ For example, in the NVMe Target Copy Offload implementation:
   in that it exposes any CMB (Controller Memory Buffer) as a P2P memory
   resource (provider), it accepts P2P memory pages as buffers in requests
   to be used directly (client) and it can also make use of the CMB as
-  submission queue entries (orchastrator).
+  submission queue entries (orchestrator).
 * The RDMA driver is a client in this arrangement so that an RNIC
   can DMA directly to the memory exposed by the NVMe device.
 * The NVMe Target driver (nvmet) can orchestrate the data from the RNIC
@@ -111,7 +111,7 @@ that's compatible with all clients using  :c:func:`pci_p2pmem_find()`.
 If more than one provider is supported, the one nearest to all the clients will
 be chosen first. If more than one provider is an equal distance away, the
 one returned will be chosen at random (it is not an arbitrary but
-truely random). This function returns the PCI device to use for the provider
+truly random). This function returns the PCI device to use for the provider
 with a reference taken and therefore when it's no longer needed it should be
 returned with pci_dev_put().
 
index 841c99529d2717c7b08149bab847d893af9b8291..b277cafce71eb25effa455c90f3c24d14430856d 100644 (file)
@@ -250,7 +250,6 @@ DMA
   dmaenginem_async_device_register()
   dmam_alloc_coherent()
   dmam_alloc_attrs()
-  dmam_declare_coherent_memory()
   dmam_free_coherent()
   dmam_pool_create()
   dmam_pool_destroy()
index bc393e0a22b82b490eae1f273e09af30f82ff821..6d2c0d340deaf576949939a7324c7cd5e7de4dcf 100644 (file)
@@ -75,7 +75,7 @@ exposure of uninitialized data through mmap.
 
 These filesystems may be used for inspiration:
 - ext2: see Documentation/filesystems/ext2.txt
-- ext4: see Documentation/filesystems/ext4/ext4.rst
+- ext4: see Documentation/filesystems/ext4/
 - xfs:  see Documentation/filesystems/xfs.txt
 
 
index a45c9fc0747b1c51fb5857afee9d781fedf13dbe..a19973a4dd1e89fa9f3a6381b6a33945e39ef111 100644 (file)
@@ -358,7 +358,7 @@ and are copied into the filesystem.  If a transaction is incomplete at
 the time of the crash, then there is no guarantee of consistency for
 the blocks in that transaction so they are discarded (which means any
 filesystem changes they represent are also lost).
-Check Documentation/filesystems/ext4/ext4.rst if you want to read more about
+Check Documentation/filesystems/ext4/ if you want to read more about
 ext4 and journaling.
 
 References
index cfbc18f0d9c985a16f6ff9dcd665f6e8d017a067..3a7b60521b94ab38654dcbaa8380a8a5bcc9d85e 100644 (file)
@@ -132,47 +132,28 @@ designed for this purpose be used, such as scrypt, PBKDF2, or Argon2.
 Per-file keys
 -------------
 
-Master keys are not used to encrypt file contents or names directly.
-Instead, a unique key is derived for each encrypted file, including
-each regular file, directory, and symbolic link.  This has several
-advantages:
-
-- In cryptosystems, the same key material should never be used for
-  different purposes.  Using the master key as both an XTS key for
-  contents encryption and as a CTS-CBC key for filenames encryption
-  would violate this rule.
-- Per-file keys simplify the choice of IVs (Initialization Vectors)
-  for contents encryption.  Without per-file keys, to ensure IV
-  uniqueness both the inode and logical block number would need to be
-  encoded in the IVs.  This would make it impossible to renumber
-  inodes, which e.g. ``resize2fs`` can do when resizing an ext4
-  filesystem.  With per-file keys, it is sufficient to encode just the
-  logical block number in the IVs.
-- Per-file keys strengthen the encryption of filenames, where IVs are
-  reused out of necessity.  With a unique key per directory, IV reuse
-  is limited to within a single directory.
-- Per-file keys allow individual files to be securely erased simply by
-  securely erasing their keys.  (Not yet implemented.)
-
-A KDF (Key Derivation Function) is used to derive per-file keys from
-the master key.  This is done instead of wrapping a randomly-generated
-key for each file because it reduces the size of the encryption xattr,
-which for some filesystems makes the xattr more likely to fit in-line
-in the filesystem's inode table.  With a KDF, only a 16-byte nonce is
-required --- long enough to make key reuse extremely unlikely.  A
-wrapped key, on the other hand, would need to be up to 64 bytes ---
-the length of an AES-256-XTS key.  Furthermore, currently there is no
-requirement to support unlocking a file with multiple alternative
-master keys or to support rotating master keys.  Instead, the master
-keys may be wrapped in userspace, e.g. as done by the `fscrypt
-<https://github.com/google/fscrypt>`_ tool.
-
-The current KDF encrypts the master key using the 16-byte nonce as an
-AES-128-ECB key.  The output is used as the derived key.  If the
-output is longer than needed, then it is truncated to the needed
-length.  Truncation is the norm for directories and symlinks, since
-those use the CTS-CBC encryption mode which requires a key half as
-long as that required by the XTS encryption mode.
+Since each master key can protect many files, it is necessary to
+"tweak" the encryption of each file so that the same plaintext in two
+files doesn't map to the same ciphertext, or vice versa.  In most
+cases, fscrypt does this by deriving per-file keys.  When a new
+encrypted inode (regular file, directory, or symlink) is created,
+fscrypt randomly generates a 16-byte nonce and stores it in the
+inode's encryption xattr.  Then, it uses a KDF (Key Derivation
+Function) to derive the file's key from the master key and nonce.
+
+The Adiantum encryption mode (see `Encryption modes and usage`_) is
+special, since it accepts longer IVs and is suitable for both contents
+and filenames encryption.  For it, a "direct key" option is offered
+where the file's nonce is included in the IVs and the master key is
+used for encryption directly.  This improves performance; however,
+users must not use the same master key for any other encryption mode.
+
+Below, the KDF and design considerations are described in more detail.
+
+The current KDF works by encrypting the master key with AES-128-ECB,
+using the file's nonce as the AES key.  The output is used as the
+derived key.  If the output is longer than needed, then it is
+truncated to the needed length.
 
 Note: this KDF meets the primary security requirement, which is to
 produce unique derived keys that preserve the entropy of the master
@@ -181,6 +162,20 @@ However, it is nonstandard and has some problems such as being
 reversible, so it is generally considered to be a mistake!  It may be
 replaced with HKDF or another more standard KDF in the future.
 
+Key derivation was chosen over key wrapping because wrapped keys would
+require larger xattrs which would be less likely to fit in-line in the
+filesystem's inode table, and there didn't appear to be any
+significant advantages to key wrapping.  In particular, currently
+there is no requirement to support unlocking a file with multiple
+alternative master keys or to support rotating master keys.  Instead,
+the master keys may be wrapped in userspace, e.g. as is done by the
+`fscrypt <https://github.com/google/fscrypt>`_ tool.
+
+Including the inode number in the IVs was considered.  However, it was
+rejected as it would have prevented ext4 filesystems from being
+resized, and by itself still wouldn't have been sufficient to prevent
+the same key from being directly reused for both XTS and CTS-CBC.
+
 Encryption modes and usage
 ==========================
 
@@ -191,54 +186,80 @@ Currently, the following pairs of encryption modes are supported:
 
 - AES-256-XTS for contents and AES-256-CTS-CBC for filenames
 - AES-128-CBC for contents and AES-128-CTS-CBC for filenames
+- Adiantum for both contents and filenames
+
+If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
 
-It is strongly recommended to use AES-256-XTS for contents encryption.
 AES-128-CBC was added only for low-powered embedded devices with
 crypto accelerators such as CAAM or CESA that do not support XTS.
 
+Adiantum is a (primarily) stream cipher-based mode that is fast even
+on CPUs without dedicated crypto instructions.  It's also a true
+wide-block mode, unlike XTS.  It can also eliminate the need to derive
+per-file keys.  However, it depends on the security of two primitives,
+XChaCha12 and AES-256, rather than just one.  See the paper
+"Adiantum: length-preserving encryption for entry-level processors"
+(https://eprint.iacr.org/2018/720.pdf) for more details.  To use
+Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled.  Also, fast
+implementations of ChaCha and NHPoly1305 should be enabled, e.g.
+CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM.
+
 New encryption modes can be added relatively easily, without changes
 to individual filesystems.  However, authenticated encryption (AE)
 modes are not currently supported because of the difficulty of dealing
 with ciphertext expansion.
 
+Contents encryption
+-------------------
+
 For file contents, each filesystem block is encrypted independently.
 Currently, only the case where the filesystem block size is equal to
-the system's page size (usually 4096 bytes) is supported.  With the
-XTS mode of operation (recommended), the logical block number within
-the file is used as the IV.  With the CBC mode of operation (not
-recommended), ESSIV is used; specifically, the IV for CBC is the
-logical block number encrypted with AES-256, where the AES-256 key is
-the SHA-256 hash of the inode's data encryption key.
-
-For filenames, the full filename is encrypted at once.  Because of the
-requirements to retain support for efficient directory lookups and
-filenames of up to 255 bytes, a constant initialization vector (IV) is
-used.  However, each encrypted directory uses a unique key, which
-limits IV reuse to within a single directory.  Note that IV reuse in
-the context of CTS-CBC encryption means that when the original
-filenames share a common prefix at least as long as the cipher block
-size (16 bytes for AES), the corresponding encrypted filenames will
-also share a common prefix.  This is undesirable; it may be fixed in
-the future by switching to an encryption mode that is a strong
-pseudorandom permutation on arbitrary-length messages, e.g. the HEH
-(Hash-Encrypt-Hash) mode.
-
-Since filenames are encrypted with the CTS-CBC mode of operation, the
-plaintext and ciphertext filenames need not be multiples of the AES
-block size, i.e. 16 bytes.  However, the minimum size that can be
-encrypted is 16 bytes, so shorter filenames are NUL-padded to 16 bytes
-before being encrypted.  In addition, to reduce leakage of filename
-lengths via their ciphertexts, all filenames are NUL-padded to the
-next 4, 8, 16, or 32-byte boundary (configurable).  32 is recommended
-since this provides the best confidentiality, at the cost of making
-directory entries consume slightly more space.  Note that since NUL
-(``\0``) is not otherwise a valid character in filenames, the padding
-will never produce duplicate plaintexts.
+the system's page size (usually 4096 bytes) is supported.
+
+Each block's IV is set to the logical block number within the file as
+a little endian number, except that:
+
+- With CBC mode encryption, ESSIV is also used.  Specifically, each IV
+  is encrypted with AES-256 where the AES-256 key is the SHA-256 hash
+  of the file's data encryption key.
+
+- In the "direct key" configuration (FS_POLICY_FLAG_DIRECT_KEY set in
+  the fscrypt_policy), the file's nonce is also appended to the IV.
+  Currently this is only allowed with the Adiantum encryption mode.
+
+Filenames encryption
+--------------------
+
+For filenames, each full filename is encrypted at once.  Because of
+the requirements to retain support for efficient directory lookups and
+filenames of up to 255 bytes, the same IV is used for every filename
+in a directory.
+
+However, each encrypted directory still uses a unique key; or
+alternatively (for the "direct key" configuration) has the file's
+nonce included in the IVs.  Thus, IV reuse is limited to within a
+single directory.
+
+With CTS-CBC, the IV reuse means that when the plaintext filenames
+share a common prefix at least as long as the cipher block size (16
+bytes for AES), the corresponding encrypted filenames will also share
+a common prefix.  This is undesirable.  Adiantum does not have this
+weakness, as it is a wide-block encryption mode.
+
+All supported filenames encryption modes accept any plaintext length
+>= 16 bytes; cipher block alignment is not required.  However,
+filenames shorter than 16 bytes are NUL-padded to 16 bytes before
+being encrypted.  In addition, to reduce leakage of filename lengths
+via their ciphertexts, all filenames are NUL-padded to the next 4, 8,
+16, or 32-byte boundary (configurable).  32 is recommended since this
+provides the best confidentiality, at the cost of making directory
+entries consume slightly more space.  Note that since NUL (``\0``) is
+not otherwise a valid character in filenames, the padding will never
+produce duplicate plaintexts.
 
 Symbolic link targets are considered a type of filename and are
-encrypted in the same way as filenames in directory entries.  Each
-symlink also uses a unique key; hence, the hardcoded IV is not a
-problem for symlinks.
+encrypted in the same way as filenames in directory entries, except
+that IV reuse is not a problem as each symlink has its own inode.
 
 User API
 ========
@@ -272,9 +293,13 @@ This structure must be initialized as follows:
   and FS_ENCRYPTION_MODE_AES_256_CTS (4) for
   ``filenames_encryption_mode``.
 
-- ``flags`` must be set to a value from ``<linux/fs.h>`` which
+- ``flags`` must contain a value from ``<linux/fs.h>`` which
   identifies the amount of NUL-padding to use when encrypting
   filenames.  If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3).
+  In addition, if the chosen encryption modes are both
+  FS_ENCRYPTION_MODE_ADIANTUM, this can contain
+  FS_POLICY_FLAG_DIRECT_KEY to specify that the master key should be
+  used directly, without key derivation.
 
 - ``master_key_descriptor`` specifies how to find the master key in
   the keyring; see `Adding keys`_.  It is up to userspace to choose a
index c8656dd029a910251bc9f6ffec70781d3a093f90..958fff945304488d60c0558347ad78198366138b 100644 (file)
@@ -160,7 +160,7 @@ them but you should handle them according to your needs.
   UHID_OUTPUT:
   This is sent if the HID device driver wants to send raw data to the I/O
   device on the interrupt channel. You should read the payload and forward it to
-  the device. The payload is of type "struct uhid_data_req".
+  the device. The payload is of type "struct uhid_output_req".
   This may be received even though you haven't received UHID_OPEN, yet.
 
   UHID_GET_REPORT:
index a8c0873beb952e620db9bb2f2df823624ac90650..b24b5343f5eb3a5e527f55b0a4dd0ff0095606cd 100644 (file)
@@ -190,7 +190,26 @@ A few EV_REL codes have special meanings:
 * REL_WHEEL, REL_HWHEEL:
 
   - These codes are used for vertical and horizontal scroll wheels,
-    respectively.
+    respectively. The value is the number of detents moved on the wheel, the
+    physical size of which varies by device. For high-resolution wheels
+    this may be an approximation based on the high-resolution scroll events,
+    see REL_WHEEL_HI_RES. These event codes are legacy codes and
+    REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES should be preferred where
+    available.
+
+* REL_WHEEL_HI_RES, REL_HWHEEL_HI_RES:
+
+  - High-resolution scroll wheel data. The accumulated value 120 represents
+    movement by one detent. For devices that do not provide high-resolution
+    scrolling, the value is always a multiple of 120. For devices with
+    high-resolution scrolling, the value may be a fraction of 120.
+
+    If a vertical scroll wheel supports high-resolution scrolling, this code
+    will be emitted in addition to REL_WHEEL or REL_HWHEEL. The REL_WHEEL
+    and REL_HWHEEL may be an approximation based on the high-resolution
+    scroll events. There is no guarantee that the high-resolution data
+    is a multiple of 120 at the time of an emulated REL_WHEEL or REL_HWHEEL
+    event.
 
 EV_ABS
 ------
index 39e75bbefc3d734b79f40485288bb25be98b91c1..32d444476a90056e8e644b5e56edcd502575a14c 100644 (file)
@@ -3674,11 +3674,20 @@ F:      drivers/input/touchscreen/chipone_icn8505.c
 
 CHROME HARDWARE PLATFORM SUPPORT
 M:     Benson Leung <bleung@chromium.org>
-M:     Olof Johansson <olof@lixom.net>
+M:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git
 F:     drivers/platform/chrome/
 
+CHROMEOS EC SUBDRIVERS
+M:     Benson Leung <bleung@chromium.org>
+M:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
+R:     Guenter Roeck <groeck@chromium.org>
+S:     Maintained
+N:     cros_ec
+N:     cros-ec
+F:     drivers/power/supply/cros_usbpd-charger.c
+
 CIRRUS LOGIC AUDIO CODEC DRIVERS
 M:     Brian Austin <brian.austin@cirrus.com>
 M:     Paul Handrigan <Paul.Handrigan@cirrus.com>
@@ -5710,7 +5719,7 @@ W:        http://ext4.wiki.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-ext4/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
 S:     Maintained
-F:     Documentation/filesystems/ext4/ext4.rst
+F:     Documentation/filesystems/ext4/
 F:     fs/ext4/
 
 Extended Verification Module (EVM)
@@ -11750,6 +11759,7 @@ F:      include/uapi/linux/pci*
 F:     lib/pci*
 F:     arch/x86/pci/
 F:     arch/x86/kernel/quirks.c
+F:     arch/x86/kernel/early-quirks.c
 
 PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
@@ -11759,6 +11769,13 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
 S:     Supported
 F:     drivers/pci/controller/
 
+PCIE DRIVER FOR AMLOGIC MESON
+M:     Yue Wang <yue.wang@Amlogic.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-amlogic@lists.infradead.org
+S:     Maintained
+F:     drivers/pci/controller/dwc/pci-meson.c
+
 PCIE DRIVER FOR AXIS ARTPEC
 M:     Jesper Nilsson <jesper.nilsson@axis.com>
 L:     linux-arm-kernel@axis.com
@@ -11791,7 +11808,6 @@ F:      Documentation/devicetree/bindings/pci/kirin-pcie.txt
 F:     drivers/pci/controller/dwc/pcie-kirin.c
 
 PCIE DRIVER FOR HISILICON STB
-M:     Jianguo Sun <sunjianguo1@huawei.com>
 M:     Shawn Guo <shawn.guo@linaro.org>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
@@ -11828,6 +11844,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
 F:     drivers/pci/controller/pci-v3-semi.c
 
+PCIE DRIVER FOR SOCIONEXT UNIPHIER
+M:     Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/uniphier-pcie.txt
+F:     drivers/pci/controller/dwc/pcie-uniphier.c
+
 PCIE DRIVER FOR ST SPEAR13XX
 M:     Pratyush Anand <pratyush.anand@gmail.com>
 L:     linux-pci@vger.kernel.org
index e69c4e13c3283577579e21239653a01bef64fd26..cf4ac791a592fdf8dc595e9407182c85bdac4243 100644 (file)
  * Address valid if:
  *  - "addr" doesn't have any high-bits set
  *  - AND "size" doesn't have any high-bits set
- *  - AND "addr+size" doesn't have any high-bits set
+ *  - AND "addr+size-(size != 0)" doesn't have any high-bits set
  *  - OR we are in kernel mode.
  */
-#define __access_ok(addr, size) \
-       ((get_fs().seg & (addr | size | (addr+size))) == 0)
+#define __access_ok(addr, size) ({                             \
+       unsigned long __ao_a = (addr), __ao_b = (size);         \
+       unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b;    \
+       (get_fs().seg & (__ao_a | __ao_b | __ao_end)) == 0; })
 
 #define access_ok(addr, size)                          \
 ({                                                     \
index d01bdee6f2f3467aaee7bf5eba3cf4f019f7e08d..98f115966391cd8ebb031dae97ba183bdad3b1f5 100644 (file)
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                        status = "disabled";
                };
 
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                        status = "disabled";
                };
 
                        interrupt-map-mask = <0 0 0 0>;
                        interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
                        ranges;
-                       num-lanes = <1>;
                        status = "disabled";
                };
        };
index 14a1028ca3a64bd54bd21608655dcf1895d25fa1..8fc4aa77f012136bf064fc555fce64f478939eb9 100644 (file)
                        ranges;
                        status = "disabled";
 
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc0 0>,
                                        <0 0 0 2 &pcie_intc0 1>,
                        ranges;
                        status = "disabled";
 
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc1 0>,
                                        <0 0 0 2 &pcie_intc1 1>,
index 6df622fb406d7ddcaf6a83c352727a25c35c882c..a966d7bfac579daa15514983d56993862363c502 100644 (file)
@@ -649,6 +649,9 @@ int pcibios_add_device(struct pci_dev *pdev)
        struct resource *res;
        int i;
 
+       if (pdev->is_physfn)
+               pdev->no_vf_scan = 1;
+
        pdev->dev.groups = zpci_attr_groups;
        pdev->dev.dma_ops = &s390_pci_dma_ops;
        zpci_map_resources(pdev);
index deebbfab5342dd858e1753b423ec53d58249d43f..5fe751ad75821f44b38996186b86879481088ac4 100644 (file)
  * sum := addr + size;  carry? --> flag = true;
  * if (sum >= addr_limit) flag = true;
  */
-#define __access_ok(addr, size)                \
-       (__addr_ok((addr) + (size)))
+#define __access_ok(addr, size)        ({                              \
+       unsigned long __ao_a = (addr), __ao_b = (size);         \
+       unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b;    \
+       __ao_end >= __ao_a && __addr_ok(__ao_end); })
+
 #define access_ok(addr, size)  \
        (__chk_user_ptr(addr),          \
         __access_ok((unsigned long __force)(addr), (size)))
index e0ff3ac8c127403a384b37c9ae15fe3902236f7d..2c0aa34af69c557a56dbf41fed11b595631434bd 100644 (file)
@@ -256,7 +256,15 @@ static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
        int npages;
        int i;
 
-       if (dma_addr == DMA_MAPPING_ERROR ||
+       if (WARN_ON_ONCE(dma_addr == DMA_MAPPING_ERROR))
+               return;
+
+       /*
+        * This driver will not always use a GART mapping, but might have
+        * created a direct mapping instead.  If that is the case there is
+        * nothing to unmap here.
+        */
+       if (dma_addr < iommu_bus_base ||
            dma_addr >= iommu_bus_base + iommu_size)
                return;
 
index 526536c81ddc41d395fd971d909a3b687e46d989..ca1e8e6dccc8afc235402e2ef7efd0a86a936a07 100644 (file)
@@ -50,8 +50,8 @@ static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
        word1 = read_pci_config_16(bus, slot, func, 0xc0);
        word2 = read_pci_config_16(bus, slot, func, 0xc2);
        if (word1 != word2) {
-               res.start = (word1 << 16) | 0x0000;
-               res.end   = (word2 << 16) | 0xffff;
+               res.start = ((resource_size_t) word1 << 16) | 0x0000;
+               res.end   = ((resource_size_t) word2 << 16) | 0xffff;
                res.flags = IORESOURCE_MEM;
                update_res(info, res.start, res.end, res.flags, 0);
        }
index 0ff27e2d98c46256cea2e491c92a0b1ac76aff83..26937ba28f789177545b2c651a3bf738b0c16b43 100644 (file)
@@ -181,7 +181,7 @@ static void vdc_blk_queue_start(struct vdc_port *port)
         * allocated a disk.
         */
        if (port->disk && vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50)
-               blk_mq_start_hw_queues(port->disk->queue);
+               blk_mq_start_stopped_hw_queues(port->disk->queue, true);
 }
 
 static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
index 145974f9662b63e603e18ac40a013f1f9a8ba2ad..4199849e37585181eace8176b55d4e81cbfd06db 100644 (file)
@@ -1,5 +1,4 @@
 menu "IEEE 1394 (FireWire) support"
-       depends on HAS_DMA
        depends on PCI || COMPILE_TEST
        # firewire-core does not depend on PCI but is
        # not useful without PCI controller driver
index cf4e190c0a72bf4df0edcd0f8a358b1a1db6833b..1c49b8266d69255bc45c546606a7b40af8ee82f0 100644 (file)
@@ -1428,6 +1428,9 @@ int amdgpu_cs_fence_to_handle_ioctl(struct drm_device *dev, void *data,
        if (IS_ERR(fence))
                return PTR_ERR(fence);
 
+       if (!fence)
+               fence = dma_fence_get_stub();
+
        switch (info->in.what) {
        case AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ:
                r = drm_syncobj_create(&syncobj, 0, fence);
index b60afeade50a3f86db57c26f993f2aacedd1c71e..8a078f4ae73dd17cc43384e605d28e4c613e7c37 100644 (file)
@@ -3476,14 +3476,16 @@ static void amdgpu_device_lock_adev(struct amdgpu_device *adev)
        mutex_lock(&adev->lock_reset);
        atomic_inc(&adev->gpu_reset_counter);
        adev->in_gpu_reset = 1;
-       /* Block kfd */
-       amdgpu_amdkfd_pre_reset(adev);
+       /* Block kfd: SRIOV would do it separately */
+       if (!amdgpu_sriov_vf(adev))
+                amdgpu_amdkfd_pre_reset(adev);
 }
 
 static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
 {
-       /*unlock kfd */
-       amdgpu_amdkfd_post_reset(adev);
+       /*unlock kfd: SRIOV would do it separately */
+       if (!amdgpu_sriov_vf(adev))
+                amdgpu_amdkfd_post_reset(adev);
        amdgpu_vf_error_trans_all(adev);
        adev->in_gpu_reset = 0;
        mutex_unlock(&adev->lock_reset);
index 9c77eaa45982b663288d18e9627689f5aacab4a3..c806f984bcc504320a39b6fe2d73fbdfee191a4f 100644 (file)
@@ -865,6 +865,7 @@ static const struct pci_device_id pciidlist[] = {
        /* VEGAM */
        {0x1002, 0x694C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGAM},
        {0x1002, 0x694E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGAM},
+       {0x1002, 0x694F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGAM},
        /* Vega 10 */
        {0x1002, 0x6860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
        {0x1002, 0x6861, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
index e0af44fd6a0cf7b52c266400510a857b74ea5efa..0a17fb1af204f0bc235ddc453fd74a8fb04fcde2 100644 (file)
@@ -32,6 +32,9 @@ static void amdgpu_job_timedout(struct drm_sched_job *s_job)
 {
        struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
        struct amdgpu_job *job = to_amdgpu_job(s_job);
+       struct amdgpu_task_info ti;
+
+       memset(&ti, 0, sizeof(struct amdgpu_task_info));
 
        if (amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) {
                DRM_ERROR("ring %s timeout, but soft recovered\n",
@@ -39,9 +42,12 @@ static void amdgpu_job_timedout(struct drm_sched_job *s_job)
                return;
        }
 
+       amdgpu_vm_get_task_info(ring->adev, job->pasid, &ti);
        DRM_ERROR("ring %s timeout, signaled seq=%u, emitted seq=%u\n",
                  job->base.sched->name, atomic_read(&ring->fence_drv.last_seq),
                  ring->fence_drv.sync_seq);
+       DRM_ERROR("Process information: process %s pid %d thread %s pid %d\n",
+                 ti.process_name, ti.tgid, ti.task_name, ti.pid);
 
        if (amdgpu_device_should_recover_gpu(ring->adev))
                amdgpu_device_gpu_recover(ring->adev, job);
index fd271f9746a29ee6799f623557ffaf0354e31b45..728e15e5d68ac75c8f787896b13cb92a6be99977 100644 (file)
@@ -912,7 +912,7 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo)
        struct ttm_operation_ctx ctx = { false, false };
        int r, i;
 
-       if (!bo->pin_count) {
+       if (WARN_ON_ONCE(!bo->pin_count)) {
                dev_warn(adev->dev, "%p unpin not necessary\n", bo);
                return 0;
        }
index 6759d898b3aba103998e177702e10526d03cc62a..8fab0d637ee51f96fa31cb5d81178d60f52db458 100644 (file)
@@ -155,14 +155,6 @@ psp_cmd_submit_buf(struct psp_context *psp,
        return ret;
 }
 
-bool psp_support_vmr_ring(struct psp_context *psp)
-{
-       if (amdgpu_sriov_vf(psp->adev) && psp->sos_fw_version > 0x80045)
-               return true;
-       else
-               return false;
-}
-
 static void psp_prep_tmr_cmd_buf(struct psp_context *psp,
                                 struct psp_gfx_cmd_resp *cmd,
                                 uint64_t tmr_mc, uint32_t size)
index 10decf70c9aa33d1b32a31f7eabe9cbba30a06f1..3ee573b4016e2118b208ec0fb466a63ed9722eb1 100644 (file)
@@ -83,12 +83,13 @@ struct psp_funcs
                                  enum AMDGPU_UCODE_ID ucode_type);
        bool (*smu_reload_quirk)(struct psp_context *psp);
        int (*mode1_reset)(struct psp_context *psp);
-       uint64_t (*xgmi_get_node_id)(struct psp_context *psp);
-       uint64_t (*xgmi_get_hive_id)(struct psp_context *psp);
+       int (*xgmi_get_node_id)(struct psp_context *psp, uint64_t *node_id);
+       int (*xgmi_get_hive_id)(struct psp_context *psp, uint64_t *hive_id);
        int (*xgmi_get_topology_info)(struct psp_context *psp, int number_devices,
                                      struct psp_xgmi_topology_info *topology);
        int (*xgmi_set_topology_info)(struct psp_context *psp, int number_devices,
                                      struct psp_xgmi_topology_info *topology);
+       bool (*support_vmr_ring)(struct psp_context *psp);
 };
 
 struct psp_xgmi_context {
@@ -192,12 +193,14 @@ struct psp_xgmi_topology_info {
                ((psp)->funcs->bootloader_load_sos ? (psp)->funcs->bootloader_load_sos((psp)) : 0)
 #define psp_smu_reload_quirk(psp) \
                ((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false)
+#define psp_support_vmr_ring(psp) \
+               ((psp)->funcs->support_vmr_ring ? (psp)->funcs->support_vmr_ring((psp)) : false)
 #define psp_mode1_reset(psp) \
                ((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false)
-#define psp_xgmi_get_node_id(psp) \
-               ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp)) : 0)
-#define psp_xgmi_get_hive_id(psp) \
-               ((psp)->funcs->xgmi_get_hive_id ? (psp)->funcs->xgmi_get_hive_id((psp)) : 0)
+#define psp_xgmi_get_node_id(psp, node_id) \
+               ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp), (node_id)) : -EINVAL)
+#define psp_xgmi_get_hive_id(psp, hive_id) \
+               ((psp)->funcs->xgmi_get_hive_id ? (psp)->funcs->xgmi_get_hive_id((psp), (hive_id)) : -EINVAL)
 #define psp_xgmi_get_topology_info(psp, num_device, topology) \
                ((psp)->funcs->xgmi_get_topology_info ? \
                (psp)->funcs->xgmi_get_topology_info((psp), (num_device), (topology)) : -EINVAL)
@@ -217,8 +220,6 @@ extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
 
 int psp_gpu_reset(struct amdgpu_device *adev);
 int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
-bool psp_support_vmr_ring(struct psp_context *psp);
-
 extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
 
 #endif
index 0beb01fef83fd38c9b940c167fa7df7d25df1f71..d87e828a084b959ee6651ad080c698eb7f2b3bca 100644 (file)
@@ -29,7 +29,7 @@
 #include <drm/drm_print.h>
 
 /* max number of rings */
-#define AMDGPU_MAX_RINGS               21
+#define AMDGPU_MAX_RINGS               23
 #define AMDGPU_MAX_GFX_RINGS           1
 #define AMDGPU_MAX_COMPUTE_RINGS       8
 #define AMDGPU_MAX_VCE_RINGS           3
index e2e42e3fbcf3365c659fc6281626e0adc6cf40e0..ecf6f96df2ad067054389ed3145f6b388f7997b0 100644 (file)
@@ -262,7 +262,7 @@ static int amdgpu_vcn_pause_dpg_mode(struct amdgpu_device *adev,
 
                                ring = &adev->vcn.ring_dec;
                                WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
-                                                  RREG32_SOC15(UVD, 0, mmUVD_SCRATCH2));
+                                                  RREG32_SOC15(UVD, 0, mmUVD_SCRATCH2) & 0x7FFFFFFF);
                                SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
                                                   UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON,
                                                   UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
@@ -322,7 +322,7 @@ static int amdgpu_vcn_pause_dpg_mode(struct amdgpu_device *adev,
 
                                ring = &adev->vcn.ring_dec;
                                WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
-                                                  RREG32_SOC15(UVD, 0, mmUVD_SCRATCH2));
+                                                  RREG32_SOC15(UVD, 0, mmUVD_SCRATCH2) & 0x7FFFFFFF);
                                SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
                                                   UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON,
                                                   UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
@@ -396,16 +396,26 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
 
        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)    {
                struct dpg_pause_state new_state;
+               unsigned int fences = 0;
+               unsigned int i;
 
-               if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC)
+               for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
+                       fences += amdgpu_fence_count_emitted(&adev->vcn.ring_enc[i]);
+               }
+               if (fences)
                        new_state.fw_based = VCN_DPG_STATE__PAUSE;
                else
-                       new_state.fw_based = adev->vcn.pause_state.fw_based;
+                       new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
 
-               if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
+               if (amdgpu_fence_count_emitted(&adev->vcn.ring_jpeg))
                        new_state.jpeg = VCN_DPG_STATE__PAUSE;
                else
-                       new_state.jpeg = adev->vcn.pause_state.jpeg;
+                       new_state.jpeg = VCN_DPG_STATE__UNPAUSE;
+
+               if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC)
+                       new_state.fw_based = VCN_DPG_STATE__PAUSE;
+               else if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
+                       new_state.jpeg = VCN_DPG_STATE__PAUSE;
 
                amdgpu_vcn_pause_dpg_mode(adev, &new_state);
        }
index 0b263a9857c6496d95a42d385099d897408e301d..8a8bc60cb6b4d482e216a0a32522cf0c1f47d881 100644 (file)
@@ -97,8 +97,19 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
        if (!adev->gmc.xgmi.supported)
                return 0;
 
-       adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp);
-       adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp);
+       ret = psp_xgmi_get_node_id(&adev->psp, &adev->gmc.xgmi.node_id);
+       if (ret) {
+               dev_err(adev->dev,
+                       "XGMI: Failed to get node id\n");
+               return ret;
+       }
+
+       ret = psp_xgmi_get_hive_id(&adev->psp, &adev->gmc.xgmi.hive_id);
+       if (ret) {
+               dev_err(adev->dev,
+                       "XGMI: Failed to get hive id\n");
+               return ret;
+       }
 
        mutex_lock(&xgmi_mutex);
        hive = amdgpu_get_xgmi_hive(adev);
index ce150de723c98132511304944720629a8a9eb460..bacdaef77b6c1ad0d3e12943e2bf53fefcea74b9 100644 (file)
@@ -718,37 +718,46 @@ static bool gmc_v9_0_keep_stolen_memory(struct amdgpu_device *adev)
        }
 }
 
-static int gmc_v9_0_late_init(void *handle)
+static int gmc_v9_0_allocate_vm_inv_eng(struct amdgpu_device *adev)
 {
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       /*
-        * The latest engine allocation on gfx9 is:
-        * Engine 0, 1: idle
-        * Engine 2, 3: firmware
-        * Engine 4~13: amdgpu ring, subject to change when ring number changes
-        * Engine 14~15: idle
-        * Engine 16: kfd tlb invalidation
-        * Engine 17: Gart flushes
-        */
-       unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 4, 4 };
+       struct amdgpu_ring *ring;
+       unsigned vm_inv_engs[AMDGPU_MAX_VMHUBS] =
+               {GFXHUB_FREE_VM_INV_ENGS_BITMAP, MMHUB_FREE_VM_INV_ENGS_BITMAP};
        unsigned i;
-       int r;
+       unsigned vmhub, inv_eng;
 
-       if (!gmc_v9_0_keep_stolen_memory(adev))
-               amdgpu_bo_late_init(adev);
+       for (i = 0; i < adev->num_rings; ++i) {
+               ring = adev->rings[i];
+               vmhub = ring->funcs->vmhub;
+
+               inv_eng = ffs(vm_inv_engs[vmhub]);
+               if (!inv_eng) {
+                       dev_err(adev->dev, "no VM inv eng for ring %s\n",
+                               ring->name);
+                       return -EINVAL;
+               }
 
-       for(i = 0; i < adev->num_rings; ++i) {
-               struct amdgpu_ring *ring = adev->rings[i];
-               unsigned vmhub = ring->funcs->vmhub;
+               ring->vm_inv_eng = inv_eng - 1;
+               change_bit(inv_eng - 1, (unsigned long *)(&vm_inv_engs[vmhub]));
 
-               ring->vm_inv_eng = vm_inv_eng[vmhub]++;
                dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n",
                         ring->name, ring->vm_inv_eng, ring->funcs->vmhub);
        }
 
-       /* Engine 16 is used for KFD and 17 for GART flushes */
-       for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i)
-               BUG_ON(vm_inv_eng[i] > 16);
+       return 0;
+}
+
+static int gmc_v9_0_late_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int r;
+
+       if (!gmc_v9_0_keep_stolen_memory(adev))
+               amdgpu_bo_late_init(adev);
+
+       r = gmc_v9_0_allocate_vm_inv_eng(adev);
+       if (r)
+               return r;
 
        if (adev->asic_type == CHIP_VEGA10 && !amdgpu_sriov_vf(adev)) {
                r = gmc_v9_0_ecc_available(adev);
index b030ca5ea1072eb66674a7ebea16ad7cdc694bc2..5c8deac65580603ac69f516efb17162efe75bfab 100644 (file)
 #ifndef __GMC_V9_0_H__
 #define __GMC_V9_0_H__
 
+       /*
+        * The latest engine allocation on gfx9 is:
+        * Engine 2, 3: firmware
+        * Engine 0, 1, 4~16: amdgpu ring,
+        *                    subject to change when ring number changes
+        * Engine 17: Gart flushes
+        */
+#define GFXHUB_FREE_VM_INV_ENGS_BITMAP         0x1FFF3
+#define MMHUB_FREE_VM_INV_ENGS_BITMAP          0x1FFF3
+
 extern const struct amd_ip_funcs gmc_v9_0_ip_funcs;
 extern const struct amdgpu_ip_block_version gmc_v9_0_ip_block;
 
index 6f9c54978cc1c09fbacd492c28b8b8ff88655950..accdedd63c98199191972ca378a4bf5becc1c182 100644 (file)
@@ -32,6 +32,7 @@
 #define smnCPM_CONTROL                                                                                  0x11180460
 #define smnPCIE_CNTL2                                                                                   0x11180070
 #define smnPCIE_CONFIG_CNTL                                                                             0x11180044
+#define smnPCIE_CI_CNTL                                                                                 0x11180080
 
 static u32 nbio_v6_1_get_rev_id(struct amdgpu_device *adev)
 {
@@ -270,6 +271,12 @@ static void nbio_v6_1_init_registers(struct amdgpu_device *adev)
 
        if (def != data)
                WREG32_PCIE(smnPCIE_CONFIG_CNTL, data);
+
+       def = data = RREG32_PCIE(smnPCIE_CI_CNTL);
+       data = REG_SET_FIELD(data, PCIE_CI_CNTL, CI_SLV_ORDERING_DIS, 1);
+
+       if (def != data)
+               WREG32_PCIE(smnPCIE_CI_CNTL, data);
 }
 
 const struct amdgpu_nbio_funcs nbio_v6_1_funcs = {
index f8cee95d61cc164e605289043d1ec31db424e617..4cd31a276dcd29a29cc2187d54ffff4ce083d170 100644 (file)
@@ -31,6 +31,7 @@
 
 #define smnCPM_CONTROL                                                                                  0x11180460
 #define smnPCIE_CNTL2                                                                                   0x11180070
+#define smnPCIE_CI_CNTL                                                                                 0x11180080
 
 static u32 nbio_v7_4_get_rev_id(struct amdgpu_device *adev)
 {
@@ -222,7 +223,13 @@ static void nbio_v7_4_detect_hw_virt(struct amdgpu_device *adev)
 
 static void nbio_v7_4_init_registers(struct amdgpu_device *adev)
 {
+       uint32_t def, data;
+
+       def = data = RREG32_PCIE(smnPCIE_CI_CNTL);
+       data = REG_SET_FIELD(data, PCIE_CI_CNTL, CI_SLV_ORDERING_DIS, 1);
 
+       if (def != data)
+               WREG32_PCIE(smnPCIE_CI_CNTL, data);
 }
 
 const struct amdgpu_nbio_funcs nbio_v7_4_funcs = {
index 6c9a1b748ca70dfb5eca172ecfc84ef429b16255..0c6e7f9b143fa692f50996aeb93de86ed19d6d13 100644 (file)
@@ -34,6 +34,7 @@
 #include "nbio/nbio_7_4_offset.h"
 
 MODULE_FIRMWARE("amdgpu/vega20_sos.bin");
+MODULE_FIRMWARE("amdgpu/vega20_asd.bin");
 MODULE_FIRMWARE("amdgpu/vega20_ta.bin");
 
 /* address block */
@@ -100,6 +101,7 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
        char fw_name[30];
        int err = 0;
        const struct psp_firmware_header_v1_0 *sos_hdr;
+       const struct psp_firmware_header_v1_0 *asd_hdr;
        const struct ta_firmware_header_v1_0 *ta_hdr;
 
        DRM_DEBUG("\n");
@@ -132,14 +134,30 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
        adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr +
                                le32_to_cpu(sos_hdr->sos_offset_bytes);
 
+       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name);
+       err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev);
+       if (err)
+               goto out1;
+
+       err = amdgpu_ucode_validate(adev->psp.asd_fw);
+       if (err)
+               goto out1;
+
+       asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data;
+       adev->psp.asd_fw_version = le32_to_cpu(asd_hdr->header.ucode_version);
+       adev->psp.asd_feature_version = le32_to_cpu(asd_hdr->ucode_feature_version);
+       adev->psp.asd_ucode_size = le32_to_cpu(asd_hdr->header.ucode_size_bytes);
+       adev->psp.asd_start_addr = (uint8_t *)asd_hdr +
+                               le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes);
+
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
        err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
        if (err)
-               goto out;
+               goto out2;
 
        err = amdgpu_ucode_validate(adev->psp.ta_fw);
        if (err)
-               goto out;
+               goto out2;
 
        ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
        adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version);
@@ -148,14 +166,18 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
                le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
 
        return 0;
+
+out2:
+       release_firmware(adev->psp.ta_fw);
+       adev->psp.ta_fw = NULL;
+out1:
+       release_firmware(adev->psp.asd_fw);
+       adev->psp.asd_fw = NULL;
 out:
-       if (err) {
-               dev_err(adev->dev,
-                       "psp v11.0: Failed to load firmware \"%s\"\n",
-                       fw_name);
-               release_firmware(adev->psp.sos_fw);
-               adev->psp.sos_fw = NULL;
-       }
+       dev_err(adev->dev,
+               "psp v11.0: Failed to load firmware \"%s\"\n", fw_name);
+       release_firmware(adev->psp.sos_fw);
+       adev->psp.sos_fw = NULL;
 
        return err;
 }
@@ -291,6 +313,13 @@ static int psp_v11_0_ring_init(struct psp_context *psp,
        return 0;
 }
 
+static bool psp_v11_0_support_vmr_ring(struct psp_context *psp)
+{
+       if (amdgpu_sriov_vf(psp->adev) && psp->sos_fw_version > 0x80045)
+               return true;
+       return false;
+}
+
 static int psp_v11_0_ring_create(struct psp_context *psp,
                                enum psp_ring_type ring_type)
 {
@@ -299,7 +328,7 @@ static int psp_v11_0_ring_create(struct psp_context *psp,
        struct psp_ring *ring = &psp->km_ring;
        struct amdgpu_device *adev = psp->adev;
 
-       if (psp_support_vmr_ring(psp)) {
+       if (psp_v11_0_support_vmr_ring(psp)) {
                /* Write low address of the ring to C2PMSG_102 */
                psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
                WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_ring_reg);
@@ -351,7 +380,7 @@ static int psp_v11_0_ring_stop(struct psp_context *psp,
        struct amdgpu_device *adev = psp->adev;
 
        /* Write the ring destroy command*/
-       if (psp_support_vmr_ring(psp))
+       if (psp_v11_0_support_vmr_ring(psp))
                WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101,
                                     GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING);
        else
@@ -362,7 +391,7 @@ static int psp_v11_0_ring_stop(struct psp_context *psp,
        mdelay(20);
 
        /* Wait for response flag (bit 31) */
-       if (psp_support_vmr_ring(psp))
+       if (psp_v11_0_support_vmr_ring(psp))
                ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
                                   0x80000000, 0x80000000, false);
        else
@@ -406,7 +435,7 @@ static int psp_v11_0_cmd_submit(struct psp_context *psp,
        uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4;
 
        /* KM (GPCOM) prepare write pointer */
-       if (psp_support_vmr_ring(psp))
+       if (psp_v11_0_support_vmr_ring(psp))
                psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102);
        else
                psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67);
@@ -438,7 +467,7 @@ static int psp_v11_0_cmd_submit(struct psp_context *psp,
 
        /* Update the write Pointer in DWORDs */
        psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw;
-       if (psp_support_vmr_ring(psp)) {
+       if (psp_v11_0_support_vmr_ring(psp)) {
                WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg);
                WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD);
        } else
@@ -680,7 +709,7 @@ static int psp_v11_0_xgmi_set_topology_info(struct psp_context *psp,
        return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO);
 }
 
-static u64 psp_v11_0_xgmi_get_hive_id(struct psp_context *psp)
+static int psp_v11_0_xgmi_get_hive_id(struct psp_context *psp, uint64_t *hive_id)
 {
        struct ta_xgmi_shared_memory *xgmi_cmd;
        int ret;
@@ -693,12 +722,14 @@ static u64 psp_v11_0_xgmi_get_hive_id(struct psp_context *psp)
        /* Invoke xgmi ta to get hive id */
        ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
        if (ret)
-               return 0;
-       else
-               return xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;
+               return ret;
+
+       *hive_id = xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;
+
+       return 0;
 }
 
-static u64 psp_v11_0_xgmi_get_node_id(struct psp_context *psp)
+static int psp_v11_0_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id)
 {
        struct ta_xgmi_shared_memory *xgmi_cmd;
        int ret;
@@ -711,9 +742,11 @@ static u64 psp_v11_0_xgmi_get_node_id(struct psp_context *psp)
        /* Invoke xgmi ta to get the node id */
        ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
        if (ret)
-               return 0;
-       else
-               return xgmi_cmd->xgmi_out_message.get_node_id.node_id;
+               return ret;
+
+       *node_id = xgmi_cmd->xgmi_out_message.get_node_id.node_id;
+
+       return 0;
 }
 
 static const struct psp_funcs psp_v11_0_funcs = {
@@ -732,6 +765,7 @@ static const struct psp_funcs psp_v11_0_funcs = {
        .xgmi_set_topology_info = psp_v11_0_xgmi_set_topology_info,
        .xgmi_get_hive_id = psp_v11_0_xgmi_get_hive_id,
        .xgmi_get_node_id = psp_v11_0_xgmi_get_node_id,
+       .support_vmr_ring = psp_v11_0_support_vmr_ring,
 };
 
 void psp_v11_0_set_psp_funcs(struct psp_context *psp)
index 7357fd56e61445f18bd16b7a2553e9eaf4d1d960..79694ff1696966ff4ac17d7c1d03e49ff42ecec6 100644 (file)
@@ -240,8 +240,11 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
         * are already been loaded.
         */
        sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
-       if (sol_reg)
+       if (sol_reg) {
+               psp->sos_fw_version = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58);
+               printk("sos fw version = 0x%x.\n", psp->sos_fw_version);
                return 0;
+       }
 
        /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */
        ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
index 4b6d3e5c821fba1f12974a9b778c1b17eaa71906..fd0bfe140ee01e6e26c12db9fc54ec48184d08dd 100644 (file)
@@ -1458,8 +1458,7 @@ static bool sdma_v4_0_fw_support_paging_queue(struct amdgpu_device *adev)
                /*return fw_version >= 31;*/
                return false;
        case CHIP_VEGA20:
-               /*return fw_version >= 115;*/
-               return false;
+               return fw_version >= 123;
        default:
                return false;
        }
@@ -1706,13 +1705,15 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev,
                amdgpu_fence_process(&adev->sdma.instance[instance].ring);
                break;
        case 1:
-               /* XXX compute */
+               if (adev->asic_type == CHIP_VEGA20)
+                       amdgpu_fence_process(&adev->sdma.instance[instance].page);
                break;
        case 2:
                /* XXX compute */
                break;
        case 3:
-               amdgpu_fence_process(&adev->sdma.instance[instance].page);
+               if (adev->asic_type != CHIP_VEGA20)
+                       amdgpu_fence_process(&adev->sdma.instance[instance].page);
                break;
        }
        return 0;
index 958b10a570731c422972967923f5b96276d8be00..49c262540940ff4897cd819fd26e2e418dd43d37 100644 (file)
 
 #define SOC15_WAIT_ON_RREG(ip, inst, reg, expected_value, mask, ret) \
        do {                                                    \
+               uint32_t old_ = 0;      \
                uint32_t tmp_ = RREG32(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg); \
                uint32_t loop = adev->usec_timeout;             \
                while ((tmp_ & (mask)) != (expected_value)) {   \
-                       udelay(2);                              \
+                       if (old_ != tmp_) {                     \
+                               loop = adev->usec_timeout;      \
+                               old_ = tmp_;                            \
+                       } else                                          \
+                               udelay(1);                              \
                        tmp_ = RREG32(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg); \
                        loop--;                                 \
                        if (!loop) {                            \
-                               DRM_ERROR("Register(%d) [%s] failed to reach value 0x%08x != 0x%08x\n", \
+                               DRM_WARN("Register(%d) [%s] failed to reach value 0x%08x != 0x%08x\n", \
                                          inst, #reg, (unsigned)expected_value, (unsigned)(tmp_ & (mask))); \
                                ret = -ETIMEDOUT;               \
                                break;                          \
index 089645e78f987485042009d80f9f0228a6091e99..aef924026a28c620373763aeb5d0c1274c1c44d2 100644 (file)
@@ -435,7 +435,7 @@ static int uvd_v7_0_sw_init(void *handle)
                        continue;
                if (!amdgpu_sriov_vf(adev)) {
                        ring = &adev->uvd.inst[j].ring;
-                       sprintf(ring->name, "uvd<%d>", j);
+                       sprintf(ring->name, "uvd_%d", ring->me);
                        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst[j].irq, 0);
                        if (r)
                                return r;
@@ -443,7 +443,7 @@ static int uvd_v7_0_sw_init(void *handle)
 
                for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
                        ring = &adev->uvd.inst[j].ring_enc[i];
-                       sprintf(ring->name, "uvd_enc%d<%d>", i, j);
+                       sprintf(ring->name, "uvd_enc_%d.%d", ring->me, i);
                        if (amdgpu_sriov_vf(adev)) {
                                ring->use_doorbell = true;
 
index 4f8352044563415876ea80de0f00a6b02ddbb79b..89bb2fef90eb725d5793c32b3c3c90aa0f23edf7 100644 (file)
@@ -214,7 +214,8 @@ static int vcn_v1_0_hw_fini(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        struct amdgpu_ring *ring = &adev->vcn.ring_dec;
 
-       if (RREG32_SOC15(VCN, 0, mmUVD_STATUS))
+       if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+               RREG32_SOC15(VCN, 0, mmUVD_STATUS))
                vcn_v1_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
 
        ring->sched.ready = false;
@@ -1087,7 +1088,8 @@ static int vcn_v1_0_start_dpg_mode(struct amdgpu_device *adev)
        WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), 0,
                        ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK);
 
-       /* initialize wptr */
+       /* initialize JPEG wptr */
+       ring = &adev->vcn.ring_jpeg;
        ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
 
        /* copy patch commands to the jpeg ring */
@@ -1159,21 +1161,29 @@ static int vcn_v1_0_stop_spg_mode(struct amdgpu_device *adev)
 static int vcn_v1_0_stop_dpg_mode(struct amdgpu_device *adev)
 {
        int ret_code = 0;
+       uint32_t tmp;
 
        /* Wait for power status to be UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF */
        SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
                        UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF,
                        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
 
-       if (!ret_code) {
-               int tmp = RREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR) & 0x7FFFFFFF;
-               /* wait for read ptr to be equal to write ptr */
-               SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RBC_RB_RPTR, tmp, 0xFFFFFFFF, ret_code);
+       /* wait for read ptr to be equal to write ptr */
+       tmp = RREG32_SOC15(UVD, 0, mmUVD_RB_WPTR);
+       SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RB_RPTR, tmp, 0xFFFFFFFF, ret_code);
 
-               SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
-                       UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF,
-                       UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
-       }
+       tmp = RREG32_SOC15(UVD, 0, mmUVD_RB_WPTR2);
+       SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RB_RPTR2, tmp, 0xFFFFFFFF, ret_code);
+
+       tmp = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
+       SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_JRBC_RB_RPTR, tmp, 0xFFFFFFFF, ret_code);
+
+       tmp = RREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR) & 0x7FFFFFFF;
+       SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RBC_RB_RPTR, tmp, 0xFFFFFFFF, ret_code);
+
+       SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
+               UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF,
+               UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
 
        /* disable dynamic power gating mode */
        WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0,
index ff2906c215fa8be32dd53e6e6899b3c780c850f4..77e3674591013167eefaf617a6d116eec626e291 100644 (file)
@@ -87,9 +87,9 @@ static u32 vi_pcie_rreg(struct amdgpu_device *adev, u32 reg)
        u32 r;
 
        spin_lock_irqsave(&adev->pcie_idx_lock, flags);
-       WREG32(mmPCIE_INDEX, reg);
-       (void)RREG32(mmPCIE_INDEX);
-       r = RREG32(mmPCIE_DATA);
+       WREG32_NO_KIQ(mmPCIE_INDEX, reg);
+       (void)RREG32_NO_KIQ(mmPCIE_INDEX);
+       r = RREG32_NO_KIQ(mmPCIE_DATA);
        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
        return r;
 }
@@ -99,10 +99,10 @@ static void vi_pcie_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
        unsigned long flags;
 
        spin_lock_irqsave(&adev->pcie_idx_lock, flags);
-       WREG32(mmPCIE_INDEX, reg);
-       (void)RREG32(mmPCIE_INDEX);
-       WREG32(mmPCIE_DATA, v);
-       (void)RREG32(mmPCIE_DATA);
+       WREG32_NO_KIQ(mmPCIE_INDEX, reg);
+       (void)RREG32_NO_KIQ(mmPCIE_INDEX);
+       WREG32_NO_KIQ(mmPCIE_DATA, v);
+       (void)RREG32_NO_KIQ(mmPCIE_DATA);
        spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
 }
 
@@ -123,8 +123,8 @@ static void vi_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
        unsigned long flags;
 
        spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       WREG32(mmSMC_IND_INDEX_11, (reg));
-       WREG32(mmSMC_IND_DATA_11, (v));
+       WREG32_NO_KIQ(mmSMC_IND_INDEX_11, (reg));
+       WREG32_NO_KIQ(mmSMC_IND_DATA_11, (v));
        spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
 }
 
index be68752c3469f32296c0cb369389fb259aa34ff2..083bd8114db1bb8d4950b3856fa224e44e21a76f 100644 (file)
@@ -1623,8 +1623,8 @@ static int kfd_ioctl_import_dmabuf(struct file *filep,
                return -EINVAL;
 
        dmabuf = dma_buf_get(args->dmabuf_fd);
-       if (!dmabuf)
-               return -EINVAL;
+       if (IS_ERR(dmabuf))
+               return PTR_ERR(dmabuf);
 
        mutex_lock(&p->mutex);
 
index d01315965af06c1b6d82c38fb796faaf61d3ba2c..a9a28dbc3e2421e36468554a554d1987b7c4f46e 100644 (file)
@@ -331,12 +331,29 @@ static void dm_crtc_high_irq(void *interrupt_params)
        struct common_irq_params *irq_params = interrupt_params;
        struct amdgpu_device *adev = irq_params->adev;
        struct amdgpu_crtc *acrtc;
+       struct dm_crtc_state *acrtc_state;
 
        acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
 
        if (acrtc) {
                drm_crtc_handle_vblank(&acrtc->base);
                amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+
+               acrtc_state = to_dm_crtc_state(acrtc->base.state);
+
+               if (acrtc_state->stream &&
+                   acrtc_state->vrr_params.supported &&
+                   acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {
+                       mod_freesync_handle_v_update(
+                               adev->dm.freesync_module,
+                               acrtc_state->stream,
+                               &acrtc_state->vrr_params);
+
+                       dc_stream_adjust_vmin_vmax(
+                               adev->dm.dc,
+                               acrtc_state->stream,
+                               &acrtc_state->vrr_params.adjust);
+               }
        }
 }
 
@@ -3009,7 +3026,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
                dc_stream_retain(state->stream);
        }
 
-       state->adjust = cur->adjust;
+       state->vrr_params = cur->vrr_params;
        state->vrr_infopacket = cur->vrr_infopacket;
        state->abm_level = cur->abm_level;
        state->vrr_supported = cur->vrr_supported;
@@ -3628,10 +3645,20 @@ static int dm_plane_atomic_check(struct drm_plane *plane,
 static int dm_plane_atomic_async_check(struct drm_plane *plane,
                                       struct drm_plane_state *new_plane_state)
 {
+       struct drm_plane_state *old_plane_state =
+               drm_atomic_get_old_plane_state(new_plane_state->state, plane);
+
        /* Only support async updates on cursor planes. */
        if (plane->type != DRM_PLANE_TYPE_CURSOR)
                return -EINVAL;
 
+       /*
+        * DRM calls prepare_fb and cleanup_fb on new_plane_state for
+        * async commits so don't allow fb changes.
+        */
+       if (old_plane_state->fb != new_plane_state->fb)
+               return -EINVAL;
+
        return 0;
 }
 
@@ -4445,9 +4472,11 @@ struct dc_stream_status *dc_state_get_stream_status(
 static void update_freesync_state_on_stream(
        struct amdgpu_display_manager *dm,
        struct dm_crtc_state *new_crtc_state,
-       struct dc_stream_state *new_stream)
+       struct dc_stream_state *new_stream,
+       struct dc_plane_state *surface,
+       u32 flip_timestamp_in_us)
 {
-       struct mod_vrr_params vrr = {0};
+       struct mod_vrr_params vrr_params = new_crtc_state->vrr_params;
        struct dc_info_packet vrr_infopacket = {0};
        struct mod_freesync_config config = new_crtc_state->freesync_config;
 
@@ -4474,43 +4503,52 @@ static void update_freesync_state_on_stream(
 
        mod_freesync_build_vrr_params(dm->freesync_module,
                                      new_stream,
-                                     &config, &vrr);
+                                     &config, &vrr_params);
+
+       if (surface) {
+               mod_freesync_handle_preflip(
+                       dm->freesync_module,
+                       surface,
+                       new_stream,
+                       flip_timestamp_in_us,
+                       &vrr_params);
+       }
 
        mod_freesync_build_vrr_infopacket(
                dm->freesync_module,
                new_stream,
-               &vrr,
+               &vrr_params,
                PACKET_TYPE_VRR,
                TRANSFER_FUNC_UNKNOWN,
                &vrr_infopacket);
 
        new_crtc_state->freesync_timing_changed =
-               (memcmp(&new_crtc_state->adjust,
-                       &vrr.adjust,
-                       sizeof(vrr.adjust)) != 0);
+               (memcmp(&new_crtc_state->vrr_params.adjust,
+                       &vrr_params.adjust,
+                       sizeof(vrr_params.adjust)) != 0);
 
        new_crtc_state->freesync_vrr_info_changed =
                (memcmp(&new_crtc_state->vrr_infopacket,
                        &vrr_infopacket,
                        sizeof(vrr_infopacket)) != 0);
 
-       new_crtc_state->adjust = vrr.adjust;
+       new_crtc_state->vrr_params = vrr_params;
        new_crtc_state->vrr_infopacket = vrr_infopacket;
 
-       new_stream->adjust = new_crtc_state->adjust;
+       new_stream->adjust = new_crtc_state->vrr_params.adjust;
        new_stream->vrr_infopacket = vrr_infopacket;
 
        if (new_crtc_state->freesync_vrr_info_changed)
                DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
                              new_crtc_state->base.crtc->base.id,
                              (int)new_crtc_state->base.vrr_enabled,
-                             (int)vrr.state);
+                             (int)vrr_params.state);
 
        if (new_crtc_state->freesync_timing_changed)
                DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n",
                              new_crtc_state->base.crtc->base.id,
-                             vrr.adjust.v_total_min,
-                             vrr.adjust.v_total_max);
+                                 vrr_params.adjust.v_total_min,
+                                 vrr_params.adjust.v_total_max);
 }
 
 /*
@@ -4524,6 +4562,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
                              struct dc_state *state)
 {
        unsigned long flags;
+       uint64_t timestamp_ns;
        uint32_t target_vblank;
        int r, vpos, hpos;
        struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
@@ -4537,6 +4576,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
        struct dc_stream_update stream_update = {0};
        struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
        struct dc_stream_status *stream_status;
+       struct dc_plane_state *surface;
 
 
        /* Prepare wait for target vblank early - before the fence-waits */
@@ -4586,6 +4626,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
        addr.address.grph.addr.high_part = upper_32_bits(afb->address);
        addr.flip_immediate = async_flip;
 
+       timestamp_ns = ktime_get_ns();
+       addr.flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
+
 
        if (acrtc->base.state->event)
                prepare_flip_isr(acrtc);
@@ -4599,8 +4642,10 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
                return;
        }
 
-       surface_updates->surface = stream_status->plane_states[0];
-       if (!surface_updates->surface) {
+       surface = stream_status->plane_states[0];
+       surface_updates->surface = surface;
+
+       if (!surface) {
                DRM_ERROR("No surface for CRTC: id=%d\n",
                        acrtc->crtc_id);
                return;
@@ -4611,7 +4656,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
                update_freesync_state_on_stream(
                        &adev->dm,
                        acrtc_state,
-                       acrtc_state->stream);
+                       acrtc_state->stream,
+                       surface,
+                       addr.flip_timestamp_in_us);
 
                if (acrtc_state->freesync_timing_changed)
                        stream_update.adjust =
@@ -4622,7 +4669,16 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
                                &acrtc_state->stream->vrr_infopacket;
        }
 
+       /* Update surface timing information. */
+       surface->time.time_elapsed_in_us[surface->time.index] =
+               addr.flip_timestamp_in_us - surface->time.prev_update_time_in_us;
+       surface->time.prev_update_time_in_us = addr.flip_timestamp_in_us;
+       surface->time.index++;
+       if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
+               surface->time.index = 0;
+
        mutex_lock(&adev->dm.dc_lock);
+
        dc_commit_updates_for_stream(adev->dm.dc,
                                             surface_updates,
                                             1,
@@ -5314,6 +5370,7 @@ static void get_freesync_config_for_crtc(
                config.max_refresh_in_uhz =
                                aconnector->max_vfreq * 1000000;
                config.vsif_supported = true;
+               config.btr = true;
        }
 
        new_crtc_state->freesync_config = config;
@@ -5324,8 +5381,8 @@ static void reset_freesync_config_for_crtc(
 {
        new_crtc_state->vrr_supported = false;
 
-       memset(&new_crtc_state->adjust, 0,
-              sizeof(new_crtc_state->adjust));
+       memset(&new_crtc_state->vrr_params, 0,
+              sizeof(new_crtc_state->vrr_params));
        memset(&new_crtc_state->vrr_infopacket, 0,
               sizeof(new_crtc_state->vrr_infopacket));
 }
index 25bb91ee80ba4b4b9e402ba58d75eb82a9d13458..fbd161ddc3f43f9bd56d07fbc2ea0a97e6849743 100644 (file)
@@ -268,7 +268,7 @@ struct dm_crtc_state {
 
        bool vrr_supported;
        struct mod_freesync_config freesync_config;
-       struct dc_crtc_timing_adjust adjust;
+       struct mod_vrr_params vrr_params;
        struct dc_info_packet vrr_infopacket;
 
        int abm_level;
index 751bb614fc0eae6b8b26647bc4f31b0893562431..c513ab6f38435b9281ec0f1799b044d3ed541115 100644 (file)
@@ -638,6 +638,7 @@ static enum bp_result get_ss_info_v4_1(
 {
        enum bp_result result = BP_RESULT_OK;
        struct atom_display_controller_info_v4_1 *disp_cntl_tbl = NULL;
+       struct atom_smu_info_v3_3 *smu_info = NULL;
 
        if (!ss_info)
                return BP_RESULT_BADINPUT;
@@ -650,6 +651,7 @@ static enum bp_result get_ss_info_v4_1(
        if (!disp_cntl_tbl)
                return BP_RESULT_BADBIOSTABLE;
 
+
        ss_info->type.STEP_AND_DELAY_INFO = false;
        ss_info->spread_percentage_divider = 1000;
        /* BIOS no longer uses target clock.  Always enable for now */
@@ -688,6 +690,19 @@ static enum bp_result get_ss_info_v4_1(
                 */
                result = BP_RESULT_UNSUPPORTED;
                break;
+       case AS_SIGNAL_TYPE_XGMI:
+               smu_info =  GET_IMAGE(struct atom_smu_info_v3_3,
+                                     DATA_TABLES(smu_info));
+               if (!smu_info)
+                       return BP_RESULT_BADBIOSTABLE;
+
+               ss_info->spread_spectrum_percentage =
+                               smu_info->waflclk_ss_percentage;
+               ss_info->spread_spectrum_range =
+                               smu_info->gpuclk_ss_rate_10hz * 10;
+               if (smu_info->waflclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE)
+                       ss_info->type.CENTER_MODE = true;
+               break;
        default:
                result = BP_RESULT_UNSUPPORTED;
        }
index 65b006ad372ebcc0e8aaaf1521d4c6f52f8ede97..8196f3bb10c786c983a57e14bdfe92fac32c519f 100644 (file)
@@ -67,6 +67,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
                return true;
 #endif
        case DCE_VERSION_12_0:
+       case DCE_VERSION_12_1:
                *h = dal_cmd_tbl_helper_dce112_get_table2();
                return true;
 
index d9c57984394bdceb4640452d5d0bde8a39feeb82..5fd52094d459efb3cbf97f12c068ff9d2d5d0b35 100644 (file)
@@ -151,10 +151,6 @@ static bool create_links(
                return false;
        }
 
-       if (connectors_num == 0 && num_virtual_links == 0) {
-               dm_error("DC: Number of connectors is zero!\n");
-       }
-
        dm_output_to_console(
                "DC: %s: connectors_num: physical:%d, virtual:%d\n",
                __func__,
@@ -1471,7 +1467,8 @@ static void commit_planes_do_stream_update(struct dc *dc,
 
                        if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
                                        stream_update->vrr_infopacket ||
-                                       stream_update->vsc_infopacket) {
+                                       stream_update->vsc_infopacket ||
+                                       stream_update->vsp_infopacket) {
                                resource_build_info_frame(pipe_ctx);
                                dc->hwss.update_info_frame(pipe_ctx);
                        }
@@ -1573,9 +1570,6 @@ static void commit_planes_for_stream(struct dc *dc,
                }
        }
 
-       if (update_type == UPDATE_TYPE_FULL)
-               context_timing_trace(dc, &context->res_ctx);
-
        // Update Type FAST, Surface updates
        if (update_type == UPDATE_TYPE_FAST) {
                /* Lock the top pipe while updating plane addrs, since freesync requires
index 4dc5846de5c4b24f8d7f71d2f2c2bbe2b821d661..52deacf398411378c1f63f02d62dc117ff0b522a 100644 (file)
@@ -215,6 +215,9 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
                return true;
        }
 
+       if (link->connector_signal == SIGNAL_TYPE_EDP)
+               link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+
        /* todo: may need to lock gpio access */
        hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
        if (hpd_pin == NULL)
@@ -339,7 +342,7 @@ bool dc_link_is_dp_sink_present(struct dc_link *link)
 {
        enum gpio_result gpio_result;
        uint32_t clock_pin = 0;
-
+       uint8_t retry = 0;
        struct ddc *ddc;
 
        enum connector_id connector_id =
@@ -368,11 +371,22 @@ bool dc_link_is_dp_sink_present(struct dc_link *link)
                return present;
        }
 
-       /* Read GPIO: DP sink is present if both clock and data pins are zero */
-       /* [anaumov] in DAL2, there was no check for GPIO failure */
-
-       gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin);
-       ASSERT(gpio_result == GPIO_RESULT_OK);
+       /*
+        * Read GPIO: DP sink is present if both clock and data pins are zero
+        *
+        * [W/A] plug-unplug DP cable, sometimes customer board has
+        * one short pulse on clk_pin(1V, < 1ms). DP will be config to HDMI/DVI
+        * then monitor can't br light up. Add retry 3 times
+        * But in real passive dongle, it need additional 3ms to detect
+        */
+       do {
+               gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin);
+               ASSERT(gpio_result == GPIO_RESULT_OK);
+               if (clock_pin)
+                       udelay(1000);
+               else
+                       break;
+       } while (retry++ < 3);
 
        present = (gpio_result == GPIO_RESULT_OK) && !clock_pin;
 
@@ -703,12 +717,26 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
                                if (memcmp(&link->dpcd_caps, &prev_dpcd_caps, sizeof(struct dpcd_caps)))
                                        same_dpcd = false;
                        }
-                       /* Active dongle downstream unplug */
+                       /* Active dongle plug in without display or downstream unplug*/
                        if (link->type == dc_connection_active_dongle
                                        && link->dpcd_caps.sink_count.
                                        bits.SINK_COUNT == 0) {
-                               if (prev_sink != NULL)
+                               if (prev_sink != NULL) {
+                                       /* Downstream unplug */
                                        dc_sink_release(prev_sink);
+                               } else {
+                                       /* Empty dongle plug in */
+                                       for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) {
+                                               int fail_count = 0;
+
+                                               dp_verify_link_cap(link,
+                                                                 &link->reported_link_cap,
+                                                                 &fail_count);
+
+                                               if (fail_count == 0)
+                                                       break;
+                                       }
+                               }
                                return true;
                        }
 
@@ -2622,11 +2650,11 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
 {
        struct dc  *core_dc = pipe_ctx->stream->ctx->dc;
 
+       core_dc->hwss.blank_stream(pipe_ctx);
+
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                deallocate_mst_payload(pipe_ctx);
 
-       core_dc->hwss.blank_stream(pipe_ctx);
-
        core_dc->hwss.disable_stream(pipe_ctx, option);
 
        disable_link(pipe_ctx->stream->sink->link, pipe_ctx->stream->signal);
index 849a3a3032f7cb71aea38dac834dc60461846998..0caacb60b02fe0df215f046c9ea460a7a5cc4625 100644 (file)
@@ -1089,6 +1089,121 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link)
        return max_link_cap;
 }
 
+static enum dc_status read_hpd_rx_irq_data(
+       struct dc_link *link,
+       union hpd_irq_data *irq_data)
+{
+       static enum dc_status retval;
+
+       /* The HW reads 16 bytes from 200h on HPD,
+        * but if we get an AUX_DEFER, the HW cannot retry
+        * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
+        * fail, so we now explicitly read 6 bytes which is
+        * the req from the above mentioned test cases.
+        *
+        * For DP 1.4 we need to read those from 2002h range.
+        */
+       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT,
+                       irq_data->raw,
+                       sizeof(union hpd_irq_data));
+       else {
+               /* Read 14 bytes in a single read and then copy only the required fields.
+                * This is more efficient than doing it in two separate AUX reads. */
+
+               uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
+
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT_ESI,
+                       tmp,
+                       sizeof(tmp));
+
+               if (retval != DC_OK)
+                       return retval;
+
+               irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
+       }
+
+       return retval;
+}
+
+static bool hpd_rx_irq_check_link_loss_status(
+       struct dc_link *link,
+       union hpd_irq_data *hpd_irq_dpcd_data)
+{
+       uint8_t irq_reg_rx_power_state = 0;
+       enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
+       union lane_status lane_status;
+       uint32_t lane;
+       bool sink_status_changed;
+       bool return_code;
+
+       sink_status_changed = false;
+       return_code = false;
+
+       if (link->cur_link_settings.lane_count == 0)
+               return return_code;
+
+       /*1. Check that Link Status changed, before re-training.*/
+
+       /*parse lane status*/
+       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
+               /* check status of lanes 0,1
+                * changed DpcdAddress_Lane01Status (0x202)
+                */
+               lane_status.raw = get_nibble_at_index(
+                       &hpd_irq_dpcd_data->bytes.lane01_status.raw,
+                       lane);
+
+               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
+                       !lane_status.bits.CR_DONE_0 ||
+                       !lane_status.bits.SYMBOL_LOCKED_0) {
+                       /* if one of the channel equalization, clock
+                        * recovery or symbol lock is dropped
+                        * consider it as (link has been
+                        * dropped) dp sink status has changed
+                        */
+                       sink_status_changed = true;
+                       break;
+               }
+       }
+
+       /* Check interlane align.*/
+       if (sink_status_changed ||
+               !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
+
+               DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
+
+               return_code = true;
+
+               /*2. Check that we can handle interrupt: Not in FS DOS,
+                *  Not in "Display Timeout" state, Link is trained.
+                */
+               dpcd_result = core_link_read_dpcd(link,
+                       DP_SET_POWER,
+                       &irq_reg_rx_power_state,
+                       sizeof(irq_reg_rx_power_state));
+
+               if (dpcd_result != DC_OK) {
+                       DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
+                               __func__);
+               } else {
+                       if (irq_reg_rx_power_state != DP_SET_POWER_D0)
+                               return_code = false;
+               }
+       }
+
+       return return_code;
+}
+
 bool dp_verify_link_cap(
        struct dc_link *link,
        struct dc_link_settings *known_limit_link_setting,
@@ -1104,12 +1219,14 @@ bool dp_verify_link_cap(
        struct clock_source *dp_cs;
        enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
        enum link_training_result status;
+       union hpd_irq_data irq_data;
 
        if (link->dc->debug.skip_detection_link_training) {
                link->verified_link_cap = *known_limit_link_setting;
                return true;
        }
 
+       memset(&irq_data, 0, sizeof(irq_data));
        success = false;
        skip_link_training = false;
 
@@ -1168,9 +1285,15 @@ bool dp_verify_link_cap(
                                (*fail_count)++;
                }
 
-               if (success)
+               if (success) {
                        link->verified_link_cap = *cur;
-
+                       udelay(1000);
+                       if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK)
+                               if (hpd_rx_irq_check_link_loss_status(
+                                               link,
+                                               &irq_data))
+                                       (*fail_count)++;
+               }
                /* always disable the link before trying another
                 * setting or before returning we'll enable it later
                 * based on the actual mode we're driving
@@ -1572,122 +1695,6 @@ void decide_link_settings(struct dc_stream_state *stream,
 }
 
 /*************************Short Pulse IRQ***************************/
-
-static bool hpd_rx_irq_check_link_loss_status(
-       struct dc_link *link,
-       union hpd_irq_data *hpd_irq_dpcd_data)
-{
-       uint8_t irq_reg_rx_power_state = 0;
-       enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
-       union lane_status lane_status;
-       uint32_t lane;
-       bool sink_status_changed;
-       bool return_code;
-
-       sink_status_changed = false;
-       return_code = false;
-
-       if (link->cur_link_settings.lane_count == 0)
-               return return_code;
-
-       /*1. Check that Link Status changed, before re-training.*/
-
-       /*parse lane status*/
-       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
-               /* check status of lanes 0,1
-                * changed DpcdAddress_Lane01Status (0x202)
-                */
-               lane_status.raw = get_nibble_at_index(
-                       &hpd_irq_dpcd_data->bytes.lane01_status.raw,
-                       lane);
-
-               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
-                       !lane_status.bits.CR_DONE_0 ||
-                       !lane_status.bits.SYMBOL_LOCKED_0) {
-                       /* if one of the channel equalization, clock
-                        * recovery or symbol lock is dropped
-                        * consider it as (link has been
-                        * dropped) dp sink status has changed
-                        */
-                       sink_status_changed = true;
-                       break;
-               }
-       }
-
-       /* Check interlane align.*/
-       if (sink_status_changed ||
-               !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
-
-               DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
-
-               return_code = true;
-
-               /*2. Check that we can handle interrupt: Not in FS DOS,
-                *  Not in "Display Timeout" state, Link is trained.
-                */
-               dpcd_result = core_link_read_dpcd(link,
-                       DP_SET_POWER,
-                       &irq_reg_rx_power_state,
-                       sizeof(irq_reg_rx_power_state));
-
-               if (dpcd_result != DC_OK) {
-                       DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
-                               __func__);
-               } else {
-                       if (irq_reg_rx_power_state != DP_SET_POWER_D0)
-                               return_code = false;
-               }
-       }
-
-       return return_code;
-}
-
-static enum dc_status read_hpd_rx_irq_data(
-       struct dc_link *link,
-       union hpd_irq_data *irq_data)
-{
-       static enum dc_status retval;
-
-       /* The HW reads 16 bytes from 200h on HPD,
-        * but if we get an AUX_DEFER, the HW cannot retry
-        * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
-        * fail, so we now explicitly read 6 bytes which is
-        * the req from the above mentioned test cases.
-        *
-        * For DP 1.4 we need to read those from 2002h range.
-        */
-       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
-               retval = core_link_read_dpcd(
-                       link,
-                       DP_SINK_COUNT,
-                       irq_data->raw,
-                       sizeof(union hpd_irq_data));
-       else {
-               /* Read 14 bytes in a single read and then copy only the required fields.
-                * This is more efficient than doing it in two separate AUX reads. */
-
-               uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
-
-               retval = core_link_read_dpcd(
-                       link,
-                       DP_SINK_COUNT_ESI,
-                       tmp,
-                       sizeof(tmp));
-
-               if (retval != DC_OK)
-                       return retval;
-
-               irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
-       }
-
-       return retval;
-}
-
 static bool allow_hpd_rx_irq(const struct dc_link *link)
 {
        /*
@@ -2240,7 +2247,8 @@ static void get_active_converter_info(
                                        translate_dpcd_max_bpc(
                                                hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
 
-                               link->dpcd_caps.dongle_caps.extendedCapValid = true;
+                               if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk != 0)
+                                       link->dpcd_caps.dongle_caps.extendedCapValid = true;
                        }
 
                        break;
index 82cd1d6e6e59d38251ff344f4a236e3b25dc4d78..0065ec7d5330d9eaa03f8d5772e1c0f855373464 100644 (file)
@@ -96,6 +96,7 @@ void dp_enable_link_phy(
                                                link_settings,
                                                clock_source);
        }
+       link->cur_link_settings = *link_settings;
 
        dp_receiver_power_ctrl(link, true);
 }
@@ -307,6 +308,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
                                                link->link_enc,
                                                link_setting,
                                                pipes[i].clock_source->id);
+                       link->cur_link_settings = *link_setting;
 
                        dp_receiver_power_ctrl(link, true);
 
@@ -316,7 +318,6 @@ void dp_retrain_link_dp_test(struct dc_link *link,
                                        skip_video_pattern,
                                        LINK_TRAINING_ATTEMPTS);
 
-                       link->cur_link_settings = *link_setting;
 
                        link->dc->hwss.enable_stream(&pipes[i]);
 
index c347afd1030f8e15e44e55888f48cdbe06f6fd34..76137df74a535b6d8c1609e2bb265787538ee87d 100644 (file)
@@ -83,7 +83,10 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
                        dc_version = DCE_VERSION_11_22;
                break;
        case FAMILY_AI:
-               dc_version = DCE_VERSION_12_0;
+               if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
+                       dc_version = DCE_VERSION_12_1;
+               else
+                       dc_version = DCE_VERSION_12_0;
                break;
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
        case FAMILY_RV:
@@ -136,6 +139,7 @@ struct resource_pool *dc_create_resource_pool(
                        num_virtual_links, dc);
                break;
        case DCE_VERSION_12_0:
+       case DCE_VERSION_12_1:
                res_pool = dce120_create_resource_pool(
                        num_virtual_links, dc);
                break;
index fcfd50b5dba09ff2aac5d6b5dad6295cecb8210d..4842d2378bbf5b28884708926dd05ccae45130db 100644 (file)
@@ -234,14 +234,14 @@ uint32_t generic_reg_wait(const struct dc_context *ctx,
                if (field_value == condition_value) {
                        if (i * delay_between_poll_us > 1000 &&
                                        !IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
-                               dm_output_to_console("REG_WAIT taking a while: %dms in %s line:%d\n",
+                               DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",
                                                delay_between_poll_us * i / 1000,
                                                func_name, line);
                        return reg_val;
                }
        }
 
-       dm_error("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
+       DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
                        delay_between_poll_us, time_out_num_tries,
                        func_name, line);
 
index 9ddfe4c6938b5a1f65e65eb4e196e9899f4ad008..e72fce4eca65c9cbca3acb1e0fd38f3819b245b4 100644 (file)
@@ -192,7 +192,6 @@ enum surface_pixel_format {
        /*swaped & float*/
        SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F,
        /*grow graphics here if necessary */
-       SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888,
        SURFACE_PIXEL_FORMAT_VIDEO_BEGIN,
        SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr =
                SURFACE_PIXEL_FORMAT_VIDEO_BEGIN,
@@ -200,6 +199,7 @@ enum surface_pixel_format {
        SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr,
        SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb,
                SURFACE_PIXEL_FORMAT_SUBSAMPLE_END,
+       SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888,
        SURFACE_PIXEL_FORMAT_INVALID
 
        /*grow 444 video here if necessary */
index bd22f51813bf195fc58094584493ff440d863fd7..afd287f08bc9520840ce1593c23d2cd98ae06cb1 100644 (file)
@@ -676,6 +676,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
 {
        struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
        struct dm_pp_power_level_change_request level_change_req;
+       int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+
+       /*TODO: W/A for dal3 linux, investigate why this works */
+       if (!clk_mgr_dce->dfs_bypass_active)
+               context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
 
        level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
        /* get max clock state from PPLIB */
@@ -690,6 +695,8 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
                clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
        }
        dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+
+       context->bw.dce.dispclk_khz = unpatched_disp_clk;
 }
 
 static void dce12_update_clocks(struct clk_mgr *clk_mgr,
index 6349ba7bec7c3bc317af484e2cf84c76f24ec29a..4bf24758217fdf7ad6537a0f5ec2fde7b5ad1950 100644 (file)
@@ -1267,10 +1267,19 @@ static void program_scaler(const struct dc *dc,
                pipe_ctx->plane_res.scl_data.lb_params.depth,
                &pipe_ctx->stream->bit_depth_params);
 
-       if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color)
+       if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) {
+               /*
+                * The way 420 is packed, 2 channels carry Y component, 1 channel
+                * alternate between Cb and Cr, so both channels need the pixel
+                * value for Y
+                */
+               if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
+                       color.color_r_cr = color.color_g_y;
+
                pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color(
                                pipe_ctx->stream_res.tg,
                                &color);
+       }
 
        pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm,
                &pipe_ctx->plane_res.scl_data);
index 0bd33a713836b6b1b0bd8c828517fc73d055a777..91e015e143550d9a4b10d8a6249df35db72c6e62 100644 (file)
@@ -2159,6 +2159,15 @@ static void dcn10_blank_pixel_data(
        color_space = stream->output_color_space;
        color_space_to_black_color(dc, color_space, &black_color);
 
+       /*
+        * The way 420 is packed, 2 channels carry Y component, 1 channel
+        * alternate between Cb and Cr, so both channels need the pixel
+        * value for Y
+        */
+       if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
+               black_color.color_r_cr = black_color.color_g_y;
+
+
        if (stream_res->tg->funcs->set_blank_color)
                stream_res->tg->funcs->set_blank_color(
                                stream_res->tg,
@@ -2348,7 +2357,8 @@ static void dcn10_apply_ctx_for_surface(
                        struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
                        /* Skip inactive pipes and ones already updated */
-                       if (!pipe_ctx->stream || pipe_ctx->stream == stream)
+                       if (!pipe_ctx->stream || pipe_ctx->stream == stream
+                                       || !pipe_ctx->plane_state)
                                continue;
 
                        pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
@@ -2362,7 +2372,8 @@ static void dcn10_apply_ctx_for_surface(
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe_ctx->stream || pipe_ctx->stream == stream)
+               if (!pipe_ctx->stream || pipe_ctx->stream == stream
+                               || !pipe_ctx->plane_state)
                        continue;
 
                dcn10_pipe_control_lock(dc, pipe_ctx, false);
index a683f4102e657496df4f4e06b0a0fafbe35af94a..c2028c4744a6446ff9bb0b3d5b838262f8d6e35e 100644 (file)
@@ -79,6 +79,7 @@ bool dal_hw_factory_init(
                dal_hw_factory_dce110_init(factory);
                return true;
        case DCE_VERSION_12_0:
+       case DCE_VERSION_12_1:
                dal_hw_factory_dce120_init(factory);
                return true;
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
index 096f45628630dc17052c14ecd1cc2e50cc88f0b8..236ca28784a9cf505fe2c046e8b0ded3dbcbf486 100644 (file)
@@ -76,6 +76,7 @@ bool dal_hw_translate_init(
                dal_hw_translate_dce110_init(translate);
                return true;
        case DCE_VERSION_12_0:
+       case DCE_VERSION_12_1:
                dal_hw_translate_dce120_init(translate);
                return true;
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
index e56093f26eed9736fe117dc7391a23ac5e552161..1ad6e49102ff1ced8326098dcd9ff5c5528d47c4 100644 (file)
@@ -90,6 +90,7 @@ struct i2caux *dal_i2caux_create(
        case DCE_VERSION_10_0:
                return dal_i2caux_dce100_create(ctx);
        case DCE_VERSION_12_0:
+       case DCE_VERSION_12_1:
                return dal_i2caux_dce120_create(ctx);
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
        case DCN_VERSION_1_0:
index f8dbfa5b89f2f67f2c2bd07435e9e9c5939384e8..7fd78a696800b50982c8744df5a47bc98240a022 100644 (file)
@@ -41,6 +41,7 @@ enum as_signal_type {
        AS_SIGNAL_TYPE_LVDS,
        AS_SIGNAL_TYPE_DISPLAY_PORT,
        AS_SIGNAL_TYPE_GPU_PLL,
+       AS_SIGNAL_TYPE_XGMI,
        AS_SIGNAL_TYPE_UNKNOWN
 };
 
index 89627133e188574addf79377073be66a0a7ec062..f5bd869d4320bdd6f552d1344e025372d15d4e21 100644 (file)
@@ -42,6 +42,7 @@ enum dce_version {
        DCE_VERSION_11_2,
        DCE_VERSION_11_22,
        DCE_VERSION_12_0,
+       DCE_VERSION_12_1,
        DCE_VERSION_MAX,
        DCN_VERSION_1_0,
 #if defined(CONFIG_DRM_AMD_DC_DCN1_01)
index 2e99ecf4ab76272e569f1023dae04626d568a959..26154f9b2178d86c3eb843ef189efdf7aff316e7 100644 (file)
 #include "soc15_common.h"
 #include "smuio/smuio_9_0_offset.h"
 #include "smuio/smuio_9_0_sh_mask.h"
+#include "nbio/nbio_7_4_sh_mask.h"
+
+#define smnPCIE_LC_SPEED_CNTL                  0x11140290
+#define smnPCIE_LC_LINK_WIDTH_CNTL             0x11140288
 
 static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
 {
@@ -2282,6 +2286,18 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
                break;
 
        case PP_PCIE:
+               soft_min_level = mask ? (ffs(mask) - 1) : 0;
+               soft_max_level = mask ? (fls(mask) - 1) : 0;
+               if (soft_min_level >= NUM_LINK_LEVELS ||
+                   soft_max_level >= NUM_LINK_LEVELS)
+                       return -EINVAL;
+
+               ret = smum_send_msg_to_smc_with_parameter(hwmgr,
+                       PPSMC_MSG_SetMinLinkDpmByIndex, soft_min_level);
+               PP_ASSERT_WITH_CODE(!ret,
+                       "Failed to set min link dpm level!",
+                       return ret);
+
                break;
 
        default:
@@ -2758,9 +2774,14 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                        data->od8_settings.od8_settings_array;
        OverDriveTable_t *od_table =
                        &(data->smc_state_table.overdrive_table);
+       struct phm_ppt_v3_information *pptable_information =
+               (struct phm_ppt_v3_information *)hwmgr->pptable;
+       PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
+       struct amdgpu_device *adev = hwmgr->adev;
        struct pp_clock_levels_with_latency clocks;
        int i, now, size = 0;
        int ret = 0;
+       uint32_t gen_speed, lane_width;
 
        switch (type) {
        case PP_SCLK:
@@ -2798,6 +2819,28 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                break;
 
        case PP_PCIE:
+               gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
+                            PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
+                           >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
+               lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
+                             PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
+                           >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
+               for (i = 0; i < NUM_LINK_LEVELS; i++)
+                       size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
+                                       (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," :
+                                       (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," :
+                                       (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," :
+                                       (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "",
+                                       (pptable->PcieLaneCount[i] == 1) ? "x1" :
+                                       (pptable->PcieLaneCount[i] == 2) ? "x2" :
+                                       (pptable->PcieLaneCount[i] == 3) ? "x4" :
+                                       (pptable->PcieLaneCount[i] == 4) ? "x8" :
+                                       (pptable->PcieLaneCount[i] == 5) ? "x12" :
+                                       (pptable->PcieLaneCount[i] == 6) ? "x16" : "",
+                                       pptable->LclkFreq[i],
+                                       (gen_speed == pptable->PcieGenSpeed[i]) &&
+                                       (lane_width == pptable->PcieLaneCount[i]) ?
+                                       "*" : "");
                break;
 
        case OD_SCLK:
index 60bd7d708e354a9b03d19be1ea1427256fc6fabc..4985384e51f6e5cc7308efc670d08a05e92ff4ec 100644 (file)
@@ -241,6 +241,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
 
        state->fence = NULL;
        state->commit = NULL;
+       state->fb_damage_clips = NULL;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
 
@@ -285,6 +286,8 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
 
        if (state->commit)
                drm_crtc_commit_put(state->commit);
+
+       drm_property_blob_put(state->fb_damage_clips);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
 
index d2a1c7372f362c686993b74ce1200010962a9858..31032407254d4dab631fb863f58ee5353dbfeb08 100644 (file)
@@ -178,7 +178,7 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
        state = drm_atomic_state_alloc(fb->dev);
        if (!state) {
                ret = -ENOMEM;
-               goto out;
+               goto out_drop_locks;
        }
        state->acquire_ctx = &ctx;
 
@@ -238,6 +238,7 @@ out:
        kfree(rects);
        drm_atomic_state_put(state);
 
+out_drop_locks:
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
 
index 77edbfcb0f75ea28b9ee3ffe51de137fc4f8743f..77ae634eb11c9e709751b9391a8f392ad9632385 100644 (file)
@@ -1900,11 +1900,11 @@ static struct cmd_info cmd_info[] = {
 
        {"MI_URB_CLEAR", OP_MI_URB_CLEAR, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
 
-       {"ME_SEMAPHORE_SIGNAL", OP_MI_SEMAPHORE_SIGNAL, F_LEN_VAR, R_ALL,
+       {"MI_SEMAPHORE_SIGNAL", OP_MI_SEMAPHORE_SIGNAL, F_LEN_VAR, R_ALL,
                D_BDW_PLUS, 0, 8, NULL},
 
-       {"ME_SEMAPHORE_WAIT", OP_MI_SEMAPHORE_WAIT, F_LEN_VAR, R_ALL, D_BDW_PLUS,
-               ADDR_FIX_1(2), 8, cmd_handler_mi_semaphore_wait},
+       {"MI_SEMAPHORE_WAIT", OP_MI_SEMAPHORE_WAIT, F_LEN_VAR, R_ALL,
+               D_BDW_PLUS, ADDR_FIX_1(2), 8, cmd_handler_mi_semaphore_wait},
 
        {"MI_STORE_DATA_IMM", OP_MI_STORE_DATA_IMM, F_LEN_VAR, R_ALL, D_BDW_PLUS,
                ADDR_FIX_1(1), 10, cmd_handler_mi_store_data_imm},
index 6ef5a7fc70df967b2de542da23501dd5d0f1369b..733a2a0d0c3096ce56feb0a3a00e56e23f4db8ae 100644 (file)
@@ -437,7 +437,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
 
        ret = intel_gvt_debugfs_init(gvt);
        if (ret)
-               gvt_err("debugfs registeration failed, go on.\n");
+               gvt_err("debugfs registration failed, go on.\n");
 
        gvt_dbg_core("gvt device initialization is done\n");
        dev_priv->gvt = gvt;
index 31f6cdbe5c424f67f29167be34496e67fcb67b85..b4ab1dad01434f9ebdd6375104433a28c1707f2a 100644 (file)
@@ -159,6 +159,10 @@ struct intel_vgpu_submission {
        struct kmem_cache *workloads;
        atomic_t running_workload_num;
        struct i915_gem_context *shadow_ctx;
+       union {
+               u64 i915_context_pml4;
+               u64 i915_context_pdps[GEN8_3LVL_PDPES];
+       };
        DECLARE_BITMAP(shadow_ctx_desc_updated, I915_NUM_ENGINES);
        DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES);
        void *ring_scan_buffer[I915_NUM_ENGINES];
index aa280bb071254547fd3d810494bd488d4edbcd44..b5475c91e2ef1b337ed083aae4c67a1d94fbe2e9 100644 (file)
@@ -475,6 +475,7 @@ static i915_reg_t force_nonpriv_white_list[] = {
        _MMIO(0x7704),
        _MMIO(0x7708),
        _MMIO(0x770c),
+       _MMIO(0x83a8),
        _MMIO(0xb110),
        GEN8_L3SQCREG4,//_MMIO(0xb118)
        _MMIO(0xe100),
index 5daa23ae566b0849379a58fa35af64b540bece33..6b9d1354ff29be770a68f75d1f5506070c45496d 100644 (file)
@@ -126,7 +126,7 @@ static const char * const irq_name[INTEL_GVT_EVENT_MAX] = {
        [FDI_RX_INTERRUPTS_TRANSCODER_C] = "FDI RX Interrupts Combined C",
        [AUDIO_CP_CHANGE_TRANSCODER_C] = "Audio CP Change Transcoder C",
        [AUDIO_CP_REQUEST_TRANSCODER_C] = "Audio CP Request Transcoder C",
-       [ERR_AND_DBG] = "South Error and Debug Interupts Combined",
+       [ERR_AND_DBG] = "South Error and Debug Interrupts Combined",
        [GMBUS] = "Gmbus",
        [SDVO_B_HOTPLUG] = "SDVO B hotplug",
        [CRT_HOTPLUG] = "CRT Hotplug",
index b8fbe3fabea3062203ad64d5ff33fd4ceebf0da2..1ad8c5e1455d782160d15c4a1c83cb6f64dad3cf 100644 (file)
@@ -1079,6 +1079,21 @@ err:
        return ret;
 }
 
+static void
+i915_context_ppgtt_root_restore(struct intel_vgpu_submission *s)
+{
+       struct i915_hw_ppgtt *i915_ppgtt = s->shadow_ctx->ppgtt;
+       int i;
+
+       if (i915_vm_is_48bit(&i915_ppgtt->vm))
+               px_dma(&i915_ppgtt->pml4) = s->i915_context_pml4;
+       else {
+               for (i = 0; i < GEN8_3LVL_PDPES; i++)
+                       px_dma(i915_ppgtt->pdp.page_directory[i]) =
+                                               s->i915_context_pdps[i];
+       }
+}
+
 /**
  * intel_vgpu_clean_submission - free submission-related resource for vGPU
  * @vgpu: a vGPU
@@ -1091,6 +1106,7 @@ void intel_vgpu_clean_submission(struct intel_vgpu *vgpu)
        struct intel_vgpu_submission *s = &vgpu->submission;
 
        intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
+       i915_context_ppgtt_root_restore(s);
        i915_gem_context_put(s->shadow_ctx);
        kmem_cache_destroy(s->workloads);
 }
@@ -1116,6 +1132,21 @@ void intel_vgpu_reset_submission(struct intel_vgpu *vgpu,
        s->ops->reset(vgpu, engine_mask);
 }
 
+static void
+i915_context_ppgtt_root_save(struct intel_vgpu_submission *s)
+{
+       struct i915_hw_ppgtt *i915_ppgtt = s->shadow_ctx->ppgtt;
+       int i;
+
+       if (i915_vm_is_48bit(&i915_ppgtt->vm))
+               s->i915_context_pml4 = px_dma(&i915_ppgtt->pml4);
+       else {
+               for (i = 0; i < GEN8_3LVL_PDPES; i++)
+                       s->i915_context_pdps[i] =
+                               px_dma(i915_ppgtt->pdp.page_directory[i]);
+       }
+}
+
 /**
  * intel_vgpu_setup_submission - setup submission-related resource for vGPU
  * @vgpu: a vGPU
@@ -1138,6 +1169,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
        if (IS_ERR(s->shadow_ctx))
                return PTR_ERR(s->shadow_ctx);
 
+       i915_context_ppgtt_root_save(s);
+
        bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
 
        s->workloads = kmem_cache_create_usercopy("gvt-g_vgpu_workload",
index 4b75ad40dd80e562a6692e90393de581455ef501..432c440223bbd161241b90ed6078472c302c82bb 100644 (file)
@@ -4,7 +4,8 @@ config DRM_NOUVEAU
         select FW_LOADER
        select DRM_KMS_HELPER
        select DRM_TTM
-       select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
+       select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT
        select X86_PLATFORM_DEVICES if ACPI && X86
        select ACPI_WMI if ACPI && X86
index d87935bf8e308f81e13ccde697fe35e86fa446c6..0ec08394e17a6a818c98a931551371db1c0362c4 100644 (file)
@@ -77,38 +77,39 @@ static inline int ttm_mem_type_from_place(const struct ttm_place *place,
        return 0;
 }
 
-static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
+static void ttm_mem_type_debug(struct ttm_bo_device *bdev, struct drm_printer *p,
+                              int mem_type)
 {
        struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-       struct drm_printer p = drm_debug_printer(TTM_PFX);
 
-       pr_err("    has_type: %d\n", man->has_type);
-       pr_err("    use_type: %d\n", man->use_type);
-       pr_err("    flags: 0x%08X\n", man->flags);
-       pr_err("    gpu_offset: 0x%08llX\n", man->gpu_offset);
-       pr_err("    size: %llu\n", man->size);
-       pr_err("    available_caching: 0x%08X\n", man->available_caching);
-       pr_err("    default_caching: 0x%08X\n", man->default_caching);
+       drm_printf(p, "    has_type: %d\n", man->has_type);
+       drm_printf(p, "    use_type: %d\n", man->use_type);
+       drm_printf(p, "    flags: 0x%08X\n", man->flags);
+       drm_printf(p, "    gpu_offset: 0x%08llX\n", man->gpu_offset);
+       drm_printf(p, "    size: %llu\n", man->size);
+       drm_printf(p, "    available_caching: 0x%08X\n", man->available_caching);
+       drm_printf(p, "    default_caching: 0x%08X\n", man->default_caching);
        if (mem_type != TTM_PL_SYSTEM)
-               (*man->func->debug)(man, &p);
+               (*man->func->debug)(man, p);
 }
 
 static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
                                        struct ttm_placement *placement)
 {
+       struct drm_printer p = drm_debug_printer(TTM_PFX);
        int i, ret, mem_type;
 
-       pr_err("No space for %p (%lu pages, %luK, %luM)\n",
-              bo, bo->mem.num_pages, bo->mem.size >> 10,
-              bo->mem.size >> 20);
+       drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n",
+                  bo, bo->mem.num_pages, bo->mem.size >> 10,
+                  bo->mem.size >> 20);
        for (i = 0; i < placement->num_placement; i++) {
                ret = ttm_mem_type_from_place(&placement->placement[i],
                                                &mem_type);
                if (ret)
                        return;
-               pr_err("  placement[%d]=0x%08X (%d)\n",
-                      i, placement->placement[i].flags, mem_type);
-               ttm_mem_type_debug(bo->bdev, mem_type);
+               drm_printf(&p, "  placement[%d]=0x%08X (%d)\n",
+                          i, placement->placement[i].flags, mem_type);
+               ttm_mem_type_debug(bo->bdev, &p, mem_type);
        }
 }
 
index a1fa2fc8c9b57fd8e3de462d35b6247bd0d3e6e3..951bb17ae8b2c823879002abe8311fbe1ab05f22 100644 (file)
@@ -70,6 +70,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
 #define QUIRK_T100_KEYBOARD            BIT(6)
 #define QUIRK_T100CHI                  BIT(7)
 #define QUIRK_G752_KEYBOARD            BIT(8)
+#define QUIRK_T101HA_DOCK              BIT(9)
 
 #define I2C_KEYBOARD_QUIRKS                    (QUIRK_FIX_NOTEBOOK_REPORT | \
                                                 QUIRK_NO_INIT_REPORTS | \
@@ -241,6 +242,18 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
        return 1;
 }
 
+static int asus_event(struct hid_device *hdev, struct hid_field *field,
+                     struct hid_usage *usage, __s32 value)
+{
+       if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
+           (usage->hid & HID_USAGE) != 0x00 && !usage->type) {
+               hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
+                        usage->hid & HID_USAGE);
+       }
+
+       return 0;
+}
+
 static int asus_raw_event(struct hid_device *hdev,
                struct hid_report *report, u8 *data, int size)
 {
@@ -510,6 +523,7 @@ static int asus_input_mapping(struct hid_device *hdev,
                case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP);                break;
                case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF);         break;
                case 0x6c: asus_map_key_clear(KEY_SLEEP);               break;
+               case 0x7c: asus_map_key_clear(KEY_MICMUTE);             break;
                case 0x82: asus_map_key_clear(KEY_CAMERA);              break;
                case 0x88: asus_map_key_clear(KEY_RFKILL);                      break;
                case 0xb5: asus_map_key_clear(KEY_CALC);                        break;
@@ -528,6 +542,9 @@ static int asus_input_mapping(struct hid_device *hdev,
                /* Fn+Space Power4Gear Hybrid */
                case 0x5c: asus_map_key_clear(KEY_PROG3);               break;
 
+               /* Fn+F5 "fan" symbol on FX503VD */
+               case 0x99: asus_map_key_clear(KEY_PROG4);               break;
+
                default:
                        /* ASUS lazily declares 256 usages, ignore the rest,
                         * as some make the keyboard appear as a pointer device. */
@@ -683,6 +700,11 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return ret;
        }
 
+       /* use hid-multitouch for T101HA touchpad */
+       if (id->driver_data & QUIRK_T101HA_DOCK &&
+           hdev->collection->usage == HID_GD_MOUSE)
+               return -ENODEV;
+
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "Asus hw start failed: %d\n", ret);
@@ -805,12 +827,17 @@ static const struct hid_device_id asus_devices[] = {
                USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
                USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+               USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
+         QUIRK_USE_KBD_BACKLIGHT },
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
                USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
          QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
                USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD),
          QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+               USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD), QUIRK_T101HA_DOCK },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
@@ -832,6 +859,7 @@ static struct hid_driver asus_driver = {
 #ifdef CONFIG_PM
        .reset_resume           = asus_reset_resume,
 #endif
+       .event                  = asus_event,
        .raw_event              = asus_raw_event
 };
 module_hid_driver(asus_driver);
index 5bec9244c45b54aa943ae5363cecdc9c5d7f38f5..f41d5fe51abe3b812b600c7fa79d789f350ef3ce 100644 (file)
@@ -172,6 +172,8 @@ static int open_collection(struct hid_parser *parser, unsigned type)
        collection->type = type;
        collection->usage = usage;
        collection->level = parser->collection_stack_ptr - 1;
+       collection->parent = parser->active_collection;
+       parser->active_collection = collection;
 
        if (type == HID_COLLECTION_APPLICATION)
                parser->device->maxapplication++;
@@ -190,6 +192,8 @@ static int close_collection(struct hid_parser *parser)
                return -EINVAL;
        }
        parser->collection_stack_ptr--;
+       if (parser->active_collection)
+               parser->active_collection = parser->active_collection->parent;
        return 0;
 }
 
@@ -290,6 +294,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
                field->usage[i].collection_index =
                        parser->local.collection_index[j];
                field->usage[i].usage_index = i;
+               field->usage[i].resolution_multiplier = 1;
        }
 
        field->maxusage = usages;
@@ -943,6 +948,167 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
 }
 EXPORT_SYMBOL_GPL(hid_validate_values);
 
+static int hid_calculate_multiplier(struct hid_device *hid,
+                                    struct hid_field *multiplier)
+{
+       int m;
+       __s32 v = *multiplier->value;
+       __s32 lmin = multiplier->logical_minimum;
+       __s32 lmax = multiplier->logical_maximum;
+       __s32 pmin = multiplier->physical_minimum;
+       __s32 pmax = multiplier->physical_maximum;
+
+       /*
+        * "Because OS implementations will generally divide the control's
+        * reported count by the Effective Resolution Multiplier, designers
+        * should take care not to establish a potential Effective
+        * Resolution Multiplier of zero."
+        * HID Usage Table, v1.12, Section 4.3.1, p31
+        */
+       if (lmax - lmin == 0)
+               return 1;
+       /*
+        * Handling the unit exponent is left as an exercise to whoever
+        * finds a device where that exponent is not 0.
+        */
+       m = ((v - lmin)/(lmax - lmin) * (pmax - pmin) + pmin);
+       if (unlikely(multiplier->unit_exponent != 0)) {
+               hid_warn(hid,
+                        "unsupported Resolution Multiplier unit exponent %d\n",
+                        multiplier->unit_exponent);
+       }
+
+       /* There are no devices with an effective multiplier > 255 */
+       if (unlikely(m == 0 || m > 255 || m < -255)) {
+               hid_warn(hid, "unsupported Resolution Multiplier %d\n", m);
+               m = 1;
+       }
+
+       return m;
+}
+
+static void hid_apply_multiplier_to_field(struct hid_device *hid,
+                                         struct hid_field *field,
+                                         struct hid_collection *multiplier_collection,
+                                         int effective_multiplier)
+{
+       struct hid_collection *collection;
+       struct hid_usage *usage;
+       int i;
+
+       /*
+        * If multiplier_collection is NULL, the multiplier applies
+        * to all fields in the report.
+        * Otherwise, it is the Logical Collection the multiplier applies to
+        * but our field may be in a subcollection of that collection.
+        */
+       for (i = 0; i < field->maxusage; i++) {
+               usage = &field->usage[i];
+
+               collection = &hid->collection[usage->collection_index];
+               while (collection && collection != multiplier_collection)
+                       collection = collection->parent;
+
+               if (collection || multiplier_collection == NULL)
+                       usage->resolution_multiplier = effective_multiplier;
+
+       }
+}
+
+static void hid_apply_multiplier(struct hid_device *hid,
+                                struct hid_field *multiplier)
+{
+       struct hid_report_enum *rep_enum;
+       struct hid_report *rep;
+       struct hid_field *field;
+       struct hid_collection *multiplier_collection;
+       int effective_multiplier;
+       int i;
+
+       /*
+        * "The Resolution Multiplier control must be contained in the same
+        * Logical Collection as the control(s) to which it is to be applied.
+        * If no Resolution Multiplier is defined, then the Resolution
+        * Multiplier defaults to 1.  If more than one control exists in a
+        * Logical Collection, the Resolution Multiplier is associated with
+        * all controls in the collection. If no Logical Collection is
+        * defined, the Resolution Multiplier is associated with all
+        * controls in the report."
+        * HID Usage Table, v1.12, Section 4.3.1, p30
+        *
+        * Thus, search from the current collection upwards until we find a
+        * logical collection. Then search all fields for that same parent
+        * collection. Those are the fields the multiplier applies to.
+        *
+        * If we have more than one multiplier, it will overwrite the
+        * applicable fields later.
+        */
+       multiplier_collection = &hid->collection[multiplier->usage->collection_index];
+       while (multiplier_collection &&
+              multiplier_collection->type != HID_COLLECTION_LOGICAL)
+               multiplier_collection = multiplier_collection->parent;
+
+       effective_multiplier = hid_calculate_multiplier(hid, multiplier);
+
+       rep_enum = &hid->report_enum[HID_INPUT_REPORT];
+       list_for_each_entry(rep, &rep_enum->report_list, list) {
+               for (i = 0; i < rep->maxfield; i++) {
+                       field = rep->field[i];
+                       hid_apply_multiplier_to_field(hid, field,
+                                                     multiplier_collection,
+                                                     effective_multiplier);
+               }
+       }
+}
+
+/*
+ * hid_setup_resolution_multiplier - set up all resolution multipliers
+ *
+ * @device: hid device
+ *
+ * Search for all Resolution Multiplier Feature Reports and apply their
+ * value to all matching Input items. This only updates the internal struct
+ * fields.
+ *
+ * The Resolution Multiplier is applied by the hardware. If the multiplier
+ * is anything other than 1, the hardware will send pre-multiplied events
+ * so that the same physical interaction generates an accumulated
+ *     accumulated_value = value * * multiplier
+ * This may be achieved by sending
+ * - "value * multiplier" for each event, or
+ * - "value" but "multiplier" times as frequently, or
+ * - a combination of the above
+ * The only guarantee is that the same physical interaction always generates
+ * an accumulated 'value * multiplier'.
+ *
+ * This function must be called before any event processing and after
+ * any SetRequest to the Resolution Multiplier.
+ */
+void hid_setup_resolution_multiplier(struct hid_device *hid)
+{
+       struct hid_report_enum *rep_enum;
+       struct hid_report *rep;
+       struct hid_usage *usage;
+       int i, j;
+
+       rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(rep, &rep_enum->report_list, list) {
+               for (i = 0; i < rep->maxfield; i++) {
+                       /* Ignore if report count is out of bounds. */
+                       if (rep->field[i]->report_count < 1)
+                               continue;
+
+                       for (j = 0; j < rep->field[i]->maxusage; j++) {
+                               usage = &rep->field[i]->usage[j];
+                               if (usage->hid == HID_GD_RESOLUTION_MULTIPLIER)
+                                       hid_apply_multiplier(hid,
+                                                            rep->field[i]);
+                       }
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
+
 /**
  * hid_open_report - open a driver-specific device report
  *
@@ -1039,9 +1205,17 @@ int hid_open_report(struct hid_device *device)
                                hid_err(device, "unbalanced delimiter at end of report description\n");
                                goto err;
                        }
+
+                       /*
+                        * fetch initial values in case the device's
+                        * default multiplier isn't the recommended 1
+                        */
+                       hid_setup_resolution_multiplier(device);
+
                        kfree(parser->collection_stack);
                        vfree(parser);
                        device->status |= HID_STAT_PARSED;
+
                        return 0;
                }
        }
index 3f0916b64c60e9bd8fcf29b22386f2a6c7cd7649..e0bb7b34f3a4de8a1f4b51a9f3bc8406b21cd621 100644 (file)
@@ -326,6 +326,8 @@ module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
 static struct hid_device_id cougar_id_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
                         USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
+                        USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD) },
        {}
 };
 MODULE_DEVICE_TABLE(hid, cougar_id_table);
index b48100236df890cdd1bbffa0daac97257357a38d..c530476edba62b7804b892e47a675396dfe1c3c8 100644 (file)
@@ -1072,11 +1072,6 @@ static int hid_debug_rdesc_show(struct seq_file *f, void *p)
        return 0;
 }
 
-static int hid_debug_rdesc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, hid_debug_rdesc_show, inode->i_private);
-}
-
 static int hid_debug_events_open(struct inode *inode, struct file *file)
 {
        int err = 0;
@@ -1211,12 +1206,7 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static const struct file_operations hid_debug_rdesc_fops = {
-       .open           = hid_debug_rdesc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(hid_debug_rdesc);
 
 static const struct file_operations hid_debug_events_fops = {
        .owner =        THIS_MODULE,
index 27519eb8ee636f8823d71a3ccf6802c8620e3745..518fa76414f560f8e76d88a2079310cc8b8c4936 100644 (file)
 #define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD  0x17e0
 #define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807
 #define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502
+#define USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD  0x183d
 #define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD    0x184a
 #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD     0x8585
 #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD     0x0101
 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
+#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
 
 #define USB_VENDOR_ID_ATEN             0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM     0x2004
 
 #define USB_VENDOR_ID_SOLID_YEAR                       0x060b
 #define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD      0x500a
+#define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD      0x700a
 
 #define USB_VENDOR_ID_SOUNDGRAPH       0x15c2
 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST    0x0034
index d6fab579848743555c53534ad933419ad69318a9..59a5608b8dc06fb3e21811605d6c81f28cf7e070 100644 (file)
@@ -712,7 +712,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                map_abs_clear(usage->hid & 0xf);
                        break;
 
-               case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+               case HID_GD_WHEEL:
+                       if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+                               set_bit(REL_WHEEL, input->relbit);
+                               map_rel(REL_WHEEL_HI_RES);
+                       } else {
+                               map_abs(usage->hid & 0xf);
+                       }
+                       break;
+               case HID_GD_SLIDER: case HID_GD_DIAL:
                        if (field->flags & HID_MAIN_ITEM_RELATIVE)
                                map_rel(usage->hid & 0xf);
                        else
@@ -1012,7 +1020,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x22f: map_key_clear(KEY_ZOOMRESET);       break;
                case 0x233: map_key_clear(KEY_SCROLLUP);        break;
                case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
-               case 0x238: map_rel(REL_HWHEEL);                break;
+               case 0x238: /* AC Pan */
+                       set_bit(REL_HWHEEL, input->relbit);
+                       map_rel(REL_HWHEEL_HI_RES);
+                       break;
                case 0x23d: map_key_clear(KEY_EDIT);            break;
                case 0x25f: map_key_clear(KEY_CANCEL);          break;
                case 0x269: map_key_clear(KEY_INSERT);          break;
@@ -1200,6 +1211,38 @@ ignore:
 
 }
 
+static void hidinput_handle_scroll(struct hid_usage *usage,
+                                  struct input_dev *input,
+                                  __s32 value)
+{
+       int code;
+       int hi_res, lo_res;
+
+       if (value == 0)
+               return;
+
+       if (usage->code == REL_WHEEL_HI_RES)
+               code = REL_WHEEL;
+       else
+               code = REL_HWHEEL;
+
+       /*
+        * Windows reports one wheel click as value 120. Where a high-res
+        * scroll wheel is present, a fraction of 120 is reported instead.
+        * Our REL_WHEEL_HI_RES axis does the same because all HW must
+        * adhere to the 120 expectation.
+        */
+       hi_res = value * 120/usage->resolution_multiplier;
+
+       usage->wheel_accumulated += hi_res;
+       lo_res = usage->wheel_accumulated/120;
+       if (lo_res)
+               usage->wheel_accumulated -= lo_res * 120;
+
+       input_event(input, EV_REL, code, lo_res);
+       input_event(input, EV_REL, usage->code, hi_res);
+}
+
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
 {
        struct input_dev *input;
@@ -1262,6 +1305,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
        if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
                return;
 
+       if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
+                                       usage->code == REL_HWHEEL_HI_RES)) {
+               hidinput_handle_scroll(usage, input, value);
+               return;
+       }
+
        if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
                        (usage->code == ABS_VOLUME)) {
                int count = abs(value);
@@ -1489,6 +1538,58 @@ static void hidinput_close(struct input_dev *dev)
        hid_hw_close(hid);
 }
 
+static void hidinput_change_resolution_multipliers(struct hid_device *hid)
+{
+       struct hid_report_enum *rep_enum;
+       struct hid_report *rep;
+       struct hid_usage *usage;
+       int i, j;
+
+       rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(rep, &rep_enum->report_list, list) {
+               bool update_needed = false;
+
+               if (rep->maxfield == 0)
+                       continue;
+
+               /*
+                * If we have more than one feature within this report we
+                * need to fill in the bits from the others before we can
+                * overwrite the ones for the Resolution Multiplier.
+                */
+               if (rep->maxfield > 1) {
+                       hid_hw_request(hid, rep, HID_REQ_GET_REPORT);
+                       hid_hw_wait(hid);
+               }
+
+               for (i = 0; i < rep->maxfield; i++) {
+                       __s32 logical_max = rep->field[i]->logical_maximum;
+
+                       /* There is no good reason for a Resolution
+                        * Multiplier to have a count other than 1.
+                        * Ignore that case.
+                        */
+                       if (rep->field[i]->report_count != 1)
+                               continue;
+
+                       for (j = 0; j < rep->field[i]->maxusage; j++) {
+                               usage = &rep->field[i]->usage[j];
+
+                               if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
+                                       continue;
+
+                               *rep->field[i]->value = logical_max;
+                               update_needed = true;
+                       }
+               }
+               if (update_needed)
+                       hid_hw_request(hid, rep, HID_REQ_SET_REPORT);
+       }
+
+       /* refresh our structs */
+       hid_setup_resolution_multiplier(hid);
+}
+
 static void report_features(struct hid_device *hid)
 {
        struct hid_driver *drv = hid->driver;
@@ -1782,6 +1883,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                }
        }
 
+       hidinput_change_resolution_multipliers(hid);
+
        list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
                if (drv->input_configured &&
                    drv->input_configured(hid, hidinput))
@@ -1840,4 +1943,3 @@ void hidinput_disconnect(struct hid_device *hid)
        cancel_work_sync(&hid->led_work);
 }
 EXPORT_SYMBOL_GPL(hidinput_disconnect);
-
index 643b6eb54442ed4bc297e182ad1b7c77a25e82c0..eacc76d2ab96019564ed6ca3b7442faf7d7b623d 100644 (file)
@@ -743,7 +743,9 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
        data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
        data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
        data_pointer->led_mute.dev = dev;
-       led_classdev_register(dev, &data_pointer->led_mute);
+       ret = led_classdev_register(dev, &data_pointer->led_mute);
+       if (ret < 0)
+               goto err;
 
        data_pointer->led_micmute.name = name_micmute;
        data_pointer->led_micmute.brightness_get =
@@ -751,7 +753,11 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
        data_pointer->led_micmute.brightness_set =
                lenovo_led_brightness_set_tpkbd;
        data_pointer->led_micmute.dev = dev;
-       led_classdev_register(dev, &data_pointer->led_micmute);
+       ret = led_classdev_register(dev, &data_pointer->led_micmute);
+       if (ret < 0) {
+               led_classdev_unregister(&data_pointer->led_mute);
+               goto err;
+       }
 
        lenovo_features_set_tpkbd(hdev);
 
index 19cc980eebce6a3019c44d55dcbef0002e1cda10..15ed6177a7a364d6b2634babe0df1be83b4cec7b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/sched/clock.h>
 #include <linux/kfifo.h>
 #include <linux/input/mt.h>
 #include <linux/workqueue.h>
@@ -64,6 +65,14 @@ MODULE_PARM_DESC(disable_tap_to_click,
 #define HIDPP_QUIRK_NO_HIDINPUT                        BIT(23)
 #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS       BIT(24)
 #define HIDPP_QUIRK_UNIFYING                   BIT(25)
+#define HIDPP_QUIRK_HI_RES_SCROLL_1P0          BIT(26)
+#define HIDPP_QUIRK_HI_RES_SCROLL_X2120                BIT(27)
+#define HIDPP_QUIRK_HI_RES_SCROLL_X2121                BIT(28)
+
+/* Convenience constant to check for any high-res support. */
+#define HIDPP_QUIRK_HI_RES_SCROLL      (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
+                                        HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
+                                        HIDPP_QUIRK_HI_RES_SCROLL_X2121)
 
 #define HIDPP_QUIRK_DELAYED_INIT               HIDPP_QUIRK_NO_HIDINPUT
 
@@ -128,6 +137,25 @@ struct hidpp_battery {
        bool online;
 };
 
+/**
+ * struct hidpp_scroll_counter - Utility class for processing high-resolution
+ *                             scroll events.
+ * @dev: the input device for which events should be reported.
+ * @wheel_multiplier: the scalar multiplier to be applied to each wheel event
+ * @remainder: counts the number of high-resolution units moved since the last
+ *             low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
+ *             only be used by class methods.
+ * @direction: direction of last movement (1 or -1)
+ * @last_time: last event time, used to reset remainder after inactivity
+ */
+struct hidpp_scroll_counter {
+       struct input_dev *dev;
+       int wheel_multiplier;
+       int remainder;
+       int direction;
+       unsigned long long last_time;
+};
+
 struct hidpp_device {
        struct hid_device *hid_dev;
        struct mutex send_mutex;
@@ -149,6 +177,7 @@ struct hidpp_device {
        unsigned long capabilities;
 
        struct hidpp_battery battery;
+       struct hidpp_scroll_counter vertical_wheel_counter;
 };
 
 /* HID++ 1.0 error codes */
@@ -391,6 +420,67 @@ static void hidpp_prefix_name(char **name, int name_length)
        *name = new_name;
 }
 
+/**
+ * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
+ *                                        events given a high-resolution wheel
+ *                                        movement.
+ * @counter: a hid_scroll_counter struct describing the wheel.
+ * @hi_res_value: the movement of the wheel, in the mouse's high-resolution
+ *                units.
+ *
+ * Given a high-resolution movement, this function converts the movement into
+ * fractions of 120 and emits high-resolution scroll events for the input
+ * device. It also uses the multiplier from &struct hid_scroll_counter to
+ * emit low-resolution scroll events when appropriate for
+ * backwards-compatibility with userspace input libraries.
+ */
+static void hidpp_scroll_counter_handle_scroll(struct hidpp_scroll_counter *counter,
+                                              int hi_res_value)
+{
+       int low_res_value, remainder, direction;
+       unsigned long long now, previous;
+
+       hi_res_value = hi_res_value * 120/counter->wheel_multiplier;
+       input_report_rel(counter->dev, REL_WHEEL_HI_RES, hi_res_value);
+
+       remainder = counter->remainder;
+       direction = hi_res_value > 0 ? 1 : -1;
+
+       now = sched_clock();
+       previous = counter->last_time;
+       counter->last_time = now;
+       /*
+        * Reset the remainder after a period of inactivity or when the
+        * direction changes. This prevents the REL_WHEEL emulation point
+        * from sliding for devices that don't always provide the same
+        * number of movements per detent.
+        */
+       if (now - previous > 1000000000 || direction != counter->direction)
+               remainder = 0;
+
+       counter->direction = direction;
+       remainder += hi_res_value;
+
+       /* Some wheels will rest 7/8ths of a detent from the previous detent
+        * after slow movement, so we want the threshold for low-res events to
+        * be in the middle between two detents (e.g. after 4/8ths) as
+        * opposed to on the detents themselves (8/8ths).
+        */
+       if (abs(remainder) >= 60) {
+               /* Add (or subtract) 1 because we want to trigger when the wheel
+                * is half-way to the next detent (i.e. scroll 1 detent after a
+                * 1/2 detent movement, 2 detents after a 1 1/2 detent movement,
+                * etc.).
+                */
+               low_res_value = remainder / 120;
+               if (low_res_value == 0)
+                       low_res_value = (hi_res_value > 0 ? 1 : -1);
+               input_report_rel(counter->dev, REL_WHEEL, low_res_value);
+               remainder -= low_res_value * 120;
+       }
+       counter->remainder = remainder;
+}
+
 /* -------------------------------------------------------------------------- */
 /* HIDP++ 1.0 commands                                                        */
 /* -------------------------------------------------------------------------- */
@@ -400,32 +490,53 @@ static void hidpp_prefix_name(char **name, int name_length)
 #define HIDPP_SET_LONG_REGISTER                                0x82
 #define HIDPP_GET_LONG_REGISTER                                0x83
 
-#define HIDPP_REG_GENERAL                              0x00
-
-static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+/**
+ * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register.
+ * @hidpp_dev: the device to set the register on.
+ * @register_address: the address of the register to modify.
+ * @byte: the byte of the register to modify. Should be less than 3.
+ * Return: 0 if successful, otherwise a negative error code.
+ */
+static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
+       u8 register_address, u8 byte, u8 bit)
 {
        struct hidpp_report response;
        int ret;
        u8 params[3] = { 0 };
 
        ret = hidpp_send_rap_command_sync(hidpp_dev,
-                                       REPORT_ID_HIDPP_SHORT,
-                                       HIDPP_GET_REGISTER,
-                                       HIDPP_REG_GENERAL,
-                                       NULL, 0, &response);
+                                         REPORT_ID_HIDPP_SHORT,
+                                         HIDPP_GET_REGISTER,
+                                         register_address,
+                                         NULL, 0, &response);
        if (ret)
                return ret;
 
        memcpy(params, response.rap.params, 3);
 
-       /* Set the battery bit */
-       params[0] |= BIT(4);
+       params[byte] |= BIT(bit);
 
        return hidpp_send_rap_command_sync(hidpp_dev,
-                                       REPORT_ID_HIDPP_SHORT,
-                                       HIDPP_SET_REGISTER,
-                                       HIDPP_REG_GENERAL,
-                                       params, 3, &response);
+                                          REPORT_ID_HIDPP_SHORT,
+                                          HIDPP_SET_REGISTER,
+                                          register_address,
+                                          params, 3, &response);
+}
+
+
+#define HIDPP_REG_GENERAL                              0x00
+
+static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+{
+       return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4);
+}
+
+#define HIDPP_REG_FEATURES                             0x01
+
+/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */
+static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev)
+{
+       return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6);
 }
 
 #define HIDPP_REG_BATTERY_STATUS                       0x07
@@ -1136,6 +1247,99 @@ static int hidpp_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
+/* -------------------------------------------------------------------------- */
+/* 0x2120: Hi-resolution scrolling                                            */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING                     0x2120
+
+#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10
+
+static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp,
+       bool enabled, u8 *multiplier)
+{
+       u8 feature_index;
+       u8 feature_type;
+       int ret;
+       u8 params[1];
+       struct hidpp_report response;
+
+       ret = hidpp_root_get_feature(hidpp,
+                                    HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
+                                    &feature_index,
+                                    &feature_type);
+       if (ret)
+               return ret;
+
+       params[0] = enabled ? BIT(0) : 0;
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+                                         CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE,
+                                         params, sizeof(params), &response);
+       if (ret)
+               return ret;
+       *multiplier = response.fap.params[1];
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* 0x2121: HiRes Wheel                                                        */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_HIRES_WHEEL         0x2121
+
+#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY   0x00
+#define CMD_HIRES_WHEEL_SET_WHEEL_MODE         0x20
+
+static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp,
+       u8 *multiplier)
+{
+       u8 feature_index;
+       u8 feature_type;
+       int ret;
+       struct hidpp_report response;
+
+       ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
+                                    &feature_index, &feature_type);
+       if (ret)
+               goto return_default;
+
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+                                         CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY,
+                                         NULL, 0, &response);
+       if (ret)
+               goto return_default;
+
+       *multiplier = response.fap.params[0];
+       return 0;
+return_default:
+       hid_warn(hidpp->hid_dev,
+                "Couldn't get wheel multiplier (error %d)\n", ret);
+       return ret;
+}
+
+static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert,
+       bool high_resolution, bool use_hidpp)
+{
+       u8 feature_index;
+       u8 feature_type;
+       int ret;
+       u8 params[1];
+       struct hidpp_report response;
+
+       ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
+                                    &feature_index, &feature_type);
+       if (ret)
+               return ret;
+
+       params[0] = (invert          ? BIT(2) : 0) |
+                   (high_resolution ? BIT(1) : 0) |
+                   (use_hidpp       ? BIT(0) : 0);
+
+       return hidpp_send_fap_command_sync(hidpp, feature_index,
+                                          CMD_HIRES_WHEEL_SET_WHEEL_MODE,
+                                          params, sizeof(params), &response);
+}
+
 /* -------------------------------------------------------------------------- */
 /* 0x4301: Solar Keyboard                                                     */
 /* -------------------------------------------------------------------------- */
@@ -1465,7 +1669,7 @@ struct hidpp_ff_work_data {
        u8 size;
 };
 
-static const signed short hiddpp_ff_effects[] = {
+static const signed short hidpp_ff_effects[] = {
        FF_CONSTANT,
        FF_PERIODIC,
        FF_SINE,
@@ -1480,7 +1684,7 @@ static const signed short hiddpp_ff_effects[] = {
        -1
 };
 
-static const signed short hiddpp_ff_effects_v2[] = {
+static const signed short hidpp_ff_effects_v2[] = {
        FF_RAMP,
        FF_FRICTION,
        FF_INERTIA,
@@ -1873,11 +2077,11 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
        version = bcdDevice & 255;
 
        /* Set supported force feedback capabilities */
-       for (j = 0; hiddpp_ff_effects[j] >= 0; j++)
-               set_bit(hiddpp_ff_effects[j], dev->ffbit);
+       for (j = 0; hidpp_ff_effects[j] >= 0; j++)
+               set_bit(hidpp_ff_effects[j], dev->ffbit);
        if (version > 1)
-               for (j = 0; hiddpp_ff_effects_v2[j] >= 0; j++)
-                       set_bit(hiddpp_ff_effects_v2[j], dev->ffbit);
+               for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++)
+                       set_bit(hidpp_ff_effects_v2[j], dev->ffbit);
 
        /* Read number of slots available in device */
        error = hidpp_send_fap_command_sync(hidpp, feature_index,
@@ -2387,10 +2591,15 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
                input_report_key(mydata->input, BTN_RIGHT,
                        !!(data[1] & M560_MOUSE_BTN_RIGHT));
 
-               if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT)
+               if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) {
                        input_report_rel(mydata->input, REL_HWHEEL, -1);
-               else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT)
+                       input_report_rel(mydata->input, REL_HWHEEL_HI_RES,
+                                        -120);
+               } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) {
                        input_report_rel(mydata->input, REL_HWHEEL, 1);
+                       input_report_rel(mydata->input, REL_HWHEEL_HI_RES,
+                                        120);
+               }
 
                v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12);
                input_report_rel(mydata->input, REL_X, v);
@@ -2399,7 +2608,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
                input_report_rel(mydata->input, REL_Y, v);
 
                v = hid_snto32(data[6], 8);
-               input_report_rel(mydata->input, REL_WHEEL, v);
+               hidpp_scroll_counter_handle_scroll(
+                               &hidpp->vertical_wheel_counter, v);
 
                input_sync(mydata->input);
        }
@@ -2426,6 +2636,8 @@ static void m560_populate_input(struct hidpp_device *hidpp,
        __set_bit(REL_Y, mydata->input->relbit);
        __set_bit(REL_WHEEL, mydata->input->relbit);
        __set_bit(REL_HWHEEL, mydata->input->relbit);
+       __set_bit(REL_WHEEL_HI_RES, mydata->input->relbit);
+       __set_bit(REL_HWHEEL_HI_RES, mydata->input->relbit);
 }
 
 static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -2527,6 +2739,37 @@ static int g920_get_config(struct hidpp_device *hidpp)
        return 0;
 }
 
+/* -------------------------------------------------------------------------- */
+/* High-resolution scroll wheels                                              */
+/* -------------------------------------------------------------------------- */
+
+static int hi_res_scroll_enable(struct hidpp_device *hidpp)
+{
+       int ret;
+       u8 multiplier = 1;
+
+       if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
+               ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
+               if (ret == 0)
+                       ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
+       } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
+               ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
+                                                          &multiplier);
+       } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ {
+               ret = hidpp10_enable_scrolling_acceleration(hidpp);
+               multiplier = 8;
+       }
+       if (ret)
+               return ret;
+
+       if (multiplier == 0)
+               multiplier = 1;
+
+       hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
+       hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier);
+       return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* Generic HID++ devices                                                      */
 /* -------------------------------------------------------------------------- */
@@ -2572,6 +2815,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
                wtp_populate_input(hidpp, input, origin_is_hid_core);
        else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
                m560_populate_input(hidpp, input, origin_is_hid_core);
+
+       if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
+               hidpp->vertical_wheel_counter.dev = input;
 }
 
 static int hidpp_input_configured(struct hid_device *hdev,
@@ -2690,6 +2936,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
        return 0;
 }
 
+static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
+       struct hid_usage *usage, __s32 value)
+{
+       /* This function will only be called for scroll events, due to the
+        * restriction imposed in hidpp_usages.
+        */
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+       struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter;
+       /* A scroll event may occur before the multiplier has been retrieved or
+        * the input device set, or high-res scroll enabling may fail. In such
+        * cases we must return early (falling back to default behaviour) to
+        * avoid a crash in hidpp_scroll_counter_handle_scroll.
+        */
+       if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
+           || counter->dev == NULL || counter->wheel_multiplier == 0)
+               return 0;
+
+       hidpp_scroll_counter_handle_scroll(counter, value);
+       return 1;
+}
+
 static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 {
        static atomic_t battery_no = ATOMIC_INIT(0);
@@ -2901,6 +3168,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
        if (hidpp->battery.ps)
                power_supply_changed(hidpp->battery.ps);
 
+       if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
+               hi_res_scroll_enable(hidpp);
+
        if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
                /* if the input nodes are already created, we can stop now */
                return;
@@ -3086,35 +3356,63 @@ static void hidpp_remove(struct hid_device *hdev)
        mutex_destroy(&hidpp->send_mutex);
 }
 
+#define LDJ_DEVICE(product) \
+       HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
+                  USB_VENDOR_ID_LOGITECH, (product))
+
 static const struct hid_device_id hidpp_devices[] = {
        { /* wireless touchpad */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4011),
+         LDJ_DEVICE(0x4011),
          .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
                         HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
        { /* wireless touchpad T650 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4101),
+         LDJ_DEVICE(0x4101),
          .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
        { /* wireless touchpad T651 */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_LOGITECH_T651),
          .driver_data = HIDPP_QUIRK_CLASS_WTP },
+       { /* Mouse Logitech Anywhere MX */
+         LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
+       { /* Mouse Logitech Cube */
+         LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
+       { /* Mouse Logitech M335 */
+         LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech M515 */
+         LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
        { /* Mouse logitech M560 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x402d),
-         .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
+         LDJ_DEVICE(0x402d),
+         .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
+               | HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
+       { /* Mouse Logitech M705 (firmware RQM17) */
+         LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
+       { /* Mouse Logitech M705 (firmware RQM67) */
+         LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech M720 */
+         LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech MX Anywhere 2 */
+         LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech MX Anywhere 2S */
+         LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech MX Master */
+         LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech MX Master 2S */
+         LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+       { /* Mouse Logitech Performance MX */
+         LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
        { /* Keyboard logitech K400 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4024),
+         LDJ_DEVICE(0x4024),
          .driver_data = HIDPP_QUIRK_CLASS_K400 },
        { /* Solar Keyboard Logitech K750 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4002),
+         LDJ_DEVICE(0x4002),
          .driver_data = HIDPP_QUIRK_CLASS_K750 },
 
-       { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+       { LDJ_DEVICE(HID_ANY_ID) },
 
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
                .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
@@ -3123,12 +3421,19 @@ static const struct hid_device_id hidpp_devices[] = {
 
 MODULE_DEVICE_TABLE(hid, hidpp_devices);
 
+static const struct hid_usage_id hidpp_usages[] = {
+       { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
 static struct hid_driver hidpp_driver = {
        .name = "logitech-hidpp-device",
        .id_table = hidpp_devices,
        .probe = hidpp_probe,
        .remove = hidpp_remove,
        .raw_event = hidpp_raw_event,
+       .usage_table = hidpp_usages,
+       .event = hidpp_event,
        .input_configured = hidpp_input_configured,
        .input_mapping = hidpp_input_mapping,
        .input_mapped = hidpp_input_mapped,
index 4a44e48e08b225a6180ad014604dabc83ce65c2d..9fc51eff10790a9f86a0ab5eadd2bb96ccfc5e76 100644 (file)
@@ -107,8 +107,6 @@ out:
 
 /*
  * The first byte of the report buffer is expected to be a report number.
- *
- * This function is to be called with the minors_lock mutex held.
  */
 static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
 {
@@ -117,6 +115,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
        __u8 *buf;
        int ret = 0;
 
+       lockdep_assert_held(&minors_lock);
+
        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                ret = -ENODEV;
                goto out;
@@ -181,8 +181,6 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
  * of buffer is the report number to request, or 0x0 if the defice does not
  * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
  * or HID_INPUT_REPORT.
- *
- * This function is to be called with the minors_lock mutex held.
  */
 static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
 {
@@ -192,6 +190,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
        int ret = 0, len;
        unsigned char report_number;
 
+       lockdep_assert_held(&minors_lock);
+
        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                ret = -ENODEV;
                goto out;
index 89f2976f9c534c475da40c3933d2775e46787ae9..fd1b6eea6d2fdcf85aeb25595e371fbfab5f8ed5 100644 (file)
@@ -346,6 +346,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
                },
                .driver_data = (void *)&sipodev_desc
        },
+       {
+               .ident = "Odys Winbook 13",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "WINBOOK 13"),
+               },
+               .driver_data = (void *)&sipodev_desc
+       },
        { }     /* Terminate list */
 };
 
index 8793cc49f8554c2b331323c86071b5371e4ce635..a6e1ee744f4d418c32745420b936afec111363dc 100644 (file)
@@ -117,6 +117,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret;
        struct ish_hw *hw;
+       unsigned long irq_flag = 0;
        struct ishtp_device *ishtp;
        struct device *dev = &pdev->dev;
 
@@ -156,8 +157,12 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
 
        /* request and enable interrupt */
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+       if (!pdev->msi_enabled && !pdev->msix_enabled)
+               irq_flag = IRQF_SHARED;
+
        ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
-                              IRQF_SHARED, KBUILD_MODNAME, ishtp);
+                              irq_flag, KBUILD_MODNAME, ishtp);
        if (ret) {
                dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
                return ret;
index cd23903ddcf194e581902102ebcd56f70459ac9a..e918d78e541c0d072ea4fe89cdfec2eb9628da4c 100644 (file)
@@ -222,7 +222,7 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
 err_hid_device:
        kfree(hid_data);
 err_hid_data:
-       kfree(hid);
+       hid_destroy_device(hid);
        return rv;
 }
 
index e895d29500eec03d10f5067c55a14602cc60de02..7869c67e5b6baf56709b4114d9cf219a9be10dc7 100644 (file)
@@ -49,6 +49,15 @@ config HWSPINLOCK_SPRD
 
          If unsure, say N.
 
+config HWSPINLOCK_STM32
+       tristate "STM32 Hardware Spinlock device"
+       depends on MACH_STM32MP157
+       depends on HWSPINLOCK
+       help
+         Say y here to support the STM32 Hardware Spinlock device.
+
+         If unsure, say N.
+
 config HSEM_U8500
        tristate "STE Hardware Semaphore functionality"
        depends on HWSPINLOCK
index b87c01a506a494c81a627062dff25ed1eae4ae4e..ed053e3f02be4a29ee282f9c2150a1a88e97415b 100644 (file)
@@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP)           += omap_hwspinlock.o
 obj-$(CONFIG_HWSPINLOCK_QCOM)          += qcom_hwspinlock.o
 obj-$(CONFIG_HWSPINLOCK_SIRF)          += sirf_hwspinlock.o
 obj-$(CONFIG_HWSPINLOCK_SPRD)          += sprd_hwspinlock.o
+obj-$(CONFIG_HWSPINLOCK_STM32)         += stm32_hwspinlock.o
 obj-$(CONFIG_HSEM_U8500)               += u8500_hsem.o
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
new file mode 100644 (file)
index 0000000..4418392
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics SA 2018
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/hwspinlock.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "hwspinlock_internal.h"
+
+#define STM32_MUTEX_COREID     BIT(8)
+#define STM32_MUTEX_LOCK_BIT   BIT(31)
+#define STM32_MUTEX_NUM_LOCKS  32
+
+struct stm32_hwspinlock {
+       struct clk *clk;
+       struct hwspinlock_device bank;
+};
+
+static int stm32_hwspinlock_trylock(struct hwspinlock *lock)
+{
+       void __iomem *lock_addr = lock->priv;
+       u32 status;
+
+       writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, lock_addr);
+       status = readl(lock_addr);
+
+       return status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID);
+}
+
+static void stm32_hwspinlock_unlock(struct hwspinlock *lock)
+{
+       void __iomem *lock_addr = lock->priv;
+
+       writel(STM32_MUTEX_COREID, lock_addr);
+}
+
+static const struct hwspinlock_ops stm32_hwspinlock_ops = {
+       .trylock        = stm32_hwspinlock_trylock,
+       .unlock         = stm32_hwspinlock_unlock,
+};
+
+static int stm32_hwspinlock_probe(struct platform_device *pdev)
+{
+       struct stm32_hwspinlock *hw;
+       void __iomem *io_base;
+       struct resource *res;
+       size_t array_size;
+       int i, ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(io_base))
+               return PTR_ERR(io_base);
+
+       array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
+       hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+
+       hw->clk = devm_clk_get(&pdev->dev, "hsem");
+       if (IS_ERR(hw->clk))
+               return PTR_ERR(hw->clk);
+
+       for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++)
+               hw->bank.lock[i].priv = io_base + i * sizeof(u32);
+
+       platform_set_drvdata(pdev, hw);
+       pm_runtime_enable(&pdev->dev);
+
+       ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops,
+                                  0, STM32_MUTEX_NUM_LOCKS);
+
+       if (ret)
+               pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static int stm32_hwspinlock_remove(struct platform_device *pdev)
+{
+       struct stm32_hwspinlock *hw = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = hwspin_lock_unregister(&hw->bank);
+       if (ret)
+               dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
+
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev)
+{
+       struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(hw->clk);
+
+       return 0;
+}
+
+static int __maybe_unused stm32_hwspinlock_runtime_resume(struct device *dev)
+{
+       struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
+
+       clk_prepare_enable(hw->clk);
+
+       return 0;
+}
+
+static const struct dev_pm_ops stm32_hwspinlock_pm_ops = {
+       SET_RUNTIME_PM_OPS(stm32_hwspinlock_runtime_suspend,
+                          stm32_hwspinlock_runtime_resume,
+                          NULL)
+};
+
+static const struct of_device_id stm32_hwpinlock_ids[] = {
+       { .compatible = "st,stm32-hwspinlock", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids);
+
+static struct platform_driver stm32_hwspinlock_driver = {
+       .probe          = stm32_hwspinlock_probe,
+       .remove         = stm32_hwspinlock_remove,
+       .driver         = {
+               .name   = "stm32_hwspinlock",
+               .of_match_table = stm32_hwpinlock_ids,
+               .pm     = &stm32_hwspinlock_pm_ops,
+       },
+};
+
+static int __init stm32_hwspinlock_init(void)
+{
+       return platform_driver_register(&stm32_hwspinlock_driver);
+}
+/* board init code might need to reserve hwspinlocks for predefined purposes */
+postcore_initcall(stm32_hwspinlock_init);
+
+static void __exit stm32_hwspinlock_exit(void)
+{
+       platform_driver_unregister(&stm32_hwspinlock_driver);
+}
+module_exit(stm32_hwspinlock_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hardware spinlock driver for STM32 SoCs");
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
index 51d34959709bade4c9baed0f14770ec4cb9719ea..bf564391091f3014bc7fb582cf96eeb666453252 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
@@ -25,6 +26,7 @@
 #define I2C_XFER_TIMEOUT    (msecs_to_jiffies(250))
 #define I2C_STOP_TIMEOUT    (msecs_to_jiffies(100))
 #define FIFO_SIZE           8
+#define SEQ_LEN             2
 
 #define GLOBAL_CONTROL         0x00
 #define   GLOBAL_MST_EN         BIT(0)
@@ -51,6 +53,7 @@
 #define   CMD_BUSY             (1<<3)
 #define   CMD_MANUAL           (0x00 | CMD_BUSY)
 #define   CMD_AUTO             (0x01 | CMD_BUSY)
+#define   CMD_SEQUENCE         (0x02 | CMD_BUSY)
 #define MST_RX_XFER            0x2c
 #define MST_TX_XFER            0x30
 #define MST_ADDR_1             0x34
@@ -87,7 +90,9 @@
  * axxia_i2c_dev - I2C device context
  * @base: pointer to register struct
  * @msg: pointer to current message
- * @msg_xfrd: number of bytes transferred in msg
+ * @msg_r: pointer to current read message (sequence transfer)
+ * @msg_xfrd: number of bytes transferred in tx_fifo
+ * @msg_xfrd_r: number of bytes transferred in rx_fifo
  * @msg_err: error code for completed message
  * @msg_complete: xfer completion object
  * @dev: device reference
 struct axxia_i2c_dev {
        void __iomem *base;
        struct i2c_msg *msg;
+       struct i2c_msg *msg_r;
        size_t msg_xfrd;
+       size_t msg_xfrd_r;
        int msg_err;
        struct completion msg_complete;
        struct device *dev;
@@ -227,14 +234,14 @@ static int i2c_m_recv_len(const struct i2c_msg *msg)
  */
 static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
 {
-       struct i2c_msg *msg = idev->msg;
+       struct i2c_msg *msg = idev->msg_r;
        size_t rx_fifo_avail = readl(idev->base + MST_RX_FIFO);
-       int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd);
+       int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd_r);
 
        while (bytes_to_transfer-- > 0) {
                int c = readl(idev->base + MST_DATA);
 
-               if (idev->msg_xfrd == 0 && i2c_m_recv_len(msg)) {
+               if (idev->msg_xfrd_r == 0 && i2c_m_recv_len(msg)) {
                        /*
                         * Check length byte for SMBus block read
                         */
@@ -247,7 +254,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
                        msg->len = 1 + c;
                        writel(msg->len, idev->base + MST_RX_XFER);
                }
-               msg->buf[idev->msg_xfrd++] = c;
+               msg->buf[idev->msg_xfrd_r++] = c;
        }
 
        return 0;
@@ -287,7 +294,7 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
        }
 
        /* RX FIFO needs service? */
-       if (i2c_m_rd(idev->msg) && (status & MST_STATUS_RFL))
+       if (i2c_m_rd(idev->msg_r) && (status & MST_STATUS_RFL))
                axxia_i2c_empty_rx_fifo(idev);
 
        /* TX FIFO needs service? */
@@ -296,22 +303,7 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
                        i2c_int_disable(idev, MST_STATUS_TFL);
        }
 
-       if (status & MST_STATUS_SCC) {
-               /* Stop completed */
-               i2c_int_disable(idev, ~MST_STATUS_TSS);
-               complete(&idev->msg_complete);
-       } else if (status & MST_STATUS_SNS) {
-               /* Transfer done */
-               i2c_int_disable(idev, ~MST_STATUS_TSS);
-               if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
-                       axxia_i2c_empty_rx_fifo(idev);
-               complete(&idev->msg_complete);
-       } else if (status & MST_STATUS_TSS) {
-               /* Transfer timeout */
-               idev->msg_err = -ETIMEDOUT;
-               i2c_int_disable(idev, ~MST_STATUS_TSS);
-               complete(&idev->msg_complete);
-       } else if (unlikely(status & MST_STATUS_ERR)) {
+       if (unlikely(status & MST_STATUS_ERR)) {
                /* Transfer error */
                i2c_int_disable(idev, ~0);
                if (status & MST_STATUS_AL)
@@ -328,6 +320,24 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
                        readl(idev->base + MST_TX_BYTES_XFRD),
                        readl(idev->base + MST_TX_XFER));
                complete(&idev->msg_complete);
+       } else if (status & MST_STATUS_SCC) {
+               /* Stop completed */
+               i2c_int_disable(idev, ~MST_STATUS_TSS);
+               complete(&idev->msg_complete);
+       } else if (status & MST_STATUS_SNS) {
+               /* Transfer done */
+               i2c_int_disable(idev, ~MST_STATUS_TSS);
+               if (i2c_m_rd(idev->msg_r) && idev->msg_xfrd_r < idev->msg_r->len)
+                       axxia_i2c_empty_rx_fifo(idev);
+               complete(&idev->msg_complete);
+       } else if (status & MST_STATUS_SS) {
+               /* Auto/Sequence transfer done */
+               complete(&idev->msg_complete);
+       } else if (status & MST_STATUS_TSS) {
+               /* Transfer timeout */
+               idev->msg_err = -ETIMEDOUT;
+               i2c_int_disable(idev, ~MST_STATUS_TSS);
+               complete(&idev->msg_complete);
        }
 
 out:
@@ -337,17 +347,9 @@ out:
        return IRQ_HANDLED;
 }
 
-static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
+static void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 {
-       u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
-       u32 rx_xfer, tx_xfer;
        u32 addr_1, addr_2;
-       unsigned long time_left;
-       unsigned int wt_value;
-
-       idev->msg = msg;
-       idev->msg_xfrd = 0;
-       reinit_completion(&idev->msg_complete);
 
        if (i2c_m_ten(msg)) {
                /* 10-bit address
@@ -367,6 +369,90 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
                addr_2 = 0;
        }
 
+       writel(addr_1, idev->base + MST_ADDR_1);
+       writel(addr_2, idev->base + MST_ADDR_2);
+}
+
+/* The NAK interrupt will be sent _before_ issuing STOP command
+ * so the controller might still be busy processing it. No
+ * interrupt will be sent at the end so we have to poll for it
+ */
+static int axxia_i2c_handle_seq_nak(struct axxia_i2c_dev *idev)
+{
+       unsigned long timeout = jiffies + I2C_XFER_TIMEOUT;
+
+       do {
+               if ((readl(idev->base + MST_COMMAND) & CMD_BUSY) == 0)
+                       return 0;
+               usleep_range(1, 100);
+       } while (time_before(jiffies, timeout));
+
+       return -ETIMEDOUT;
+}
+
+static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[])
+{
+       u32 int_mask = MST_STATUS_ERR | MST_STATUS_SS | MST_STATUS_RFL;
+       u32 rlen = i2c_m_recv_len(&msgs[1]) ? I2C_SMBUS_BLOCK_MAX : msgs[1].len;
+       unsigned long time_left;
+
+       axxia_i2c_set_addr(idev, &msgs[0]);
+
+       writel(msgs[0].len, idev->base + MST_TX_XFER);
+       writel(rlen, idev->base + MST_RX_XFER);
+
+       idev->msg = &msgs[0];
+       idev->msg_r = &msgs[1];
+       idev->msg_xfrd = 0;
+       idev->msg_xfrd_r = 0;
+       axxia_i2c_fill_tx_fifo(idev);
+
+       writel(CMD_SEQUENCE, idev->base + MST_COMMAND);
+
+       reinit_completion(&idev->msg_complete);
+       i2c_int_enable(idev, int_mask);
+
+       time_left = wait_for_completion_timeout(&idev->msg_complete,
+                                               I2C_XFER_TIMEOUT);
+
+       i2c_int_disable(idev, int_mask);
+
+       axxia_i2c_empty_rx_fifo(idev);
+
+       if (idev->msg_err == -ENXIO) {
+               if (axxia_i2c_handle_seq_nak(idev))
+                       axxia_i2c_init(idev);
+       } else if (readl(idev->base + MST_COMMAND) & CMD_BUSY) {
+               dev_warn(idev->dev, "busy after xfer\n");
+       }
+
+       if (time_left == 0) {
+               idev->msg_err = -ETIMEDOUT;
+               i2c_recover_bus(&idev->adapter);
+               axxia_i2c_init(idev);
+       }
+
+       if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
+               axxia_i2c_init(idev);
+
+       return idev->msg_err;
+}
+
+static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
+{
+       u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
+       u32 rx_xfer, tx_xfer;
+       unsigned long time_left;
+       unsigned int wt_value;
+
+       idev->msg = msg;
+       idev->msg_r = msg;
+       idev->msg_xfrd = 0;
+       idev->msg_xfrd_r = 0;
+       reinit_completion(&idev->msg_complete);
+
+       axxia_i2c_set_addr(idev, msg);
+
        if (i2c_m_rd(msg)) {
                /* I2C read transfer */
                rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len;
@@ -379,8 +465,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 
        writel(rx_xfer, idev->base + MST_RX_XFER);
        writel(tx_xfer, idev->base + MST_TX_XFER);
-       writel(addr_1, idev->base + MST_ADDR_1);
-       writel(addr_2, idev->base + MST_ADDR_2);
 
        if (i2c_m_rd(msg))
                int_mask |= MST_STATUS_RFL;
@@ -445,6 +529,18 @@ static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
        return 0;
 }
 
+/* This function checks if the msgs[] array contains messages compatible with
+ * Sequence mode of operation. This mode assumes there will be exactly one
+ * write of non-zero length followed by exactly one read of non-zero length,
+ * both targeted at the same client device.
+ */
+static bool axxia_i2c_sequence_ok(struct i2c_msg msgs[], int num)
+{
+       return num == SEQ_LEN && !i2c_m_rd(&msgs[0]) && i2c_m_rd(&msgs[1]) &&
+              msgs[0].len > 0 && msgs[0].len <= FIFO_SIZE &&
+              msgs[1].len > 0 && msgs[0].addr == msgs[1].addr;
+}
+
 static int
 axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
@@ -453,6 +549,12 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int ret = 0;
 
        idev->msg_err = 0;
+
+       if (axxia_i2c_sequence_ok(msgs, num)) {
+               ret = axxia_i2c_xfer_seq(idev, msgs);
+               return ret ? : SEQ_LEN;
+       }
+
        i2c_int_enable(idev, MST_STATUS_TSS);
 
        for (i = 0; ret == 0 && i < num; ++i)
index 44deae78913e5fa259927d1b5e8b6bf9aee60138..ec6e69aa3a8e5ac455c0ede516d96b75fc7a87a8 100644 (file)
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * BCM2835 master mode driver
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/clk.h>
index eb76b76f4754edfed8ba4641d854de97c593969e..82bcd9a78759198befef1d588235def83cdf7f9f 100644 (file)
@@ -1,13 +1,7 @@
-/*
- *  Copyright (C) 2013 Google, Inc
- *
- *  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.
- *
- * Expose an I2C passthrough to the ChromeOS EC.
- */
+// SPDX-License-Identifier: GPL-2.0+
+// Expose an I2C passthrough to the ChromeOS EC.
+//
+// Copyright (C) 2013 Google, Inc.
 
 #include <linux/module.h>
 #include <linux/i2c.h>
index 6f6e1dfe7ccee3982d4e824215b53ef2e48772ff..d78023d42a350b6195b653aebd9d97fe85aed203 100644 (file)
@@ -437,7 +437,7 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
                                break;
                        }
 
-                       if (unlikely(signal_pending(current))){
+                       if (signal_pending(current)){
                                DBG("%d: poll interrupted\n", dev->idx);
                                ret = -ERESTARTSYS;
                                break;
index c406700789e1f9c5a3af5c3fa62f045180702bb1..fa9ad53845d9a36bef9927bd9f53c783b397bfd9 100644 (file)
@@ -1090,7 +1090,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
        /* Get I2C clock */
        i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2c_imx->clk)) {
-               dev_err(&pdev->dev, "can't get I2C clock\n");
+               if (PTR_ERR(i2c_imx->clk) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "can't get I2C clock\n");
                return PTR_ERR(i2c_imx->clk);
        }
 
index 0d1c3ec8cb40734f96529dffadffc28d686c22ac..02d23edb2fb10abae55075bd121df69c6893eb66 100644 (file)
@@ -75,6 +75,7 @@
 /* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */
 #define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59
 #define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a
+#define PCI_DEVICE_ID_INTEL_CDF_SMT    0x18ac
 #define PCI_DEVICE_ID_INTEL_DNV_SMT    0x19ac
 #define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15
 
@@ -181,6 +182,7 @@ struct ismt_priv {
 static const struct pci_device_id ismt_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
        { 0, }
index 96b4572e6d9cc4465decf7993616595caa492da3..b6b5a495118b6dc8e13ff7582ab815a684778152 100644 (file)
@@ -475,6 +475,7 @@ disable_clk:
 }
 
 static const struct of_device_id owl_i2c_of_match[] = {
+       { .compatible = "actions,s700-i2c" },
        { .compatible = "actions,s900-i2c" },
        { /* sentinel */ }
 };
index f6f4ed8afc9386ac34fe7be9ee40e575ac6e00ee..281113c28314efb32d889c21e3344e8f408e87a0 100644 (file)
@@ -229,9 +229,9 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
                return (be32_to_cpup(prop) & 0xff) >> 1;
 
        /* Now handle some devices with missing "reg" properties */
-       if (!strcmp(node->name, "cereal"))
+       if (of_node_name_eq(node, "cereal"))
                return 0x60;
-       else if (!strcmp(node->name, "deq"))
+       else if (of_node_name_eq(node, "deq"))
                return 0x34;
 
        dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
@@ -304,7 +304,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap,
        }
 
        /* Now look for known workarounds */
-       if (!strcmp(node->name, "deq")) {
+       if (of_node_name_eq(node, "deq")) {
                /* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
                if (addr == 0x34) {
                        snprintf(type, type_size, "MAC,tas3001");
@@ -331,7 +331,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
         * case we skip this function completely as the device-tree will
         * not contain anything useful.
         */
-       if (!strcmp(adap->dev.of_node->name, "via-pmu"))
+       if (of_node_name_eq(adap->dev.of_node, "via-pmu"))
                return;
 
        for_each_child_of_node(adap->dev.of_node, node) {
index a7a7a9c3bc7c499b59f4672399adf7ec3691f667..a64f2ff3cb49ce47b41dda39d00bf92e532cab75 100644 (file)
@@ -800,6 +800,7 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = {
 static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
        { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
+       { .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
        { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
@@ -808,6 +809,7 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
        { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
        { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
        { .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
        {},
index 62d023e737d9c2f60a26ea4174e78154dc10e877..13e1213561d4b40335b44ff28d832d7840a4b4d2 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 
 #define STM32F7_SCLH_MAX                       BIT(8)
 #define STM32F7_SCLL_MAX                       BIT(8)
 
+#define STM32F7_AUTOSUSPEND_DELAY              (HZ / 100)
+
 /**
  * struct stm32f7_i2c_spec - private i2c specification timing
  * @rate: I2C bus speed (Hz)
@@ -276,6 +282,7 @@ struct stm32f7_i2c_msg {
  * slave)
  * @dma: dma data
  * @use_dma: boolean to know if dma is used in the current transfer
+ * @regmap: holds SYSCFG phandle for Fast Mode Plus bits
  */
 struct stm32f7_i2c_dev {
        struct i2c_adapter adap;
@@ -296,6 +303,7 @@ struct stm32f7_i2c_dev {
        bool master_mode;
        struct stm32_i2c_dma *dma;
        bool use_dma;
+       struct regmap *regmap;
 };
 
 /**
@@ -1545,15 +1553,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
        i2c_dev->msg_id = 0;
        f7_msg->smbus = false;
 
-       ret = clk_enable(i2c_dev->clk);
-       if (ret) {
-               dev_err(i2c_dev->dev, "Failed to enable clock\n");
+       ret = pm_runtime_get_sync(i2c_dev->dev);
+       if (ret < 0)
                return ret;
-       }
 
        ret = stm32f7_i2c_wait_free_bus(i2c_dev);
        if (ret)
-               goto clk_free;
+               goto pm_free;
 
        stm32f7_i2c_xfer_msg(i2c_dev, msgs);
 
@@ -1569,8 +1575,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
                ret = -ETIMEDOUT;
        }
 
-clk_free:
-       clk_disable(i2c_dev->clk);
+pm_free:
+       pm_runtime_mark_last_busy(i2c_dev->dev);
+       pm_runtime_put_autosuspend(i2c_dev->dev);
 
        return (ret < 0) ? ret : num;
 }
@@ -1592,39 +1599,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
        f7_msg->read_write = read_write;
        f7_msg->smbus = true;
 
-       ret = clk_enable(i2c_dev->clk);
-       if (ret) {
-               dev_err(i2c_dev->dev, "Failed to enable clock\n");
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
                return ret;
-       }
 
        ret = stm32f7_i2c_wait_free_bus(i2c_dev);
        if (ret)
-               goto clk_free;
+               goto pm_free;
 
        ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
        if (ret)
-               goto clk_free;
+               goto pm_free;
 
        timeout = wait_for_completion_timeout(&i2c_dev->complete,
                                              i2c_dev->adap.timeout);
        ret = f7_msg->result;
        if (ret)
-               goto clk_free;
+               goto pm_free;
 
        if (!timeout) {
                dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
                if (i2c_dev->use_dma)
                        dmaengine_terminate_all(dma->chan_using);
                ret = -ETIMEDOUT;
-               goto clk_free;
+               goto pm_free;
        }
 
        /* Check PEC */
        if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
                ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
                if (ret)
-                       goto clk_free;
+                       goto pm_free;
        }
 
        if (read_write && size != I2C_SMBUS_QUICK) {
@@ -1649,8 +1654,9 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                }
        }
 
-clk_free:
-       clk_disable(i2c_dev->clk);
+pm_free:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
        return ret;
 }
 
@@ -1676,13 +1682,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
        if (ret)
                return ret;
 
-       if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
-               ret = clk_enable(i2c_dev->clk);
-               if (ret) {
-                       dev_err(dev, "Failed to enable clock\n");
-                       return ret;
-               }
-       }
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               return ret;
 
        if (id == 0) {
                /* Configure Own Address 1 */
@@ -1703,7 +1705,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
                oar2 &= ~STM32F7_I2C_OAR2_MASK;
                if (slave->flags & I2C_CLIENT_TEN) {
                        ret = -EOPNOTSUPP;
-                       goto exit;
+                       goto pm_free;
                }
 
                oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
@@ -1712,7 +1714,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
                writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
        } else {
                ret = -ENODEV;
-               goto exit;
+               goto pm_free;
        }
 
        /* Enable ACK */
@@ -1723,11 +1725,10 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
                STM32F7_I2C_CR1_PE;
        stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
 
-       return 0;
-
-exit:
-       if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
-               clk_disable(i2c_dev->clk);
+       ret = 0;
+pm_free:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 
        return ret;
 }
@@ -1745,6 +1746,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
 
        WARN_ON(!i2c_dev->slave[id]);
 
+       ret = pm_runtime_get_sync(i2c_dev->dev);
+       if (ret < 0)
+               return ret;
+
        if (id == 0) {
                mask = STM32F7_I2C_OAR1_OA1EN;
                stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
@@ -1755,14 +1760,39 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
 
        i2c_dev->slave[id] = NULL;
 
-       if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+       if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
                stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
-               clk_disable(i2c_dev->clk);
-       }
+
+       pm_runtime_mark_last_busy(i2c_dev->dev);
+       pm_runtime_put_autosuspend(i2c_dev->dev);
 
        return 0;
 }
 
+static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
+                                         struct stm32f7_i2c_dev *i2c_dev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+       u32 reg, mask;
+
+       i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp");
+       if (IS_ERR(i2c_dev->regmap)) {
+               /* Optional */
+               return 0;
+       }
+
+       ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1, &reg);
+       if (ret)
+               return ret;
+
+       ret = of_property_read_u32_index(np, "st,syscfg-fmp", 2, &mask);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(i2c_dev->regmap, reg, mask, mask);
+}
+
 static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
@@ -1819,6 +1849,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Error: Missing controller clock\n");
                return PTR_ERR(i2c_dev->clk);
        }
+
        ret = clk_prepare_enable(i2c_dev->clk);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
@@ -1828,12 +1859,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
        i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
        ret = device_property_read_u32(&pdev->dev, "clock-frequency",
                                       &clk_rate);
-       if (!ret && clk_rate >= 1000000)
+       if (!ret && clk_rate >= 1000000) {
                i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
-       else if (!ret && clk_rate >= 400000)
+               ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
+               if (ret)
+                       goto clk_free;
+       } else if (!ret && clk_rate >= 400000) {
                i2c_dev->speed = STM32_I2C_SPEED_FAST;
-       else if (!ret && clk_rate >= 100000)
+       } else if (!ret && clk_rate >= 100000) {
                i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
+       }
 
        rst = devm_reset_control_get(&pdev->dev, NULL);
        if (IS_ERR(rst)) {
@@ -1888,8 +1923,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
        if (ret)
                goto clk_free;
 
-       stm32f7_i2c_hw_config(i2c_dev);
-
        adap = &i2c_dev->adap;
        i2c_set_adapdata(adap, i2c_dev);
        snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
@@ -1908,18 +1941,35 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
                                             STM32F7_I2C_TXDR,
                                             STM32F7_I2C_RXDR);
 
-       ret = i2c_add_adapter(adap);
-       if (ret)
-               goto clk_free;
-
        platform_set_drvdata(pdev, i2c_dev);
 
-       clk_disable(i2c_dev->clk);
+       pm_runtime_set_autosuspend_delay(i2c_dev->dev,
+                                        STM32F7_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(i2c_dev->dev);
+       pm_runtime_set_active(i2c_dev->dev);
+       pm_runtime_enable(i2c_dev->dev);
+
+       pm_runtime_get_noresume(&pdev->dev);
+
+       stm32f7_i2c_hw_config(i2c_dev);
+
+       ret = i2c_add_adapter(adap);
+       if (ret)
+               goto pm_disable;
 
        dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
 
+       pm_runtime_mark_last_busy(i2c_dev->dev);
+       pm_runtime_put_autosuspend(i2c_dev->dev);
+
        return 0;
 
+pm_disable:
+       pm_runtime_put_noidle(i2c_dev->dev);
+       pm_runtime_disable(i2c_dev->dev);
+       pm_runtime_set_suspended(i2c_dev->dev);
+       pm_runtime_dont_use_autosuspend(i2c_dev->dev);
+
 clk_free:
        clk_disable_unprepare(i2c_dev->clk);
 
@@ -1936,11 +1986,50 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
        }
 
        i2c_del_adapter(&i2c_dev->adap);
+       pm_runtime_get_sync(i2c_dev->dev);
 
-       clk_unprepare(i2c_dev->clk);
+       clk_disable_unprepare(i2c_dev->clk);
+
+       pm_runtime_put_noidle(i2c_dev->dev);
+       pm_runtime_disable(i2c_dev->dev);
+       pm_runtime_set_suspended(i2c_dev->dev);
+       pm_runtime_dont_use_autosuspend(i2c_dev->dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int stm32f7_i2c_runtime_suspend(struct device *dev)
+{
+       struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+       if (!stm32f7_i2c_is_slave_registered(i2c_dev))
+               clk_disable_unprepare(i2c_dev->clk);
+
+       return 0;
+}
+
+static int stm32f7_i2c_runtime_resume(struct device *dev)
+{
+       struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+       int ret;
+
+       if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
+               ret = clk_prepare_enable(i2c_dev->clk);
+               if (ret) {
+                       dev_err(dev, "failed to prepare_enable clock\n");
+                       return ret;
+               }
+       }
 
        return 0;
 }
+#endif
+
+static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
+       SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
+                          stm32f7_i2c_runtime_resume, NULL)
+};
 
 static const struct of_device_id stm32f7_i2c_match[] = {
        { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
@@ -1952,6 +2041,7 @@ static struct platform_driver stm32f7_i2c_driver = {
        .driver = {
                .name = "stm32f7-i2c",
                .of_match_table = stm32f7_i2c_match,
+               .pm = &stm32f7_i2c_pm_ops,
        },
        .probe = stm32f7_i2c_probe,
        .remove = stm32f7_i2c_remove,
index 437294ea2f0ad9381035c19f00ffae82ada203c8..e417ebf7628c6aab5ed58f6395598be5e495a3f1 100644 (file)
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * drivers/i2c/busses/i2c-tegra.c
  *
  * Copyright (C) 2010 Google, Inc.
  * Author: Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
  */
 
 #include <linux/kernel.h>
@@ -145,8 +136,8 @@ enum msg_end_type {
  * @has_continue_xfer_support: Continue transfer supports.
  * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
  *             complete interrupt per packet basis.
- * @has_single_clk_source: The i2c controller has single clock source. Tegra30
- *             and earlier Socs has two clock sources i.e. div-clk and
+ * @has_single_clk_source: The I2C controller has single clock source. Tegra30
+ *             and earlier SoCs have two clock sources i.e. div-clk and
  *             fast-clk.
  * @has_config_load_reg: Has the config load register to load the new
  *             configuration.
@@ -154,8 +145,17 @@ enum msg_end_type {
  * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
  *             applicable if there is no fast clock source i.e. single clock
  *             source.
+ * @clk_divisor_fast_plus_mode: Clock divisor in fast mode plus. It is
+ *             applicable if there is no fast clock source (i.e. single
+ *             clock source).
+ * @has_multi_master_mode: The I2C controller supports running in single-master
+ *             or multi-master mode.
+ * @has_slcg_override_reg: The I2C controller supports a register that
+ *             overrides the second level clock gating.
+ * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
+ *             provides additional features and allows for longer messages to
+ *             be transferred in one go.
  */
-
 struct tegra_i2c_hw_feature {
        bool has_continue_xfer_support;
        bool has_per_pkt_xfer_complete_irq;
@@ -170,22 +170,27 @@ struct tegra_i2c_hw_feature {
 };
 
 /**
- * struct tegra_i2c_dev        - per device i2c context
+ * struct tegra_i2c_dev - per device I2C context
  * @dev: device reference for power management
- * @hw: Tegra i2c hw feature.
- * @adapter: core i2c layer adapter information
- * @div_clk: clock reference for div clock of i2c controller.
- * @fast_clk: clock reference for fast clock of i2c controller.
+ * @hw: Tegra I2C HW feature
+ * @adapter: core I2C layer adapter information
+ * @div_clk: clock reference for div clock of I2C controller
+ * @fast_clk: clock reference for fast clock of I2C controller
+ * @rst: reset control for the I2C controller
  * @base: ioremapped registers cookie
- * @cont_id: i2c controller id, used for for packet header
- * @irq: irq number of transfer complete interrupt
- * @is_dvc: identifies the DVC i2c controller, has a different register layout
+ * @cont_id: I2C controller ID, used for packet header
+ * @irq: IRQ number of transfer complete interrupt
+ * @irq_disabled: used to track whether or not the interrupt is enabled
+ * @is_dvc: identifies the DVC I2C controller, has a different register layout
  * @msg_complete: transfer completion notifier
  * @msg_err: error code for completed message
  * @msg_buf: pointer to current message data
  * @msg_buf_remaining: size of unsent data in the message buffer
  * @msg_read: identifies read transfers
- * @bus_clk_rate: current i2c bus clock rate
+ * @bus_clk_rate: current I2C bus clock rate
+ * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
+ * @is_multimaster_mode: track if I2C controller is in multi-master mode
+ * @xfer_lock: lock to serialize transfer submission and processing
  */
 struct tegra_i2c_dev {
        struct device *dev;
@@ -608,11 +613,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
        u32 status;
        const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
        struct tegra_i2c_dev *i2c_dev = dev_id;
-       unsigned long flags;
 
        status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
-       spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
+       spin_lock(&i2c_dev->xfer_lock);
        if (status == 0) {
                dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
                         i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
@@ -670,7 +674,7 @@ err:
 
        complete(&i2c_dev->msg_complete);
 done:
-       spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
+       spin_unlock(&i2c_dev->xfer_lock);
        return IRQ_HANDLED;
 }
 
index 47ab34ee1a9d68ab07e242b1ea65347a43d2c163..8872453e26c07c65c12b2aca5f9f14a6924f91f7 100644 (file)
@@ -1232,6 +1232,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
        } while (0)
 
        SET_DEVICE_OP(dev_ops, add_gid);
+       SET_DEVICE_OP(dev_ops, advise_mr);
        SET_DEVICE_OP(dev_ops, alloc_dm);
        SET_DEVICE_OP(dev_ops, alloc_fmr);
        SET_DEVICE_OP(dev_ops, alloc_hw_stats);
index be03b5738f71570bc932e3dc0149578ee9e9465f..efa0f2949dc740c9fbf1903b2ea26199b1a2e293 100644 (file)
@@ -780,9 +780,8 @@ int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids)
        req.cos0 = cpu_to_le16(cids[0]);
        req.cos1 = cpu_to_le16(cids[1]);
 
-       bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, NULL,
-                                    0);
-       return 0;
+       return bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp,
+                                               NULL, 0);
 }
 
 int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw,
index 1bd8c1b1dba1c52ff449e0bb42ceda78cef79f82..fd6ea1f75085ee0590a1eb0508689cba3d358e71 100644 (file)
@@ -73,8 +73,7 @@ static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
        /* Wait until all page fault handlers using the mr complete. */
-       if (mr->umem && mr->umem->is_odp)
-               synchronize_srcu(&dev->mr_srcu);
+       synchronize_srcu(&dev->mr_srcu);
 #endif
 
        return err;
@@ -238,9 +237,6 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
 {
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
-#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
-       bool odp_mkey_exist = false;
-#endif
        struct mlx5_ib_mr *tmp_mr;
        struct mlx5_ib_mr *mr;
        LIST_HEAD(del_list);
@@ -253,10 +249,6 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
                        break;
                }
                mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
-#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
-               if (mr->umem && mr->umem->is_odp)
-                       odp_mkey_exist = true;
-#endif
                list_move(&mr->list, &del_list);
                ent->cur--;
                ent->size--;
@@ -265,8 +257,7 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
        }
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
-       if (odp_mkey_exist)
-               synchronize_srcu(&dev->mr_srcu);
+       synchronize_srcu(&dev->mr_srcu);
 #endif
 
        list_for_each_entry_safe(mr, tmp_mr, &del_list, list) {
@@ -581,7 +572,6 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
 {
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
-       bool odp_mkey_exist = false;
        struct mlx5_ib_mr *tmp_mr;
        struct mlx5_ib_mr *mr;
        LIST_HEAD(del_list);
@@ -594,8 +584,6 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
                        break;
                }
                mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
-               if (mr->umem && mr->umem->is_odp)
-                       odp_mkey_exist = true;
                list_move(&mr->list, &del_list);
                ent->cur--;
                ent->size--;
@@ -604,8 +592,7 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
        }
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
-       if (odp_mkey_exist)
-               synchronize_srcu(&dev->mr_srcu);
+       synchronize_srcu(&dev->mr_srcu);
 #endif
 
        list_for_each_entry_safe(mr, tmp_mr, &del_list, list) {
index 9c94c1b9ec35da6bdcda4cfb430a8024aa17775c..dd2ae640bc848add5f316d2285b497347e6d69ea 100644 (file)
@@ -837,7 +837,8 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
                goto err_umem;
        }
 
-       uid = (attr->qp_type != IB_QPT_XRC_TGT) ? to_mpd(pd)->uid : 0;
+       uid = (attr->qp_type != IB_QPT_XRC_TGT &&
+              attr->qp_type != IB_QPT_XRC_INI) ? to_mpd(pd)->uid : 0;
        MLX5_SET(create_qp_in, *in, uid, uid);
        pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas);
        if (ubuffer->umem)
index 505fa36487629ce003b1ac78a2414efbe18e4195..93b16237b76774c986580792b7160cd7a9c85c3e 100644 (file)
@@ -492,6 +492,8 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        int i;
 
        qp = idr_find(&dev->qpidr.idr, conn_param->qpn);
+       if (unlikely(!qp))
+               return -EINVAL;
 
        laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
        raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
index 6d35570092d67bbfd0814739126fc7a372085d42..78fa777c87b1997c0f7ab8629801338923070aea 100644 (file)
@@ -669,7 +669,6 @@ static void __ipoib_reap_ah(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = ipoib_priv(dev);
        struct ipoib_ah *ah, *tah;
-       LIST_HEAD(remove_list);
        unsigned long flags;
 
        netif_tx_lock_bh(dev);
index 9a0a1e0934d5da3334e56c6b1ed9973d9daa00f7..fd4af4de03b40117c98a4584bf0c4b7eedd3dba9 100644 (file)
@@ -2147,14 +2147,12 @@ EXPORT_SYMBOL(md_integrity_register);
  */
 int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
 {
-       struct blk_integrity *bi_rdev;
        struct blk_integrity *bi_mddev;
        char name[BDEVNAME_SIZE];
 
        if (!mddev->gendisk)
                return 0;
 
-       bi_rdev = bdev_get_integrity(rdev->bdev);
        bi_mddev = blk_get_integrity(mddev->gendisk);
 
        if (!bi_mddev) /* nothing to do */
@@ -5693,14 +5691,10 @@ int md_run(struct mddev *mddev)
        return 0;
 
 abort:
-       if (mddev->flush_bio_pool) {
-               mempool_destroy(mddev->flush_bio_pool);
-               mddev->flush_bio_pool = NULL;
-       }
-       if (mddev->flush_pool){
-               mempool_destroy(mddev->flush_pool);
-               mddev->flush_pool = NULL;
-       }
+       mempool_destroy(mddev->flush_bio_pool);
+       mddev->flush_bio_pool = NULL;
+       mempool_destroy(mddev->flush_pool);
+       mddev->flush_pool = NULL;
 
        return err;
 }
index b98e746e7fc4fd05fb8c0eaf2118f9f6a4f778d3..abb5d382f64d1db9fd53f71d89d96064a2a2c437 100644 (file)
@@ -1124,6 +1124,29 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
        kfree(plug);
 }
 
+/*
+ * 1. Register the new request and wait if the reconstruction thread has put
+ * up a bar for new requests. Continue immediately if no resync is active
+ * currently.
+ * 2. If IO spans the reshape position.  Need to wait for reshape to pass.
+ */
+static void regular_request_wait(struct mddev *mddev, struct r10conf *conf,
+                                struct bio *bio, sector_t sectors)
+{
+       wait_barrier(conf);
+       while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+           bio->bi_iter.bi_sector < conf->reshape_progress &&
+           bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
+               raid10_log(conf->mddev, "wait reshape");
+               allow_barrier(conf);
+               wait_event(conf->wait_barrier,
+                          conf->reshape_progress <= bio->bi_iter.bi_sector ||
+                          conf->reshape_progress >= bio->bi_iter.bi_sector +
+                          sectors);
+               wait_barrier(conf);
+       }
+}
+
 static void raid10_read_request(struct mddev *mddev, struct bio *bio,
                                struct r10bio *r10_bio)
 {
@@ -1132,7 +1155,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
        const int op = bio_op(bio);
        const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
        int max_sectors;
-       sector_t sectors;
        struct md_rdev *rdev;
        char b[BDEVNAME_SIZE];
        int slot = r10_bio->read_slot;
@@ -1166,30 +1188,8 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
                }
                rcu_read_unlock();
        }
-       /*
-        * Register the new request and wait if the reconstruction
-        * thread has put up a bar for new requests.
-        * Continue immediately if no resync is active currently.
-        */
-       wait_barrier(conf);
-
-       sectors = r10_bio->sectors;
-       while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-           bio->bi_iter.bi_sector < conf->reshape_progress &&
-           bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
-               /*
-                * IO spans the reshape position.  Need to wait for reshape to
-                * pass
-                */
-               raid10_log(conf->mddev, "wait reshape");
-               allow_barrier(conf);
-               wait_event(conf->wait_barrier,
-                          conf->reshape_progress <= bio->bi_iter.bi_sector ||
-                          conf->reshape_progress >= bio->bi_iter.bi_sector +
-                          sectors);
-               wait_barrier(conf);
-       }
 
+       regular_request_wait(mddev, conf, bio, r10_bio->sectors);
        rdev = read_balance(conf, r10_bio, &max_sectors);
        if (!rdev) {
                if (err_rdev) {
@@ -1209,7 +1209,9 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
                struct bio *split = bio_split(bio, max_sectors,
                                              gfp, &conf->bio_split);
                bio_chain(split, bio);
+               allow_barrier(conf);
                generic_make_request(bio);
+               wait_barrier(conf);
                bio = split;
                r10_bio->master_bio = bio;
                r10_bio->sectors = max_sectors;
@@ -1332,30 +1334,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
                finish_wait(&conf->wait_barrier, &w);
        }
 
-       /*
-        * Register the new request and wait if the reconstruction
-        * thread has put up a bar for new requests.
-        * Continue immediately if no resync is active currently.
-        */
-       wait_barrier(conf);
-
        sectors = r10_bio->sectors;
-       while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-           bio->bi_iter.bi_sector < conf->reshape_progress &&
-           bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
-               /*
-                * IO spans the reshape position.  Need to wait for reshape to
-                * pass
-                */
-               raid10_log(conf->mddev, "wait reshape");
-               allow_barrier(conf);
-               wait_event(conf->wait_barrier,
-                          conf->reshape_progress <= bio->bi_iter.bi_sector ||
-                          conf->reshape_progress >= bio->bi_iter.bi_sector +
-                          sectors);
-               wait_barrier(conf);
-       }
-
+       regular_request_wait(mddev, conf, bio, sectors);
        if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
            (mddev->reshape_backwards
             ? (bio->bi_iter.bi_sector < conf->reshape_safe &&
@@ -1514,7 +1494,9 @@ retry_write:
                struct bio *split = bio_split(bio, r10_bio->sectors,
                                              GFP_NOIO, &conf->bio_split);
                bio_chain(split, bio);
+               allow_barrier(conf);
                generic_make_request(bio);
+               wait_barrier(conf);
                bio = split;
                r10_bio->master_bio = bio;
        }
index fe7a1d27a017b52574d91d22f270ab9b4ed34743..a846faefa210385a9e1fb9674e97199b73cf33a1 100644 (file)
@@ -13,7 +13,7 @@ config EEPROM_AT24
          ones like at24c64, 24lc02 or fm24c04:
 
             24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
-            24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
+            24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024, 24c2048
 
          Unless you like data loss puzzles, always be sure that any chip
          you configure as a 24c32 (32 kbit) or larger is NOT really a
index 636ed7149793b5c4eeac354a4415cb945a570c4a..ddfcf4ade7bf33b46fbc0f5256d32a10240c74c9 100644 (file)
@@ -156,6 +156,7 @@ AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16);
 AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16);
 AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16);
 AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16);
+AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
 /* identical to 24c08 ? */
 AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
 
@@ -182,6 +183,7 @@ static const struct i2c_device_id at24_ids[] = {
        { "24c256",     (kernel_ulong_t)&at24_data_24c256 },
        { "24c512",     (kernel_ulong_t)&at24_data_24c512 },
        { "24c1024",    (kernel_ulong_t)&at24_data_24c1024 },
+       { "24c2048",    (kernel_ulong_t)&at24_data_24c2048 },
        { "at24",       0 },
        { /* END OF LIST */ }
 };
@@ -210,6 +212,7 @@ static const struct of_device_id at24_of_match[] = {
        { .compatible = "atmel,24c256",         .data = &at24_data_24c256 },
        { .compatible = "atmel,24c512",         .data = &at24_data_24c512 },
        { .compatible = "atmel,24c1024",        .data = &at24_data_24c1024 },
+       { .compatible = "atmel,24c2048",        .data = &at24_data_24c2048 },
        { /* END OF LIST */ },
 };
 MODULE_DEVICE_TABLE(of, at24_of_match);
index 31ec770b433da35dc036e9a98231d67fe21c0e9c..4310c7a4212eb1402b3e2eff10a717b7da26ea16 100644 (file)
@@ -103,9 +103,9 @@ config PCI_PF_STUB
        depends on PCI_IOV
        help
          Say Y or M here if you want to enable support for devices that
-         require SR-IOV support, while at the same time the PF itself is
-         not providing any actual services on the host itself such as
-         storage or networking.
+         require SR-IOV support, while at the same time the PF (Physical
+         Function) itself is not providing any actual services on the
+         host itself such as storage or networking.
 
          When in doubt, say N.
 
index 91b0194240a57e8f1d1d78ab682f20135002a68d..548c58223868cada23a84085b58f2ac509ffb9e6 100644 (file)
@@ -89,8 +89,8 @@ config PCI_EXYNOS
        select PCIE_DW_HOST
 
 config PCI_IMX6
-       bool "Freescale i.MX6 PCIe controller"
-       depends on SOC_IMX6Q || (ARM && COMPILE_TEST)
+       bool "Freescale i.MX6/7 PCIe controller"
+       depends on SOC_IMX6Q || SOC_IMX7D || (ARM && COMPILE_TEST)
        depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW_HOST
 
@@ -193,4 +193,24 @@ config PCIE_HISI_STB
        help
           Say Y here if you want PCIe controller support on HiSilicon STB SoCs
 
+config PCI_MESON
+       bool "MESON PCIe controller"
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW_HOST
+       help
+         Say Y here if you want to enable PCI controller support on Amlogic
+         SoCs. The PCI controller on Amlogic is based on DesignWare hardware
+         and therefore the driver re-uses the DesignWare core functions to
+         implement the driver.
+
+config PCIE_UNIPHIER
+       bool "Socionext UniPhier PCIe controllers"
+       depends on ARCH_UNIPHIER || COMPILE_TEST
+       depends on OF && HAS_IOMEM
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW_HOST
+       help
+         Say Y here if you want PCIe controller support on UniPhier SoCs.
+         This driver supports LD20 and PXs3 SoCs.
+
 endmenu
index fcf91eacfc63287078128afea020ecf62b329305..7bcdcdf5024eb9355016ee26c8c3a40a9cef73af 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
+obj-$(CONFIG_PCI_MESON) += pci-meson.o
+obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
 
 # The following drivers are for devices that use the generic ACPI
 # pci_root.c driver but don't support standard ECAM config access.
index 88af6bff945f36cbb9b746bb92775a9b8ca073d0..52e47dac028f7c43c7dde99945b2961b22554016 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/reset.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 #include "pcie-designware.h"
 
@@ -59,6 +61,11 @@ struct imx6_pcie {
        u32                     tx_swing_low;
        int                     link_gen;
        struct regulator        *vpcie;
+
+       /* power domain for pcie */
+       struct device           *pd_pcie;
+       /* power domain for pcie phy */
+       struct device           *pd_pcie_phy;
 };
 
 /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
@@ -67,6 +74,7 @@ struct imx6_pcie {
 #define PHY_PLL_LOCK_WAIT_USLEEP_MAX   200
 
 /* PCIe Root Complex registers (memory-mapped) */
+#define PCIE_RC_IMX6_MSI_CAP                   0x50
 #define PCIE_RC_LCR                            0x7c
 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1       0x1
 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2       0x2
@@ -290,6 +298,43 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
        return 1;
 }
 
+static int imx6_pcie_attach_pd(struct device *dev)
+{
+       struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+       struct device_link *link;
+
+       /* Do nothing when in a single power domain */
+       if (dev->pm_domain)
+               return 0;
+
+       imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie");
+       if (IS_ERR(imx6_pcie->pd_pcie))
+               return PTR_ERR(imx6_pcie->pd_pcie);
+       link = device_link_add(dev, imx6_pcie->pd_pcie,
+                       DL_FLAG_STATELESS |
+                       DL_FLAG_PM_RUNTIME |
+                       DL_FLAG_RPM_ACTIVE);
+       if (!link) {
+               dev_err(dev, "Failed to add device_link to pcie pd.\n");
+               return -EINVAL;
+       }
+
+       imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy");
+       if (IS_ERR(imx6_pcie->pd_pcie_phy))
+               return PTR_ERR(imx6_pcie->pd_pcie_phy);
+
+       device_link_add(dev, imx6_pcie->pd_pcie_phy,
+                       DL_FLAG_STATELESS |
+                       DL_FLAG_PM_RUNTIME |
+                       DL_FLAG_RPM_ACTIVE);
+       if (IS_ERR(link)) {
+               dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link));
+               return PTR_ERR(link);
+       }
+
+       return 0;
+}
+
 static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
 {
        struct device *dev = imx6_pcie->pci->dev;
@@ -765,8 +810,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
 
 static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
 {
-       reset_control_assert(imx6_pcie->turnoff_reset);
-       reset_control_deassert(imx6_pcie->turnoff_reset);
+       struct device *dev = imx6_pcie->pci->dev;
+
+       /* Some variants have a turnoff reset in DT */
+       if (imx6_pcie->turnoff_reset) {
+               reset_control_assert(imx6_pcie->turnoff_reset);
+               reset_control_deassert(imx6_pcie->turnoff_reset);
+               goto pm_turnoff_sleep;
+       }
+
+       /* Others poke directly at IOMUXC registers */
+       switch (imx6_pcie->variant) {
+       case IMX6SX:
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+                               IMX6SX_GPR12_PCIE_PM_TURN_OFF,
+                               IMX6SX_GPR12_PCIE_PM_TURN_OFF);
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+                               IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
+               break;
+       default:
+               dev_err(dev, "PME_Turn_Off not implemented\n");
+               return;
+       }
 
        /*
         * Components with an upstream port must respond to
@@ -775,6 +840,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
         * The standard recommends a 1-10ms timeout after which to
         * proceed anyway as if acks were received.
         */
+pm_turnoff_sleep:
        usleep_range(1000, 10000);
 }
 
@@ -784,18 +850,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
        clk_disable_unprepare(imx6_pcie->pcie_phy);
        clk_disable_unprepare(imx6_pcie->pcie_bus);
 
-       if (imx6_pcie->variant == IMX7D) {
+       switch (imx6_pcie->variant) {
+       case IMX6SX:
+               clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
+               break;
+       case IMX7D:
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
                                   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
                                   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
+               break;
+       default:
+               break;
        }
 }
 
+static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie)
+{
+       return (imx6_pcie->variant == IMX7D ||
+               imx6_pcie->variant == IMX6SX);
+}
+
 static int imx6_pcie_suspend_noirq(struct device *dev)
 {
        struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
 
-       if (imx6_pcie->variant != IMX7D)
+       if (!imx6_pcie_supports_suspend(imx6_pcie))
                return 0;
 
        imx6_pcie_pm_turnoff(imx6_pcie);
@@ -811,7 +890,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
        struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
        struct pcie_port *pp = &imx6_pcie->pci->pp;
 
-       if (imx6_pcie->variant != IMX7D)
+       if (!imx6_pcie_supports_suspend(imx6_pcie))
                return 0;
 
        imx6_pcie_assert_core_reset(imx6_pcie);
@@ -840,6 +919,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
        struct resource *dbi_base;
        struct device_node *node = dev->of_node;
        int ret;
+       u16 val;
 
        imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL);
        if (!imx6_pcie)
@@ -977,10 +1057,22 @@ static int imx6_pcie_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, imx6_pcie);
 
+       ret = imx6_pcie_attach_pd(dev);
+       if (ret)
+               return ret;
+
        ret = imx6_add_pcie_port(imx6_pcie, pdev);
        if (ret < 0)
                return ret;
 
+       if (pci_msi_enabled()) {
+               val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP +
+                                       PCI_MSI_FLAGS);
+               val |= PCI_MSI_FLAGS_ENABLE;
+               dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS,
+                                  val);
+       }
+
        return 0;
 }
 
index 7aa9a82b7ebd62043c5c8fd6c64c10b190cd1c9b..ce45bde29bf888d3bd4d80710105b8c5fd970274 100644 (file)
@@ -222,12 +222,12 @@ static const struct dw_pcie_ops dw_ls_pcie_ops = {
        .link_up = ls_pcie_link_up,
 };
 
-static struct ls_pcie_drvdata ls1021_drvdata = {
+static const struct ls_pcie_drvdata ls1021_drvdata = {
        .ops = &ls1021_pcie_host_ops,
        .dw_pcie_ops = &dw_ls1021_pcie_ops,
 };
 
-static struct ls_pcie_drvdata ls1043_drvdata = {
+static const struct ls_pcie_drvdata ls1043_drvdata = {
        .lut_offset = 0x10000,
        .ltssm_shift = 24,
        .lut_dbg = 0x7fc,
@@ -235,7 +235,7 @@ static struct ls_pcie_drvdata ls1043_drvdata = {
        .dw_pcie_ops = &dw_ls_pcie_ops,
 };
 
-static struct ls_pcie_drvdata ls1046_drvdata = {
+static const struct ls_pcie_drvdata ls1046_drvdata = {
        .lut_offset = 0x80000,
        .ltssm_shift = 24,
        .lut_dbg = 0x407fc,
@@ -243,7 +243,7 @@ static struct ls_pcie_drvdata ls1046_drvdata = {
        .dw_pcie_ops = &dw_ls_pcie_ops,
 };
 
-static struct ls_pcie_drvdata ls2080_drvdata = {
+static const struct ls_pcie_drvdata ls2080_drvdata = {
        .lut_offset = 0x80000,
        .ltssm_shift = 0,
        .lut_dbg = 0x7fc,
@@ -251,7 +251,7 @@ static struct ls_pcie_drvdata ls2080_drvdata = {
        .dw_pcie_ops = &dw_ls_pcie_ops,
 };
 
-static struct ls_pcie_drvdata ls2088_drvdata = {
+static const struct ls_pcie_drvdata ls2088_drvdata = {
        .lut_offset = 0x80000,
        .ltssm_shift = 0,
        .lut_dbg = 0x407fc,
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
new file mode 100644 (file)
index 0000000..241ebe0
--- /dev/null
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Amlogic MESON SoCs
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Yue Wang <yue.wang@amlogic.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+#define to_meson_pcie(x) dev_get_drvdata((x)->dev)
+
+/* External local bus interface registers */
+#define PLR_OFFSET                     0x700
+#define PCIE_PORT_LINK_CTRL_OFF                (PLR_OFFSET + 0x10)
+#define FAST_LINK_MODE                 BIT(7)
+#define LINK_CAPABLE_MASK              GENMASK(21, 16)
+#define LINK_CAPABLE_X1                        BIT(16)
+
+#define PCIE_GEN2_CTRL_OFF             (PLR_OFFSET + 0x10c)
+#define NUM_OF_LANES_MASK              GENMASK(12, 8)
+#define NUM_OF_LANES_X1                        BIT(8)
+#define DIRECT_SPEED_CHANGE            BIT(17)
+
+#define TYPE1_HDR_OFFSET               0x0
+#define PCIE_STATUS_COMMAND            (TYPE1_HDR_OFFSET + 0x04)
+#define PCI_IO_EN                      BIT(0)
+#define PCI_MEM_SPACE_EN               BIT(1)
+#define PCI_BUS_MASTER_EN              BIT(2)
+
+#define PCIE_BASE_ADDR0                        (TYPE1_HDR_OFFSET + 0x10)
+#define PCIE_BASE_ADDR1                        (TYPE1_HDR_OFFSET + 0x14)
+
+#define PCIE_CAP_OFFSET                        0x70
+#define PCIE_DEV_CTRL_DEV_STUS         (PCIE_CAP_OFFSET + 0x08)
+#define PCIE_CAP_MAX_PAYLOAD_MASK      GENMASK(7, 5)
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x)   ((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_MASK     GENMASK(14, 12)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x)  ((x) << 12)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0                      0x0
+#define APP_LTSSM_ENABLE               BIT(7)
+
+#define PCIE_CFG_STATUS12              0x30
+#define IS_SMLH_LINK_UP(x)             ((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x)             ((x) & (1 << 16))
+#define IS_LTSSM_UP(x)                 ((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17              0x44
+#define PM_CURRENT_STATE(x)            (((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT            4000
+#define PORT_CLK_RATE                  100000000UL
+#define MAX_PAYLOAD_SIZE               256
+#define MAX_READ_REQ_SIZE              256
+#define MESON_PCIE_PHY_POWERUP         0x1c
+#define PCIE_RESET_DELAY               500
+#define PCIE_SHARED_RESET              1
+#define PCIE_NORMAL_RESET              0
+
+enum pcie_data_rate {
+       PCIE_GEN1,
+       PCIE_GEN2,
+       PCIE_GEN3,
+       PCIE_GEN4
+};
+
+struct meson_pcie_mem_res {
+       void __iomem *elbi_base;
+       void __iomem *cfg_base;
+       void __iomem *phy_base;
+};
+
+struct meson_pcie_clk_res {
+       struct clk *clk;
+       struct clk *mipi_gate;
+       struct clk *port_clk;
+       struct clk *general_clk;
+};
+
+struct meson_pcie_rc_reset {
+       struct reset_control *phy;
+       struct reset_control *port;
+       struct reset_control *apb;
+};
+
+struct meson_pcie {
+       struct dw_pcie pci;
+       struct meson_pcie_mem_res mem_res;
+       struct meson_pcie_clk_res clk_res;
+       struct meson_pcie_rc_reset mrst;
+       struct gpio_desc *reset_gpio;
+};
+
+static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
+                                                 const char *id,
+                                                 u32 reset_type)
+{
+       struct device *dev = mp->pci.dev;
+       struct reset_control *reset;
+
+       if (reset_type == PCIE_SHARED_RESET)
+               reset = devm_reset_control_get_shared(dev, id);
+       else
+               reset = devm_reset_control_get(dev, id);
+
+       return reset;
+}
+
+static int meson_pcie_get_resets(struct meson_pcie *mp)
+{
+       struct meson_pcie_rc_reset *mrst = &mp->mrst;
+
+       mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
+       if (IS_ERR(mrst->phy))
+               return PTR_ERR(mrst->phy);
+       reset_control_deassert(mrst->phy);
+
+       mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
+       if (IS_ERR(mrst->port))
+               return PTR_ERR(mrst->port);
+       reset_control_deassert(mrst->port);
+
+       mrst->apb = meson_pcie_get_reset(mp, "apb", PCIE_SHARED_RESET);
+       if (IS_ERR(mrst->apb))
+               return PTR_ERR(mrst->apb);
+       reset_control_deassert(mrst->apb);
+
+       return 0;
+}
+
+static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
+                                       struct meson_pcie *mp,
+                                       const char *id)
+{
+       struct device *dev = mp->pci.dev;
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
+
+       return devm_ioremap_resource(dev, res);
+}
+
+static void __iomem *meson_pcie_get_mem_shared(struct platform_device *pdev,
+                                              struct meson_pcie *mp,
+                                              const char *id)
+{
+       struct device *dev = mp->pci.dev;
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
+       if (!res) {
+               dev_err(dev, "No REG resource %s\n", id);
+               return ERR_PTR(-ENXIO);
+       }
+
+       return devm_ioremap(dev, res->start, resource_size(res));
+}
+
+static int meson_pcie_get_mems(struct platform_device *pdev,
+                              struct meson_pcie *mp)
+{
+       mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
+       if (IS_ERR(mp->mem_res.elbi_base))
+               return PTR_ERR(mp->mem_res.elbi_base);
+
+       mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
+       if (IS_ERR(mp->mem_res.cfg_base))
+               return PTR_ERR(mp->mem_res.cfg_base);
+
+       /* Meson SoC has two PCI controllers use same phy register*/
+       mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
+       if (IS_ERR(mp->mem_res.phy_base))
+               return PTR_ERR(mp->mem_res.phy_base);
+
+       return 0;
+}
+
+static void meson_pcie_power_on(struct meson_pcie *mp)
+{
+       writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
+}
+
+static void meson_pcie_reset(struct meson_pcie *mp)
+{
+       struct meson_pcie_rc_reset *mrst = &mp->mrst;
+
+       reset_control_assert(mrst->phy);
+       udelay(PCIE_RESET_DELAY);
+       reset_control_deassert(mrst->phy);
+       udelay(PCIE_RESET_DELAY);
+
+       reset_control_assert(mrst->port);
+       reset_control_assert(mrst->apb);
+       udelay(PCIE_RESET_DELAY);
+       reset_control_deassert(mrst->port);
+       reset_control_deassert(mrst->apb);
+       udelay(PCIE_RESET_DELAY);
+}
+
+static inline struct clk *meson_pcie_probe_clock(struct device *dev,
+                                                const char *id, u64 rate)
+{
+       struct clk *clk;
+       int ret;
+
+       clk = devm_clk_get(dev, id);
+       if (IS_ERR(clk))
+               return clk;
+
+       if (rate) {
+               ret = clk_set_rate(clk, rate);
+               if (ret) {
+                       dev_err(dev, "set clk rate failed, ret = %d\n", ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       ret = clk_prepare_enable(clk);
+       if (ret) {
+               dev_err(dev, "couldn't enable clk\n");
+               return ERR_PTR(ret);
+       }
+
+       devm_add_action_or_reset(dev,
+                                (void (*) (void *))clk_disable_unprepare,
+                                clk);
+
+       return clk;
+}
+
+static int meson_pcie_probe_clocks(struct meson_pcie *mp)
+{
+       struct device *dev = mp->pci.dev;
+       struct meson_pcie_clk_res *res = &mp->clk_res;
+
+       res->port_clk = meson_pcie_probe_clock(dev, "port", PORT_CLK_RATE);
+       if (IS_ERR(res->port_clk))
+               return PTR_ERR(res->port_clk);
+
+       res->mipi_gate = meson_pcie_probe_clock(dev, "pcie_mipi_en", 0);
+       if (IS_ERR(res->mipi_gate))
+               return PTR_ERR(res->mipi_gate);
+
+       res->general_clk = meson_pcie_probe_clock(dev, "pcie_general", 0);
+       if (IS_ERR(res->general_clk))
+               return PTR_ERR(res->general_clk);
+
+       res->clk = meson_pcie_probe_clock(dev, "pcie", 0);
+       if (IS_ERR(res->clk))
+               return PTR_ERR(res->clk);
+
+       return 0;
+}
+
+static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
+{
+       writel(val, mp->mem_res.elbi_base + reg);
+}
+
+static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
+{
+       return readl(mp->mem_res.elbi_base + reg);
+}
+
+static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
+{
+       return readl(mp->mem_res.cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
+{
+       writel(val, mp->mem_res.cfg_base + reg);
+}
+
+static void meson_pcie_assert_reset(struct meson_pcie *mp)
+{
+       gpiod_set_value_cansleep(mp->reset_gpio, 0);
+       udelay(500);
+       gpiod_set_value_cansleep(mp->reset_gpio, 1);
+}
+
+static void meson_pcie_init_dw(struct meson_pcie *mp)
+{
+       u32 val;
+
+       val = meson_cfg_readl(mp, PCIE_CFG0);
+       val |= APP_LTSSM_ENABLE;
+       meson_cfg_writel(mp, val, PCIE_CFG0);
+
+       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
+       val &= ~LINK_CAPABLE_MASK;
+       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
+
+       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
+       val |= LINK_CAPABLE_X1 | FAST_LINK_MODE;
+       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
+
+       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
+       val &= ~NUM_OF_LANES_MASK;
+       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
+
+       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
+       val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
+       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
+
+       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
+       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
+}
+
+static int meson_size_to_payload(struct meson_pcie *mp, int size)
+{
+       struct device *dev = mp->pci.dev;
+
+       /*
+        * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+        * So if input size is not 2^order alignment or less than 2^7 or bigger
+        * than 2^12, just set to default size 2^(1+7).
+        */
+       if (!is_power_of_2(size) || size < 128 || size > 4096) {
+               dev_warn(dev, "payload size %d, set to default 256\n", size);
+               return 1;
+       }
+
+       return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *mp, int size)
+{
+       u32 val;
+       int max_payload_size = meson_size_to_payload(mp, size);
+
+       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
+       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+
+       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
+{
+       u32 val;
+       int max_rd_req_size = meson_size_to_payload(mp, size);
+
+       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
+       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+
+       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+}
+
+static inline void meson_enable_memory_space(struct meson_pcie *mp)
+{
+       /* Set the RC Bus Master, Memory Space and I/O Space enables */
+       meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
+                        PCIE_STATUS_COMMAND);
+}
+
+static int meson_pcie_establish_link(struct meson_pcie *mp)
+{
+       struct dw_pcie *pci = &mp->pci;
+       struct pcie_port *pp = &pci->pp;
+
+       meson_pcie_init_dw(mp);
+       meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
+       meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+
+       dw_pcie_setup_rc(pp);
+       meson_enable_memory_space(mp);
+
+       meson_pcie_assert_reset(mp);
+
+       return dw_pcie_wait_for_link(pci);
+}
+
+static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
+{
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(&mp->pci.pp);
+}
+
+static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+                                 u32 *val)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       int ret;
+
+       ret = dw_pcie_read(pci->dbi_base + where, size, val);
+       if (ret != PCIBIOS_SUCCESSFUL)
+               return ret;
+
+       /*
+        * There is a bug in the MESON AXG PCIe controller whereby software
+        * cannot program the PCI_CLASS_DEVICE register, so we must fabricate
+        * the return value in the config accessors.
+        */
+       if (where == PCI_CLASS_REVISION && size == 4)
+               *val = (PCI_CLASS_BRIDGE_PCI << 16) | (*val & 0xffff);
+       else if (where == PCI_CLASS_DEVICE && size == 2)
+               *val = PCI_CLASS_BRIDGE_PCI;
+       else if (where == PCI_CLASS_DEVICE && size == 1)
+               *val = PCI_CLASS_BRIDGE_PCI & 0xff;
+       else if (where == PCI_CLASS_DEVICE + 1 && size == 1)
+               *val = (PCI_CLASS_BRIDGE_PCI >> 8) & 0xff;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
+                                 int size, u32 val)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+       return dw_pcie_write(pci->dbi_base + where, size, val);
+}
+
+static int meson_pcie_link_up(struct dw_pcie *pci)
+{
+       struct meson_pcie *mp = to_meson_pcie(pci);
+       struct device *dev = pci->dev;
+       u32 speed_okay = 0;
+       u32 cnt = 0;
+       u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
+
+       do {
+               state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12);
+               state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17);
+               smlh_up = IS_SMLH_LINK_UP(state12);
+               rdlh_up = IS_RDLH_LINK_UP(state12);
+               ltssm_up = IS_LTSSM_UP(state12);
+
+               if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+                       speed_okay = 1;
+
+               if (smlh_up)
+                       dev_dbg(dev, "smlh_link_up is on\n");
+               if (rdlh_up)
+                       dev_dbg(dev, "rdlh_link_up is on\n");
+               if (ltssm_up)
+                       dev_dbg(dev, "ltssm_up is on\n");
+               if (speed_okay)
+                       dev_dbg(dev, "speed_okay\n");
+
+               if (smlh_up && rdlh_up && ltssm_up && speed_okay)
+                       return 1;
+
+               cnt++;
+
+               udelay(10);
+       } while (cnt < WAIT_LINKUP_TIMEOUT);
+
+       dev_err(dev, "error: wait linkup timeout\n");
+       return 0;
+}
+
+static int meson_pcie_host_init(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct meson_pcie *mp = to_meson_pcie(pci);
+       int ret;
+
+       ret = meson_pcie_establish_link(mp);
+       if (ret)
+               return ret;
+
+       meson_pcie_enable_interrupts(mp);
+
+       return 0;
+}
+
+static const struct dw_pcie_host_ops meson_pcie_host_ops = {
+       .rd_own_conf = meson_pcie_rd_own_conf,
+       .wr_own_conf = meson_pcie_wr_own_conf,
+       .host_init = meson_pcie_host_init,
+};
+
+static int meson_add_pcie_port(struct meson_pcie *mp,
+                              struct platform_device *pdev)
+{
+       struct dw_pcie *pci = &mp->pci;
+       struct pcie_port *pp = &pci->pp;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               pp->msi_irq = platform_get_irq(pdev, 0);
+               if (pp->msi_irq < 0) {
+                       dev_err(dev, "failed to get MSI IRQ\n");
+                       return pp->msi_irq;
+               }
+       }
+
+       pp->ops = &meson_pcie_host_ops;
+       pci->dbi_base = mp->mem_res.elbi_base;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+       .link_up = meson_pcie_link_up,
+};
+
+static int meson_pcie_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dw_pcie *pci;
+       struct meson_pcie *mp;
+       int ret;
+
+       mp = devm_kzalloc(dev, sizeof(*mp), GFP_KERNEL);
+       if (!mp)
+               return -ENOMEM;
+
+       pci = &mp->pci;
+       pci->dev = dev;
+       pci->ops = &dw_pcie_ops;
+
+       mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(mp->reset_gpio)) {
+               dev_err(dev, "get reset gpio failed\n");
+               return PTR_ERR(mp->reset_gpio);
+       }
+
+       ret = meson_pcie_get_resets(mp);
+       if (ret) {
+               dev_err(dev, "get reset resource failed, %d\n", ret);
+               return ret;
+       }
+
+       ret = meson_pcie_get_mems(pdev, mp);
+       if (ret) {
+               dev_err(dev, "get memory resource failed, %d\n", ret);
+               return ret;
+       }
+
+       meson_pcie_power_on(mp);
+       meson_pcie_reset(mp);
+
+       ret = meson_pcie_probe_clocks(mp);
+       if (ret) {
+               dev_err(dev, "init clock resources failed, %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, mp);
+
+       ret = meson_add_pcie_port(mp, pdev);
+       if (ret < 0) {
+               dev_err(dev, "Add PCIe port failed, %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id meson_pcie_of_match[] = {
+       {
+               .compatible = "amlogic,axg-pcie",
+       },
+       {},
+};
+
+static struct platform_driver meson_pcie_driver = {
+       .probe = meson_pcie_probe,
+       .driver = {
+               .name = "meson-pcie",
+               .of_match_table = meson_pcie_of_match,
+       },
+};
+
+builtin_platform_driver(meson_pcie_driver);
index 0c389a30ef5d371135ff80adba6396a08f5a69c8..b171b6bc15c84c9fbef3ee20d992c2f526beeef3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/resource.h>
 #include <linux/of_pci.h>
 #include <linux/of_irq.h>
+#include <linux/gpio/consumer.h>
 
 #include "pcie-designware.h"
 
@@ -29,6 +30,7 @@ struct armada8k_pcie {
        struct dw_pcie *pci;
        struct clk *clk;
        struct clk *clk_reg;
+       struct gpio_desc *reset_gpio;
 };
 
 #define PCIE_VENDOR_REGS_OFFSET                0x8000
@@ -137,6 +139,12 @@ static int armada8k_pcie_host_init(struct pcie_port *pp)
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
 
+       if (pcie->reset_gpio) {
+               /* assert and then deassert the reset signal */
+               gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+               msleep(100);
+               gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+       }
        dw_pcie_setup_rc(pp);
        armada8k_pcie_establish_link(pcie);
 
@@ -249,6 +257,14 @@ static int armada8k_pcie_probe(struct platform_device *pdev)
                goto fail_clkreg;
        }
 
+       /* Get reset gpio signal and hold asserted (logically high) */
+       pcie->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                  GPIOD_OUT_HIGH);
+       if (IS_ERR(pcie->reset_gpio)) {
+               ret = PTR_ERR(pcie->reset_gpio);
+               goto fail_clkreg;
+       }
+
        platform_set_drvdata(pdev, pcie);
 
        ret = armada8k_add_pcie_port(pcie, pdev);
index de8635af4cde296922ca4b0afd22bc86aee261d8..a543c45c722422371e5d61f53b7c6b4f84400635 100644 (file)
@@ -503,6 +503,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
                dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
                return -EINVAL;
        }
+       if (pci->iatu_unroll_enabled && !pci->atu_base) {
+               dev_err(dev, "atu_base is not populated\n");
+               return -EINVAL;
+       }
 
        ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
        if (ret < 0) {
index 29a05759a29421aab29efb6026ffec9d083abef1..721d60a5d9e461ac0fd14ca6766266651fd4255f 100644 (file)
@@ -99,9 +99,6 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
                                               (i * MAX_MSI_IRQS_PER_CTRL) +
                                               pos);
                        generic_handle_irq(irq);
-                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS +
-                                               (i * MSI_REG_CTRL_BLOCK_SIZE),
-                                           4, 1 << pos);
                        pos++;
                }
        }
@@ -168,8 +165,8 @@ static void dw_pci_bottom_mask(struct irq_data *data)
                bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
                pp->irq_status[ctrl] &= ~(1 << bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
-                                   pp->irq_status[ctrl]);
+               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+                                   ~pp->irq_status[ctrl]);
        }
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
@@ -191,8 +188,8 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
                bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
                pp->irq_status[ctrl] |= 1 << bit;
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
-                                   pp->irq_status[ctrl]);
+               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+                                   ~pp->irq_status[ctrl]);
        }
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
@@ -200,13 +197,22 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
 
 static void dw_pci_bottom_ack(struct irq_data *d)
 {
-       struct msi_desc *msi = irq_data_get_msi_desc(d);
-       struct pcie_port *pp;
+       struct pcie_port *pp  = irq_data_get_irq_chip_data(d);
+       unsigned int res, bit, ctrl;
+       unsigned long flags;
+
+       ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+       res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+
+       raw_spin_lock_irqsave(&pp->lock, flags);
 
-       pp = msi_desc_to_pci_sysdata(msi);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);
 
        if (pp->ops->msi_irq_ack)
                pp->ops->msi_irq_ack(d->hwirq, pp);
+
+       raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
 
 static struct irq_chip dw_pci_msi_bottom_irq_chip = {
@@ -658,10 +664,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
 
        /* Initialize IRQ Status array */
-       for (ctrl = 0; ctrl < num_ctrls; ctrl++)
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+       for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
+                                       (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+                                   4, ~0);
+               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
                                        (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
-                                   4, &pp->irq_status[ctrl]);
+                                   4, ~0);
+               pp->irq_status[ctrl] = 0;
+       }
 
        /* Setup RC BARs */
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
@@ -699,6 +710,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
                dev_dbg(pci->dev, "iATU unroll: %s\n",
                        pci->iatu_unroll_enabled ? "enabled" : "disabled");
 
+               if (pci->iatu_unroll_enabled && !pci->atu_base)
+                       pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+
                dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
                                          PCIE_ATU_TYPE_MEM, pp->mem_base,
                                          pp->mem_bus_addr, pp->mem_size);
index 2153956a0b207cae268ffabf8392a3025f22432b..93ef8c31fb39240b5e8d43db6a65f06768fe975d 100644 (file)
@@ -93,7 +93,7 @@ static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
 {
        u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
 
-       return dw_pcie_readl_dbi(pci, offset + reg);
+       return dw_pcie_readl_atu(pci, offset + reg);
 }
 
 static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
@@ -101,7 +101,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
 {
        u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
 
-       dw_pcie_writel_dbi(pci, offset + reg, val);
+       dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
@@ -187,7 +187,7 @@ static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
 {
        u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
 
-       return dw_pcie_readl_dbi(pci, offset + reg);
+       return dw_pcie_readl_atu(pci, offset + reg);
 }
 
 static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
@@ -195,7 +195,7 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
 {
        u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
 
-       dw_pcie_writel_dbi(pci, offset + reg, val);
+       dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
 static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
index 0989d880ac46cf27109c11931f4524cfa4ba3d21..9943d8c68335daa4ca5e6e413d95296c34daeda7 100644 (file)
 #define PCIE_ATU_UNR_LOWER_TARGET      0x14
 #define PCIE_ATU_UNR_UPPER_TARGET      0x18
 
+/*
+ * The default address offset between dbi_base and atu_base. Root controller
+ * drivers are not required to initialize atu_base if the offset matches this
+ * default; the driver core automatically derives atu_base from dbi_base using
+ * this offset, if atu_base not set.
+ */
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
 /* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)       \
-                       ((0x3 << 20) | ((region) << 9))
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
+               ((region) << 9)
 
-#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region)                                \
-                       ((0x3 << 20) | ((region) << 9) | (0x1 << 8))
+#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
+               (((region) << 9) | (0x1 << 8))
 
 #define MAX_MSI_IRQS                   256
 #define MAX_MSI_IRQS_PER_CTRL          32
@@ -219,6 +227,8 @@ struct dw_pcie {
        struct device           *dev;
        void __iomem            *dbi_base;
        void __iomem            *dbi_base2;
+       /* Used when iatu_unroll_enabled is true */
+       void __iomem            *atu_base;
        u32                     num_viewport;
        u8                      iatu_unroll_enabled;
        struct pcie_port        pp;
@@ -289,6 +299,16 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
        return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4);
 }
 
+static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
+{
+       __dw_pcie_write_dbi(pci, pci->atu_base, reg, 0x4, val);
+}
+
+static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
+{
+       return __dw_pcie_read_dbi(pci, pci->atu_base, reg, 0x4);
+}
+
 static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
 {
        u32 reg;
index 7b32e619b959c8697eb16287c9e7d547581d97fd..954bc2b74bbcd60727395ca523a5a4f98242c4a9 100644 (file)
@@ -202,7 +202,7 @@ static int histb_pcie_host_init(struct pcie_port *pp)
        return 0;
 }
 
-static struct dw_pcie_host_ops histb_pcie_host_ops = {
+static const struct dw_pcie_host_ops histb_pcie_host_ops = {
        .rd_own_conf = histb_pcie_rd_own_conf,
        .wr_own_conf = histb_pcie_wr_own_conf,
        .host_init = histb_pcie_host_init,
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
new file mode 100644 (file)
index 0000000..d5dc402
--- /dev/null
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for UniPhier SoCs
+ * Copyright 2018 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+#define PCL_PINCTRL0                   0x002c
+#define PCL_PERST_PLDN_REGEN           BIT(12)
+#define PCL_PERST_NOE_REGEN            BIT(11)
+#define PCL_PERST_OUT_REGEN            BIT(8)
+#define PCL_PERST_PLDN_REGVAL          BIT(4)
+#define PCL_PERST_NOE_REGVAL           BIT(3)
+#define PCL_PERST_OUT_REGVAL           BIT(0)
+
+#define PCL_PIPEMON                    0x0044
+#define PCL_PCLK_ALIVE                 BIT(15)
+
+#define PCL_APP_READY_CTRL             0x8008
+#define PCL_APP_LTSSM_ENABLE           BIT(0)
+
+#define PCL_APP_PM0                    0x8078
+#define PCL_SYS_AUX_PWR_DET            BIT(8)
+
+#define PCL_RCV_INT                    0x8108
+#define PCL_RCV_INT_ALL_ENABLE         GENMASK(20, 17)
+#define PCL_CFG_BW_MGT_STATUS          BIT(4)
+#define PCL_CFG_LINK_AUTO_BW_STATUS    BIT(3)
+#define PCL_CFG_AER_RC_ERR_MSI_STATUS  BIT(2)
+#define PCL_CFG_PME_MSI_STATUS         BIT(1)
+
+#define PCL_RCV_INTX                   0x810c
+#define PCL_RCV_INTX_ALL_ENABLE                GENMASK(19, 16)
+#define PCL_RCV_INTX_ALL_MASK          GENMASK(11, 8)
+#define PCL_RCV_INTX_MASK_SHIFT                8
+#define PCL_RCV_INTX_ALL_STATUS                GENMASK(3, 0)
+#define PCL_RCV_INTX_STATUS_SHIFT      0
+
+#define PCL_STATUS_LINK                        0x8140
+#define PCL_RDLH_LINK_UP               BIT(1)
+#define PCL_XMLH_LINK_UP               BIT(0)
+
+struct uniphier_pcie_priv {
+       void __iomem *base;
+       struct dw_pcie pci;
+       struct clk *clk;
+       struct reset_control *rst;
+       struct phy *phy;
+       struct irq_domain *legacy_irq_domain;
+};
+
+#define to_uniphier_pcie(x)    dev_get_drvdata((x)->dev)
+
+static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv,
+                                      bool enable)
+{
+       u32 val;
+
+       val = readl(priv->base + PCL_APP_READY_CTRL);
+       if (enable)
+               val |= PCL_APP_LTSSM_ENABLE;
+       else
+               val &= ~PCL_APP_LTSSM_ENABLE;
+       writel(val, priv->base + PCL_APP_READY_CTRL);
+}
+
+static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
+{
+       u32 val;
+
+       /* use auxiliary power detection */
+       val = readl(priv->base + PCL_APP_PM0);
+       val |= PCL_SYS_AUX_PWR_DET;
+       writel(val, priv->base + PCL_APP_PM0);
+
+       /* assert PERST# */
+       val = readl(priv->base + PCL_PINCTRL0);
+       val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
+                | PCL_PERST_PLDN_REGVAL);
+       val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
+               | PCL_PERST_PLDN_REGEN;
+       writel(val, priv->base + PCL_PINCTRL0);
+
+       uniphier_pcie_ltssm_enable(priv, false);
+
+       usleep_range(100000, 200000);
+
+       /* deassert PERST# */
+       val = readl(priv->base + PCL_PINCTRL0);
+       val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
+       writel(val, priv->base + PCL_PINCTRL0);
+}
+
+static int uniphier_pcie_wait_rc(struct uniphier_pcie_priv *priv)
+{
+       u32 status;
+       int ret;
+
+       /* wait PIPE clock */
+       ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status,
+                                status & PCL_PCLK_ALIVE, 100000, 1000000);
+       if (ret) {
+               dev_err(priv->pci.dev,
+                       "Failed to initialize controller in RC mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int uniphier_pcie_link_up(struct dw_pcie *pci)
+{
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       u32 val, mask;
+
+       val = readl(priv->base + PCL_STATUS_LINK);
+       mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;
+
+       return (val & mask) == mask;
+}
+
+static int uniphier_pcie_establish_link(struct dw_pcie *pci)
+{
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+
+       if (dw_pcie_link_up(pci))
+               return 0;
+
+       uniphier_pcie_ltssm_enable(priv, true);
+
+       return dw_pcie_wait_for_link(pci);
+}
+
+static void uniphier_pcie_stop_link(struct dw_pcie *pci)
+{
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+
+       uniphier_pcie_ltssm_enable(priv, false);
+}
+
+static void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv)
+{
+       writel(PCL_RCV_INT_ALL_ENABLE, priv->base + PCL_RCV_INT);
+       writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX);
+}
+
+static void uniphier_pcie_irq_disable(struct uniphier_pcie_priv *priv)
+{
+       writel(0, priv->base + PCL_RCV_INT);
+       writel(0, priv->base + PCL_RCV_INTX);
+}
+
+static void uniphier_pcie_irq_ack(struct irq_data *d)
+{
+       struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       u32 val;
+
+       val = readl(priv->base + PCL_RCV_INTX);
+       val &= ~PCL_RCV_INTX_ALL_STATUS;
+       val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_STATUS_SHIFT);
+       writel(val, priv->base + PCL_RCV_INTX);
+}
+
+static void uniphier_pcie_irq_mask(struct irq_data *d)
+{
+       struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       u32 val;
+
+       val = readl(priv->base + PCL_RCV_INTX);
+       val &= ~PCL_RCV_INTX_ALL_MASK;
+       val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
+       writel(val, priv->base + PCL_RCV_INTX);
+}
+
+static void uniphier_pcie_irq_unmask(struct irq_data *d)
+{
+       struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       u32 val;
+
+       val = readl(priv->base + PCL_RCV_INTX);
+       val &= ~PCL_RCV_INTX_ALL_MASK;
+       val &= ~BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
+       writel(val, priv->base + PCL_RCV_INTX);
+}
+
+static struct irq_chip uniphier_pcie_irq_chip = {
+       .name = "PCI",
+       .irq_ack = uniphier_pcie_irq_ack,
+       .irq_mask = uniphier_pcie_irq_mask,
+       .irq_unmask = uniphier_pcie_irq_unmask,
+};
+
+static int uniphier_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+                                 irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &uniphier_pcie_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(irq, domain->host_data);
+
+       return 0;
+}
+
+static const struct irq_domain_ops uniphier_intx_domain_ops = {
+       .map = uniphier_pcie_intx_map,
+};
+
+static void uniphier_pcie_irq_handler(struct irq_desc *desc)
+{
+       struct pcie_port *pp = irq_desc_get_handler_data(desc);
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned long reg;
+       u32 val, bit, virq;
+
+       /* INT for debug */
+       val = readl(priv->base + PCL_RCV_INT);
+
+       if (val & PCL_CFG_BW_MGT_STATUS)
+               dev_dbg(pci->dev, "Link Bandwidth Management Event\n");
+       if (val & PCL_CFG_LINK_AUTO_BW_STATUS)
+               dev_dbg(pci->dev, "Link Autonomous Bandwidth Event\n");
+       if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS)
+               dev_dbg(pci->dev, "Root Error\n");
+       if (val & PCL_CFG_PME_MSI_STATUS)
+               dev_dbg(pci->dev, "PME Interrupt\n");
+
+       writel(val, priv->base + PCL_RCV_INT);
+
+       /* INTx */
+       chained_irq_enter(chip, desc);
+
+       val = readl(priv->base + PCL_RCV_INTX);
+       reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val);
+
+       for_each_set_bit(bit, &reg, PCI_NUM_INTX) {
+               virq = irq_linear_revmap(priv->legacy_irq_domain, bit);
+               generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       struct device_node *np = pci->dev->of_node;
+       struct device_node *np_intc;
+
+       np_intc = of_get_child_by_name(np, "legacy-interrupt-controller");
+       if (!np_intc) {
+               dev_err(pci->dev, "Failed to get legacy-interrupt-controller node\n");
+               return -EINVAL;
+       }
+
+       pp->irq = irq_of_parse_and_map(np_intc, 0);
+       if (!pp->irq) {
+               dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n");
+               return -EINVAL;
+       }
+
+       priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,
+                                               &uniphier_intx_domain_ops, pp);
+       if (!priv->legacy_irq_domain) {
+               dev_err(pci->dev, "Failed to get INTx domain\n");
+               return -ENODEV;
+       }
+
+       irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler,
+                                        pp);
+
+       return 0;
+}
+
+static int uniphier_pcie_host_init(struct pcie_port *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+       int ret;
+
+       ret = uniphier_pcie_config_legacy_irq(pp);
+       if (ret)
+               return ret;
+
+       uniphier_pcie_irq_enable(priv);
+
+       dw_pcie_setup_rc(pp);
+       ret = uniphier_pcie_establish_link(pci);
+       if (ret)
+               return ret;
+
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(pp);
+
+       return 0;
+}
+
+static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
+       .host_init = uniphier_pcie_host_init,
+};
+
+static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
+                                 struct platform_device *pdev)
+{
+       struct dw_pcie *pci = &priv->pci;
+       struct pcie_port *pp = &pci->pp;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       pp->ops = &uniphier_pcie_host_ops;
+
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+               if (pp->msi_irq < 0)
+                       return pp->msi_irq;
+       }
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dev, "Failed to initialize host (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
+{
+       int ret;
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
+
+       ret = reset_control_deassert(priv->rst);
+       if (ret)
+               goto out_clk_disable;
+
+       uniphier_pcie_init_rc(priv);
+
+       ret = phy_init(priv->phy);
+       if (ret)
+               goto out_rst_assert;
+
+       ret = uniphier_pcie_wait_rc(priv);
+       if (ret)
+               goto out_phy_exit;
+
+       return 0;
+
+out_phy_exit:
+       phy_exit(priv->phy);
+out_rst_assert:
+       reset_control_assert(priv->rst);
+out_clk_disable:
+       clk_disable_unprepare(priv->clk);
+
+       return ret;
+}
+
+static void uniphier_pcie_host_disable(struct uniphier_pcie_priv *priv)
+{
+       uniphier_pcie_irq_disable(priv);
+       phy_exit(priv->phy);
+       reset_control_assert(priv->rst);
+       clk_disable_unprepare(priv->clk);
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+       .start_link = uniphier_pcie_establish_link,
+       .stop_link = uniphier_pcie_stop_link,
+       .link_up = uniphier_pcie_link_up,
+};
+
+static int uniphier_pcie_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct uniphier_pcie_priv *priv;
+       struct resource *res;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->pci.dev = dev;
+       priv->pci.ops = &dw_pcie_ops;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+       priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
+       if (IS_ERR(priv->pci.dbi_base))
+               return PTR_ERR(priv->pci.dbi_base);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "link");
+       priv->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       priv->rst = devm_reset_control_get_shared(dev, NULL);
+       if (IS_ERR(priv->rst))
+               return PTR_ERR(priv->rst);
+
+       priv->phy = devm_phy_optional_get(dev, "pcie-phy");
+       if (IS_ERR(priv->phy))
+               return PTR_ERR(priv->phy);
+
+       platform_set_drvdata(pdev, priv);
+
+       ret = uniphier_pcie_host_enable(priv);
+       if (ret)
+               return ret;
+
+       return uniphier_add_pcie_port(priv, pdev);
+}
+
+static int uniphier_pcie_remove(struct platform_device *pdev)
+{
+       struct uniphier_pcie_priv *priv = platform_get_drvdata(pdev);
+
+       uniphier_pcie_host_disable(priv);
+
+       return 0;
+}
+
+static const struct of_device_id uniphier_pcie_match[] = {
+       { .compatible = "socionext,uniphier-pcie", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, uniphier_pcie_match);
+
+static struct platform_driver uniphier_pcie_driver = {
+       .probe  = uniphier_pcie_probe,
+       .remove = uniphier_pcie_remove,
+       .driver = {
+               .name = "uniphier-pcie",
+               .of_match_table = uniphier_pcie_match,
+       },
+};
+builtin_platform_driver(uniphier_pcie_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
index d069a76cbb95b883806acccb0bb3733caa639834..55e471c18e8d84fd9f49a0b8dd57468f6155ee36 100644 (file)
@@ -161,7 +161,6 @@ struct mtk_pcie_soc {
  * @obff_ck: pointer to OBFF functional block operating clock
  * @pipe_ck: pointer to LTSSM and PHY/MAC layer operating clock
  * @phy: pointer to PHY control block
- * @lane: lane count
  * @slot: port slot
  * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
@@ -182,7 +181,6 @@ struct mtk_pcie_port {
        struct clk *obff_ck;
        struct clk *pipe_ck;
        struct phy *phy;
-       u32 lane;
        u32 slot;
        int irq;
        struct irq_domain *irq_domain;
@@ -197,29 +195,20 @@ struct mtk_pcie_port {
  * @dev: pointer to PCIe device
  * @base: IO mapped register base
  * @free_ck: free-run reference clock
- * @io: IO resource
- * @pio: PIO resource
  * @mem: non-prefetchable memory resource
- * @busn: bus range
- * @offset: IO / Memory offset
  * @ports: pointer to PCIe port information
  * @soc: pointer to SoC-dependent operations
+ * @busnr: root bus number
  */
 struct mtk_pcie {
        struct device *dev;
        void __iomem *base;
        struct clk *free_ck;
 
-       struct resource io;
-       struct resource pio;
        struct resource mem;
-       struct resource busn;
-       struct {
-               resource_size_t mem;
-               resource_size_t io;
-       } offset;
        struct list_head ports;
        const struct mtk_pcie_soc *soc;
+       unsigned int busnr;
 };
 
 static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
@@ -904,12 +893,6 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
        if (!port)
                return -ENOMEM;
 
-       err = of_property_read_u32(node, "num-lanes", &port->lane);
-       if (err) {
-               dev_err(dev, "missing num-lanes property\n");
-               return err;
-       }
-
        snprintf(name, sizeof(name), "port%d", slot);
        regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
        port->base = devm_ioremap_resource(dev, regs);
@@ -1045,55 +1028,43 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
 {
        struct device *dev = pcie->dev;
        struct device_node *node = dev->of_node, *child;
-       struct of_pci_range_parser parser;
-       struct of_pci_range range;
-       struct resource res;
        struct mtk_pcie_port *port, *tmp;
+       struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+       struct list_head *windows = &host->windows;
+       struct resource_entry *win, *tmp_win;
+       resource_size_t io_base;
        int err;
 
-       if (of_pci_range_parser_init(&parser, node)) {
-               dev_err(dev, "missing \"ranges\" property\n");
-               return -EINVAL;
-       }
+       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+                                                   windows, &io_base);
+       if (err)
+               return err;
 
-       for_each_of_pci_range(&parser, &range) {
-               err = of_pci_range_to_resource(&range, node, &res);
-               if (err < 0)
-                       return err;
+       err = devm_request_pci_bus_resources(dev, windows);
+       if (err < 0)
+               return err;
 
-               switch (res.flags & IORESOURCE_TYPE_BITS) {
+       /* Get the I/O and memory ranges from DT */
+       resource_list_for_each_entry_safe(win, tmp_win, windows) {
+               switch (resource_type(win->res)) {
                case IORESOURCE_IO:
-                       pcie->offset.io = res.start - range.pci_addr;
-
-                       memcpy(&pcie->pio, &res, sizeof(res));
-                       pcie->pio.name = node->full_name;
-
-                       pcie->io.start = range.cpu_addr;
-                       pcie->io.end = range.cpu_addr + range.size - 1;
-                       pcie->io.flags = IORESOURCE_MEM;
-                       pcie->io.name = "I/O";
-
-                       memcpy(&res, &pcie->io, sizeof(res));
+                       err = devm_pci_remap_iospace(dev, win->res, io_base);
+                       if (err) {
+                               dev_warn(dev, "error %d: failed to map resource %pR\n",
+                                        err, win->res);
+                               resource_list_destroy_entry(win);
+                       }
                        break;
-
                case IORESOURCE_MEM:
-                       pcie->offset.mem = res.start - range.pci_addr;
-
-                       memcpy(&pcie->mem, &res, sizeof(res));
+                       memcpy(&pcie->mem, win->res, sizeof(*win->res));
                        pcie->mem.name = "non-prefetchable";
                        break;
+               case IORESOURCE_BUS:
+                       pcie->busnr = win->res->start;
+                       break;
                }
        }
 
-       err = of_pci_parse_bus_range(node, &pcie->busn);
-       if (err < 0) {
-               dev_err(dev, "failed to parse bus ranges property: %d\n", err);
-               pcie->busn.name = node->name;
-               pcie->busn.start = 0;
-               pcie->busn.end = 0xff;
-               pcie->busn.flags = IORESOURCE_BUS;
-       }
-
        for_each_available_child_of_node(node, child) {
                int slot;
 
@@ -1125,28 +1096,6 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
        return 0;
 }
 
-static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
-{
-       struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
-       struct list_head *windows = &host->windows;
-       struct device *dev = pcie->dev;
-       int err;
-
-       pci_add_resource_offset(windows, &pcie->pio, pcie->offset.io);
-       pci_add_resource_offset(windows, &pcie->mem, pcie->offset.mem);
-       pci_add_resource(windows, &pcie->busn);
-
-       err = devm_request_pci_bus_resources(dev, windows);
-       if (err < 0)
-               return err;
-
-       err = devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start);
-       if (err)
-               return err;
-
-       return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1169,11 +1118,7 @@ static int mtk_pcie_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       err = mtk_pcie_request_resources(pcie);
-       if (err)
-               goto put_resources;
-
-       host->busnr = pcie->busn.start;
+       host->busnr = pcie->busnr;
        host->dev.parent = pcie->dev;
        host->ops = pcie->soc->ops;
        host->map_irq = of_irq_parse_and_map_pci;
index 9616eca3182f95f764b2314be28e71f5c395a2db..3aa115ed3a65752a8f019eb022722858eef0320f 100644 (file)
@@ -252,6 +252,27 @@ int __weak pcibios_sriov_disable(struct pci_dev *pdev)
        return 0;
 }
 
+static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs)
+{
+       unsigned int i;
+       int rc;
+
+       if (dev->no_vf_scan)
+               return 0;
+
+       for (i = 0; i < num_vfs; i++) {
+               rc = pci_iov_add_virtfn(dev, i);
+               if (rc)
+                       goto failed;
+       }
+       return 0;
+failed:
+       while (i--)
+               pci_iov_remove_virtfn(dev, i);
+
+       return rc;
+}
+
 static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 {
        int rc;
@@ -337,21 +358,15 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        msleep(100);
        pci_cfg_access_unlock(dev);
 
-       for (i = 0; i < initial; i++) {
-               rc = pci_iov_add_virtfn(dev, i);
-               if (rc)
-                       goto failed;
-       }
+       rc = sriov_add_vfs(dev, initial);
+       if (rc)
+               goto err_pcibios;
 
        kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
        iov->num_VFs = nr_virtfn;
 
        return 0;
 
-failed:
-       while (i--)
-               pci_iov_remove_virtfn(dev, i);
-
 err_pcibios:
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
@@ -368,17 +383,26 @@ err_pcibios:
        return rc;
 }
 
-static void sriov_disable(struct pci_dev *dev)
+static void sriov_del_vfs(struct pci_dev *dev)
 {
-       int i;
        struct pci_sriov *iov = dev->sriov;
+       int i;
 
-       if (!iov->num_VFs)
+       if (dev->no_vf_scan)
                return;
 
        for (i = 0; i < iov->num_VFs; i++)
                pci_iov_remove_virtfn(dev, i);
+}
+
+static void sriov_disable(struct pci_dev *dev)
+{
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->num_VFs)
+               return;
 
+       sriov_del_vfs(dev);
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
index a2eb25271c9697a9bd60c220be4d5273114cf98d..c52298d76e64debef6ea1c02d984e4dadd58f3c8 100644 (file)
@@ -416,7 +416,7 @@ static int upstream_bridge_distance_warn(struct pci_dev *provider,
  *
  * Returns -1 if any of the clients are not compatible (behind the same
  * root port as the provider), otherwise returns a positive number where
- * a lower number is the preferrable choice. (If there's one client
+ * a lower number is the preferable choice. (If there's one client
  * that's the same as the provider it will return 0, which is best choice).
  *
  * For now, "compatible" means the provider and the clients are all behind
@@ -487,7 +487,7 @@ EXPORT_SYMBOL_GPL(pci_has_p2pmem);
  * @num_clients: number of client devices in the list
  *
  * If multiple devices are behind the same switch, the one "closest" to the
- * client devices in use will be chosen first. (So if one of the providers are
+ * client devices in use will be chosen first. (So if one of the providers is
  * the same as one of the clients, that provider will be used ahead of any
  * other providers that are unrelated). If multiple providers are an equal
  * distance away, one will be chosen at random.
@@ -574,7 +574,7 @@ EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
  * pci_free_p2pmem - free peer-to-peer DMA memory
  * @pdev: the device the memory was allocated from
  * @addr: address of the memory that was allocated
- * @size: number of bytes that was allocated
+ * @size: number of bytes that were allocated
  */
 void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
 {
@@ -611,7 +611,7 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
  * @nents: the number of SG entries in the list
  * @length: number of bytes to allocate
  *
- * Returns 0 on success
+ * Return: %NULL on error or &struct scatterlist pointer and @nents on success
  */
 struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
                                         unsigned int *nents, u32 length)
@@ -667,7 +667,7 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
  *
  * Published memory can be used by other PCI device drivers for
  * peer-2-peer DMA operations. Non-published memory is reserved for
- * exlusive use of the device driver that registers the peer-to-peer
+ * exclusive use of the device driver that registers the peer-to-peer
  * memory.
  */
 void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
@@ -727,7 +727,7 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
  * @use_p2pdma: returns whether to enable p2pdma or not
  *
  * Parses an attribute value to decide whether to enable p2pdma.
- * The value can select a PCI device (using it's full BDF device
+ * The value can select a PCI device (using its full BDF device
  * name) or a boolean (in any format strtobool() accepts). A false
  * value disables p2pdma, a true value expects the caller
  * to automatically find a compatible device and specifying a PCI device
@@ -778,7 +778,7 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_enable_store);
  *             whether p2pdma is enabled
  * @page: contents of the stored value
  * @p2p_dev: the selected p2p device (NULL if no device is selected)
- * @use_p2pdma: whether p2pdme has been enabled
+ * @use_p2pdma: whether p2pdma has been enabled
  *
  * Attributes that use pci_p2pdma_enable_store() should use this function
  * to show the value of the attribute.
index ea55444e6eaddfcb572a9b2dd50f9dceb0b08a3c..79b1610a8bebe7c156125ccf877e8e3b50e58d2d 100644 (file)
@@ -1251,30 +1251,29 @@ static int pci_pm_runtime_suspend(struct device *dev)
                return 0;
        }
 
-       if (!pm || !pm->runtime_suspend)
-               return -ENOSYS;
-
        pci_dev->state_saved = false;
-       error = pm->runtime_suspend(dev);
-       if (error) {
+       if (pm && pm->runtime_suspend) {
+               error = pm->runtime_suspend(dev);
                /*
                 * -EBUSY and -EAGAIN is used to request the runtime PM core
                 * to schedule a new suspend, so log the event only with debug
                 * log level.
                 */
-               if (error == -EBUSY || error == -EAGAIN)
+               if (error == -EBUSY || error == -EAGAIN) {
                        dev_dbg(dev, "can't suspend now (%pf returned %d)\n",
                                pm->runtime_suspend, error);
-               else
+                       return error;
+               } else if (error) {
                        dev_err(dev, "can't suspend (%pf returned %d)\n",
                                pm->runtime_suspend, error);
-
-               return error;
+                       return error;
+               }
        }
 
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
-       if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+       if (pm && pm->runtime_suspend
+           && !pci_dev->state_saved && pci_dev->current_state != PCI_D0
            && pci_dev->current_state != PCI_UNKNOWN) {
                WARN_ONCE(pci_dev->current_state != prev,
                        "PCI PM: State of device not saved by %pF\n",
@@ -1292,7 +1291,7 @@ static int pci_pm_runtime_suspend(struct device *dev)
 
 static int pci_pm_runtime_resume(struct device *dev)
 {
-       int rc;
+       int rc = 0;
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
@@ -1306,14 +1305,12 @@ static int pci_pm_runtime_resume(struct device *dev)
        if (!pci_dev->driver)
                return 0;
 
-       if (!pm || !pm->runtime_resume)
-               return -ENOSYS;
-
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
        pci_enable_wake(pci_dev, PCI_D0, false);
        pci_fixup_device(pci_fixup_resume, pci_dev);
 
-       rc = pm->runtime_resume(dev);
+       if (pm && pm->runtime_resume)
+               rc = pm->runtime_resume(dev);
 
        pci_dev->runtime_d3cold = false;
 
index 662b7457db2374d9c7fd039d2e40a54cfda5dc5b..224d886341158ba55494da1c766a933b0cfaeefc 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef DRIVERS_PCI_H
 #define DRIVERS_PCI_H
 
+#include <linux/pci.h>
+
 #define PCI_FIND_CAP_TTL       48
 
 #define PCI_VSEC_ID_INTEL_TBT  0x1234  /* Thunderbolt */
index f78860ce884bc531860bba73bce96b83f1c444ae..727e3c1ef9a4173a1f36841946b3ee8dab4598e7 100644 (file)
@@ -53,8 +53,6 @@ struct pcie_link_state {
        struct pcie_link_state *root;   /* pointer to the root port link */
        struct pcie_link_state *parent; /* pointer to the parent Link state */
        struct list_head sibling;       /* node in link_list */
-       struct list_head children;      /* list of child link states */
-       struct list_head link;          /* node in parent's children list */
 
        /* ASPM state */
        u32 aspm_support:7;             /* Supported ASPM state */
@@ -850,8 +848,6 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
                return NULL;
 
        INIT_LIST_HEAD(&link->sibling);
-       INIT_LIST_HEAD(&link->children);
-       INIT_LIST_HEAD(&link->link);
        link->pdev = pdev;
        link->downstream = pci_function_0(pdev->subordinate);
 
@@ -877,7 +873,6 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
 
                link->parent = parent;
                link->root = link->parent->root;
-               list_add(&link->link, &parent->children);
        }
 
        list_add(&link->sibling, &link_list);
@@ -1001,7 +996,6 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
        /* All functions are removed, so just disable ASPM for the link */
        pcie_config_aspm_link(link, 0);
        list_del(&link->sibling);
-       list_del(&link->link);
        /* Clock PM is for endpoint device */
        free_link_state(link);
 
index e495f04394d074176d55857d71a20bac2de501d2..fbbf00b0992e50e946f7a5ebd465324bf8c8f2de 100644 (file)
@@ -71,19 +71,19 @@ static inline void *get_service_data(struct pcie_device *dev)
 
 struct pcie_port_service_driver {
        const char *name;
-       int (*probe) (struct pcie_device *dev);
-       void (*remove) (struct pcie_device *dev);
-       int (*suspend) (struct pcie_device *dev);
-       int (*resume_noirq) (struct pcie_device *dev);
-       int (*resume) (struct pcie_device *dev);
-       int (*runtime_suspend) (struct pcie_device *dev);
-       int (*runtime_resume) (struct pcie_device *dev);
+       int (*probe)(struct pcie_device *dev);
+       void (*remove)(struct pcie_device *dev);
+       int (*suspend)(struct pcie_device *dev);
+       int (*resume_noirq)(struct pcie_device *dev);
+       int (*resume)(struct pcie_device *dev);
+       int (*runtime_suspend)(struct pcie_device *dev);
+       int (*runtime_resume)(struct pcie_device *dev);
 
        /* Device driver may resume normal operations */
        void (*error_resume)(struct pci_dev *dev);
 
        /* Link Reset Capability - AER service driver specific */
-       pci_ers_result_t (*reset_link) (struct pci_dev *dev);
+       pci_ers_result_t (*reset_link)(struct pci_dev *dev);
 
        int port_type;  /* Type of the port this driver can handle */
        u32 service;    /* Port service this device represents */
index 4700d24e5d55a1b456698c4725e8d9d2811c03c7..b0a413f3f7cabbdc0ccf5f0f9b06c137c5144cc8 100644 (file)
@@ -618,6 +618,30 @@ static void quirk_amd_nl_class(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB,
                quirk_amd_nl_class);
 
+/*
+ * Synopsys USB 3.x host HAPS platform has a class code of
+ * PCI_CLASS_SERIAL_USB_XHCI, and xhci driver can claim it.  However, these
+ * devices should use dwc3-haps driver.  Change these devices' class code to
+ * PCI_CLASS_SERIAL_USB_DEVICE to prevent the xhci-pci driver from claiming
+ * them.
+ */
+static void quirk_synopsys_haps(struct pci_dev *pdev)
+{
+       u32 class = pdev->class;
+
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3:
+       case PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI:
+       case PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31:
+               pdev->class = PCI_CLASS_SERIAL_USB_DEVICE;
+               pci_info(pdev, "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n",
+                        class, pdev->class);
+               break;
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SYNOPSYS, PCI_ANY_ID,
+                        quirk_synopsys_haps);
+
 /*
  * Let's make the southbridge information explicit instead of having to
  * worry about people probing the ACPI areas, for example.. (Yes, it
index 54a8b30dda38c446c8c4f839ba2c6cb8be504a8d..6c5536d3d42a3ef76b8d63fd70d32d8373679369 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/uaccess.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
-
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/nospec.h>
 
 MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
@@ -25,6 +25,11 @@ static int max_devices = 16;
 module_param(max_devices, int, 0644);
 MODULE_PARM_DESC(max_devices, "max number of switchtec device instances");
 
+static bool use_dma_mrpc = 1;
+module_param(use_dma_mrpc, bool, 0644);
+MODULE_PARM_DESC(use_dma_mrpc,
+                "Enable the use of the DMA MRPC feature");
+
 static dev_t switchtec_devt;
 static DEFINE_IDA(switchtec_minor_ida);
 
@@ -113,6 +118,19 @@ static void stuser_set_state(struct switchtec_user *stuser,
 
 static void mrpc_complete_cmd(struct switchtec_dev *stdev);
 
+static void flush_wc_buf(struct switchtec_dev *stdev)
+{
+       struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
+
+       /*
+        * odb (outbound doorbell) register is processed by low latency
+        * hardware and w/o side effect
+        */
+       mmio_dbmsg = (void __iomem *)stdev->mmio_ntb +
+               SWITCHTEC_NTB_REG_DBMSG_OFFSET;
+       ioread32(&mmio_dbmsg->odb);
+}
+
 static void mrpc_cmd_submit(struct switchtec_dev *stdev)
 {
        /* requires the mrpc_mutex to already be held when called */
@@ -128,16 +146,18 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev)
        stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user,
                            list);
 
+       if (stdev->dma_mrpc) {
+               stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS;
+               memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE);
+       }
+
        stuser_set_state(stuser, MRPC_RUNNING);
        stdev->mrpc_busy = 1;
        memcpy_toio(&stdev->mmio_mrpc->input_data,
                    stuser->data, stuser->data_len);
+       flush_wc_buf(stdev);
        iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd);
 
-       stuser->status = ioread32(&stdev->mmio_mrpc->status);
-       if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS)
-               mrpc_complete_cmd(stdev);
-
        schedule_delayed_work(&stdev->mrpc_timeout,
                              msecs_to_jiffies(500));
 }
@@ -170,7 +190,11 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev)
        stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user,
                            list);
 
-       stuser->status = ioread32(&stdev->mmio_mrpc->status);
+       if (stdev->dma_mrpc)
+               stuser->status = stdev->dma_mrpc->status;
+       else
+               stuser->status = ioread32(&stdev->mmio_mrpc->status);
+
        if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS)
                return;
 
@@ -180,13 +204,19 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev)
        if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE)
                goto out;
 
-       stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value);
+       if (stdev->dma_mrpc)
+               stuser->return_code = stdev->dma_mrpc->rtn_code;
+       else
+               stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value);
        if (stuser->return_code != 0)
                goto out;
 
-       memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data,
-                     stuser->read_len);
-
+       if (stdev->dma_mrpc)
+               memcpy(stuser->data, &stdev->dma_mrpc->data,
+                             stuser->read_len);
+       else
+               memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data,
+                             stuser->read_len);
 out:
        complete_all(&stuser->comp);
        list_del_init(&stuser->list);
@@ -221,7 +251,10 @@ static void mrpc_timeout_work(struct work_struct *work)
 
        mutex_lock(&stdev->mrpc_mutex);
 
-       status = ioread32(&stdev->mmio_mrpc->status);
+       if (stdev->dma_mrpc)
+               status = stdev->dma_mrpc->status;
+       else
+               status = ioread32(&stdev->mmio_mrpc->status);
        if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) {
                schedule_delayed_work(&stdev->mrpc_timeout,
                                      msecs_to_jiffies(500));
@@ -229,7 +262,6 @@ static void mrpc_timeout_work(struct work_struct *work)
        }
 
        mrpc_complete_cmd(stdev);
-
 out:
        mutex_unlock(&stdev->mrpc_mutex);
 }
@@ -800,6 +832,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev,
 {
        int ret;
        int nr_idxs;
+       unsigned int event_flags;
        struct switchtec_ioctl_event_ctl ctl;
 
        if (copy_from_user(&ctl, uctl, sizeof(ctl)))
@@ -821,7 +854,9 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev,
                else
                        return -EINVAL;
 
+               event_flags = ctl.flags;
                for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) {
+                       ctl.flags = event_flags;
                        ret = event_ctl(stdev, &ctl);
                        if (ret < 0)
                                return ret;
@@ -1017,10 +1052,24 @@ static void enable_link_state_events(struct switchtec_dev *stdev)
        }
 }
 
+static void enable_dma_mrpc(struct switchtec_dev *stdev)
+{
+       writeq(stdev->dma_mrpc_dma_addr, &stdev->mmio_mrpc->dma_addr);
+       flush_wc_buf(stdev);
+       iowrite32(SWITCHTEC_DMA_MRPC_EN, &stdev->mmio_mrpc->dma_en);
+}
+
 static void stdev_release(struct device *dev)
 {
        struct switchtec_dev *stdev = to_stdev(dev);
 
+       if (stdev->dma_mrpc) {
+               iowrite32(0, &stdev->mmio_mrpc->dma_en);
+               flush_wc_buf(stdev);
+               writeq(0, &stdev->mmio_mrpc->dma_addr);
+               dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
+                               stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
+       }
        kfree(stdev);
 }
 
@@ -1176,10 +1225,27 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev)
        return ret;
 }
 
+
+static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev)
+{
+       struct switchtec_dev *stdev = dev;
+       irqreturn_t ret = IRQ_NONE;
+
+       iowrite32(SWITCHTEC_EVENT_CLEAR |
+                 SWITCHTEC_EVENT_EN_IRQ,
+                 &stdev->mmio_part_cfg->mrpc_comp_hdr);
+       schedule_work(&stdev->mrpc_work);
+
+       ret = IRQ_HANDLED;
+       return ret;
+}
+
 static int switchtec_init_isr(struct switchtec_dev *stdev)
 {
        int nvecs;
        int event_irq;
+       int dma_mrpc_irq;
+       int rc;
 
        nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4,
                                      PCI_IRQ_MSIX | PCI_IRQ_MSI);
@@ -1194,9 +1260,29 @@ static int switchtec_init_isr(struct switchtec_dev *stdev)
        if (event_irq < 0)
                return event_irq;
 
-       return devm_request_irq(&stdev->pdev->dev, event_irq,
+       rc = devm_request_irq(&stdev->pdev->dev, event_irq,
                                switchtec_event_isr, 0,
                                KBUILD_MODNAME, stdev);
+
+       if (rc)
+               return rc;
+
+       if (!stdev->dma_mrpc)
+               return rc;
+
+       dma_mrpc_irq = ioread32(&stdev->mmio_mrpc->dma_vector);
+       if (dma_mrpc_irq < 0 || dma_mrpc_irq >= nvecs)
+               return -EFAULT;
+
+       dma_mrpc_irq  = pci_irq_vector(stdev->pdev, dma_mrpc_irq);
+       if (dma_mrpc_irq < 0)
+               return dma_mrpc_irq;
+
+       rc = devm_request_irq(&stdev->pdev->dev, dma_mrpc_irq,
+                               switchtec_dma_mrpc_isr, 0,
+                               KBUILD_MODNAME, stdev);
+
+       return rc;
 }
 
 static void init_pff(struct switchtec_dev *stdev)
@@ -1232,19 +1318,38 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
                              struct pci_dev *pdev)
 {
        int rc;
+       void __iomem *map;
+       unsigned long res_start, res_len;
 
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
 
-       rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME);
+       rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
        if (rc)
                return rc;
 
        pci_set_master(pdev);
 
-       stdev->mmio = pcim_iomap_table(pdev)[0];
-       stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET;
+       res_start = pci_resource_start(pdev, 0);
+       res_len = pci_resource_len(pdev, 0);
+
+       if (!devm_request_mem_region(&pdev->dev, res_start,
+                                    res_len, KBUILD_MODNAME))
+               return -EBUSY;
+
+       stdev->mmio_mrpc = devm_ioremap_wc(&pdev->dev, res_start,
+                                          SWITCHTEC_GAS_TOP_CFG_OFFSET);
+       if (!stdev->mmio_mrpc)
+               return -ENOMEM;
+
+       map = devm_ioremap(&pdev->dev,
+                          res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET,
+                          res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET);
+       if (!map)
+               return -ENOMEM;
+
+       stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET;
        stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET;
        stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;
        stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET;
@@ -1262,6 +1367,19 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
 
        pci_set_drvdata(pdev, stdev);
 
+       if (!use_dma_mrpc)
+               return 0;
+
+       if (ioread32(&stdev->mmio_mrpc->dma_ver) == 0)
+               return 0;
+
+       stdev->dma_mrpc = dma_zalloc_coherent(&stdev->pdev->dev,
+                                             sizeof(*stdev->dma_mrpc),
+                                             &stdev->dma_mrpc_dma_addr,
+                                             GFP_KERNEL);
+       if (stdev->dma_mrpc == NULL)
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -1293,6 +1411,9 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
                  &stdev->mmio_part_cfg->mrpc_comp_hdr);
        enable_link_state_events(stdev);
 
+       if (stdev->dma_mrpc)
+               enable_dma_mrpc(stdev);
+
        rc = cdev_device_add(&stdev->cdev, &stdev->dev);
        if (rc)
                goto err_devadd;
@@ -1318,7 +1439,6 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
        cdev_device_del(&stdev->cdev, &stdev->dev);
        ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt));
        dev_info(&stdev->dev, "unregistered.\n");
-
        stdev_kill(stdev);
        put_device(&stdev->dev);
 }
index b6fd4838f60f3f9c198988072e7dd25d6a01d02a..cc7baf0ecb3c925ccda8b17138e23c3d20e2426e 100644 (file)
@@ -575,12 +575,13 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
 
 int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
 {
+       u8 event_type;
        u32 host_event;
        int ret;
 
        if (!ec_dev->mkbp_event_supported) {
                ret = get_keyboard_state_event(ec_dev);
-               if (ret < 0)
+               if (ret <= 0)
                        return ret;
 
                if (wake_event)
@@ -590,15 +591,26 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
        }
 
        ret = get_next_event(ec_dev);
-       if (ret < 0)
+       if (ret <= 0)
                return ret;
 
        if (wake_event) {
+               event_type = ec_dev->event_data.event_type;
                host_event = cros_ec_get_host_event(ec_dev);
 
-               /* Consider non-host_event as wake event */
-               *wake_event = !host_event ||
-                             !!(host_event & ec_dev->host_event_wake_mask);
+               /*
+                * Sensor events need to be parsed by the sensor sub-device.
+                * Defer them, and don't report the wakeup here.
+                */
+               if (event_type == EC_MKBP_EVENT_SENSOR_FIFO)
+                       *wake_event = false;
+               /* Masked host-events should not count as wake events. */
+               else if (host_event &&
+                        !(host_event & ec_dev->host_event_wake_mask))
+                       *wake_event = false;
+               /* Consider all other events as wake events. */
+               else
+                       *wake_event = true;
        }
 
        return ret;
index c9cc33881befc1bedd44f11e512d5c6cbdb7251f..02d57d98ef9bd41190257a9d05ca028cb07c0fd1 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/property.h>
 
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31       0xabcf
-
 /**
  * struct dwc3_haps - Driver private structure
  * @dwc3: child dwc3 platform_device
index e413f54208f4b038ef5f33b989da97d7e3927e2f..ae7712c9687a63db39fc256bc0e298e00cecc278 100644 (file)
@@ -184,7 +184,7 @@ config FB_MACMODES
        depends on FB
 
 config FB_BACKLIGHT
-       bool
+       tristate
        depends on FB
        select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_CLASS_DEVICE
@@ -2037,7 +2037,8 @@ config FB_XILINX
 
 config FB_GOLDFISH
        tristate "Goldfish Framebuffer"
-       depends on FB && HAS_DMA && (GOLDFISH || COMPILE_TEST)
+       depends on FB
+       depends on GOLDFISH || COMPILE_TEST
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index ff561073ee4ecf9710079f3a41a677c34dfb10ae..42f909618f049e55846a6f9cc489806815e9da43 100644 (file)
@@ -287,14 +287,17 @@ static int clps711x_fb_probe(struct platform_device *pdev)
        }
 
        ret = of_get_fb_videomode(disp, &cfb->mode, OF_USE_NATIVE_MODE);
-       if (ret)
+       if (ret) {
+               of_node_put(disp);
                goto out_fb_release;
+       }
 
        of_property_read_u32(disp, "ac-prescale", &cfb->ac_prescale);
        cfb->cmap_invert = of_property_read_bool(disp, "cmap-invert");
 
        ret = of_property_read_u32(disp, "bits-per-pixel",
                                   &info->var.bits_per_pixel);
+       of_node_put(disp);
        if (ret)
                goto out_fb_release;
 
index 8958ccc8b1ac397685a5e98c1ff9e361605db84e..8976190b6c1ffbdecd5776100cbebb13cf879b11 100644 (file)
@@ -3064,7 +3064,7 @@ static int fbcon_fb_unbind(int idx)
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
                if (con2fb_map[i] != idx &&
                    con2fb_map[i] != -1) {
-                       new_idx = i;
+                       new_idx = con2fb_map[i];
                        break;
                }
        }
index 861bf80816192cafdbc4b0c81201c1d007d1caa8..558ed2ed31249d083ecb4e8d275415c48141be61 100644 (file)
@@ -436,7 +436,9 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
                        image->dx += image->width + 8;
                }
        } else if (rotate == FB_ROTATE_UD) {
-               for (x = 0; x < num; x++) {
+               u32 dx = image->dx;
+
+               for (x = 0; x < num && image->dx <= dx; x++) {
                        info->fbops->fb_imageblit(info, image);
                        image->dx -= image->width + 8;
                }
@@ -448,7 +450,9 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
                        image->dy += image->height + 8;
                }
        } else if (rotate == FB_ROTATE_CCW) {
-               for (x = 0; x < num; x++) {
+               u32 dy = image->dy;
+
+               for (x = 0; x < num && image->dy <= dy; x++) {
                        info->fbops->fb_imageblit(info, image);
                        image->dy -= image->height + 8;
                }
@@ -502,8 +506,25 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
                fb_set_logo(info, logo, logo_new, fb_logo.depth);
        }
 
+#ifdef CONFIG_FB_LOGO_CENTER
+       {
+               int xres = info->var.xres;
+               int yres = info->var.yres;
+
+               if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) {
+                       xres = info->var.yres;
+                       yres = info->var.xres;
+               }
+
+               while (n && (n * (logo->width + 8) - 8 > xres))
+                       --n;
+               image.dx = (xres - n * (logo->width + 8) - 8) / 2;
+               image.dy = y ?: (yres - logo->height) / 2;
+       }
+#else
        image.dx = 0;
        image.dy = y;
+#endif
        image.width = logo->width;
        image.height = logo->height;
 
@@ -521,7 +542,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
                info->pseudo_palette = saved_pseudo_palette;
        kfree(logo_new);
        kfree(logo_rotate);
-       return logo->height;
+       return image.dy + logo->height;
 }
 
 
@@ -573,8 +594,8 @@ static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
        unsigned int i;
 
        for (i = 0; i < fb_logo_ex_num; i++)
-               y += fb_show_logo_line(info, rotate,
-                                      fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
+               y = fb_show_logo_line(info, rotate,
+                                     fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
 
        return y;
 }
@@ -600,6 +621,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
 {
        int depth = fb_get_color_depth(&info->var, &info->fix);
        unsigned int yres;
+       int height;
 
        memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -661,7 +683,12 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
                }
        }
 
-       return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
+       height = fb_logo.logo->height;
+#ifdef CONFIG_FB_LOGO_CENTER
+       height += (yres - fb_logo.logo->height) / 2;
+#endif
+
+       return fb_prepare_extra_logos(info, height, yres);
 }
 
 int fb_show_logo(struct fb_info *info, int rotate)
index e31a182b42bf206ed9c1f682072e1e3e003dc8e1..44cca39f2b5123a0b4eafc3a5b57b2d86790fea8 100644 (file)
@@ -60,7 +60,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
        info->device = dev;
        info->fbcon_rotate_hint = -1;
 
-#ifdef CONFIG_FB_BACKLIGHT
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
        mutex_init(&info->bl_curve_mutex);
 #endif
 
@@ -429,7 +429,7 @@ static ssize_t show_fbstate(struct device *device,
        return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
 }
 
-#ifdef CONFIG_FB_BACKLIGHT
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
 static ssize_t store_bl_curve(struct device *device,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
@@ -510,7 +510,7 @@ static struct device_attribute device_attrs[] = {
        __ATTR(stride, S_IRUGO, show_stride, NULL),
        __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
        __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
-#ifdef CONFIG_FB_BACKLIGHT
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
        __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
 #endif
 };
@@ -551,7 +551,7 @@ void fb_cleanup_device(struct fb_info *fb_info)
        }
 }
 
-#ifdef CONFIG_FB_BACKLIGHT
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
 /* This function generates a linear backlight curve
  *
  *     0: off
index 332a56b6811f920be0a370b280261d9a02071490..9a5451ba4d44dc289ee1ec1092fc864d5e2a5b7c 100644 (file)
@@ -1575,8 +1575,7 @@ static void uninstall_fb(struct fb_info *info)
 
        unregister_framebuffer(info);
        unmap_video_memory(info);
-       if (&info->cmap)
-               fb_dealloc_cmap(&info->cmap);
+       fb_dealloc_cmap(&info->cmap);
 
        mfbi->registered = 0;
 }
index a5e58a829ea06cce584eff6da0ca9694a4e262e9..b4bcf3a4a6475be6bd1da796c476bbbf2a47f915 100644 (file)
@@ -99,24 +99,14 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
 }
 
 #if defined(CONFIG_FB_OMAP2_DSS_DEBUGFS)
-static int dss_debug_show(struct seq_file *s, void *unused)
+static int dss_show(struct seq_file *s, void *unused)
 {
        void (*func)(struct seq_file *) = s->private;
        func(s);
        return 0;
 }
 
-static int dss_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, dss_debug_show, inode->i_private);
-}
-
-static const struct file_operations dss_debug_fops = {
-       .open           = dss_debug_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dss);
 
 static struct dentry *dss_debugfs_dir;
 
@@ -130,7 +120,7 @@ static int dss_initialize_debugfs(void)
        }
 
        debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
-                       &dss_debug_dump_clocks, &dss_debug_fops);
+                       &dss_debug_dump_clocks, &dss_fops);
 
        return 0;
 }
@@ -145,7 +135,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
        struct dentry *d;
 
        d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
-                       write, &dss_debug_fops);
+                       write, &dss_fops);
 
        return PTR_ERR_OR_ZERO(d);
 }
index e31340fad3c7af576c9ad26ff7603449135f3fb3..1410f476e135d99aa1d5a16277e31c42908a3f85 100644 (file)
@@ -279,7 +279,7 @@ static void set_clock_divider(struct pxa168fb_info *fbi,
 
        /* check whether divisor is too small. */
        if (divider_int < 2) {
-               dev_warn(fbi->dev, "Warning: clock source is too slow."
+               dev_warn(fbi->dev, "Warning: clock source is too slow. "
                                "Try smaller resolution\n");
                divider_int = 2;
        }
index bbed039617a4259b0517cb09e1f88676158ad8eb..d59c8a59f58270214eb859e0c27c65cae81f1f48 100644 (file)
@@ -2234,10 +2234,8 @@ static struct pxafb_mach_info *of_pxafb_of_mach_info(struct device *dev)
        if (!info)
                return ERR_PTR(-ENOMEM);
        ret = of_get_pxafb_mode_info(dev, info);
-       if (ret) {
-               kfree(info->modes);
+       if (ret)
                return ERR_PTR(ret);
-       }
 
        /*
         * On purpose, neither lccrX registers nor video memory size can be
index 070026a7e55a507273f8a6a8d7c9b2f9cce70c3c..1d034dddc556949426369d81b0c49b5f3a61176b 100644 (file)
@@ -1598,7 +1598,7 @@ static int dlfb_usb_probe(struct usb_interface *intf,
        dlfb = kzalloc(sizeof(*dlfb), GFP_KERNEL);
        if (!dlfb) {
                dev_err(&intf->dev, "%s: failed to allocate dlfb\n", __func__);
-               goto error;
+               return -ENOMEM;
        }
 
        INIT_LIST_HEAD(&dlfb->deferred_free);
@@ -1703,7 +1703,7 @@ static int dlfb_usb_probe(struct usb_interface *intf,
 error:
        if (dlfb->info) {
                dlfb_ops_destroy(dlfb->info);
-       } else if (dlfb) {
+       } else {
                usb_put_dev(dlfb->udev);
                kfree(dlfb);
        }
@@ -1730,12 +1730,10 @@ static void dlfb_usb_disconnect(struct usb_interface *intf)
        /* this function will wait for all in-flight urbs to complete */
        dlfb_free_urb_list(dlfb);
 
-       if (info) {
-               /* remove udlfb's sysfs interfaces */
-               for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
-                       device_remove_file(info->dev, &fb_device_attrs[i]);
-               device_remove_bin_file(info->dev, &edid_attr);
-       }
+       /* remove udlfb's sysfs interfaces */
+       for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+               device_remove_file(info->dev, &fb_device_attrs[i]);
+       device_remove_bin_file(info->dev, &edid_attr);
 
        unregister_framebuffer(info);
 }
index 440a6636d8f0a894648efcfbd15f38ea8f80ddea..34dc8e53a1e9db4266e0f1aacb22a0b48fd027bc 100644 (file)
@@ -1979,7 +1979,7 @@ MODULE_PARM_DESC(noedid,
 module_param(vram_remap, uint, 0);
 MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]");
 module_param(vram_total, uint, 0);
-MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]");
+MODULE_PARM_DESC(vram_total, "Set total amount of video memory [MiB]");
 module_param(maxclk, ushort, 0);
 MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data");
 module_param(maxhf, ushort, 0);
index d1f6196c8b9a4b329bf5b73aa6222d3ef7d3647f..1e972c4e88b1418de27cae80ebaeb41e853c411c 100644 (file)
@@ -10,6 +10,15 @@ menuconfig LOGO
 
 if LOGO
 
+config FB_LOGO_CENTER
+       bool "Center the logo"
+       depends on FB=y
+       help
+         When this option is selected, the bootup logo is centered both
+         horizontally and vertically. If more than one logo is displayed
+         due to multiple CPUs, the collected line of logos is centered
+         as a whole.
+
 config FB_LOGO_EXTRA
        bool
        depends on FB=y
index 0f46cf550907fcc4a0675b85df9e3331f010e744..4dc788e3bc96b0b5936b9f8df186ef97f1a2cb6c 100644 (file)
@@ -133,15 +133,25 @@ struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
 }
 EXPORT_SYMBOL(fscrypt_get_ctx);
 
+void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
+                        const struct fscrypt_info *ci)
+{
+       memset(iv, 0, ci->ci_mode->ivsize);
+       iv->lblk_num = cpu_to_le64(lblk_num);
+
+       if (ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY)
+               memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
+
+       if (ci->ci_essiv_tfm != NULL)
+               crypto_cipher_encrypt_one(ci->ci_essiv_tfm, iv->raw, iv->raw);
+}
+
 int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
                           u64 lblk_num, struct page *src_page,
                           struct page *dest_page, unsigned int len,
                           unsigned int offs, gfp_t gfp_flags)
 {
-       struct {
-               __le64 index;
-               u8 padding[FS_IV_SIZE - sizeof(__le64)];
-       } iv;
+       union fscrypt_iv iv;
        struct skcipher_request *req = NULL;
        DECLARE_CRYPTO_WAIT(wait);
        struct scatterlist dst, src;
@@ -151,15 +161,7 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
 
        BUG_ON(len == 0);
 
-       BUILD_BUG_ON(sizeof(iv) != FS_IV_SIZE);
-       BUILD_BUG_ON(AES_BLOCK_SIZE != FS_IV_SIZE);
-       iv.index = cpu_to_le64(lblk_num);
-       memset(iv.padding, 0, sizeof(iv.padding));
-
-       if (ci->ci_essiv_tfm != NULL) {
-               crypto_cipher_encrypt_one(ci->ci_essiv_tfm, (u8 *)&iv,
-                                         (u8 *)&iv);
-       }
+       fscrypt_generate_iv(&iv, lblk_num, ci);
 
        req = skcipher_request_alloc(tfm, gfp_flags);
        if (!req)
index d7a0f682ca12296050b6cfb4122440244b8b68e1..7ff40a73dbece841c8d219d1143432020f25f6a1 100644 (file)
@@ -40,10 +40,11 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
 {
        struct skcipher_request *req = NULL;
        DECLARE_CRYPTO_WAIT(wait);
-       struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
-       int res = 0;
-       char iv[FS_CRYPTO_BLOCK_SIZE];
+       struct fscrypt_info *ci = inode->i_crypt_info;
+       struct crypto_skcipher *tfm = ci->ci_ctfm;
+       union fscrypt_iv iv;
        struct scatterlist sg;
+       int res;
 
        /*
         * Copy the filename to the output buffer for encrypting in-place and
@@ -55,7 +56,7 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
        memset(out + iname->len, 0, olen - iname->len);
 
        /* Initialize the IV */
-       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
+       fscrypt_generate_iv(&iv, 0, ci);
 
        /* Set up the encryption request */
        req = skcipher_request_alloc(tfm, GFP_NOFS);
@@ -65,7 +66,7 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
                        CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
                        crypto_req_done, &wait);
        sg_init_one(&sg, out, olen);
-       skcipher_request_set_crypt(req, &sg, &sg, olen, iv);
+       skcipher_request_set_crypt(req, &sg, &sg, olen, &iv);
 
        /* Do the encryption */
        res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
@@ -94,9 +95,10 @@ static int fname_decrypt(struct inode *inode,
        struct skcipher_request *req = NULL;
        DECLARE_CRYPTO_WAIT(wait);
        struct scatterlist src_sg, dst_sg;
-       struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
-       int res = 0;
-       char iv[FS_CRYPTO_BLOCK_SIZE];
+       struct fscrypt_info *ci = inode->i_crypt_info;
+       struct crypto_skcipher *tfm = ci->ci_ctfm;
+       union fscrypt_iv iv;
+       int res;
 
        /* Allocate request */
        req = skcipher_request_alloc(tfm, GFP_NOFS);
@@ -107,12 +109,12 @@ static int fname_decrypt(struct inode *inode,
                crypto_req_done, &wait);
 
        /* Initialize IV */
-       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
+       fscrypt_generate_iv(&iv, 0, ci);
 
        /* Create decryption request */
        sg_init_one(&src_sg, iname->name, iname->len);
        sg_init_one(&dst_sg, oname->name, oname->len);
-       skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
+       skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv);
        res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
        skcipher_request_free(req);
        if (res < 0) {
index 79debfc9cef9172896717299f1403f828159afd7..7424f851eb5cfbc50e47bee579bfaa8bad04e6f4 100644 (file)
@@ -17,7 +17,6 @@
 #include <crypto/hash.h>
 
 /* Encryption parameters */
-#define FS_IV_SIZE                     16
 #define FS_KEY_DERIVATION_NONCE_SIZE   16
 
 /**
@@ -52,16 +51,42 @@ struct fscrypt_symlink_data {
 } __packed;
 
 /*
- * A pointer to this structure is stored in the file system's in-core
- * representation of an inode.
+ * fscrypt_info - the "encryption key" for an inode
+ *
+ * When an encrypted file's key is made available, an instance of this struct is
+ * allocated and stored in ->i_crypt_info.  Once created, it remains until the
+ * inode is evicted.
  */
 struct fscrypt_info {
+
+       /* The actual crypto transform used for encryption and decryption */
+       struct crypto_skcipher *ci_ctfm;
+
+       /*
+        * Cipher for ESSIV IV generation.  Only set for CBC contents
+        * encryption, otherwise is NULL.
+        */
+       struct crypto_cipher *ci_essiv_tfm;
+
+       /*
+        * Encryption mode used for this inode.  It corresponds to either
+        * ci_data_mode or ci_filename_mode, depending on the inode type.
+        */
+       struct fscrypt_mode *ci_mode;
+
+       /*
+        * If non-NULL, then this inode uses a master key directly rather than a
+        * derived key, and ci_ctfm will equal ci_master_key->mk_ctfm.
+        * Otherwise, this inode uses a derived key.
+        */
+       struct fscrypt_master_key *ci_master_key;
+
+       /* fields from the fscrypt_context */
        u8 ci_data_mode;
        u8 ci_filename_mode;
        u8 ci_flags;
-       struct crypto_skcipher *ci_ctfm;
-       struct crypto_cipher *ci_essiv_tfm;
-       u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
+       u8 ci_master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+       u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE];
 };
 
 typedef enum {
@@ -83,6 +108,10 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
            filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
                return true;
 
+       if (contents_mode == FS_ENCRYPTION_MODE_ADIANTUM &&
+           filenames_mode == FS_ENCRYPTION_MODE_ADIANTUM)
+               return true;
+
        return false;
 }
 
@@ -107,6 +136,22 @@ fscrypt_msg(struct super_block *sb, const char *level, const char *fmt, ...);
 #define fscrypt_err(sb, fmt, ...)              \
        fscrypt_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
 
+#define FSCRYPT_MAX_IV_SIZE    32
+
+union fscrypt_iv {
+       struct {
+               /* logical block number within the file */
+               __le64 lblk_num;
+
+               /* per-file nonce; only set in DIRECT_KEY mode */
+               u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+       };
+       u8 raw[FSCRYPT_MAX_IV_SIZE];
+};
+
+void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
+                        const struct fscrypt_info *ci);
+
 /* fname.c */
 extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
                         u8 *out, unsigned int olen);
@@ -115,6 +160,16 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
                                         u32 *encrypted_len_ret);
 
 /* keyinfo.c */
+
+struct fscrypt_mode {
+       const char *friendly_name;
+       const char *cipher_str;
+       int keysize;
+       int ivsize;
+       bool logged_impl_name;
+       bool needs_essiv;
+};
+
 extern void __exit fscrypt_essiv_cleanup(void);
 
 #endif /* _FSCRYPT_PRIVATE_H */
index 7874c9bb2fc532e3177cb9280e84b3db87659d69..1e11a683f63df7a7c8bc725621c2fe3d978578f4 100644 (file)
  */
 
 #include <keys/user-type.h>
+#include <linux/hashtable.h>
 #include <linux/scatterlist.h>
 #include <linux/ratelimit.h>
 #include <crypto/aes.h>
+#include <crypto/algapi.h>
 #include <crypto/sha.h>
 #include <crypto/skcipher.h>
 #include "fscrypt_private.h"
 
 static struct crypto_shash *essiv_hash_tfm;
 
+/* Table of keys referenced by FS_POLICY_FLAG_DIRECT_KEY policies */
+static DEFINE_HASHTABLE(fscrypt_master_keys, 6); /* 6 bits = 64 buckets */
+static DEFINE_SPINLOCK(fscrypt_master_keys_lock);
+
 /*
  * Key derivation function.  This generates the derived key by encrypting the
  * master key with AES-128-ECB using the inode's nonce as the AES key.
@@ -123,56 +129,37 @@ invalid:
        return ERR_PTR(-ENOKEY);
 }
 
-/* Find the master key, then derive the inode's actual encryption key */
-static int find_and_derive_key(const struct inode *inode,
-                              const struct fscrypt_context *ctx,
-                              u8 *derived_key, unsigned int derived_keysize)
-{
-       struct key *key;
-       const struct fscrypt_key *payload;
-       int err;
-
-       key = find_and_lock_process_key(FS_KEY_DESC_PREFIX,
-                                       ctx->master_key_descriptor,
-                                       derived_keysize, &payload);
-       if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) {
-               key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix,
-                                               ctx->master_key_descriptor,
-                                               derived_keysize, &payload);
-       }
-       if (IS_ERR(key))
-               return PTR_ERR(key);
-       err = derive_key_aes(payload->raw, ctx, derived_key, derived_keysize);
-       up_read(&key->sem);
-       key_put(key);
-       return err;
-}
-
-static struct fscrypt_mode {
-       const char *friendly_name;
-       const char *cipher_str;
-       int keysize;
-       bool logged_impl_name;
-} available_modes[] = {
+static struct fscrypt_mode available_modes[] = {
        [FS_ENCRYPTION_MODE_AES_256_XTS] = {
                .friendly_name = "AES-256-XTS",
                .cipher_str = "xts(aes)",
                .keysize = 64,
+               .ivsize = 16,
        },
        [FS_ENCRYPTION_MODE_AES_256_CTS] = {
                .friendly_name = "AES-256-CTS-CBC",
                .cipher_str = "cts(cbc(aes))",
                .keysize = 32,
+               .ivsize = 16,
        },
        [FS_ENCRYPTION_MODE_AES_128_CBC] = {
                .friendly_name = "AES-128-CBC",
                .cipher_str = "cbc(aes)",
                .keysize = 16,
+               .ivsize = 16,
+               .needs_essiv = true,
        },
        [FS_ENCRYPTION_MODE_AES_128_CTS] = {
                .friendly_name = "AES-128-CTS-CBC",
                .cipher_str = "cts(cbc(aes))",
                .keysize = 16,
+               .ivsize = 16,
+       },
+       [FS_ENCRYPTION_MODE_ADIANTUM] = {
+               .friendly_name = "Adiantum",
+               .cipher_str = "adiantum(xchacha12,aes)",
+               .keysize = 32,
+               .ivsize = 32,
        },
 };
 
@@ -198,14 +185,196 @@ select_encryption_mode(const struct fscrypt_info *ci, const struct inode *inode)
        return ERR_PTR(-EINVAL);
 }
 
-static void put_crypt_info(struct fscrypt_info *ci)
+/* Find the master key, then derive the inode's actual encryption key */
+static int find_and_derive_key(const struct inode *inode,
+                              const struct fscrypt_context *ctx,
+                              u8 *derived_key, const struct fscrypt_mode *mode)
 {
-       if (!ci)
+       struct key *key;
+       const struct fscrypt_key *payload;
+       int err;
+
+       key = find_and_lock_process_key(FS_KEY_DESC_PREFIX,
+                                       ctx->master_key_descriptor,
+                                       mode->keysize, &payload);
+       if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) {
+               key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix,
+                                               ctx->master_key_descriptor,
+                                               mode->keysize, &payload);
+       }
+       if (IS_ERR(key))
+               return PTR_ERR(key);
+
+       if (ctx->flags & FS_POLICY_FLAG_DIRECT_KEY) {
+               if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) {
+                       fscrypt_warn(inode->i_sb,
+                                    "direct key mode not allowed with %s",
+                                    mode->friendly_name);
+                       err = -EINVAL;
+               } else if (ctx->contents_encryption_mode !=
+                          ctx->filenames_encryption_mode) {
+                       fscrypt_warn(inode->i_sb,
+                                    "direct key mode not allowed with different contents and filenames modes");
+                       err = -EINVAL;
+               } else {
+                       memcpy(derived_key, payload->raw, mode->keysize);
+                       err = 0;
+               }
+       } else {
+               err = derive_key_aes(payload->raw, ctx, derived_key,
+                                    mode->keysize);
+       }
+       up_read(&key->sem);
+       key_put(key);
+       return err;
+}
+
+/* Allocate and key a symmetric cipher object for the given encryption mode */
+static struct crypto_skcipher *
+allocate_skcipher_for_mode(struct fscrypt_mode *mode, const u8 *raw_key,
+                          const struct inode *inode)
+{
+       struct crypto_skcipher *tfm;
+       int err;
+
+       tfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
+       if (IS_ERR(tfm)) {
+               fscrypt_warn(inode->i_sb,
+                            "error allocating '%s' transform for inode %lu: %ld",
+                            mode->cipher_str, inode->i_ino, PTR_ERR(tfm));
+               return tfm;
+       }
+       if (unlikely(!mode->logged_impl_name)) {
+               /*
+                * fscrypt performance can vary greatly depending on which
+                * crypto algorithm implementation is used.  Help people debug
+                * performance problems by logging the ->cra_driver_name the
+                * first time a mode is used.  Note that multiple threads can
+                * race here, but it doesn't really matter.
+                */
+               mode->logged_impl_name = true;
+               pr_info("fscrypt: %s using implementation \"%s\"\n",
+                       mode->friendly_name,
+                       crypto_skcipher_alg(tfm)->base.cra_driver_name);
+       }
+       crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+       err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize);
+       if (err)
+               goto err_free_tfm;
+
+       return tfm;
+
+err_free_tfm:
+       crypto_free_skcipher(tfm);
+       return ERR_PTR(err);
+}
+
+/* Master key referenced by FS_POLICY_FLAG_DIRECT_KEY policy */
+struct fscrypt_master_key {
+       struct hlist_node mk_node;
+       refcount_t mk_refcount;
+       const struct fscrypt_mode *mk_mode;
+       struct crypto_skcipher *mk_ctfm;
+       u8 mk_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+       u8 mk_raw[FS_MAX_KEY_SIZE];
+};
+
+static void free_master_key(struct fscrypt_master_key *mk)
+{
+       if (mk) {
+               crypto_free_skcipher(mk->mk_ctfm);
+               kzfree(mk);
+       }
+}
+
+static void put_master_key(struct fscrypt_master_key *mk)
+{
+       if (!refcount_dec_and_lock(&mk->mk_refcount, &fscrypt_master_keys_lock))
                return;
+       hash_del(&mk->mk_node);
+       spin_unlock(&fscrypt_master_keys_lock);
 
-       crypto_free_skcipher(ci->ci_ctfm);
-       crypto_free_cipher(ci->ci_essiv_tfm);
-       kmem_cache_free(fscrypt_info_cachep, ci);
+       free_master_key(mk);
+}
+
+/*
+ * Find/insert the given master key into the fscrypt_master_keys table.  If
+ * found, it is returned with elevated refcount, and 'to_insert' is freed if
+ * non-NULL.  If not found, 'to_insert' is inserted and returned if it's
+ * non-NULL; otherwise NULL is returned.
+ */
+static struct fscrypt_master_key *
+find_or_insert_master_key(struct fscrypt_master_key *to_insert,
+                         const u8 *raw_key, const struct fscrypt_mode *mode,
+                         const struct fscrypt_info *ci)
+{
+       unsigned long hash_key;
+       struct fscrypt_master_key *mk;
+
+       /*
+        * Careful: to avoid potentially leaking secret key bytes via timing
+        * information, we must key the hash table by descriptor rather than by
+        * raw key, and use crypto_memneq() when comparing raw keys.
+        */
+
+       BUILD_BUG_ON(sizeof(hash_key) > FS_KEY_DESCRIPTOR_SIZE);
+       memcpy(&hash_key, ci->ci_master_key_descriptor, sizeof(hash_key));
+
+       spin_lock(&fscrypt_master_keys_lock);
+       hash_for_each_possible(fscrypt_master_keys, mk, mk_node, hash_key) {
+               if (memcmp(ci->ci_master_key_descriptor, mk->mk_descriptor,
+                          FS_KEY_DESCRIPTOR_SIZE) != 0)
+                       continue;
+               if (mode != mk->mk_mode)
+                       continue;
+               if (crypto_memneq(raw_key, mk->mk_raw, mode->keysize))
+                       continue;
+               /* using existing tfm with same (descriptor, mode, raw_key) */
+               refcount_inc(&mk->mk_refcount);
+               spin_unlock(&fscrypt_master_keys_lock);
+               free_master_key(to_insert);
+               return mk;
+       }
+       if (to_insert)
+               hash_add(fscrypt_master_keys, &to_insert->mk_node, hash_key);
+       spin_unlock(&fscrypt_master_keys_lock);
+       return to_insert;
+}
+
+/* Prepare to encrypt directly using the master key in the given mode */
+static struct fscrypt_master_key *
+fscrypt_get_master_key(const struct fscrypt_info *ci, struct fscrypt_mode *mode,
+                      const u8 *raw_key, const struct inode *inode)
+{
+       struct fscrypt_master_key *mk;
+       int err;
+
+       /* Is there already a tfm for this key? */
+       mk = find_or_insert_master_key(NULL, raw_key, mode, ci);
+       if (mk)
+               return mk;
+
+       /* Nope, allocate one. */
+       mk = kzalloc(sizeof(*mk), GFP_NOFS);
+       if (!mk)
+               return ERR_PTR(-ENOMEM);
+       refcount_set(&mk->mk_refcount, 1);
+       mk->mk_mode = mode;
+       mk->mk_ctfm = allocate_skcipher_for_mode(mode, raw_key, inode);
+       if (IS_ERR(mk->mk_ctfm)) {
+               err = PTR_ERR(mk->mk_ctfm);
+               mk->mk_ctfm = NULL;
+               goto err_free_mk;
+       }
+       memcpy(mk->mk_descriptor, ci->ci_master_key_descriptor,
+              FS_KEY_DESCRIPTOR_SIZE);
+       memcpy(mk->mk_raw, raw_key, mode->keysize);
+
+       return find_or_insert_master_key(mk, raw_key, mode, ci);
+
+err_free_mk:
+       free_master_key(mk);
+       return ERR_PTR(err);
 }
 
 static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
@@ -275,11 +444,67 @@ void __exit fscrypt_essiv_cleanup(void)
        crypto_free_shash(essiv_hash_tfm);
 }
 
+/*
+ * Given the encryption mode and key (normally the derived key, but for
+ * FS_POLICY_FLAG_DIRECT_KEY mode it's the master key), set up the inode's
+ * symmetric cipher transform object(s).
+ */
+static int setup_crypto_transform(struct fscrypt_info *ci,
+                                 struct fscrypt_mode *mode,
+                                 const u8 *raw_key, const struct inode *inode)
+{
+       struct fscrypt_master_key *mk;
+       struct crypto_skcipher *ctfm;
+       int err;
+
+       if (ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY) {
+               mk = fscrypt_get_master_key(ci, mode, raw_key, inode);
+               if (IS_ERR(mk))
+                       return PTR_ERR(mk);
+               ctfm = mk->mk_ctfm;
+       } else {
+               mk = NULL;
+               ctfm = allocate_skcipher_for_mode(mode, raw_key, inode);
+               if (IS_ERR(ctfm))
+                       return PTR_ERR(ctfm);
+       }
+       ci->ci_master_key = mk;
+       ci->ci_ctfm = ctfm;
+
+       if (mode->needs_essiv) {
+               /* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */
+               WARN_ON(mode->ivsize != AES_BLOCK_SIZE);
+               WARN_ON(ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY);
+
+               err = init_essiv_generator(ci, raw_key, mode->keysize);
+               if (err) {
+                       fscrypt_warn(inode->i_sb,
+                                    "error initializing ESSIV generator for inode %lu: %d",
+                                    inode->i_ino, err);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+static void put_crypt_info(struct fscrypt_info *ci)
+{
+       if (!ci)
+               return;
+
+       if (ci->ci_master_key) {
+               put_master_key(ci->ci_master_key);
+       } else {
+               crypto_free_skcipher(ci->ci_ctfm);
+               crypto_free_cipher(ci->ci_essiv_tfm);
+       }
+       kmem_cache_free(fscrypt_info_cachep, ci);
+}
+
 int fscrypt_get_encryption_info(struct inode *inode)
 {
        struct fscrypt_info *crypt_info;
        struct fscrypt_context ctx;
-       struct crypto_skcipher *ctfm;
        struct fscrypt_mode *mode;
        u8 *raw_key = NULL;
        int res;
@@ -312,74 +537,42 @@ int fscrypt_get_encryption_info(struct inode *inode)
        if (ctx.flags & ~FS_POLICY_FLAGS_VALID)
                return -EINVAL;
 
-       crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
+       crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS);
        if (!crypt_info)
                return -ENOMEM;
 
        crypt_info->ci_flags = ctx.flags;
        crypt_info->ci_data_mode = ctx.contents_encryption_mode;
        crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
-       crypt_info->ci_ctfm = NULL;
-       crypt_info->ci_essiv_tfm = NULL;
-       memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
-                               sizeof(crypt_info->ci_master_key));
+       memcpy(crypt_info->ci_master_key_descriptor, ctx.master_key_descriptor,
+              FS_KEY_DESCRIPTOR_SIZE);
+       memcpy(crypt_info->ci_nonce, ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
 
        mode = select_encryption_mode(crypt_info, inode);
        if (IS_ERR(mode)) {
                res = PTR_ERR(mode);
                goto out;
        }
+       WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE);
+       crypt_info->ci_mode = mode;
 
        /*
-        * This cannot be a stack buffer because it is passed to the scatterlist
-        * crypto API as part of key derivation.
+        * This cannot be a stack buffer because it may be passed to the
+        * scatterlist crypto API as part of key derivation.
         */
        res = -ENOMEM;
        raw_key = kmalloc(mode->keysize, GFP_NOFS);
        if (!raw_key)
                goto out;
 
-       res = find_and_derive_key(inode, &ctx, raw_key, mode->keysize);
+       res = find_and_derive_key(inode, &ctx, raw_key, mode);
        if (res)
                goto out;
 
-       ctfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
-       if (IS_ERR(ctfm)) {
-               res = PTR_ERR(ctfm);
-               fscrypt_warn(inode->i_sb,
-                            "error allocating '%s' transform for inode %lu: %d",
-                            mode->cipher_str, inode->i_ino, res);
-               goto out;
-       }
-       if (unlikely(!mode->logged_impl_name)) {
-               /*
-                * fscrypt performance can vary greatly depending on which
-                * crypto algorithm implementation is used.  Help people debug
-                * performance problems by logging the ->cra_driver_name the
-                * first time a mode is used.  Note that multiple threads can
-                * race here, but it doesn't really matter.
-                */
-               mode->logged_impl_name = true;
-               pr_info("fscrypt: %s using implementation \"%s\"\n",
-                       mode->friendly_name,
-                       crypto_skcipher_alg(ctfm)->base.cra_driver_name);
-       }
-       crypt_info->ci_ctfm = ctfm;
-       crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
-       res = crypto_skcipher_setkey(ctfm, raw_key, mode->keysize);
+       res = setup_crypto_transform(crypt_info, mode, raw_key, inode);
        if (res)
                goto out;
 
-       if (S_ISREG(inode->i_mode) &&
-           crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) {
-               res = init_essiv_generator(crypt_info, raw_key, mode->keysize);
-               if (res) {
-                       fscrypt_warn(inode->i_sb,
-                                    "error initializing ESSIV generator for inode %lu: %d",
-                                    inode->i_ino, res);
-                       goto out;
-               }
-       }
        if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
                crypt_info = NULL;
 out:
index c6d431a5cce932fd80385415fe598aca0f74ba05..f490de921ce82f32debeadaf22bc30f192d76e1c 100644 (file)
@@ -199,7 +199,8 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
        child_ci = child->i_crypt_info;
 
        if (parent_ci && child_ci) {
-               return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
+               return memcmp(parent_ci->ci_master_key_descriptor,
+                             child_ci->ci_master_key_descriptor,
                              FS_KEY_DESCRIPTOR_SIZE) == 0 &&
                        (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
                        (parent_ci->ci_filename_mode ==
@@ -254,7 +255,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
        ctx.contents_encryption_mode = ci->ci_data_mode;
        ctx.filenames_encryption_mode = ci->ci_filename_mode;
        ctx.flags = ci->ci_flags;
-       memcpy(ctx.master_key_descriptor, ci->ci_master_key,
+       memcpy(ctx.master_key_descriptor, ci->ci_master_key_descriptor,
               FS_KEY_DESCRIPTOR_SIZE);
        get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
        BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE);
index 26a7fe5c4fd3cbc7b8d40d193a3c350b2163bb6c..712f00995390ee021249bb6f8478db30f0f8f3bb 100644 (file)
@@ -116,8 +116,16 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                goto out;
        }
 
+       ret = file_write_and_wait_range(file, start, end);
+       if (ret)
+               return ret;
+
        if (!journal) {
-               ret = __generic_file_fsync(file, start, end, datasync);
+               struct writeback_control wbc = {
+                       .sync_mode = WB_SYNC_ALL
+               };
+
+               ret = ext4_write_inode(inode, &wbc);
                if (!ret)
                        ret = ext4_sync_parent(inode);
                if (test_opt(inode->i_sb, BARRIER))
@@ -125,9 +133,6 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                goto out;
        }
 
-       ret = file_write_and_wait_range(file, start, end);
-       if (ret)
-               return ret;
        /*
         * data=writeback,ordered:
         *  The caller's filemap_fdatawrite()/wait will sync the data.
@@ -159,6 +164,9 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                        ret = err;
        }
 out:
+       err = file_check_and_advance_wb_err(file);
+       if (ret == 0)
+               ret = err;
        trace_ext4_sync_file_exit(inode, ret);
        return ret;
 }
index 27373d88b5f0115341b4c574599bd21ee8767fee..56f6e1782d5f7db9148e0b868e0297362aa7bb24 100644 (file)
@@ -1890,12 +1890,12 @@ int ext4_inline_data_fiemap(struct inode *inode,
        physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data;
        physical += offsetof(struct ext4_inode, i_block);
 
-       if (physical)
-               error = fiemap_fill_next_extent(fieinfo, start, physical,
-                                               inline_len, flags);
        brelse(iloc.bh);
 out:
        up_read(&EXT4_I(inode)->xattr_sem);
+       if (physical)
+               error = fiemap_fill_next_extent(fieinfo, start, physical,
+                                               inline_len, flags);
        return (error < 0 ? error : 0);
 }
 
index 9affabd07682141dec0454ebfd01c15ff8512db7..34d7e0703cc6f1677010416f1671df883c85a669 100644 (file)
@@ -2778,7 +2778,8 @@ static int ext4_writepages(struct address_space *mapping,
                 * We may need to convert up to one extent per block in
                 * the page and we may dirty the inode.
                 */
-               rsv_blocks = 1 + (PAGE_SIZE >> inode->i_blkbits);
+               rsv_blocks = 1 + ext4_chunk_trans_blocks(inode,
+                                               PAGE_SIZE >> inode->i_blkbits);
        }
 
        /*
@@ -4833,7 +4834,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
        gid_t i_gid;
        projid_t i_projid;
 
-       if (((flags & EXT4_IGET_NORMAL) &&
+       if ((!(flags & EXT4_IGET_SPECIAL) &&
             (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)) ||
            (ino < EXT4_ROOT_INO) ||
            (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) {
index d6c142d73d99afa47fcd784c831bfee2c52d7c84..fb12d3c17c1b1a48c5e6554b59e22fdeb7182daa 100644 (file)
@@ -4902,7 +4902,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        ext4_superblock_csum_set(sb);
        if (sync)
                lock_buffer(sbh);
-       if (buffer_write_io_error(sbh)) {
+       if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
                /*
                 * Oh, dear.  A previous attempt to write the
                 * superblock failed.  This could happen because the
index 2ad5c363d7d57e55b8a83adac03ba2647856887f..cb422cbe587db6f38bffae72ff98a065a31b14e2 100644 (file)
@@ -35,13 +35,12 @@ extern void debug_dma_map_single(struct device *dev, const void *addr,
 
 extern void debug_dma_map_page(struct device *dev, struct page *page,
                               size_t offset, size_t size,
-                              int direction, dma_addr_t dma_addr,
-                              bool map_single);
+                              int direction, dma_addr_t dma_addr);
 
 extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
 
 extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
-                                size_t size, int direction, bool map_single);
+                                size_t size, int direction);
 
 extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
                             int nents, int mapped_ents, int direction);
@@ -95,8 +94,7 @@ static inline void debug_dma_map_single(struct device *dev, const void *addr,
 
 static inline void debug_dma_map_page(struct device *dev, struct page *page,
                                      size_t offset, size_t size,
-                                     int direction, dma_addr_t dma_addr,
-                                     bool map_single)
+                                     int direction, dma_addr_t dma_addr)
 {
 }
 
@@ -106,8 +104,7 @@ static inline void debug_dma_mapping_error(struct device *dev,
 }
 
 static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
-                                       size_t size, int direction,
-                                       bool map_single)
+                                       size_t size, int direction)
 {
 }
 
index ba521d5506c90baf24af896c852ac400d1298451..cef2127e1d70497f6035af75ee0c74af7ef1c075 100644 (file)
@@ -194,33 +194,6 @@ static inline int dma_mmap_from_global_coherent(struct vm_area_struct *vma,
 }
 #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
 
-#ifdef CONFIG_HAS_DMA
-#include <asm/dma-mapping.h>
-static inline const struct dma_map_ops *get_dma_ops(struct device *dev)
-{
-       if (dev && dev->dma_ops)
-               return dev->dma_ops;
-       return get_arch_dma_ops(dev ? dev->bus : NULL);
-}
-
-static inline void set_dma_ops(struct device *dev,
-                              const struct dma_map_ops *dma_ops)
-{
-       dev->dma_ops = dma_ops;
-}
-#else
-/*
- * Define the dma api to allow compilation of dma dependent code.
- * Code that depends on the dma-mapping API needs to set 'depends on HAS_DMA'
- * in its Kconfig, unless it already depends on <something> || COMPILE_TEST,
- * where <something> guarantuees the availability of the dma-mapping API.
- */
-static inline const struct dma_map_ops *get_dma_ops(struct device *dev)
-{
-       return NULL;
-}
-#endif
-
 static inline bool dma_is_direct(const struct dma_map_ops *ops)
 {
        return likely(!ops);
@@ -284,32 +257,41 @@ static inline void dma_direct_sync_sg_for_cpu(struct device *dev,
 }
 #endif
 
-static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
-                                             size_t size,
-                                             enum dma_data_direction dir,
-                                             unsigned long attrs)
+#ifdef CONFIG_HAS_DMA
+#include <asm/dma-mapping.h>
+
+static inline const struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+       if (dev && dev->dma_ops)
+               return dev->dma_ops;
+       return get_arch_dma_ops(dev ? dev->bus : NULL);
+}
+
+static inline void set_dma_ops(struct device *dev,
+                              const struct dma_map_ops *dma_ops)
+{
+       dev->dma_ops = dma_ops;
+}
+
+static inline dma_addr_t dma_map_page_attrs(struct device *dev,
+               struct page *page, size_t offset, size_t size,
+               enum dma_data_direction dir, unsigned long attrs)
 {
        const struct dma_map_ops *ops = get_dma_ops(dev);
        dma_addr_t addr;
 
        BUG_ON(!valid_dma_direction(dir));
-       debug_dma_map_single(dev, ptr, size);
        if (dma_is_direct(ops))
-               addr = dma_direct_map_page(dev, virt_to_page(ptr),
-                               offset_in_page(ptr), size, dir, attrs);
+               addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
        else
-               addr = ops->map_page(dev, virt_to_page(ptr),
-                               offset_in_page(ptr), size, dir, attrs);
-       debug_dma_map_page(dev, virt_to_page(ptr),
-                          offset_in_page(ptr), size,
-                          dir, addr, true);
+               addr = ops->map_page(dev, page, offset, size, dir, attrs);
+       debug_dma_map_page(dev, page, offset, size, dir, addr);
+
        return addr;
 }
 
-static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
-                                         size_t size,
-                                         enum dma_data_direction dir,
-                                         unsigned long attrs)
+static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        const struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -318,13 +300,7 @@ static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
                dma_direct_unmap_page(dev, addr, size, dir, attrs);
        else if (ops->unmap_page)
                ops->unmap_page(dev, addr, size, dir, attrs);
-       debug_dma_unmap_page(dev, addr, size, dir, true);
-}
-
-static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
-               size_t size, enum dma_data_direction dir, unsigned long attrs)
-{
-       return dma_unmap_single_attrs(dev, addr, size, dir, attrs);
+       debug_dma_unmap_page(dev, addr, size, dir);
 }
 
 /*
@@ -363,25 +339,6 @@ static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg
                ops->unmap_sg(dev, sg, nents, dir, attrs);
 }
 
-static inline dma_addr_t dma_map_page_attrs(struct device *dev,
-                                           struct page *page,
-                                           size_t offset, size_t size,
-                                           enum dma_data_direction dir,
-                                           unsigned long attrs)
-{
-       const struct dma_map_ops *ops = get_dma_ops(dev);
-       dma_addr_t addr;
-
-       BUG_ON(!valid_dma_direction(dir));
-       if (dma_is_direct(ops))
-               addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
-       else
-               addr = ops->map_page(dev, page, offset, size, dir, attrs);
-       debug_dma_map_page(dev, page, offset, size, dir, addr, false);
-
-       return addr;
-}
-
 static inline dma_addr_t dma_map_resource(struct device *dev,
                                          phys_addr_t phys_addr,
                                          size_t size,
@@ -431,13 +388,6 @@ static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
        debug_dma_sync_single_for_cpu(dev, addr, size, dir);
 }
 
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-               dma_addr_t addr, unsigned long offset, size_t size,
-               enum dma_data_direction dir)
-{
-       return dma_sync_single_for_cpu(dev, addr + offset, size, dir);
-}
-
 static inline void dma_sync_single_for_device(struct device *dev,
                                              dma_addr_t addr, size_t size,
                                              enum dma_data_direction dir)
@@ -452,13 +402,6 @@ static inline void dma_sync_single_for_device(struct device *dev,
        debug_dma_sync_single_for_device(dev, addr, size, dir);
 }
 
-static inline void dma_sync_single_range_for_device(struct device *dev,
-               dma_addr_t addr, unsigned long offset, size_t size,
-               enum dma_data_direction dir)
-{
-       return dma_sync_single_for_device(dev, addr + offset, size, dir);
-}
-
 static inline void
 dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
                    int nelems, enum dma_data_direction dir)
@@ -488,15 +431,174 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 
 }
 
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       debug_dma_mapping_error(dev, dma_addr);
+
+       if (dma_addr == DMA_MAPPING_ERROR)
+               return -ENOMEM;
+       return 0;
+}
+
+void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t flag, unsigned long attrs);
+void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+               dma_addr_t dma_handle, unsigned long attrs);
+void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t gfp, unsigned long attrs);
+void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+               dma_addr_t dma_handle);
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+               enum dma_data_direction dir);
+int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               unsigned long attrs);
+int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               unsigned long attrs);
+int dma_supported(struct device *dev, u64 mask);
+int dma_set_mask(struct device *dev, u64 mask);
+int dma_set_coherent_mask(struct device *dev, u64 mask);
+u64 dma_get_required_mask(struct device *dev);
+#else /* CONFIG_HAS_DMA */
+static inline dma_addr_t dma_map_page_attrs(struct device *dev,
+               struct page *page, size_t offset, size_t size,
+               enum dma_data_direction dir, unsigned long attrs)
+{
+       return DMA_MAPPING_ERROR;
+}
+static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+}
+static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
+               int nents, enum dma_data_direction dir, unsigned long attrs)
+{
+       return 0;
+}
+static inline void dma_unmap_sg_attrs(struct device *dev,
+               struct scatterlist *sg, int nents, enum dma_data_direction dir,
+               unsigned long attrs)
+{
+}
+static inline dma_addr_t dma_map_resource(struct device *dev,
+               phys_addr_t phys_addr, size_t size, enum dma_data_direction dir,
+               unsigned long attrs)
+{
+       return DMA_MAPPING_ERROR;
+}
+static inline void dma_unmap_resource(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+}
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir)
+{
+}
+static inline void dma_sync_single_for_device(struct device *dev,
+               dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+}
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+               struct scatterlist *sg, int nelems, enum dma_data_direction dir)
+{
+}
+static inline void dma_sync_sg_for_device(struct device *dev,
+               struct scatterlist *sg, int nelems, enum dma_data_direction dir)
+{
+}
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return -ENOMEM;
+}
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+               dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
+{
+       return NULL;
+}
+static void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+               dma_addr_t dma_handle, unsigned long attrs)
+{
+}
+static inline void *dmam_alloc_attrs(struct device *dev, size_t size,
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
+{
+       return NULL;
+}
+static inline void dmam_free_coherent(struct device *dev, size_t size,
+               void *vaddr, dma_addr_t dma_handle)
+{
+}
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+               enum dma_data_direction dir)
+{
+}
+static inline int dma_get_sgtable_attrs(struct device *dev,
+               struct sg_table *sgt, void *cpu_addr, dma_addr_t dma_addr,
+               size_t size, unsigned long attrs)
+{
+       return -ENXIO;
+}
+static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               unsigned long attrs)
+{
+       return -ENXIO;
+}
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       return 0;
+}
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+       return -EIO;
+}
+static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+       return -EIO;
+}
+static inline u64 dma_get_required_mask(struct device *dev)
+{
+       return 0;
+}
+#endif /* CONFIG_HAS_DMA */
+
+static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+       debug_dma_map_single(dev, ptr, size);
+       return dma_map_page_attrs(dev, virt_to_page(ptr), offset_in_page(ptr),
+                       size, dir, attrs);
+}
+
+static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+       return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+               dma_addr_t addr, unsigned long offset, size_t size,
+               enum dma_data_direction dir)
+{
+       return dma_sync_single_for_cpu(dev, addr + offset, size, dir);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+               dma_addr_t addr, unsigned long offset, size_t size,
+               enum dma_data_direction dir)
+{
+       return dma_sync_single_for_device(dev, addr + offset, size, dir);
+}
+
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
 #define dma_map_page(d, p, o, s, r) dma_map_page_attrs(d, p, o, s, r, 0)
 #define dma_unmap_page(d, a, s, r) dma_unmap_page_attrs(d, a, s, r, 0)
-
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-               enum dma_data_direction dir);
+#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
 
 extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
                void *cpu_addr, dma_addr_t dma_addr, size_t size,
@@ -516,25 +618,10 @@ bool dma_in_atomic_pool(void *start, size_t size);
 void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags);
 bool dma_free_from_pool(void *start, size_t size);
 
-int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
-               void *cpu_addr, dma_addr_t dma_addr, size_t size,
-               unsigned long attrs);
-#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
-
 int
 dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr,
                dma_addr_t dma_addr, size_t size, unsigned long attrs);
 
-int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
-               void *cpu_addr, dma_addr_t dma_addr, size_t size,
-               unsigned long attrs);
-#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
-
-void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t flag, unsigned long attrs);
-void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
-               dma_addr_t dma_handle, unsigned long attrs);
-
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp)
 {
@@ -549,18 +636,6 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
        return dma_free_attrs(dev, size, cpu_addr, dma_handle, 0);
 }
 
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       debug_dma_mapping_error(dev, dma_addr);
-
-       if (dma_addr == DMA_MAPPING_ERROR)
-               return -ENOMEM;
-       return 0;
-}
-
-int dma_supported(struct device *dev, u64 mask);
-int dma_set_mask(struct device *dev, u64 mask);
-int dma_set_coherent_mask(struct device *dev, u64 mask);
 
 static inline u64 dma_get_mask(struct device *dev)
 {
@@ -593,8 +668,6 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
        return dma_set_mask_and_coherent(dev, mask);
 }
 
-extern u64 dma_get_required_mask(struct device *dev);
-
 #ifndef arch_setup_dma_ops
 static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
                                      u64 size, const struct iommu_ops *iommu,
@@ -691,43 +764,12 @@ dma_mark_declared_memory_occupied(struct device *dev,
 }
 #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
 
-/*
- * Managed DMA API
- */
-#ifdef CONFIG_HAS_DMA
-extern void *dmam_alloc_coherent(struct device *dev, size_t size,
-                                dma_addr_t *dma_handle, gfp_t gfp);
-extern void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
-                              dma_addr_t dma_handle);
-#else /* !CONFIG_HAS_DMA */
 static inline void *dmam_alloc_coherent(struct device *dev, size_t size,
-                                       dma_addr_t *dma_handle, gfp_t gfp)
-{ return NULL; }
-static inline void dmam_free_coherent(struct device *dev, size_t size,
-                                     void *vaddr, dma_addr_t dma_handle) { }
-#endif /* !CONFIG_HAS_DMA */
-
-extern void *dmam_alloc_attrs(struct device *dev, size_t size,
-                             dma_addr_t *dma_handle, gfp_t gfp,
-                             unsigned long attrs);
-#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
-extern int dmam_declare_coherent_memory(struct device *dev,
-                                       phys_addr_t phys_addr,
-                                       dma_addr_t device_addr, size_t size,
-                                       int flags);
-extern void dmam_release_declared_memory(struct device *dev);
-#else /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
-static inline int dmam_declare_coherent_memory(struct device *dev,
-                               phys_addr_t phys_addr, dma_addr_t device_addr,
-                               size_t size, gfp_t gfp)
-{
-       return 0;
-}
-
-static inline void dmam_release_declared_memory(struct device *dev)
+               dma_addr_t *dma_handle, gfp_t gfp)
 {
+       return dmam_alloc_attrs(dev, size, dma_handle, gfp,
+                       (gfp & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0);
 }
-#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
 
 static inline void *dma_alloc_wc(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t gfp)
index a3cab6dc9b4402503210cab850a9b99c27fd6307..7cdd31a6971914c174ed8bcf46c27ceaee54057b 100644 (file)
@@ -485,7 +485,7 @@ struct fb_info {
        struct list_head modelist;      /* mode list */
        struct fb_videomode *mode;      /* current mode */
 
-#ifdef CONFIG_FB_BACKLIGHT
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
        /* assigned backlight device */
        /* set before framebuffer registration, 
           remove after unregister */
index a355d61940f28957ec61b4424d49732a85118ffd..d99287327ef23f630e321d4705da2ef0248a257a 100644 (file)
@@ -219,6 +219,7 @@ struct hid_item {
 #define HID_GD_VBRZ            0x00010045
 #define HID_GD_VNO             0x00010046
 #define HID_GD_FEATURE         0x00010047
+#define HID_GD_RESOLUTION_MULTIPLIER   0x00010048
 #define HID_GD_SYSTEM_CONTROL  0x00010080
 #define HID_GD_UP              0x00010090
 #define HID_GD_DOWN            0x00010091
@@ -232,12 +233,14 @@ struct hid_item {
 #define HID_DC_BATTERYSTRENGTH 0x00060020
 
 #define HID_CP_CONSUMER_CONTROL        0x000c0001
+#define HID_CP_AC_PAN          0x000c0238
 
 #define HID_DG_DIGITIZER       0x000d0001
 #define HID_DG_PEN             0x000d0002
 #define HID_DG_LIGHTPEN                0x000d0003
 #define HID_DG_TOUCHSCREEN     0x000d0004
 #define HID_DG_TOUCHPAD                0x000d0005
+#define HID_DG_WHITEBOARD      0x000d0006
 #define HID_DG_STYLUS          0x000d0020
 #define HID_DG_PUCK            0x000d0021
 #define HID_DG_FINGER          0x000d0022
@@ -427,6 +430,7 @@ struct hid_local {
  */
 
 struct hid_collection {
+       struct hid_collection *parent;
        unsigned type;
        unsigned usage;
        unsigned level;
@@ -436,12 +440,16 @@ struct hid_usage {
        unsigned  hid;                  /* hid usage code */
        unsigned  collection_index;     /* index into collection array */
        unsigned  usage_index;          /* index into usage array */
+       __s8      resolution_multiplier;/* Effective Resolution Multiplier
+                                          (HUT v1.12, 4.3.1), default: 1 */
        /* hidinput data */
+       __s8      wheel_factor;         /* 120/resolution_multiplier */
        __u16     code;                 /* input driver code */
        __u8      type;                 /* input driver type */
        __s8      hat_min;              /* hat switch fun */
        __s8      hat_max;              /* ditto */
        __s8      hat_dir;              /* ditto */
+       __s16     wheel_accumulated;    /* hi-res wheel */
 };
 
 struct hid_input;
@@ -650,6 +658,7 @@ struct hid_parser {
        unsigned int         *collection_stack;
        unsigned int          collection_stack_ptr;
        unsigned int          collection_stack_size;
+       struct hid_collection *active_collection;
        struct hid_device    *device;
        unsigned int          scan_flags;
 };
@@ -836,7 +845,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev,
 
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
-#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006)))
+#define IS_INPUT_APPLICATION(a) \
+               (((a >= HID_UP_GENDESK) && (a <= HID_GD_MULTIAXIS)) \
+               || ((a >= HID_DG_PEN) && (a <= HID_DG_WHITEBOARD)) \
+               || (a == HID_GD_SYSTEM_CONTROL) || (a == HID_CP_CONSUMER_CONTROL) \
+               || (a == HID_GD_WIRELESS_RADIO_CTLS))
 
 /* HID core API */
 
@@ -892,6 +905,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
                                       unsigned int type, unsigned int id,
                                       unsigned int field_index,
                                       unsigned int report_counts);
+
+void hid_setup_resolution_multiplier(struct hid_device *hid);
 int hid_open_report(struct hid_device *device);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
index e44e3ec8a9c7d0e4c389a4c65360dbc3e14ab86a..de8b588c8776da5526b78f66a107e871a0dd952c 100644 (file)
@@ -317,7 +317,9 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev);
  * @wake_event: Pointer to a bool set to true upon return if the event might be
  *              treated as a wake event. Ignored if null.
  *
- * Return: 0 on success or negative error code.
+ * Return: negative error code on errors; 0 for no data; or else number of
+ * bytes received (i.e., an event was retrieved successfully). Event types are
+ * written out to @ec_dev->event_data.event_type on success.
  */
 int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
 
@@ -329,7 +331,7 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
  * events raised and call the functions in the ec notifier. This function
  * is a helper to know which events are raised.
  *
- * Return: 0 on success or negative error code.
+ * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
  */
 u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
 
index 6c1ad160ed879090c9fdb3ec6cd8772bb3431d03..c1b25f5e386d55e12545d1d958dc119cba7eb2dc 100644 (file)
 #define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK                        (0x1 << 1)
 
 #define IMX6SX_GPR12_PCIE_TEST_POWERDOWN               BIT(30)
+#define IMX6SX_GPR12_PCIE_PM_TURN_OFF                  BIT(16)
 #define IMX6SX_GPR12_PCIE_RX_EQ_MASK                   (0x7 << 0)
 #define IMX6SX_GPR12_PCIE_RX_EQ_2                      (0x2 << 0)
 
index 1ab78a23ae08ee0fcee07b0293dcb5349fdb67bf..65f1d8c2f08202ea6683a596e67f252de95bea4e 100644 (file)
@@ -413,6 +413,7 @@ struct pci_dev {
        unsigned int    non_compliant_bars:1;   /* Broken BARs; ignore them */
        unsigned int    is_probed:1;            /* Device probing in progress */
        unsigned int    link_active_reporting:1;/* Device capable of reporting link active */
+       unsigned int    no_vf_scan:1;           /* Don't scan for VFs after IOV enablement */
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
@@ -772,9 +773,9 @@ struct pci_driver {
        int  (*suspend)(struct pci_dev *dev, pm_message_t state);       /* Device suspended */
        int  (*suspend_late)(struct pci_dev *dev, pm_message_t state);
        int  (*resume_early)(struct pci_dev *dev);
-       int  (*resume) (struct pci_dev *dev);   /* Device woken up */
-       void (*shutdown) (struct pci_dev *dev);
-       int  (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* On PF */
+       int  (*resume)(struct pci_dev *dev);    /* Device woken up */
+       void (*shutdown)(struct pci_dev *dev);
+       int  (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
        const struct pci_error_handlers *err_handler;
        const struct attribute_group **groups;
        struct device_driver    driver;
index d86d5a2477fc03a2100626b82ed142fb486b3a6c..5eaf39dbc388a95d99a34f258d17ed6fb1dcffc7 100644 (file)
 #define PCI_DEVICE_ID_CENATEK_IDE      0x0001
 
 #define PCI_VENDOR_ID_SYNOPSYS         0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31       0xabcf
 
 #define PCI_VENDOR_ID_USR              0x16ec
 
index ea8505204fdfc6dd17cab030f9ead1af419455ef..605cf46c17bd315919e1c4f3425eb9ebc5e89028 100644 (file)
@@ -35,6 +35,7 @@ extern const char raid6_empty_zero_page[PAGE_SIZE];
 #include <limits.h>
 #include <stddef.h>
 #include <sys/mman.h>
+#include <sys/time.h>
 #include <sys/types.h>
 
 /* Not standard, but glibc defines it */
@@ -52,7 +53,9 @@ extern const char raid6_empty_zero_page[PAGE_SIZE];
 
 #define __init
 #define __exit
-#define __attribute_const__ __attribute__((const))
+#ifndef __attribute_const__
+# define __attribute_const__ __attribute__((const))
+#endif
 #define noinline __attribute__((noinline))
 
 #define preempt_enable()
@@ -67,6 +70,9 @@ extern const char raid6_empty_zero_page[PAGE_SIZE];
 #define MODULE_DESCRIPTION(desc)
 #define subsys_initcall(x)
 #define module_exit(x)
+
+#define IS_ENABLED(x) (x)
+#define CONFIG_RAID6_PQ_BENCHMARK 1
 #endif /* __KERNEL__ */
 
 /* Routine choices */
index ab400af6f0ce369ce073b7c75d05fbd64e355cef..eee0412bdf4b82bb4ddd6063b636d9dabe145fdb 100644 (file)
@@ -29,6 +29,7 @@
 #define SWITCHTEC_EVENT_EN_IRQ   BIT(3)
 #define SWITCHTEC_EVENT_FATAL    BIT(4)
 
+#define SWITCHTEC_DMA_MRPC_EN  BIT(0)
 enum {
        SWITCHTEC_GAS_MRPC_OFFSET       = 0x0000,
        SWITCHTEC_GAS_TOP_CFG_OFFSET    = 0x1000,
@@ -46,6 +47,10 @@ struct mrpc_regs {
        u32 cmd;
        u32 status;
        u32 ret_value;
+       u32 dma_en;
+       u64 dma_addr;
+       u32 dma_vector;
+       u32 dma_ver;
 } __packed;
 
 enum mrpc_status {
@@ -342,6 +347,14 @@ struct pff_csr_regs {
 
 struct switchtec_ntb;
 
+struct dma_mrpc_output {
+       u32 status;
+       u32 cmd_id;
+       u32 rtn_code;
+       u32 output_size;
+       u8 data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
+};
+
 struct switchtec_dev {
        struct pci_dev *pdev;
        struct device dev;
@@ -381,6 +394,9 @@ struct switchtec_dev {
        u8 link_event_count[SWITCHTEC_MAX_PFF_CSR];
 
        struct switchtec_ntb *sndev;
+
+       struct dma_mrpc_output *dma_mrpc;
+       dma_addr_t dma_mrpc_dma_addr;
 };
 
 static inline struct switchtec_dev *to_stdev(struct device *dev)
index 6cd9b198b7c64eb94821f2e3f2c5201e6c6d25eb..b6aac7ee1f670c231aac75a5da7e1ca4e9a567a0 100644 (file)
@@ -393,11 +393,9 @@ struct fb_cursor {
        struct fb_image image;  /* Cursor image */
 };
 
-#ifdef CONFIG_FB_BACKLIGHT
 /* Settings for the generic backlight code */
 #define FB_BACKLIGHT_LEVELS    128
 #define FB_BACKLIGHT_MAX       0xFF
-#endif
 
 
 #endif /* _UAPI_LINUX_FB_H */
index 53a22e8e040803891afcb4d12fca60661bfe7a3e..121e82ce296b5a4d9e85757e94e3d9521897cb56 100644 (file)
@@ -223,7 +223,8 @@ struct fsxattr {
 #define FS_POLICY_FLAGS_PAD_16         0x02
 #define FS_POLICY_FLAGS_PAD_32         0x03
 #define FS_POLICY_FLAGS_PAD_MASK       0x03
-#define FS_POLICY_FLAGS_VALID          0x03
+#define FS_POLICY_FLAG_DIRECT_KEY      0x04    /* use master key directly */
+#define FS_POLICY_FLAGS_VALID          0x07
 
 /* Encryption algorithms */
 #define FS_ENCRYPTION_MODE_INVALID             0
@@ -235,6 +236,7 @@ struct fsxattr {
 #define FS_ENCRYPTION_MODE_AES_128_CTS         6
 #define FS_ENCRYPTION_MODE_SPECK128_256_XTS    7 /* Removed, do not use. */
 #define FS_ENCRYPTION_MODE_SPECK128_256_CTS    8 /* Removed, do not use. */
+#define FS_ENCRYPTION_MODE_ADIANTUM            9
 
 struct fscrypt_policy {
        __u8 version;
index ae366b87426accef1c49b4fdeee478717e0d60ea..7f14d4a66c28c1c13d1388c6dacfcff30711edab 100644 (file)
  * the situation described above.
  */
 #define REL_RESERVED           0x0a
+#define REL_WHEEL_HI_RES       0x0b
+#define REL_HWHEEL_HI_RES      0x0c
 #define REL_MAX                        0x0f
 #define REL_CNT                        (REL_MAX+1)
 
index 597d40893862696ed76457c7071c8d5fd074f612..66f0fb7e9a3ac359579273cd3993e16efe61b8d4 100644 (file)
@@ -223,7 +223,6 @@ int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
         */
        return mem->flags & DMA_MEMORY_EXCLUSIVE;
 }
-EXPORT_SYMBOL(dma_alloc_from_dev_coherent);
 
 void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle)
 {
@@ -268,7 +267,6 @@ int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr)
 
        return __dma_release_from_coherent(mem, order, vaddr);
 }
-EXPORT_SYMBOL(dma_release_from_dev_coherent);
 
 int dma_release_from_global_coherent(int order, void *vaddr)
 {
index 164706da2a73ff59e8c422abdecb892dbb67ae88..23cf5361bcf1b24f71e6bd1e849fbeef611a2a5b 100644 (file)
@@ -49,7 +49,6 @@
 
 enum {
        dma_debug_single,
-       dma_debug_page,
        dma_debug_sg,
        dma_debug_coherent,
        dma_debug_resource,
@@ -1300,8 +1299,7 @@ void debug_dma_map_single(struct device *dev, const void *addr,
 EXPORT_SYMBOL(debug_dma_map_single);
 
 void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
-                       size_t size, int direction, dma_addr_t dma_addr,
-                       bool map_single)
+                       size_t size, int direction, dma_addr_t dma_addr)
 {
        struct dma_debug_entry *entry;
 
@@ -1316,7 +1314,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
                return;
 
        entry->dev       = dev;
-       entry->type      = dma_debug_page;
+       entry->type      = dma_debug_single;
        entry->pfn       = page_to_pfn(page);
        entry->offset    = offset,
        entry->dev_addr  = dma_addr;
@@ -1324,9 +1322,6 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
        entry->direction = direction;
        entry->map_err_type = MAP_ERR_NOT_CHECKED;
 
-       if (map_single)
-               entry->type = dma_debug_single;
-
        check_for_stack(dev, page, offset);
 
        if (!PageHighMem(page)) {
@@ -1378,10 +1373,10 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 EXPORT_SYMBOL(debug_dma_mapping_error);
 
 void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
-                         size_t size, int direction, bool map_single)
+                         size_t size, int direction)
 {
        struct dma_debug_entry ref = {
-               .type           = dma_debug_page,
+               .type           = dma_debug_single,
                .dev            = dev,
                .dev_addr       = addr,
                .size           = size,
@@ -1390,10 +1385,6 @@ void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
 
        if (unlikely(dma_debug_disabled()))
                return;
-
-       if (map_single)
-               ref.type = dma_debug_single;
-
        check_unmap(&ref);
 }
 EXPORT_SYMBOL(debug_dma_unmap_page);
@@ -1521,7 +1512,6 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
 
        add_dma_entry(entry);
 }
-EXPORT_SYMBOL(debug_dma_alloc_coherent);
 
 void debug_dma_free_coherent(struct device *dev, size_t size,
                         void *virt, dma_addr_t addr)
@@ -1549,7 +1539,6 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
 
        check_unmap(&ref);
 }
-EXPORT_SYMBOL(debug_dma_free_coherent);
 
 void debug_dma_map_resource(struct device *dev, phys_addr_t addr, size_t size,
                            int direction, dma_addr_t dma_addr)
index d7c34d2d1ba5888d0a8c8f6f92f0175f08ac0eb4..a11006b6d8e87d5f64db77e777da08355a32ad8d 100644 (file)
@@ -45,45 +45,6 @@ static int dmam_match(struct device *dev, void *res, void *match_data)
        return 0;
 }
 
-/**
- * dmam_alloc_coherent - Managed dma_alloc_coherent()
- * @dev: Device to allocate coherent memory for
- * @size: Size of allocation
- * @dma_handle: Out argument for allocated DMA handle
- * @gfp: Allocation flags
- *
- * Managed dma_alloc_coherent().  Memory allocated using this function
- * will be automatically released on driver detach.
- *
- * RETURNS:
- * Pointer to allocated memory on success, NULL on failure.
- */
-void *dmam_alloc_coherent(struct device *dev, size_t size,
-                          dma_addr_t *dma_handle, gfp_t gfp)
-{
-       struct dma_devres *dr;
-       void *vaddr;
-
-       dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
-       if (!dr)
-               return NULL;
-
-       vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp);
-       if (!vaddr) {
-               devres_free(dr);
-               return NULL;
-       }
-
-       dr->vaddr = vaddr;
-       dr->dma_handle = *dma_handle;
-       dr->size = size;
-
-       devres_add(dev, dr);
-
-       return vaddr;
-}
-EXPORT_SYMBOL(dmam_alloc_coherent);
-
 /**
  * dmam_free_coherent - Managed dma_free_coherent()
  * @dev: Device to free coherent memory for
@@ -144,61 +105,6 @@ void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
 }
 EXPORT_SYMBOL(dmam_alloc_attrs);
 
-#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
-
-static void dmam_coherent_decl_release(struct device *dev, void *res)
-{
-       dma_release_declared_memory(dev);
-}
-
-/**
- * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()
- * @dev: Device to declare coherent memory for
- * @phys_addr: Physical address of coherent memory to be declared
- * @device_addr: Device address of coherent memory to be declared
- * @size: Size of coherent memory to be declared
- * @flags: Flags
- *
- * Managed dma_declare_coherent_memory().
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
-                                dma_addr_t device_addr, size_t size, int flags)
-{
-       void *res;
-       int rc;
-
-       res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL);
-       if (!res)
-               return -ENOMEM;
-
-       rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size,
-                                        flags);
-       if (!rc)
-               devres_add(dev, res);
-       else
-               devres_free(res);
-
-       return rc;
-}
-EXPORT_SYMBOL(dmam_declare_coherent_memory);
-
-/**
- * dmam_release_declared_memory - Managed dma_release_declared_memory().
- * @dev: Device to release declared coherent memory for
- *
- * Managed dmam_release_declared_memory().
- */
-void dmam_release_declared_memory(struct device *dev)
-{
-       WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
-}
-EXPORT_SYMBOL(dmam_release_declared_memory);
-
-#endif
-
 /*
  * Create scatter-list for the already allocated DMA buffer.
  */
index 18cc09fc27b92a4fff6670d7916c0de364b1a031..7a723194ecbed71bec2db5265c932c2f84a8b123 100644 (file)
@@ -204,8 +204,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                ret = dma_alloc_from_pool(size, &page, flags);
                if (!ret)
                        return NULL;
-               *dma_handle = phys_to_dma(dev, page_to_phys(page));
-               return ret;
+               goto done;
        }
 
        page = __dma_direct_alloc_pages(dev, size, dma_handle, flags, attrs);
@@ -215,8 +214,10 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
        /* remove any dirty cache lines on the kernel alias */
        arch_dma_prep_coherent(page, size);
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
-               return page; /* opaque cookie */
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+               ret = page; /* opaque cookie */
+               goto done;
+       }
 
        /* create a coherent mapping */
        ret = dma_common_contiguous_remap(page, size, VM_USERMAP,
@@ -227,9 +228,9 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                return ret;
        }
 
-       *dma_handle = phys_to_dma(dev, page_to_phys(page));
        memset(ret, 0, size);
-
+done:
+       *dma_handle = phys_to_dma(dev, page_to_phys(page));
        return ret;
 }
 
index 79bc2eef9c14c067cd8616c0d10f7c96b2e5f6ab..a9e56539bd11687881ec3e43c1e11cd85d8a4157 100644 (file)
@@ -10,6 +10,14 @@ menu "Library routines"
 config RAID6_PQ
        tristate
 
+config RAID6_PQ_BENCHMARK
+       bool "Automatically choose fastest RAID6 PQ functions"
+       depends on RAID6_PQ
+       default y
+       help
+         Benchmark all available RAID6 PQ functions on init and choose the
+         fastest one.
+
 config BITREVERSE
        tristate
 
index 5065b1e7e32759535942fed1e149079e61c1dcda..7e4f7a8ffa8e2adcf6def548c9ddfc4233728547 100644 (file)
@@ -34,64 +34,64 @@ struct raid6_calls raid6_call;
 EXPORT_SYMBOL_GPL(raid6_call);
 
 const struct raid6_calls * const raid6_algos[] = {
-#if defined(__ia64__)
-       &raid6_intx16,
-       &raid6_intx32,
-#endif
 #if defined(__i386__) && !defined(__arch_um__)
-       &raid6_mmxx1,
-       &raid6_mmxx2,
-       &raid6_sse1x1,
-       &raid6_sse1x2,
-       &raid6_sse2x1,
-       &raid6_sse2x2,
-#ifdef CONFIG_AS_AVX2
-       &raid6_avx2x1,
-       &raid6_avx2x2,
-#endif
 #ifdef CONFIG_AS_AVX512
-       &raid6_avx512x1,
        &raid6_avx512x2,
+       &raid6_avx512x1,
 #endif
-#endif
-#if defined(__x86_64__) && !defined(__arch_um__)
-       &raid6_sse2x1,
-       &raid6_sse2x2,
-       &raid6_sse2x4,
 #ifdef CONFIG_AS_AVX2
-       &raid6_avx2x1,
        &raid6_avx2x2,
-       &raid6_avx2x4,
+       &raid6_avx2x1,
+#endif
+       &raid6_sse2x2,
+       &raid6_sse2x1,
+       &raid6_sse1x2,
+       &raid6_sse1x1,
+       &raid6_mmxx2,
+       &raid6_mmxx1,
 #endif
+#if defined(__x86_64__) && !defined(__arch_um__)
 #ifdef CONFIG_AS_AVX512
-       &raid6_avx512x1,
-       &raid6_avx512x2,
        &raid6_avx512x4,
+       &raid6_avx512x2,
+       &raid6_avx512x1,
 #endif
+#ifdef CONFIG_AS_AVX2
+       &raid6_avx2x4,
+       &raid6_avx2x2,
+       &raid6_avx2x1,
+#endif
+       &raid6_sse2x4,
+       &raid6_sse2x2,
+       &raid6_sse2x1,
 #endif
 #ifdef CONFIG_ALTIVEC
-       &raid6_altivec1,
-       &raid6_altivec2,
-       &raid6_altivec4,
-       &raid6_altivec8,
-       &raid6_vpermxor1,
-       &raid6_vpermxor2,
-       &raid6_vpermxor4,
        &raid6_vpermxor8,
+       &raid6_vpermxor4,
+       &raid6_vpermxor2,
+       &raid6_vpermxor1,
+       &raid6_altivec8,
+       &raid6_altivec4,
+       &raid6_altivec2,
+       &raid6_altivec1,
 #endif
 #if defined(CONFIG_S390)
        &raid6_s390vx8,
 #endif
-       &raid6_intx1,
-       &raid6_intx2,
-       &raid6_intx4,
-       &raid6_intx8,
 #ifdef CONFIG_KERNEL_MODE_NEON
-       &raid6_neonx1,
-       &raid6_neonx2,
-       &raid6_neonx4,
        &raid6_neonx8,
+       &raid6_neonx4,
+       &raid6_neonx2,
+       &raid6_neonx1,
 #endif
+#if defined(__ia64__)
+       &raid6_intx32,
+       &raid6_intx16,
+#endif
+       &raid6_intx8,
+       &raid6_intx4,
+       &raid6_intx2,
+       &raid6_intx1,
        NULL
 };
 
@@ -163,6 +163,11 @@ static inline const struct raid6_calls *raid6_choose_gen(
                        if ((*algo)->valid && !(*algo)->valid())
                                continue;
 
+                       if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) {
+                               best = *algo;
+                               break;
+                       }
+
                        perf = 0;
 
                        preempt_disable();
index 79777645cac9c1243518f4f4bf403cdc567aa9ea..3ab8720aa2f843cad399f30300b0bbfa60f314e6 100644 (file)
@@ -34,6 +34,9 @@ endif
 
 ifeq ($(IS_X86),yes)
         OBJS   += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o avx512.o recov_avx512.o
+        CFLAGS += $(shell echo "pshufb %xmm0, %xmm0" |         \
+                    gcc -c -x assembler - >&/dev/null &&       \
+                    rm ./-.o && echo -DCONFIG_AS_SSSE3=1)
         CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" |   \
                     gcc -c -x assembler - >&/dev/null &&       \
                     rm ./-.o && echo -DCONFIG_AS_AVX2=1)
index 218099b5ed31d1e971d8d64b0951a31b8e310c01..f0f91461a9f45c350fd8fccc0ccaf6c9578e4b3a 100644 (file)
@@ -42,72 +42,14 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr,
        return 0;
 }
 
-/*
- * Later we can get more picky about what "in core" means precisely.
- * For now, simply check to see if the page is in the page cache,
- * and is up to date; i.e. that no page-in operation would be required
- * at this time if an application were to map and access this page.
- */
-static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
-{
-       unsigned char present = 0;
-       struct page *page;
-
-       /*
-        * When tmpfs swaps out a page from a file, any process mapping that
-        * file will not get a swp_entry_t in its pte, but rather it is like
-        * any other file mapping (ie. marked !present and faulted in with
-        * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
-        */
-#ifdef CONFIG_SWAP
-       if (shmem_mapping(mapping)) {
-               page = find_get_entry(mapping, pgoff);
-               /*
-                * shmem/tmpfs may return swap: account for swapcache
-                * page too.
-                */
-               if (xa_is_value(page)) {
-                       swp_entry_t swp = radix_to_swp_entry(page);
-                       page = find_get_page(swap_address_space(swp),
-                                            swp_offset(swp));
-               }
-       } else
-               page = find_get_page(mapping, pgoff);
-#else
-       page = find_get_page(mapping, pgoff);
-#endif
-       if (page) {
-               present = PageUptodate(page);
-               put_page(page);
-       }
-
-       return present;
-}
-
-static int __mincore_unmapped_range(unsigned long addr, unsigned long end,
-                               struct vm_area_struct *vma, unsigned char *vec)
-{
-       unsigned long nr = (end - addr) >> PAGE_SHIFT;
-       int i;
-
-       if (vma->vm_file) {
-               pgoff_t pgoff;
-
-               pgoff = linear_page_index(vma, addr);
-               for (i = 0; i < nr; i++, pgoff++)
-                       vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff);
-       } else {
-               for (i = 0; i < nr; i++)
-                       vec[i] = 0;
-       }
-       return nr;
-}
-
 static int mincore_unmapped_range(unsigned long addr, unsigned long end,
                                   struct mm_walk *walk)
 {
-       walk->private += __mincore_unmapped_range(addr, end,
-                                                 walk->vma, walk->private);
+       unsigned char *vec = walk->private;
+       unsigned long nr = (end - addr) >> PAGE_SHIFT;
+
+       memset(vec, 0, nr);
+       walk->private += nr;
        return 0;
 }
 
@@ -127,8 +69,9 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
                goto out;
        }
 
+       /* We'll consider a THP page under construction to be there */
        if (pmd_trans_unstable(pmd)) {
-               __mincore_unmapped_range(addr, end, vma, vec);
+               memset(vec, 1, nr);
                goto out;
        }
 
@@ -137,28 +80,17 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
                pte_t pte = *ptep;
 
                if (pte_none(pte))
-                       __mincore_unmapped_range(addr, addr + PAGE_SIZE,
-                                                vma, vec);
+                       *vec = 0;
                else if (pte_present(pte))
                        *vec = 1;
                else { /* pte is a swap entry */
                        swp_entry_t entry = pte_to_swp_entry(pte);
 
-                       if (non_swap_entry(entry)) {
-                               /*
-                                * migration or hwpoison entries are always
-                                * uptodate
-                                */
-                               *vec = 1;
-                       } else {
-#ifdef CONFIG_SWAP
-                               *vec = mincore_page(swap_address_space(entry),
-                                                   swp_offset(entry));
-#else
-                               WARN_ON(1);
-                               *vec = 1;
-#endif
-                       }
+                       /*
+                        * migration or hwpoison entries are always
+                        * uptodate
+                        */
+                       *vec = !!non_swap_entry(entry);
                }
                vec++;
        }
index 9bfd8ff6de82e654571bc74ec2b6f2c6c5559675..37a0ffcb4d63f11b6f3b10561e4a06da04c26ab9 100644 (file)
@@ -119,7 +119,7 @@ int main(int argc, char **argv)
        if (res < 0)
                perror("HIDIOCSFEATURE");
        else
-               printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
+               printf("ioctl HIDIOCSFEATURE returned: %d\n", res);
 
        /* Get Feature */
        buf[0] = 0x9; /* Report Number */
index 49b13553eaaecf136e14d29f2f9cc9518471e49b..e8f1bd6b29b120fa997fa3b122ee35eb6f70169d 100644 (file)
@@ -89,6 +89,11 @@ struct dummy *livepatch_fix1_dummy_alloc(void)
         * pointer to handle resource release.
         */
        leak = kzalloc(sizeof(int), GFP_KERNEL);
+       if (!leak) {
+               kfree(d);
+               return NULL;
+       }
+
        klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
                         shadow_leak_ctor, leak);
 
index 4c54b250332da8af667ea5aa54351bc4a08e90c2..4aa8a88d3cd6375489a3fc23b644f43b884e26af 100644 (file)
@@ -118,6 +118,10 @@ noinline struct dummy *dummy_alloc(void)
 
        /* Oops, forgot to save leak! */
        leak = kzalloc(sizeof(int), GFP_KERNEL);
+       if (!leak) {
+               kfree(d);
+               return NULL;
+       }
 
        pr_info("%s: dummy @ %p, expires @ %lx\n",
                __func__, d, d->jiffies_expire);
index d47b8f73e2e74f42bf02891f73a66d0e9d7d287a..5467c6bf9cebebd01e03acd3e38d3cbc8c47e977 100644 (file)
@@ -82,8 +82,8 @@ FEATURE_TESTS_EXTRA :=                  \
          cplus-demangle                 \
          hello                          \
          libbabeltrace                  \
-         liberty                        \
-         liberty-z                      \
+         libbfd-liberty                 \
+         libbfd-liberty-z               \
          libunwind-debug-frame          \
          libunwind-debug-frame-arm      \
          libunwind-debug-frame-aarch64  \
index 2dbcc0d00f52d05ecc1853889fb141321e70f420..7ceb4441b6277729215ea4ea26193e60d0095f2e 100644 (file)
@@ -17,8 +17,8 @@ FILES=                                          \
          test-libbfd.bin                        \
          test-disassembler-four-args.bin        \
          test-reallocarray.bin                 \
-         test-liberty.bin                       \
-         test-liberty-z.bin                     \
+         test-libbfd-liberty.bin                \
+         test-libbfd-liberty-z.bin              \
          test-cplus-demangle.bin                \
          test-libelf.bin                        \
          test-libelf-getphdrnum.bin             \
@@ -210,7 +210,7 @@ $(OUTPUT)test-libpython-version.bin:
        $(BUILD)
 
 $(OUTPUT)test-libbfd.bin:
-       $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
+       $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
 
 $(OUTPUT)test-disassembler-four-args.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
@@ -218,10 +218,10 @@ $(OUTPUT)test-disassembler-four-args.bin:
 $(OUTPUT)test-reallocarray.bin:
        $(BUILD)
 
-$(OUTPUT)test-liberty.bin:
+$(OUTPUT)test-libbfd-liberty.bin:
        $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
 
-$(OUTPUT)test-liberty-z.bin:
+$(OUTPUT)test-libbfd-liberty-z.bin:
        $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
 
 $(OUTPUT)test-cplus-demangle.bin:
index 240eda014b371b4e1c63f607e6853d387f475392..6ecdd10678260f278475787af8d7b1e61e970bae 100644 (file)
@@ -12,7 +12,7 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
+override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
diff --git a/tools/include/uapi/linux/usbdevice_fs.h b/tools/include/uapi/linux/usbdevice_fs.h
new file mode 100644 (file)
index 0000000..964e872
--- /dev/null
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*****************************************************************************/
+
+/*
+ *     usbdevice_fs.h  --  USB device file system.
+ *
+ *     Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ */
+
+/*****************************************************************************/
+
+#ifndef _UAPI_LINUX_USBDEVICE_FS_H
+#define _UAPI_LINUX_USBDEVICE_FS_H
+
+#include <linux/types.h>
+#include <linux/magic.h>
+
+/* --------------------------------------------------------------------- */
+
+/* usbdevfs ioctl codes */
+
+struct usbdevfs_ctrltransfer {
+       __u8 bRequestType;
+       __u8 bRequest;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+       __u32 timeout;  /* in milliseconds */
+       void __user *data;
+};
+
+struct usbdevfs_bulktransfer {
+       unsigned int ep;
+       unsigned int len;
+       unsigned int timeout; /* in milliseconds */
+       void __user *data;
+};
+
+struct usbdevfs_setinterface {
+       unsigned int interface;
+       unsigned int altsetting;
+};
+
+struct usbdevfs_disconnectsignal {
+       unsigned int signr;
+       void __user *context;
+};
+
+#define USBDEVFS_MAXDRIVERNAME 255
+
+struct usbdevfs_getdriver {
+       unsigned int interface;
+       char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_connectinfo {
+       unsigned int devnum;
+       unsigned char slow;
+};
+
+#define USBDEVFS_URB_SHORT_NOT_OK      0x01
+#define USBDEVFS_URB_ISO_ASAP          0x02
+#define USBDEVFS_URB_BULK_CONTINUATION 0x04
+#define USBDEVFS_URB_NO_FSBR           0x20    /* Not used */
+#define USBDEVFS_URB_ZERO_PACKET       0x40
+#define USBDEVFS_URB_NO_INTERRUPT      0x80
+
+#define USBDEVFS_URB_TYPE_ISO             0
+#define USBDEVFS_URB_TYPE_INTERRUPT       1
+#define USBDEVFS_URB_TYPE_CONTROL         2
+#define USBDEVFS_URB_TYPE_BULK            3
+
+struct usbdevfs_iso_packet_desc {
+       unsigned int length;
+       unsigned int actual_length;
+       unsigned int status;
+};
+
+struct usbdevfs_urb {
+       unsigned char type;
+       unsigned char endpoint;
+       int status;
+       unsigned int flags;
+       void __user *buffer;
+       int buffer_length;
+       int actual_length;
+       int start_frame;
+       union {
+               int number_of_packets;  /* Only used for isoc urbs */
+               unsigned int stream_id; /* Only used with bulk streams */
+       };
+       int error_count;
+       unsigned int signr;     /* signal to be sent on completion,
+                                 or 0 if none should be sent. */
+       void __user *usercontext;
+       struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+/* ioctls for talking directly to drivers */
+struct usbdevfs_ioctl {
+       int     ifno;           /* interface 0..N ; negative numbers reserved */
+       int     ioctl_code;     /* MUST encode size + direction of data so the
+                                * macros in <asm/ioctl.h> give correct values */
+       void __user *data;      /* param buffer (in, or out) */
+};
+
+/* You can do most things with hubs just through control messages,
+ * except find out what device connects to what port. */
+struct usbdevfs_hub_portinfo {
+       char nports;            /* number of downstream ports in this hub */
+       char port [127];        /* e.g. port 3 connects to device 27 */
+};
+
+/* System and bus capability flags */
+#define USBDEVFS_CAP_ZERO_PACKET               0x01
+#define USBDEVFS_CAP_BULK_CONTINUATION         0x02
+#define USBDEVFS_CAP_NO_PACKET_SIZE_LIM                0x04
+#define USBDEVFS_CAP_BULK_SCATTER_GATHER       0x08
+#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT     0x10
+#define USBDEVFS_CAP_MMAP                      0x20
+#define USBDEVFS_CAP_DROP_PRIVILEGES           0x40
+
+/* USBDEVFS_DISCONNECT_CLAIM flags & struct */
+
+/* disconnect-and-claim if the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER    0x01
+/* disconnect-and-claim except when the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER        0x02
+
+struct usbdevfs_disconnect_claim {
+       unsigned int interface;
+       unsigned int flags;
+       char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_streams {
+       unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
+       unsigned int num_eps;
+       unsigned char eps[0];
+};
+
+/*
+ * USB_SPEED_* values returned by USBDEVFS_GET_SPEED are defined in
+ * linux/usb/ch9.h
+ */
+
+#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
+#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
+#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
+#define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
+#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+#define USBDEVFS_DISCARDURB        _IO('U', 11)
+#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
+#define USBDEVFS_REAPURB32         _IOW('U', 12, __u32)
+#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, __u32)
+#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
+#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
+#define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
+#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
+#define USBDEVFS_IOCTL32           _IOWR('U', 18, struct usbdevfs_ioctl32)
+#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
+#define USBDEVFS_RESET             _IO('U', 20)
+#define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
+#define USBDEVFS_DISCONNECT        _IO('U', 22)
+#define USBDEVFS_CONNECT           _IO('U', 23)
+#define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
+#define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
+#define USBDEVFS_GET_CAPABILITIES  _IOR('U', 26, __u32)
+#define USBDEVFS_DISCONNECT_CLAIM  _IOR('U', 27, struct usbdevfs_disconnect_claim)
+#define USBDEVFS_ALLOC_STREAMS     _IOR('U', 28, struct usbdevfs_streams)
+#define USBDEVFS_FREE_STREAMS      _IOR('U', 29, struct usbdevfs_streams)
+#define USBDEVFS_DROP_PRIVILEGES   _IOW('U', 30, __u32)
+#define USBDEVFS_GET_SPEED         _IO('U', 31)
+
+#endif /* _UAPI_LINUX_USBDEVICE_FS_H */
index 07c1857c3d7a9eeb5d5e94847f7ac6f1163393ae..b441c88cafa1f3a18cbb42d82ca90429e1f4d1a9 100644 (file)
@@ -702,18 +702,20 @@ endif
 
 ifeq ($(feature-libbfd), 1)
   EXTLIBS += -lbfd
+else
+  # we are on a system that requires -liberty and (maybe) -lz
+  # to link against -lbfd; test each case individually here
 
   # call all detections now so we get correct
   # status in VF output
-  $(call feature_check,liberty)
-  $(call feature_check,liberty-z)
-  $(call feature_check,cplus-demangle)
+  $(call feature_check,libbfd-liberty)
+  $(call feature_check,libbfd-liberty-z)
 
-  ifeq ($(feature-liberty), 1)
-    EXTLIBS += -liberty
+  ifeq ($(feature-libbfd-liberty), 1)
+    EXTLIBS += -lbfd -liberty
   else
-    ifeq ($(feature-liberty-z), 1)
-      EXTLIBS += -liberty -lz
+    ifeq ($(feature-libbfd-liberty-z), 1)
+      EXTLIBS += -lbfd -liberty -lz
     endif
   endif
 endif
@@ -723,24 +725,24 @@ ifdef NO_DEMANGLE
 else
   ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
     EXTLIBS += -liberty
-    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
   else
-    ifneq ($(feature-libbfd), 1)
-      ifneq ($(feature-liberty), 1)
-        ifneq ($(feature-liberty-z), 1)
-          # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
-          # or any of 'bfd iberty z' trinity
-          ifeq ($(feature-cplus-demangle), 1)
-            EXTLIBS += -liberty
-            CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
-          else
-            msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
-            CFLAGS += -DNO_DEMANGLE
-          endif
-        endif
+    ifeq ($(filter -liberty,$(EXTLIBS)),)
+      $(call feature_check,cplus-demangle)
+
+      # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
+      # or any of 'bfd iberty z' trinity
+      ifeq ($(feature-cplus-demangle), 1)
+        EXTLIBS += -liberty
+      else
+        msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
+        CFLAGS += -DNO_DEMANGLE
       endif
     endif
   endif
+
+  ifneq ($(filter -liberty,$(EXTLIBS)),)
+    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
+  endif
 endif
 
 ifneq ($(filter -lbfd,$(EXTLIBS)),)
index bd23e3f3089532ba70aeb64b23396817cea88d85..ff29c3372ec3bacc70e8f2fe473ac1bd68699542 100644 (file)
@@ -497,6 +497,12 @@ prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
 $(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl)
        $(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@
 
+usbdevfs_ioctl_array := $(beauty_ioctl_outdir)/usbdevfs_ioctl_array.c
+usbdevfs_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/usbdevfs_ioctl.sh
+
+$(usbdevfs_ioctl_array): $(linux_uapi_dir)/usbdevice_fs.h $(usbdevfs_ioctl_tbl)
+       $(Q)$(SHELL) '$(usbdevfs_ioctl_tbl)' $(linux_uapi_dir) > $@
+
 x86_arch_prctl_code_array := $(beauty_outdir)/x86_arch_prctl_code_array.c
 x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh
 
@@ -624,6 +630,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
        $(mount_flags_array) \
        $(perf_ioctl_array) \
        $(prctl_option_array) \
+       $(usbdevfs_ioctl_array) \
        $(x86_arch_prctl_code_array) \
        $(rename_flags_array) \
        $(arch_errno_name_array)
@@ -923,6 +930,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
                $(OUTPUT)$(vhost_virtio_ioctl_array) \
                $(OUTPUT)$(perf_ioctl_array) \
                $(OUTPUT)$(prctl_option_array) \
+               $(OUTPUT)$(usbdevfs_ioctl_array) \
                $(OUTPUT)$(x86_arch_prctl_code_array) \
                $(OUTPUT)$(rename_flags_array) \
                $(OUTPUT)$(arch_errno_name_array)
index f3aa9d02a5ab5d3cc5a78fd15d9d483fdbd64907..d340d2e42776175811388eefb4fa0376caeacbab 100644 (file)
@@ -68,7 +68,7 @@ struct c2c_hist_entry {
        struct hist_entry       he;
 };
 
-static char const *coalesce_default = "pid,iaddr";
+static char const *coalesce_default = "iaddr";
 
 struct perf_c2c {
        struct perf_tool        tool;
@@ -1878,7 +1878,7 @@ static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
        return hpp_list__parse(&c2c_hists->list, output, sort);
 }
 
-#define DISPLAY_LINE_LIMIT  0.0005
+#define DISPLAY_LINE_LIMIT  0.001
 
 static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
 {
index 3728b50e52e20d0eb43780ec354d0c2242d6c414..d079f36d342d4ca6024b46a52de349b1ea95ac4a 100644 (file)
@@ -1073,9 +1073,18 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 
        /*
         * Print final block upto sample
+        *
+        * Due to pipeline delays the LBRs might be missing a branch
+        * or two, which can result in very large or negative blocks
+        * between final branch and sample. When this happens just
+        * continue walking after the last TO until we hit a branch.
         */
        start = br->entries[0].to;
        end = sample->ip;
+       if (end < start) {
+               /* Missing jump. Scan 128 bytes for the next branch */
+               end = start + 128;
+       }
        len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
        printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
        if (len <= 0) {
@@ -1084,7 +1093,6 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                              machine, thread, &x.is64bit, &x.cpumode, false);
                if (len <= 0)
                        goto out;
-
                printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
                        dump_insn(&x, sample->ip, buffer, len, NULL));
                if (PRINT_FIELD(SRCCODE))
@@ -1096,6 +1104,13 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                                   dump_insn(&x, start + off, buffer + off, len - off, &ilen));
                if (ilen == 0)
                        break;
+               if (arch_is_branch(buffer + off, len - off, x.is64bit) && start + off != sample->ip) {
+                       /*
+                        * Hit a missing branch. Just stop.
+                        */
+                       printed += fprintf(fp, "\t... not reaching sample ...\n");
+                       break;
+               }
                if (PRINT_FIELD(SRCCODE))
                        print_srccode(thread, x.cpumode, start + off);
        }
@@ -1167,7 +1182,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
                                           struct addr_location *al, FILE *fp)
 {
        struct perf_event_attr *attr = &evsel->attr;
-       size_t depth = thread_stack__depth(thread);
+       size_t depth = thread_stack__depth(thread, sample->cpu);
        const char *name = NULL;
        static int spacing;
        int len = 0;
@@ -1701,7 +1716,7 @@ static bool show_event(struct perf_sample *sample,
                       struct thread *thread,
                       struct addr_location *al)
 {
-       int depth = thread_stack__depth(thread);
+       int depth = thread_stack__depth(thread, sample->cpu);
 
        if (!symbol_conf.graph_function)
                return true;
index ebde59e61133629104b55fd133c415794172662e..adbf28183560ad30c34377250e5433a6abf27d26 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/stringify.h>
 #include <linux/time64.h>
 #include <fcntl.h>
+#include <sys/sysmacros.h>
 
 #include "sane_ctype.h"
 
@@ -112,8 +113,9 @@ struct trace {
        } stats;
        unsigned int            max_stack;
        unsigned int            min_stack;
-       bool                    sort_events;
+       int                     raw_augmented_syscalls_args_size;
        bool                    raw_augmented_syscalls;
+       bool                    sort_events;
        bool                    not_ev_qualifier;
        bool                    live;
        bool                    full_time;
@@ -283,12 +285,17 @@ out_delete:
        return -ENOENT;
 }
 
-static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel)
+static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel, struct perf_evsel *tp)
 {
        struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
 
-       if (evsel->priv != NULL) {       /* field, sizeof_field, offsetof_field */
-               if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap))
+       if (evsel->priv != NULL) {
+               struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
+               if (syscall_id == NULL)
+                       syscall_id = perf_evsel__field(tp, "__syscall_nr");
+               if (syscall_id == NULL)
+                       goto out_delete;
+               if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
                        goto out_delete;
 
                return 0;
@@ -974,9 +981,9 @@ struct thread_trace {
                char          *name;
        } filename;
        struct {
-               int       max;
-               char      **table;
-       } paths;
+               int           max;
+               struct file   *table;
+       } files;
 
        struct intlist *syscall_stats;
 };
@@ -986,7 +993,7 @@ static struct thread_trace *thread_trace__new(void)
        struct thread_trace *ttrace =  zalloc(sizeof(struct thread_trace));
 
        if (ttrace)
-               ttrace->paths.max = -1;
+               ttrace->files.max = -1;
 
        ttrace->syscall_stats = intlist__new(NULL);
 
@@ -1030,30 +1037,48 @@ void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
 
 static const size_t trace__entry_str_size = 2048;
 
-static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
+static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
 {
-       struct thread_trace *ttrace = thread__priv(thread);
-
-       if (fd > ttrace->paths.max) {
-               char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
+       if (fd > ttrace->files.max) {
+               struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
 
-               if (npath == NULL)
-                       return -1;
+               if (nfiles == NULL)
+                       return NULL;
 
-               if (ttrace->paths.max != -1) {
-                       memset(npath + ttrace->paths.max + 1, 0,
-                              (fd - ttrace->paths.max) * sizeof(char *));
+               if (ttrace->files.max != -1) {
+                       memset(nfiles + ttrace->files.max + 1, 0,
+                              (fd - ttrace->files.max) * sizeof(struct file));
                } else {
-                       memset(npath, 0, (fd + 1) * sizeof(char *));
+                       memset(nfiles, 0, (fd + 1) * sizeof(struct file));
                }
 
-               ttrace->paths.table = npath;
-               ttrace->paths.max   = fd;
+               ttrace->files.table = nfiles;
+               ttrace->files.max   = fd;
        }
 
-       ttrace->paths.table[fd] = strdup(pathname);
+       return ttrace->files.table + fd;
+}
 
-       return ttrace->paths.table[fd] != NULL ? 0 : -1;
+struct file *thread__files_entry(struct thread *thread, int fd)
+{
+       return thread_trace__files_entry(thread__priv(thread), fd);
+}
+
+static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
+{
+       struct thread_trace *ttrace = thread__priv(thread);
+       struct file *file = thread_trace__files_entry(ttrace, fd);
+
+       if (file != NULL) {
+               struct stat st;
+               if (stat(pathname, &st) == 0)
+                       file->dev_maj = major(st.st_rdev);
+               file->pathname = strdup(pathname);
+               if (file->pathname)
+                       return 0;
+       }
+
+       return -1;
 }
 
 static int thread__read_fd_path(struct thread *thread, int fd)
@@ -1093,7 +1118,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
        if (fd < 0)
                return NULL;
 
-       if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
+       if ((fd > ttrace->files.max || ttrace->files.table[fd].pathname == NULL)) {
                if (!trace->live)
                        return NULL;
                ++trace->stats.proc_getname;
@@ -1101,7 +1126,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
                        return NULL;
        }
 
-       return ttrace->paths.table[fd];
+       return ttrace->files.table[fd].pathname;
 }
 
 size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
@@ -1140,8 +1165,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
        size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
        struct thread_trace *ttrace = thread__priv(arg->thread);
 
-       if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
-               zfree(&ttrace->paths.table[fd]);
+       if (ttrace && fd >= 0 && fd <= ttrace->files.max)
+               zfree(&ttrace->files.table[fd].pathname);
 
        return printed;
 }
@@ -1768,16 +1793,16 @@ 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, bool raw_augmented)
+static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, int raw_augmented_args_size)
 {
        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.
+        * and there we get all 6 syscall args plus the tracepoint common fields
+        * that gets calculated at the start 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
@@ -1785,7 +1810,7 @@ static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sam
         * 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;
+       int args_size = raw_augmented_args_size ?: sc->args_size;
 
        *augmented_args_size = sample->raw_size - args_size;
        if (*augmented_args_size > 0)
@@ -1839,7 +1864,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, trace->raw_augmented_syscalls);
+               augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
        ttrace->entry_time = sample->time;
        msg = ttrace->entry_str;
        printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
@@ -1897,7 +1922,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, trace->raw_augmented_syscalls);
+       augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
        syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
        fprintf(trace->output, "%s", msg);
        err = 0;
@@ -2686,7 +2711,9 @@ static int trace__set_ev_qualifier_filter(struct trace *trace)
 {
        if (trace->syscalls.map)
                return trace__set_ev_qualifier_bpf_filter(trace);
-       return trace__set_ev_qualifier_tp_filter(trace);
+       if (trace->syscalls.events.sys_enter)
+               return trace__set_ev_qualifier_tp_filter(trace);
+       return 0;
 }
 
 static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused,
@@ -3812,13 +3839,6 @@ int cmd_trace(int argc, const char **argv)
         * syscall.
         */
        if (trace.syscalls.events.augmented) {
-               evsel = trace.syscalls.events.augmented;
-
-               if (perf_evsel__init_augmented_syscall_tp(evsel) ||
-                   perf_evsel__init_augmented_syscall_tp_args(evsel))
-                       goto out;
-               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;
 
@@ -3827,9 +3847,41 @@ int cmd_trace(int argc, const char **argv)
                                goto init_augmented_syscall_tp;
                        }
 
+                       if (strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_enter") == 0) {
+                               struct perf_evsel *augmented = trace.syscalls.events.augmented;
+                               if (perf_evsel__init_augmented_syscall_tp(augmented, evsel) ||
+                                   perf_evsel__init_augmented_syscall_tp_args(augmented))
+                                       goto out;
+                               augmented->handler = trace__sys_enter;
+                       }
+
                        if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
+                               struct syscall_tp *sc;
 init_augmented_syscall_tp:
-                               perf_evsel__init_augmented_syscall_tp(evsel);
+                               if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
+                                       goto out;
+                               sc = evsel->priv;
+                               /*
+                                * 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 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.
+                                */
+                               if (trace.raw_augmented_syscalls)
+                                       trace.raw_augmented_syscalls_args_size = (6 + 1) * sizeof(long) + sc->id.offset;
                                perf_evsel__init_augmented_syscall_tp_ret(evsel);
                                evsel->handler = trace__sys_exit;
                        }
index 8e811ea0cf851d4f8cce17999939a2747629c9b6..6cb98f8570a22fdfcc30b952dc9cfcecf7c5a6ed 100755 (executable)
@@ -14,6 +14,7 @@ include/uapi/linux/perf_event.h
 include/uapi/linux/prctl.h
 include/uapi/linux/sched.h
 include/uapi/linux/stat.h
+include/uapi/linux/usbdevice_fs.h
 include/uapi/linux/vhost.h
 include/uapi/sound/asound.h
 include/linux/bits.h
index 83c5b202e00e8b93a1fc1b098fa74bcddc988008..139d485a6f1611d664039ae3c50bdc0930421886 100644 (file)
@@ -32,6 +32,13 @@ size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, boo
 struct trace;
 struct thread;
 
+struct file {
+       char *pathname;
+       int  dev_maj;
+};
+
+struct file *thread__files_entry(struct thread *thread, int fd);
+
 struct strarrays {
        int             nr_entries;
        struct strarray **entries;
index 9efeb6a936c24a379eead7f25be5558dfbaf4c76..620350d4120965f7dc4e3a396c4d7a6cc00a3d88 100644 (file)
@@ -112,6 +112,17 @@ static size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size)
        return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
 }
 
+static size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size)
+{
+#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c"
+       static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, "");
+
+       if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL)
+               return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]);
+
+       return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir);
+}
+
 static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
 {
        const char *prefix = "_IOC_";
@@ -157,9 +168,20 @@ static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, boo
        return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
 }
 
+#ifndef USB_DEVICE_MAJOR
+#define USB_DEVICE_MAJOR 189
+#endif // USB_DEVICE_MAJOR
+
 size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
 {
        unsigned long cmd = arg->val;
+       unsigned int fd = syscall_arg__val(arg, 0);
+       struct file *file = thread__files_entry(arg->thread, fd);
+
+       if (file != NULL) {
+               if (file->dev_maj == USB_DEVICE_MAJOR)
+                       return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size);
+       }
 
        return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
 }
index eb31089790e3d0ce9630bbe75df04c18a5b671f7..859a8a9db2c62d545c2bf6d28361e14c88300d81 100644 (file)
@@ -18,8 +18,8 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
        }
 
        P_MMAP_PROT(READ);
-       P_MMAP_PROT(EXEC);
        P_MMAP_PROT(WRITE);
+       P_MMAP_PROT(EXEC);
        P_MMAP_PROT(SEM);
        P_MMAP_PROT(GROWSDOWN);
        P_MMAP_PROT(GROWSUP);
index 4600c28a3cfe75a8aef9f37862cef0a1d468625b..637722e2796bc30affb39717d31697f0e0b00101 100644 (file)
@@ -9,7 +9,7 @@
 static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
 {
        bool show_prefix = arg->show_string_prefix;
-       const char *prefix = "SECOMP_SET_MODE_";
+       const char *prefix = "SECCOMP_SET_MODE_";
        int op = arg->val;
        size_t printed = 0;
 
@@ -34,7 +34,7 @@ static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
                                                   struct syscall_arg *arg)
 {
        bool show_prefix = arg->show_string_prefix;
-       const char *prefix = "SECOMP_FILTER_FLAG_";
+       const char *prefix = "SECCOMP_FILTER_FLAG_";
        int printed = 0, flags = arg->val;
 
 #define        P_FLAG(n) \
diff --git a/tools/perf/trace/beauty/usbdevfs_ioctl.sh b/tools/perf/trace/beauty/usbdevfs_ioctl.sh
new file mode 100755 (executable)
index 0000000..930b80f
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1
+
+[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
+
+printf "static const char *usbdevfs_ioctl_cmds[] = {\n"
+regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*"
+egrep $regex ${header_dir}/usbdevice_fs.h | egrep -v 'USBDEVFS_\w+32[[:space:]]' | \
+       sed -r "s/$regex/\2 \1/g"       | \
+       sort | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n\n"
+printf "#if 0\n"
+printf "static const char *usbdevfs_ioctl_32_cmds[] = {\n"
+regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*"
+egrep $regex ${header_dir}/usbdevice_fs.h | egrep 'USBDEVFS_\w+32[[:space:]]' | \
+       sed -r "s/$regex/\2 \1/g"       | \
+       sort | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
+printf "#endif\n"
index 10988d3de7cec8940f3e4904cdb537a6f32cc690..2bd8585db93c30df83d2d0740a596a56a2a1f8f7 100644 (file)
@@ -13,3 +13,11 @@ const char *dump_insn(struct perf_insn *x __maybe_unused,
                *lenp = 0;
        return "?";
 }
+
+__weak
+int arch_is_branch(const unsigned char *buf __maybe_unused,
+                  size_t len __maybe_unused,
+                  int x86_64 __maybe_unused)
+{
+       return 0;
+}
index 0e06280a88602bb28d4596fbce45314e06aa4236..650125061530934c3f175d90ca8c82e2c59f99ca 100644 (file)
@@ -20,4 +20,6 @@ struct perf_insn {
 
 const char *dump_insn(struct perf_insn *x, u64 ip,
                      u8 *inbuf, int inlen, int *lenp);
+int arch_is_branch(const unsigned char *buf, size_t len, int x86_64);
+
 #endif
index 7b27d77306c229d2478d8ceea9e668a4cee5a24d..ee6ca65f81f4769d59bb7d2550af42ad30747fc7 100644 (file)
@@ -451,7 +451,7 @@ static int intel_bts_process_buffer(struct intel_bts_queue *btsq,
                        continue;
                intel_bts_get_branch_type(btsq, branch);
                if (btsq->bts->synth_opts.thread_stack)
-                       thread_stack__event(thread, btsq->sample_flags,
+                       thread_stack__event(thread, btsq->cpu, btsq->sample_flags,
                                            le64_to_cpu(branch->from),
                                            le64_to_cpu(branch->to),
                                            btsq->intel_pt_insn.length,
@@ -523,7 +523,7 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
            !btsq->bts->synth_opts.thread_stack && thread &&
            (!old_buffer || btsq->bts->sampling_mode ||
             (btsq->bts->snapshot_mode && !buffer->consecutive)))
-               thread_stack__set_trace_nr(thread, buffer->buffer_nr + 1);
+               thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1);
 
        err = intel_bts_process_buffer(btsq, buffer, thread);
 
index 54818828023bf4ad0960165d26afce60fe7166d1..1c0e289f01e6fe077079de8de4ae7f6fe3c43323 100644 (file)
@@ -180,6 +180,14 @@ int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
        return 0;
 }
 
+int arch_is_branch(const unsigned char *buf, size_t len, int x86_64)
+{
+       struct intel_pt_insn in;
+       if (intel_pt_get_insn(buf, len, x86_64, &in) < 0)
+               return -1;
+       return in.branch != INTEL_PT_BR_NO_BRANCH;
+}
+
 const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
                      u8 *inbuf, int inlen, int *lenp)
 {
index 149ff361ca789e460cd896beaa439ff7b225c2a2..2e72373ec6df653a88c7bb3413d37a3c2053ae02 100644 (file)
@@ -1174,7 +1174,7 @@ static void intel_pt_prep_sample(struct intel_pt *pt,
        intel_pt_prep_b_sample(pt, ptq, event, sample);
 
        if (pt->synth_opts.callchain) {
-               thread_stack__sample(ptq->thread, ptq->chain,
+               thread_stack__sample(ptq->thread, ptq->cpu, ptq->chain,
                                     pt->synth_opts.callchain_sz + 1,
                                     sample->ip, pt->kernel_start);
                sample->callchain = ptq->chain;
@@ -1526,11 +1526,11 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
                return 0;
 
        if (pt->synth_opts.callchain || pt->synth_opts.thread_stack)
-               thread_stack__event(ptq->thread, ptq->flags, state->from_ip,
+               thread_stack__event(ptq->thread, ptq->cpu, ptq->flags, state->from_ip,
                                    state->to_ip, ptq->insn_len,
                                    state->trace_nr);
        else
-               thread_stack__set_trace_nr(ptq->thread, state->trace_nr);
+               thread_stack__set_trace_nr(ptq->thread, ptq->cpu, state->trace_nr);
 
        if (pt->sample_branches) {
                err = intel_pt_synth_branch_sample(ptq);
index 47628e85c5ebea3e160f4fe380a64590087887f1..dda0ac978b1eb2371d9feebc64154d5cf9bb949e 100644 (file)
@@ -939,7 +939,8 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
 
                file = PyFile_FromFile(fp, "perf", "r", NULL);
 #else
-               file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1, NULL, NULL, NULL, 1);
+               file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1,
+                                    NULL, NULL, NULL, 0);
 #endif
                if (file == NULL)
                        goto free_list;
index 78a067777144af9e67425c6d36167d3326f40eed..5456c84c7dd13f2869ebde581782ceeaabad932a 100644 (file)
@@ -1527,6 +1527,13 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
        return machine__findnew_thread(&session->machines.host, -1, pid);
 }
 
+/*
+ * Threads are identified by pid and tid, and the idle task has pid == tid == 0.
+ * So here a single thread is created for that, but actually there is a separate
+ * idle task per cpu, so there should be one 'struct thread' per cpu, but there
+ * is only 1. That causes problems for some tools, requiring workarounds. For
+ * example get_idle_thread() in builtin-sched.c, or thread_stack__per_cpu().
+ */
 int perf_session__register_idle_thread(struct perf_session *session)
 {
        struct thread *thread;
index 61a4286a74dc9f86c333036013d5abe914b81b3f..d52f27f373ce5dd6daf2b99bbb6977aeabb574be 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/rbtree.h>
 #include <linux/list.h>
+#include <linux/log2.h>
 #include <errno.h>
 #include "thread.h"
 #include "event.h"
@@ -60,6 +61,7 @@ struct thread_stack_entry {
  * @last_time: last timestamp
  * @crp: call/return processor
  * @comm: current comm
+ * @arr_sz: size of array if this is the first element of an array
  */
 struct thread_stack {
        struct thread_stack_entry *stack;
@@ -71,8 +73,19 @@ struct thread_stack {
        u64 last_time;
        struct call_return_processor *crp;
        struct comm *comm;
+       unsigned int arr_sz;
 };
 
+/*
+ * Assume pid == tid == 0 identifies the idle task as defined by
+ * perf_session__register_idle_thread(). The idle task is really 1 task per cpu,
+ * and therefore requires a stack for each cpu.
+ */
+static inline bool thread_stack__per_cpu(struct thread *thread)
+{
+       return !(thread->tid || thread->pid_);
+}
+
 static int thread_stack__grow(struct thread_stack *ts)
 {
        struct thread_stack_entry *new_stack;
@@ -91,19 +104,14 @@ static int thread_stack__grow(struct thread_stack *ts)
        return 0;
 }
 
-static struct thread_stack *thread_stack__new(struct thread *thread,
-                                             struct call_return_processor *crp)
+static int thread_stack__init(struct thread_stack *ts, struct thread *thread,
+                             struct call_return_processor *crp)
 {
-       struct thread_stack *ts;
-
-       ts = zalloc(sizeof(struct thread_stack));
-       if (!ts)
-               return NULL;
+       int err;
 
-       if (thread_stack__grow(ts)) {
-               free(ts);
-               return NULL;
-       }
+       err = thread_stack__grow(ts);
+       if (err)
+               return err;
 
        if (thread->mg && thread->mg->machine)
                ts->kernel_start = machine__kernel_start(thread->mg->machine);
@@ -111,9 +119,72 @@ static struct thread_stack *thread_stack__new(struct thread *thread,
                ts->kernel_start = 1ULL << 63;
        ts->crp = crp;
 
+       return 0;
+}
+
+static struct thread_stack *thread_stack__new(struct thread *thread, int cpu,
+                                             struct call_return_processor *crp)
+{
+       struct thread_stack *ts = thread->ts, *new_ts;
+       unsigned int old_sz = ts ? ts->arr_sz : 0;
+       unsigned int new_sz = 1;
+
+       if (thread_stack__per_cpu(thread) && cpu > 0)
+               new_sz = roundup_pow_of_two(cpu + 1);
+
+       if (!ts || new_sz > old_sz) {
+               new_ts = calloc(new_sz, sizeof(*ts));
+               if (!new_ts)
+                       return NULL;
+               if (ts)
+                       memcpy(new_ts, ts, old_sz * sizeof(*ts));
+               new_ts->arr_sz = new_sz;
+               zfree(&thread->ts);
+               thread->ts = new_ts;
+               ts = new_ts;
+       }
+
+       if (thread_stack__per_cpu(thread) && cpu > 0 &&
+           (unsigned int)cpu < ts->arr_sz)
+               ts += cpu;
+
+       if (!ts->stack &&
+           thread_stack__init(ts, thread, crp))
+               return NULL;
+
        return ts;
 }
 
+static struct thread_stack *thread__cpu_stack(struct thread *thread, int cpu)
+{
+       struct thread_stack *ts = thread->ts;
+
+       if (cpu < 0)
+               cpu = 0;
+
+       if (!ts || (unsigned int)cpu >= ts->arr_sz)
+               return NULL;
+
+       ts += cpu;
+
+       if (!ts->stack)
+               return NULL;
+
+       return ts;
+}
+
+static inline struct thread_stack *thread__stack(struct thread *thread,
+                                                   int cpu)
+{
+       if (!thread)
+               return NULL;
+
+       if (thread_stack__per_cpu(thread))
+               return thread__cpu_stack(thread, cpu);
+
+       return thread->ts;
+}
+
 static int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
                              bool trace_end)
 {
@@ -226,25 +297,37 @@ static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
 
 int thread_stack__flush(struct thread *thread)
 {
-       if (thread->ts)
-               return __thread_stack__flush(thread, thread->ts);
+       struct thread_stack *ts = thread->ts;
+       unsigned int pos;
+       int err = 0;
 
-       return 0;
+       if (ts) {
+               for (pos = 0; pos < ts->arr_sz; pos++) {
+                       int ret = __thread_stack__flush(thread, ts + pos);
+
+                       if (ret)
+                               err = ret;
+               }
+       }
+
+       return err;
 }
 
-int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+int thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
                        u64 to_ip, u16 insn_len, u64 trace_nr)
 {
+       struct thread_stack *ts = thread__stack(thread, cpu);
+
        if (!thread)
                return -EINVAL;
 
-       if (!thread->ts) {
-               thread->ts = thread_stack__new(thread, NULL);
-               if (!thread->ts) {
+       if (!ts) {
+               ts = thread_stack__new(thread, cpu, NULL);
+               if (!ts) {
                        pr_warning("Out of memory: no thread stack\n");
                        return -ENOMEM;
                }
-               thread->ts->trace_nr = trace_nr;
+               ts->trace_nr = trace_nr;
        }
 
        /*
@@ -252,14 +335,14 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
         * the stack might be completely invalid.  Better to report nothing than
         * to report something misleading, so flush the stack.
         */
-       if (trace_nr != thread->ts->trace_nr) {
-               if (thread->ts->trace_nr)
-                       __thread_stack__flush(thread, thread->ts);
-               thread->ts->trace_nr = trace_nr;
+       if (trace_nr != ts->trace_nr) {
+               if (ts->trace_nr)
+                       __thread_stack__flush(thread, ts);
+               ts->trace_nr = trace_nr;
        }
 
        /* Stop here if thread_stack__process() is in use */
-       if (thread->ts->crp)
+       if (ts->crp)
                return 0;
 
        if (flags & PERF_IP_FLAG_CALL) {
@@ -270,7 +353,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
                ret_addr = from_ip + insn_len;
                if (ret_addr == to_ip)
                        return 0; /* Zero-length calls are excluded */
-               return thread_stack__push(thread->ts, ret_addr,
+               return thread_stack__push(ts, ret_addr,
                                          flags & PERF_IP_FLAG_TRACE_END);
        } else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
                /*
@@ -280,32 +363,52 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
                 * address, so try to pop that. Also, do not expect a call made
                 * when the trace ended, to return, so pop that.
                 */
-               thread_stack__pop(thread->ts, to_ip);
-               thread_stack__pop_trace_end(thread->ts);
+               thread_stack__pop(ts, to_ip);
+               thread_stack__pop_trace_end(ts);
        } else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
-               thread_stack__pop(thread->ts, to_ip);
+               thread_stack__pop(ts, to_ip);
        }
 
        return 0;
 }
 
-void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
+void thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr)
 {
-       if (!thread || !thread->ts)
+       struct thread_stack *ts = thread__stack(thread, cpu);
+
+       if (!ts)
                return;
 
-       if (trace_nr != thread->ts->trace_nr) {
-               if (thread->ts->trace_nr)
-                       __thread_stack__flush(thread, thread->ts);
-               thread->ts->trace_nr = trace_nr;
+       if (trace_nr != ts->trace_nr) {
+               if (ts->trace_nr)
+                       __thread_stack__flush(thread, ts);
+               ts->trace_nr = trace_nr;
        }
 }
 
+static void __thread_stack__free(struct thread *thread, struct thread_stack *ts)
+{
+       __thread_stack__flush(thread, ts);
+       zfree(&ts->stack);
+}
+
+static void thread_stack__reset(struct thread *thread, struct thread_stack *ts)
+{
+       unsigned int arr_sz = ts->arr_sz;
+
+       __thread_stack__free(thread, ts);
+       memset(ts, 0, sizeof(*ts));
+       ts->arr_sz = arr_sz;
+}
+
 void thread_stack__free(struct thread *thread)
 {
-       if (thread->ts) {
-               __thread_stack__flush(thread, thread->ts);
-               zfree(&thread->ts->stack);
+       struct thread_stack *ts = thread->ts;
+       unsigned int pos;
+
+       if (ts) {
+               for (pos = 0; pos < ts->arr_sz; pos++)
+                       __thread_stack__free(thread, ts + pos);
                zfree(&thread->ts);
        }
 }
@@ -315,9 +418,11 @@ static inline u64 callchain_context(u64 ip, u64 kernel_start)
        return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
 }
 
-void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+void thread_stack__sample(struct thread *thread, int cpu,
+                         struct ip_callchain *chain,
                          size_t sz, u64 ip, u64 kernel_start)
 {
+       struct thread_stack *ts = thread__stack(thread, cpu);
        u64 context = callchain_context(ip, kernel_start);
        u64 last_context;
        size_t i, j;
@@ -330,15 +435,15 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
        chain->ips[0] = context;
        chain->ips[1] = ip;
 
-       if (!thread || !thread->ts) {
+       if (!ts) {
                chain->nr = 2;
                return;
        }
 
        last_context = context;
 
-       for (i = 2, j = 1; i < sz && j <= thread->ts->cnt; i++, j++) {
-               ip = thread->ts->stack[thread->ts->cnt - j].ret_addr;
+       for (i = 2, j = 1; i < sz && j <= ts->cnt; i++, j++) {
+               ip = ts->stack[ts->cnt - j].ret_addr;
                context = callchain_context(ip, kernel_start);
                if (context != last_context) {
                        if (i >= sz - 1)
@@ -449,7 +554,7 @@ static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
        return 1;
 }
 
-static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
+static int thread_stack__bottom(struct thread_stack *ts,
                                struct perf_sample *sample,
                                struct addr_location *from_al,
                                struct addr_location *to_al, u64 ref)
@@ -474,7 +579,7 @@ static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
        if (!cp)
                return -ENOMEM;
 
-       return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
+       return thread_stack__push_cp(ts, ip, sample->time, ref, cp,
                                     true, false);
 }
 
@@ -590,24 +695,19 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
                          struct addr_location *to_al, u64 ref,
                          struct call_return_processor *crp)
 {
-       struct thread_stack *ts = thread->ts;
+       struct thread_stack *ts = thread__stack(thread, sample->cpu);
        int err = 0;
 
-       if (ts) {
-               if (!ts->crp) {
-                       /* Supersede thread_stack__event() */
-                       thread_stack__free(thread);
-                       thread->ts = thread_stack__new(thread, crp);
-                       if (!thread->ts)
-                               return -ENOMEM;
-                       ts = thread->ts;
-                       ts->comm = comm;
-               }
-       } else {
-               thread->ts = thread_stack__new(thread, crp);
-               if (!thread->ts)
+       if (ts && !ts->crp) {
+               /* Supersede thread_stack__event() */
+               thread_stack__reset(thread, ts);
+               ts = NULL;
+       }
+
+       if (!ts) {
+               ts = thread_stack__new(thread, sample->cpu, crp);
+               if (!ts)
                        return -ENOMEM;
-               ts = thread->ts;
                ts->comm = comm;
        }
 
@@ -621,8 +721,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 
        /* If the stack is empty, put the current symbol on the stack */
        if (!ts->cnt) {
-               err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
-                                          ref);
+               err = thread_stack__bottom(ts, sample, from_al, to_al, ref);
                if (err)
                        return err;
        }
@@ -671,9 +770,11 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
        return err;
 }
 
-size_t thread_stack__depth(struct thread *thread)
+size_t thread_stack__depth(struct thread *thread, int cpu)
 {
-       if (!thread->ts)
+       struct thread_stack *ts = thread__stack(thread, cpu);
+
+       if (!ts)
                return 0;
-       return thread->ts->cnt;
+       return ts->cnt;
 }
index f97c00a8c2514dcc102f8e25d32e474815e2b030..1f626f4a1c40f00a41e7191edfd536cbf8b260f6 100644 (file)
@@ -80,14 +80,14 @@ struct call_return_processor {
        void *data;
 };
 
-int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+int thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
                        u64 to_ip, u16 insn_len, u64 trace_nr);
-void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
-void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+void thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr);
+void thread_stack__sample(struct thread *thread, int cpu, struct ip_callchain *chain,
                          size_t sz, u64 ip, u64 kernel_start);
 int thread_stack__flush(struct thread *thread);
 void thread_stack__free(struct thread *thread);
-size_t thread_stack__depth(struct thread *thread);
+size_t thread_stack__depth(struct thread *thread, int cpu);
 
 struct call_return_processor *
 call_return_processor__new(int (*process)(struct call_return *cr, void *data),
index 2ab25aa382638c69a98582eb09c907b1fa07d402..1598b4fa0b11222bef515bcaa056df609a6a856f 100644 (file)
@@ -9,13 +9,13 @@ ifeq ("$(origin O)", "command line")
 endif
 
 turbostat : turbostat.c
-CFLAGS +=      -Wall
-CFLAGS +=      -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
-CFLAGS +=      -DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
+override CFLAGS +=     -Wall
+override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=     -DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
 
 %: %.c
        @mkdir -p $(BUILD_OUTPUT)
-       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
+       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 
 .PHONY : clean
 clean :
index f4534fb8b95158a5fb1e789739e32d754b0b1ae4..ae7a0e09b72276219f302517a7b1e0660ded3fcb 100644 (file)
@@ -9,12 +9,12 @@ ifeq ("$(origin O)", "command line")
 endif
 
 x86_energy_perf_policy : x86_energy_perf_policy.c
-CFLAGS +=      -Wall
-CFLAGS +=      -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=     -Wall
+override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 
 %: %.c
        @mkdir -p $(BUILD_OUTPUT)
-       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
+       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 
 .PHONY : clean
 clean :
index 735a510230c3f606d8939362e7a718555564b78d..89a2444c1df263a9a29df0c5b84bf14bdf0951c0 100644 (file)
@@ -6,13 +6,13 @@ VERSION = 1.0
 
 BINDIR=usr/bin
 WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS+= -O1 ${WARNFLAGS}
+override CFLAGS+= -O1 ${WARNFLAGS}
 # Add "-fstack-protector" only if toolchain supports it.
-CFLAGS+= $(call cc-option,-fstack-protector)
+override CFLAGS+= $(call cc-option,-fstack-protector-strong)
 CC?= $(CROSS_COMPILE)gcc
 PKG_CONFIG?= pkg-config
 
-CFLAGS+=-D VERSION=\"$(VERSION)\"
+override CFLAGS+=-D VERSION=\"$(VERSION)\"
 LDFLAGS+=
 TARGET=tmon
 
@@ -29,7 +29,7 @@ TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null
                     $(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
                     echo -lpanel -lncurses)
 
-CFLAGS    += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
+override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
                     $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
 
 OBJS = tmon.o tui.o sysfs.o pid.o