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;