Merge tag 'spi-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 21:02:43 +0000 (14:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 21:02:43 +0000 (14:02 -0700)
Pull spi updates from Mark Brown:
 "The big theme for this release has been performance, we've had a
  series of unrelated overhauls of a few drivers all with a big
  peformance component.

  Otherwise it's been relatively quiet, highlights include:

   - A big overhaul of the spi-fsl-dspi driver improving the code
     quality, performance and stability from Vladimir Oltean.

   - A big performance enhancement for the bc2835 (Raspberry Pi) driver
     for unidirectional transfers from Lukas Wunner.

   - Improved performance on small transfers for the uniphier driver
     from Keiji Hayashibara.

   - Lots of coccinelle generated cleanups from Yue Haibing.

   - New device support for Freescale ls2080a and Nuvoton NPCM FIU"

* tag 'spi-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (102 commits)
  spi: mediatek: support large PA
  spi: mediatek: add spi support for mt6765 IC
  dt-bindings: spi: update bindings for MT6765 SoC
  spi: bcm2835: Speed up RX-only DMA transfers by zero-filling TX FIFO
  spi: bcm2835: Speed up TX-only DMA transfers by clearing RX FIFO
  dmaengine: bcm2835: Avoid accessing memory when copying zeroes
  spi: bcm2835: Cache CS register value for ->prepare_message()
  dmaengine: bcm2835: Document struct bcm2835_dmadev
  spi: Guarantee cacheline alignment of driver-private data
  dmaengine: bcm2835: Allow reusable descriptors
  dmaengine: bcm2835: Allow cyclic transactions without interrupt
  spi: bcm2835: Drop dma_pending flag
  spi: bcm2835: Work around DONE bit erratum
  spi-gpio: Use PTR_ERR_OR_ZERO() in spi_gpio_request()
  spi: Use an abbreviated pointer to ctlr->cur_msg in __spi_pump_messages
  spi: npcm-fiu: remove set but not used variable 'retlen'
  spi: fsl-spi: use devm_platform_ioremap_resource() to simplify code
  spi: zynq-qspi: use devm_platform_ioremap_resource() to simplify code
  spi: zynqmp: use devm_platform_ioremap_resource() to simplify code
  spi: xlp: use devm_platform_ioremap_resource() to simplify code
  ...

235 files changed:
Documentation/devicetree/bindings/hwmon/ads1015.txt [deleted file]
Documentation/devicetree/bindings/hwmon/as370.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
Documentation/devicetree/bindings/hwmon/lm75.txt
Documentation/devicetree/bindings/iio/adc/ads1015.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/act8865-regulator.txt
Documentation/devicetree/bindings/regulator/fixed-regulator.yaml
Documentation/devicetree/bindings/regulator/mt6358-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
Documentation/devicetree/bindings/regulator/sy8824x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/twl-regulator.txt
Documentation/devicetree/bindings/regulator/uniphier-regulator.txt
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/hwmon/ads1015.rst [deleted file]
Documentation/hwmon/index.rst
Documentation/hwmon/inspur-ipsps1.rst [new file with mode: 0644]
Documentation/hwmon/lm75.rst
Documentation/hwmon/pxe1610 [deleted file]
Documentation/hwmon/pxe1610.rst [new file with mode: 0644]
Documentation/hwmon/shtc1.rst
Documentation/hwmon/submitting-patches.rst
Documentation/riscv/boot-image-header.txt
Documentation/security/tpm/index.rst
Documentation/security/tpm/tpm_ftpm_tee.rst [new file with mode: 0644]
MAINTAINERS
Makefile
arch/riscv/include/asm/image.h
arch/riscv/kernel/head.S
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/sparc/kernel/sys_sparc_64.c
arch/x86/include/asm/kvm_host.h
arch/x86/kernel/amd_nb.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/mce/severity.c
arch/x86/kvm/mmu.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/x86.c
arch/x86/purgatory/Makefile
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_qca.c
drivers/char/tpm/Kconfig
drivers/char/tpm/Makefile
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm_ftpm_tee.c [new file with mode: 0644]
drivers/char/tpm/tpm_ftpm_tee.h [new file with mode: 0644]
drivers/char/tpm/tpm_tis_core.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/altera_edac.c
drivers/edac/altera_edac.h
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/bluefield_edac.c [new file with mode: 0644]
drivers/edac/edac_mc.c
drivers/edac/edac_mc.h
drivers/edac/edac_mc_sysfs.c
drivers/edac/ghes_edac.c
drivers/edac/i5100_edac.c
drivers/edac/pnd2_edac.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/lima/lima_gem.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/ads1015.c [deleted file]
drivers/hwmon/adt7475.c
drivers/hwmon/as370-hwmon.c [new file with mode: 0644]
drivers/hwmon/asb100.c
drivers/hwmon/coretemp.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm75.c
drivers/hwmon/ltc2990.c
drivers/hwmon/nct6775.c
drivers/hwmon/nct7904.c
drivers/hwmon/npcm750-pwm-fan.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/ibm-cffps.c
drivers/hwmon/pmbus/inspur-ipsps.c [new file with mode: 0644]
drivers/hwmon/pmbus/max31785.c
drivers/hwmon/pmbus/ucd9000.c
drivers/hwmon/raspberrypi-hwmon.c
drivers/hwmon/shtc1.c
drivers/hwmon/smm665.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/iio/adc/Kconfig
drivers/isdn/capi/capi.c
drivers/mmc/host/bcm2835.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/sdhci-pci-o2micro.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/uniphier-sd.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/natsemi/sonic.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/hamradio/6pack.c
drivers/net/phy/phylink.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wimax/i2400m/op-rfkill.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/marvell/mwifiex/ie.c
drivers/net/wireless/marvell/mwifiex/uap_cmd.c
drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/rsi/rsi_91x_usb.c
drivers/nfc/st95hf/core.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
drivers/pinctrl/aspeed/pinmux-aspeed.c
drivers/pinctrl/aspeed/pinmux-aspeed.h
drivers/ras/Makefile
drivers/ras/cec.c
drivers/ras/debugfs.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/act8865-regulator.c
drivers/regulator/act8945a-regulator.c
drivers/regulator/core.c
drivers/regulator/da9062-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/da9211-regulator.c
drivers/regulator/fixed.c
drivers/regulator/helpers.c
drivers/regulator/lm363x-regulator.c
drivers/regulator/lp87565-regulator.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686-regulator.c
drivers/regulator/max8660.c
drivers/regulator/mt6358-regulator.c [new file with mode: 0644]
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/slg51000-regulator.c
drivers/regulator/stm32-booster.c
drivers/regulator/sy8824x.c [new file with mode: 0644]
drivers/regulator/tps65132-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/twl6030-regulator.c
drivers/regulator/uniphier-regulator.c
drivers/vhost/vhost.c
drivers/virtio/virtio_ring.c
fs/btrfs/extent_io.c
fs/btrfs/tree-log.c
fs/ext4/inode.c
include/dt-bindings/regulator/active-semi,8865-regulator.h [new file with mode: 0644]
include/linux/edac.h
include/linux/pci_ids.h
include/linux/phy_fixed.h
include/linux/pid.h
include/linux/regulator/consumer.h
include/linux/regulator/mt6358-regulator.h [new file with mode: 0644]
include/linux/syscalls.h
include/net/ip_fib.h
include/net/nexthop.h
include/net/xfrm.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/isdn/capicmd.h
include/uapi/linux/wait.h
ipc/util.h
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/events/hw_breakpoint.c
kernel/exit.c
kernel/fork.c
kernel/irq/resend.c
kernel/signal.c
lib/Kconfig
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bridge/br_mdb.c
net/bridge/br_netfilter_hooks.c
net/core/dev.c
net/core/skbuff.c
net/core/sock_map.c
net/ipv4/fib_semantics.c
net/ipv4/tcp_input.c
net/ipv6/ping.c
net/ipv6/route.c
net/mac80211/cfg.c
net/mac80211/sta_info.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nft_fib_netdev.c
net/netfilter/nft_socket.c
net/qrtr/tun.c
net/rds/bind.c
net/rxrpc/input.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/sch_hhf.c
net/sctp/protocol.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/tipc/name_distr.c
net/xfrm/xfrm_interface.c
net/xfrm/xfrm_policy.c
tools/testing/selftests/cgroup/test_freezer.c
tools/testing/selftests/net/fib_nexthops.sh
tools/testing/selftests/net/xfrm_policy.sh
tools/testing/selftests/pidfd/.gitignore
tools/testing/selftests/pidfd/Makefile
tools/testing/selftests/pidfd/pidfd.h
tools/testing/selftests/pidfd/pidfd_open_test.c
tools/testing/selftests/pidfd/pidfd_poll_test.c [new file with mode: 0644]
tools/testing/selftests/pidfd/pidfd_test.c
tools/testing/selftests/pidfd/pidfd_wait.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
deleted file mode 100644 (file)
index 918a507..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-ADS1015 (I2C)
-
-This device is a 12-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-For configuration all possible combinations are mapped to 8 channels:
-  0: Voltage over AIN0 and AIN1.
-  1: Voltage over AIN0 and AIN3.
-  2: Voltage over AIN1 and AIN3.
-  3: Voltage over AIN2 and AIN3.
-  4: Voltage over AIN0 and GND.
-  5: Voltage over AIN1 and GND.
-  6: Voltage over AIN2 and GND.
-  7: Voltage over AIN3 and GND.
-
-Each channel can be configured individually:
- - pga is the programmable gain amplifier (values are full scale)
-    0: +/- 6.144 V
-    1: +/- 4.096 V
-    2: +/- 2.048 V (default)
-    3: +/- 1.024 V
-    4: +/- 0.512 V
-    5: +/- 0.256 V
- - data_rate in samples per second
-    0: 128
-    1: 250
-    2: 490
-    3: 920
-    4: 1600 (default)
-    5: 2400
-    6: 3300
-
-1) The /ads1015 node
-
-  Required properties:
-
-   - compatible : must be "ti,ads1015"
-   - reg : I2C bus address of the device
-   - #address-cells : must be <1>
-   - #size-cells : must be <0>
-
-  The node contains child nodes for each channel that the platform uses.
-
-  Example ADS1015 node:
-
-    ads1015@49 {
-           compatible = "ti,ads1015";
-           reg = <0x49>;
-           #address-cells = <1>;
-           #size-cells = <0>;
-
-           [ child node definitions... ]
-    }
-
-2) channel nodes
-
-  Required properties:
-
-   - reg : the channel number
-
-  Optional properties:
-
-   - ti,gain : the programmable gain amplifier setting
-   - ti,datarate : the converter data rate
-
-  Example ADS1015 channel node:
-
-    channel@4 {
-           reg = <4>;
-           ti,gain = <3>;
-           ti,datarate = <5>;
-    };
diff --git a/Documentation/devicetree/bindings/hwmon/as370.txt b/Documentation/devicetree/bindings/hwmon/as370.txt
new file mode 100644 (file)
index 0000000..d102fe7
--- /dev/null
@@ -0,0 +1,11 @@
+Bindings for Synaptics AS370 PVT sensors
+
+Required properties:
+- compatible : "syna,as370-hwmon"
+- reg        : address and length of the register set.
+
+Example:
+       hwmon@ea0810 {
+               compatible = "syna,as370-hwmon";
+               reg = <0xea0810 0xc>;
+       };
index f68a0a68fc524cdc1ee547313892a34e78248800..1036f65fb778eeb54d6e600d0722c5c6a1746680 100644 (file)
@@ -1,8 +1,10 @@
-Device-tree bindings for IBM Common Form Factor Power Supply Version 1
-----------------------------------------------------------------------
+Device-tree bindings for IBM Common Form Factor Power Supply Versions 1 and 2
+-----------------------------------------------------------------------------
 
 Required properties:
- - compatible = "ibm,cffps1";
+ - compatible                          : Must be one of the following:
+                                               "ibm,cffps1"
+                                               "ibm,cffps2"
  - reg = < I2C bus address >;          : Address of the power supply on the
                                          I2C bus.
 
index 586b5ed70be7a0f2ff21e49c60ba2ae072645083..273616702c51b5f089c521dd49d734b42879aa29 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
                "maxim,max31725",
                "maxim,max31726",
                "maxim,mcp980x",
+               "nxp,pct2075",
                "st,stds75",
                "st,stlm75",
                "microchip,tcn75",
diff --git a/Documentation/devicetree/bindings/iio/adc/ads1015.txt b/Documentation/devicetree/bindings/iio/adc/ads1015.txt
new file mode 100644 (file)
index 0000000..918a507
--- /dev/null
@@ -0,0 +1,73 @@
+ADS1015 (I2C)
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+For configuration all possible combinations are mapped to 8 channels:
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured individually:
+ - pga is the programmable gain amplifier (values are full scale)
+    0: +/- 6.144 V
+    1: +/- 4.096 V
+    2: +/- 2.048 V (default)
+    3: +/- 1.024 V
+    4: +/- 0.512 V
+    5: +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600 (default)
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C bus address of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+           compatible = "ti,ads1015";
+           reg = <0x49>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+
+           [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter data rate
+
+  Example ADS1015 channel node:
+
+    channel@4 {
+           reg = <4>;
+           ti,gain = <3>;
+           ti,datarate = <5>;
+    };
index 3ae9f1088845ba4fecf43b90102256317f4b71e8..b9f58e480349896655d2d6d97881c641a2666fcb 100644 (file)
@@ -34,6 +34,9 @@ Optional input supply properties:
   - inl67-supply: The input supply for LDO_REG3 and LDO_REG4
 
 Any standard regulator properties can be used to configure the single regulator.
+regulator-initial-mode, regulator-allowed-modes and regulator-mode could be specified
+for act8865 using mode values from dt-bindings/regulator/active-semi,8865-regulator.h
+file.
 
 The valid names for regulators are:
        - for act8846:
@@ -47,6 +50,8 @@ The valid names for regulators are:
 Example:
 --------
 
+#include <dt-bindings/regulator/active-semi,8865-regulator.h>
+
                i2c1: i2c@f0018000 {
                        pmic: act8865@5b {
                                compatible = "active-semi,act8865";
@@ -65,9 +70,19 @@ Example:
                                                regulator-name = "VCC_1V2";
                                                regulator-min-microvolt = <1100000>;
                                                regulator-max-microvolt = <1300000>;
-                                               regulator-suspend-mem-microvolt = <1150000>;
-                                               regulator-suspend-standby-microvolt = <1150000>;
                                                regulator-always-on;
+
+                                               regulator-allowed-modes = <ACT8865_REGULATOR_MODE_FIXED>,
+                                                                         <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               regulator-initial-mode = <ACT8865_REGULATOR_MODE_FIXED>;
+
+                                               regulator-state-mem {
+                                                       regulator-on-in-suspend;
+                                                       regulator-suspend-min-microvolt = <1150000>;
+                                                       regulator-suspend-max-microvolt = <1150000>;
+                                                       regulator-changeable-in-suspend;
+                                                       regulator-mode = <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               };
                                        };
 
                                        vcc_3v3_reg: DCDC_REG3 {
@@ -82,6 +97,14 @@ Example:
                                                regulator-min-microvolt = <3300000>;
                                                regulator-max-microvolt = <3300000>;
                                                regulator-always-on;
+
+                                               regulator-allowed-modes = <ACT8865_REGULATOR_MODE_NORMAL>,
+                                                                         <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               regulator-initial-mode = <ACT8865_REGULATOR_MODE_NORMAL>;
+
+                                               regulator-state-mem {
+                                                       regulator-off-in-suspend;
+                                               };
                                        };
 
                                        vddfuse_reg: LDO_REG2 {
index a650b457085de27f96a56dffd0026e8016cafb66..a78150c47aa2a67b8759c7a7c450e9edd20a375b 100644 (file)
@@ -19,9 +19,19 @@ description:
 allOf:
   - $ref: "regulator.yaml#"
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: regulator-fixed-clock
+  required:
+    - clocks
+
 properties:
   compatible:
-    const: regulator-fixed
+    enum:
+      - const: regulator-fixed
+      - const: regulator-fixed-clock
 
   regulator-name: true
 
@@ -29,6 +39,13 @@ properties:
     description: gpio to use for enable control
     maxItems: 1
 
+  clocks:
+    description:
+      clock to use for enable control. This binding is only available if
+      the compatible is chosen to regulator-fixed-clock. The clock binding
+      is mandatory if compatible is chosen to regulator-fixed-clock.
+    maxItems: 1
+
   startup-delay-us:
     description: startup time in microseconds
     $ref: /schemas/types.yaml#/definitions/uint32
diff --git a/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt
new file mode 100644 (file)
index 0000000..9a90a92
--- /dev/null
@@ -0,0 +1,358 @@
+MediaTek MT6358 Regulator
+
+All voltage regulators provided by the MT6358 PMIC are described as the
+subnodes of the MT6358 regulators node. Each regulator is named according
+to its regulator type, buck_<name> and ldo_<name>. The definition for each
+of these nodes is defined using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vdram1, buck_vcore, buck_vpa, buck_vproc11, buck_vproc12, buck_vgpu,
+  buck_vs2, buck_vmodem, buck_vs1
+LDO:
+  ldo_vdram2, ldo_vsim1, ldo_vibr, ldo_vrf12, ldo_vio18, ldo_vusb, ldo_vcamio,
+  ldo_vcamd, ldo_vcn18, ldo_vfe28, ldo_vsram_proc11, ldo_vcn28, ldo_vsram_others,
+  ldo_vsram_gpu, ldo_vxo22, ldo_vefuse, ldo_vaux18, ldo_vmch, ldo_vbif28,
+  ldo_vsram_proc12, ldo_vcama1, ldo_vemc, ldo_vio28, ldo_va12, ldo_vrf18,
+  ldo_vcn33_bt, ldo_vcn33_wifi, ldo_vcama2, ldo_vmc, ldo_vldo28, ldo_vaud28,
+  ldo_vsim2
+
+Example:
+
+       pmic {
+               compatible = "mediatek,mt6358";
+
+               mt6358regulator: mt6358regulator {
+                       compatible = "mediatek,mt6358-regulator";
+
+                       mt6358_vdram1_reg: buck_vdram1 {
+                               regulator-compatible = "buck_vdram1";
+                               regulator-name = "vdram1";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2087500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcore_reg: buck_vcore {
+                               regulator-name = "vcore";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vpa_reg: buck_vpa {
+                               regulator-name = "vpa";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3650000>;
+                               regulator-ramp-delay = <50000>;
+                               regulator-enable-ramp-delay = <250>;
+                       };
+
+                       mt6358_vproc11_reg: buck_vproc11 {
+                               regulator-name = "vproc11";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vproc12_reg: buck_vproc12 {
+                               regulator-name = "vproc12";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vgpu_reg: buck_vgpu {
+                               regulator-name = "vgpu";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                       };
+
+                       mt6358_vs2_reg: buck_vs2 {
+                               regulator-name = "vs2";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2087500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vmodem_reg: buck_vmodem {
+                               regulator-name = "vmodem";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <900>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vs1_reg: buck_vs1 {
+                               regulator-name = "vs1";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <2587500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vdram2_reg: ldo_vdram2 {
+                               regulator-name = "vdram2";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <3300>;
+                       };
+
+                       mt6358_vsim1_reg: ldo_vsim1 {
+                               regulator-name = "vsim1";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+
+                       mt6358_vibr_reg: ldo_vibr {
+                               regulator-name = "vibr";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vrf12_reg: ldo_vrf12 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vrf12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       mt6358_vio18_reg: ldo_vio18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vio18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <2700>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vusb_reg: ldo_vusb {
+                               regulator-name = "vusb";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcamio_reg: ldo_vcamio {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcamio";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcamd_reg: ldo_vcamd {
+                               regulator-name = "vcamd";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcn18_reg: ldo_vcn18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcn18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vfe28_reg: ldo_vfe28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vfe28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_proc11_reg: ldo_vsram_proc11 {
+                               regulator-name = "vsram_proc11";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcn28_reg: ldo_vcn28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcn28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_others_reg: ldo_vsram_others {
+                               regulator-name = "vsram_others";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vsram_gpu_reg: ldo_vsram_gpu {
+                               regulator-name = "vsram_gpu";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                       };
+
+                       mt6358_vxo22_reg: ldo_vxo22 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vxo22";
+                               regulator-min-microvolt = <2200000>;
+                               regulator-max-microvolt = <2200000>;
+                               regulator-enable-ramp-delay = <120>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vefuse_reg: ldo_vefuse {
+                               regulator-name = "vefuse";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <1900000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vaux18_reg: ldo_vaux18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vaux18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vmch_reg: ldo_vmch {
+                               regulator-name = "vmch";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vbif28_reg: ldo_vbif28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vbif28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_proc12_reg: ldo_vsram_proc12 {
+                               regulator-name = "vsram_proc12";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcama1_reg: ldo_vcama1 {
+                               regulator-name = "vcama1";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vemc_reg: ldo_vemc {
+                               regulator-name = "vemc";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vio28_reg: ldo_vio28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vio28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_va12_reg: ldo_va12 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "va12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vrf18_reg: ldo_vrf18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vrf18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       mt6358_vcn33_bt_reg: ldo_vcn33_bt {
+                               regulator-name = "vcn33_bt";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3500000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcn33_wifi_reg: ldo_vcn33_wifi {
+                               regulator-name = "vcn33_wifi";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3500000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcama2_reg: ldo_vcama2 {
+                               regulator-name = "vcama2";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vmc_reg: ldo_vmc {
+                               regulator-name = "vmc";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vldo28_reg: ldo_vldo28 {
+                               regulator-name = "vldo28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vaud28_reg: ldo_vaud28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vaud28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsim2_reg: ldo_vsim2 {
+                               regulator-name = "vsim2";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+               };
+       };
index 14d2eee96b3d5e075ed90af0ca9e042eae0ee065..bab9f71140b835161fba4895c7fddca8df786598 100644 (file)
@@ -22,9 +22,12 @@ RPMh resource.
 
 The names used for regulator nodes must match those supported by a given PMIC.
 Supported regulator node names:
+       PM8005:         smps1 - smps4
+       PM8009:         smps1 - smps2, ldo1 - ldo7
+       PM8150:         smps1 - smps10, ldo1 - ldo18
+       PM8150L:        smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
        PM8998:         smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
        PMI8998:        bob
-       PM8005:         smps1 - smps4
 
 ========================
 First Level Nodes - PMIC
@@ -33,9 +36,13 @@ First Level Nodes - PMIC
 - compatible
        Usage:      required
        Value type: <string>
-       Definition: Must be one of: "qcom,pm8998-rpmh-regulators",
-                   "qcom,pmi8998-rpmh-regulators" or
-                   "qcom,pm8005-rpmh-regulators".
+       Definition: Must be one of below:
+                   "qcom,pm8005-rpmh-regulators"
+                   "qcom,pm8009-rpmh-regulators"
+                   "qcom,pm8150-rpmh-regulators"
+                   "qcom,pm8150l-rpmh-regulators"
+                   "qcom,pm8998-rpmh-regulators"
+                   "qcom,pmi8998-rpmh-regulators"
 
 - qcom,pmic-id
        Usage:      required
diff --git a/Documentation/devicetree/bindings/regulator/sy8824x.txt b/Documentation/devicetree/bindings/regulator/sy8824x.txt
new file mode 100644 (file)
index 0000000..c5e9585
--- /dev/null
@@ -0,0 +1,24 @@
+SY8824C/SY8824E/SY20276 Voltage regulator
+
+Required properties:
+- compatible: Must be one of the following.
+       "silergy,sy8824c"
+       "silergy,sy8824e"
+       "silergy,sy20276"
+       "silergy,sy20278"
+- reg: I2C slave address
+
+Any property defined as part of the core regulator binding, defined in
+./regulator.txt, can also be used.
+
+Example:
+
+       vcore: regulator@00 {
+               compatible = "silergy,sy8824c";
+               reg = <0x66>;
+               regulator-name = "vcore";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1150000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
index 74a91c4f8530a4cd17cb5d184554c6cd283163e8..549f80436debca8eed1558f547264967cba89a42 100644 (file)
@@ -71,3 +71,10 @@ Example:
                regulator-min-microvolt  = <1000000>;
                regulator-max-microvolt  = <3000000>;
        };
+
+For twl6030 regulators/LDOs:
+
+ - ti,retain-on-reset: Does not turn off the supplies during warm
+                       reset. Could be needed for VMMC, as TWL6030
+                       reset sequence for this signal does not comply
+                       with the SD specification.
index c9919f4b92d2121ef25471c1f22df69f621a911c..94fd38b0d163fdcedc20085c442e3c510ed4f292 100644 (file)
@@ -13,6 +13,7 @@ this layer. These clocks and resets should be described in each property.
 Required properties:
 - compatible: Should be
     "socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC
+    "socionext,uniphier-pro5-usb3-regulator" - for Pro5 SoC
     "socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC
     "socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC
     "socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC
@@ -20,12 +21,12 @@ Required properties:
 - clocks: A list of phandles to the clock gate for USB3 glue layer.
        According to the clock-names, appropriate clocks are required.
 - clock-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 - resets: A list of phandles to the reset control for USB3 glue layer.
        According to the reset-names, appropriate resets are required.
 - reset-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 
 See Documentation/devicetree/bindings/regulator/regulator.txt
index 2e742d399e87b039cc77f04c53ff33634e94c177..870ac52d2225923961712ced3a51c030cba0a386 100644 (file)
@@ -104,6 +104,8 @@ properties:
           - infineon,slb9645tt
             # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
           - infineon,tlv493d-a1b6
+            # Inspur Power System power supply unit version 1
+          - inspur,ipsps1
             # Intersil ISL29028 Ambient Light and Proximity Sensor
           - isil,isl29028
             # Intersil ISL29030 Ambient Light and Proximity Sensor
index 6992bbbbffab6a57b185a244048ea9d03d60ea15..d61a203138cbe91686142b9d070a28514cd799d0 100644 (file)
@@ -575,6 +575,8 @@ patternProperties:
     description: Micro Crystal AG
   "^micron,.*":
     description: Micron Technology Inc.
+  "^microsoft,.*":
+    description: Microsoft Corporation
   "^mikroe,.*":
     description: MikroElektronika d.o.o.
   "^miniand,.*":
diff --git a/Documentation/hwmon/ads1015.rst b/Documentation/hwmon/ads1015.rst
deleted file mode 100644 (file)
index e0951c4..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Kernel driver ads1015
-=====================
-
-Supported chips:
-
-  * Texas Instruments ADS1015
-
-    Prefix: 'ads1015'
-
-    Datasheet: Publicly available at the Texas Instruments website:
-
-              http://focus.ti.com/lit/ds/symlink/ads1015.pdf
-
-  * Texas Instruments ADS1115
-
-    Prefix: 'ads1115'
-
-    Datasheet: Publicly available at the Texas Instruments website:
-
-              http://focus.ti.com/lit/ds/symlink/ads1115.pdf
-
-Authors:
-       Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
-
-Description
------------
-
-This driver implements support for the Texas Instruments ADS1015/ADS1115.
-
-This device is a 12/16-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-The inputs can be made available by 8 sysfs input files in0_input - in7_input:
-
-  - in0: Voltage over AIN0 and AIN1.
-  - in1: Voltage over AIN0 and AIN3.
-  - in2: Voltage over AIN1 and AIN3.
-  - in3: Voltage over AIN2 and AIN3.
-  - in4: Voltage over AIN0 and GND.
-  - in5: Voltage over AIN1 and GND.
-  - in6: Voltage over AIN2 and GND.
-  - in7: Voltage over AIN3 and GND.
-
-Which inputs are available can be configured using platform data or devicetree.
-
-By default all inputs are exported.
-
-Platform Data
--------------
-
-In linux/platform_data/ads1015.h platform data is defined, channel_data contains
-configuration data for the used input combinations:
-
-- pga is the programmable gain amplifier (values are full scale)
-
-    - 0: +/- 6.144 V
-    - 1: +/- 4.096 V
-    - 2: +/- 2.048 V
-    - 3: +/- 1.024 V
-    - 4: +/- 0.512 V
-    - 5: +/- 0.256 V
-
-- data_rate in samples per second
-
-    - 0: 128
-    - 1: 250
-    - 2: 490
-    - 3: 920
-    - 4: 1600
-    - 5: 2400
-    - 6: 3300
-
-Example::
-
-  struct ads1015_platform_data data = {
-       .channel_data = {
-               [2] = { .enabled = true, .pga = 1, .data_rate = 0 },
-               [4] = { .enabled = true, .pga = 4, .data_rate = 5 },
-       }
-  };
-
-In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
-(FS +/- 0.512 V, 2400 SPS) would be created.
-
-Devicetree
-----------
-
-Configuration is also possible via devicetree:
-Documentation/devicetree/bindings/hwmon/ads1015.txt
index ee090e51653a65d6302cf979baaf51ff660e62f0..8147c3f218bfb11167ca160ebc69c3d33b5b07f4 100644 (file)
@@ -30,7 +30,6 @@ Hardware Monitoring Kernel Drivers
    adm1031
    adm1275
    adm9240
-   ads1015
    ads7828
    adt7410
    adt7411
@@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers
    pcf8591
    pmbus
    powr1220
+   pxe1610
    pwm-fan
    raspberrypi-hwmon
    sch5627
diff --git a/Documentation/hwmon/inspur-ipsps1.rst b/Documentation/hwmon/inspur-ipsps1.rst
new file mode 100644 (file)
index 0000000..2b871ae
--- /dev/null
@@ -0,0 +1,79 @@
+Kernel driver inspur-ipsps1
+=======================
+
+Supported chips:
+
+  * Inspur Power System power supply unit
+
+Author: John Wang <wangzqbj@inspur.com>
+
+Description
+-----------
+
+This driver supports Inspur Power System power supplies. This driver
+is a client to the core PMBus driver.
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+Sysfs entries
+-------------
+
+The following attributes are supported:
+
+======================= ======================================================
+curr1_input            Measured input current
+curr1_label            "iin"
+curr1_max              Maximum current
+curr1_max_alarm                Current high alarm
+curr2_input            Measured output current in mA.
+curr2_label            "iout1"
+curr2_crit             Critical maximum current
+curr2_crit_alarm       Current critical high alarm
+curr2_max              Maximum current
+curr2_max_alarm                Current high alarm
+
+fan1_alarm             Fan 1 warning.
+fan1_fault             Fan 1 fault.
+fan1_input             Fan 1 speed in RPM.
+
+in1_alarm              Input voltage under-voltage alarm.
+in1_input              Measured input voltage in mV.
+in1_label              "vin"
+in2_input              Measured output voltage in mV.
+in2_label              "vout1"
+in2_lcrit              Critical minimum output voltage
+in2_lcrit_alarm                Output voltage critical low alarm
+in2_max                        Maximum output voltage
+in2_max_alarm          Output voltage high alarm
+in2_min                        Minimum output voltage
+in2_min_alarm          Output voltage low alarm
+
+power1_alarm           Input fault or alarm.
+power1_input           Measured input power in uW.
+power1_label           "pin"
+power1_max             Input power limit
+power2_max_alarm       Output power high alarm
+power2_max             Output power limit
+power2_input           Measured output power in uW.
+power2_label           "pout"
+
+temp[1-3]_input                Measured temperature
+temp[1-2]_max          Maximum temperature
+temp[1-3]_max_alarm    Temperature high alarm
+
+vendor                 Manufacturer name
+model                  Product model
+part_number            Product part number
+serial_number          Product serial number
+fw_version             Firmware version
+hw_version             Hardware version
+mode                   Work mode. Can be set to active or
+                       standby, when set to standby, PSU will
+                       automatically switch between standby
+                       and redundancy mode.
+======================= ======================================================
index ba8acbd2a6cb3f0c1945e3f9fa4d5b2699fcc27e..e749f827c00236ba7d5ada47d4ec34b1d1c86db6 100644 (file)
@@ -119,9 +119,9 @@ Supported chips:
 
               http://www.ti.com/product/tmp275
 
-  * NXP LM75B
+  * NXP LM75B, PCT2075
 
-    Prefix: 'lm75b'
+    Prefix: 'lm75b', 'pct2075'
 
     Addresses scanned: none
 
@@ -129,6 +129,8 @@ Supported chips:
 
               http://www.nxp.com/documents/data_sheet/LM75B.pdf
 
+               http://www.nxp.com/docs/en/data-sheet/PCT2075.pdf
+
 Author: Frodo Looijaard <frodol@dds.nl>
 
 Description
diff --git a/Documentation/hwmon/pxe1610 b/Documentation/hwmon/pxe1610
deleted file mode 100644 (file)
index 211cede..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Kernel driver pxe1610
-=====================
-
-Supported chips:
-  * Infineon PXE1610
-    Prefix: 'pxe1610'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-  * Infineon PXE1110
-    Prefix: 'pxe1110'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-  * Infineon PXM1310
-    Prefix: 'pxm1310'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-Author: Vijay Khemka <vijaykhemka@fb.com>
-
-
-Description
------------
-
-PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
-and compliant to
-       -- Intel VR13 DC-DC converter specifications.
-       -- Intel SVID protocol.
-Used for Vcore power regulation for Intel VR13 based microprocessors
-       -- Servers, Workstations, and High-end desktops
-
-PXM1310 is a Multi-rail Controller and it is compliant to
-       -- Intel VR13 DC-DC converter specifications.
-       -- Intel SVID protocol.
-Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
-IMVP8 based systems
-
-
-Usage Notes
------------
-
-This driver does not probe for PMBus devices. You will have
-to instantiate devices explicitly.
-
-Example: the following commands will load the driver for an PXE1610
-at address 0x70 on I2C bus #4:
-
-# modprobe pxe1610
-# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
-
-It can also be instantiated by declaring in device tree
-
-
-Sysfs attributes
-----------------
-
-curr1_label            "iin"
-curr1_input            Measured input current
-curr1_alarm            Current high alarm
-
-curr[2-4]_label                "iout[1-3]"
-curr[2-4]_input                Measured output current
-curr[2-4]_crit         Critical maximum current
-curr[2-4]_crit_alarm   Current critical high alarm
-
-in1_label              "vin"
-in1_input              Measured input voltage
-in1_crit               Critical maximum input voltage
-in1_crit_alarm         Input voltage critical high alarm
-
-in[2-4]_label          "vout[1-3]"
-in[2-4]_input          Measured output voltage
-in[2-4]_lcrit          Critical minimum output voltage
-in[2-4]_lcrit_alarm    Output voltage critical low alarm
-in[2-4]_crit           Critical maximum output voltage
-in[2-4]_crit_alarm     Output voltage critical high alarm
-
-power1_label           "pin"
-power1_input           Measured input power
-power1_alarm           Input power high alarm
-
-power[2-4]_label       "pout[1-3]"
-power[2-4]_input       Measured output power
-
-temp[1-3]_input                Measured temperature
-temp[1-3]_crit         Critical high temperature
-temp[1-3]_crit_alarm   Chip temperature critical high alarm
-temp[1-3]_max          Maximum temperature
-temp[1-3]_max_alarm    Chip temperature high alarm
diff --git a/Documentation/hwmon/pxe1610.rst b/Documentation/hwmon/pxe1610.rst
new file mode 100644 (file)
index 0000000..4f23888
--- /dev/null
@@ -0,0 +1,107 @@
+Kernel driver pxe1610
+=====================
+
+Supported chips:
+
+  * Infineon PXE1610
+
+    Prefix: 'pxe1610'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXE1110
+
+    Prefix: 'pxe1110'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXM1310
+
+    Prefix: 'pxm1310'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+Author: Vijay Khemka <vijaykhemka@fb.com>
+
+
+Description
+-----------
+
+PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
+and compliant to
+
+       - Intel VR13 DC-DC converter specifications.
+       - Intel SVID protocol.
+
+Used for Vcore power regulation for Intel VR13 based microprocessors
+
+       - Servers, Workstations, and High-end desktops
+
+PXM1310 is a Multi-rail Controller and it is compliant to
+
+       - Intel VR13 DC-DC converter specifications.
+       - Intel SVID protocol.
+
+Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
+IMVP8 based systems
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have
+to instantiate devices explicitly.
+
+Example: the following commands will load the driver for an PXE1610
+at address 0x70 on I2C bus #4::
+
+    # modprobe pxe1610
+    # echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
+
+It can also be instantiated by declaring in device tree
+
+
+Sysfs attributes
+----------------
+
+======================  ====================================
+curr1_label            "iin"
+curr1_input            Measured input current
+curr1_alarm            Current high alarm
+
+curr[2-4]_label                "iout[1-3]"
+curr[2-4]_input                Measured output current
+curr[2-4]_crit         Critical maximum current
+curr[2-4]_crit_alarm   Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in[2-4]_label          "vout[1-3]"
+in[2-4]_input          Measured output voltage
+in[2-4]_lcrit          Critical minimum output voltage
+in[2-4]_lcrit_alarm    Output voltage critical low alarm
+in[2-4]_crit           Critical maximum output voltage
+in[2-4]_crit_alarm     Output voltage critical high alarm
+
+power1_label           "pin"
+power1_input           Measured input power
+power1_alarm           Input power high alarm
+
+power[2-4]_label       "pout[1-3]"
+power[2-4]_input       Measured output power
+
+temp[1-3]_input                Measured temperature
+temp[1-3]_crit         Critical high temperature
+temp[1-3]_crit_alarm   Chip temperature critical high alarm
+temp[1-3]_max          Maximum temperature
+temp[1-3]_max_alarm    Chip temperature high alarm
+======================  ====================================
index aa116332ba26087a35f72b1541ee388ac21b7d1f..9b0f1eee5bf2adad564efba59a791da5039400d4 100644 (file)
@@ -19,7 +19,17 @@ Supported chips:
 
     Addresses scanned: none
 
-    Datasheet: Not publicly available
+    Datasheet: http://www.sensirion.com/file/datasheet_shtw1
+
+
+
+  * Sensirion SHTC3
+
+    Prefix: 'shtc3'
+
+    Addresses scanned: none
+
+    Datasheet: http://www.sensirion.com/file/datasheet_shtc3
 
 
 
@@ -30,10 +40,9 @@ Author:
 Description
 -----------
 
-This driver implements support for the Sensirion SHTC1 chip, a humidity and
-temperature sensor. Temperature is measured in degrees celsius, relative
-humidity is expressed as a percentage. Driver can be used as well for SHTW1
-chip, which has the same electrical interface.
+This driver implements support for the Sensirion SHTC1, SHTW1, and SHTC3
+chips, a humidity and temperature sensor. Temperature is measured in degrees
+celsius, relative humidity is expressed as a percentage.
 
 The device communicates with the I2C protocol. All sensors are set to I2C
 address 0x70. See Documentation/i2c/instantiating-devices for methods to
index 452fc28d8e0bb3f7efefc6f20c5a0786ae72b22e..9a218ea996d8633e8705d4f9e8f41f0e90f3b2ad 100644 (file)
@@ -20,6 +20,10 @@ increase the chances of your change being accepted.
   errors, no warnings, and few if any check messages. If there are any
   messages, please be prepared to explain.
 
+* Please use the standard multi-line comment style. Do not mix C and C++
+  style comments in a single driver (with the exception of the SPDX license
+  identifier).
+
 * If your patch generates checkpatch errors, warnings, or check messages,
   please refrain from explanations such as "I prefer that coding style".
   Keep in mind that each unnecessary message helps hiding a real problem,
@@ -120,8 +124,8 @@ increase the chances of your change being accepted.
   completely initialize your chip and your driver first, then register with
   the hwmon subsystem.
 
-* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove
-  function, hwmon_device_register_with_groups() to register your driver with the
+* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
+  function, hwmon_device_register_with_info() to register your driver with the
   hwmon subsystem. Try using devm_add_action() instead of a remove function if
   possible. Do not use hwmon_device_register().
 
index 1b73fea23b39f11fee9be7207fb8b359c0e7e73f..14b1492f689bbe71c983a1baba1756d4e79e4204 100644 (file)
@@ -18,7 +18,7 @@ The following 64-byte header is present in decompressed Linux kernel image.
        u32 res1  = 0;            /* Reserved */
        u64 res2  = 0;            /* Reserved */
        u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
-       u32 res3;                 /* Reserved for additional RISC-V specific header */
+       u32 magic2 = 0x56534905;  /* Magic number 2, little endian, "RSC\x05" */
        u32 res4;                 /* Reserved for PE COFF offset */
 
 This header format is compliant with PE/COFF header and largely inspired from
@@ -37,13 +37,14 @@ Notes:
        Bits 16:31 - Major version
 
   This preserves compatibility across newer and older version of the header.
-  The current version is defined as 0.1.
+  The current version is defined as 0.2.
 
-- res3 is reserved for offset to any other additional fields. This makes the
-  header extendible in future. One example would be to accommodate ISA
-  extension for RISC-V in future. For current version, it is set to be zero.
+- The "magic" field is deprecated as of version 0.2.  In a future
+  release, it may be removed.  This originally should have matched up
+  with the ARM64 header "magic" field, but unfortunately does not.
+  The "magic2" field replaces it, matching up with the ARM64 header.
 
-- In current header, the flag field has only one field.
+- In current header, the flags field has only one field.
        Bit 0: Kernel endianness. 1 if BE, 0 if LE.
 
 - Image size is mandatory for boot loader to load kernel image. Booting will
index 3296533e54cfbcd08e2b27c4c79a3c2ce19cab96..487852fda33e959cf8d24a32d949e6fe0ad5bf92 100644 (file)
@@ -6,3 +6,4 @@ Trusted Platform Module documentation
 
    tpm_vtpm_proxy
    xen-tpmfront
+   tpm_ftpm_tee
diff --git a/Documentation/security/tpm/tpm_ftpm_tee.rst b/Documentation/security/tpm/tpm_ftpm_tee.rst
new file mode 100644 (file)
index 0000000..8c2bae1
--- /dev/null
@@ -0,0 +1,27 @@
+=============================================
+Firmware TPM Driver
+=============================================
+
+This document describes the firmware Trusted Platform Module (fTPM)
+device driver.
+
+Introduction
+============
+
+This driver is a shim for firmware implemented in ARM's TrustZone
+environment. The driver allows programs to interact with the TPM in the same
+way they would interact with a hardware TPM.
+
+Design
+======
+
+The driver acts as a thin layer that passes commands to and from a TPM
+implemented in firmware. The driver itself doesn't contain much logic and is
+used more like a dumb pipe between firmware and kernel/userspace.
+
+The firmware itself is based on the following paper:
+https://www.microsoft.com/en-us/research/wp-content/uploads/2017/06/ftpm1.pdf
+
+When the driver is loaded it will expose ``/dev/tpmX`` character devices to
+userspace which will enable userspace to communicate with the firmware TPM
+through this device.
index e7a47b5210fdd0b38e684e6f5a672153ea05f150..67b776c624ae09609931edd2c22a93220dfcd8d2 100644 (file)
@@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
 
-ADS1015 HARDWARE MONITOR DRIVER
-M:     Dirk Eibach <eibach@gdsys.de>
-L:     linux-hwmon@vger.kernel.org
-S:     Maintained
-F:     Documentation/hwmon/ads1015.rst
-F:     drivers/hwmon/ads1015.c
-F:     include/linux/platform_data/ads1015.h
-
 ADT746X FAN DRIVER
 M:     Colin Leroy <colin@colino.net>
 S:     Maintained
@@ -5761,6 +5753,11 @@ S:       Supported
 F:     drivers/edac/aspeed_edac.c
 F:     Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
 
+EDAC-BLUEFIELD
+M:     Shravan Kumar Ramani <sramani@mellanox.com>
+S:     Supported
+F:     drivers/edac/bluefield_edac.c
+
 EDAC-CALXEDA
 M:     Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
@@ -5785,10 +5782,11 @@ F:      drivers/edac/thunderx_edac*
 EDAC-CORE
 M:     Borislav Petkov <bp@alien8.de>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
+M:     Tony Luck <tony.luck@intel.com>
 R:     James Morse <james.morse@arm.com>
+R:     Robert Richter <rrichter@marvell.com>
 L:     linux-edac@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
 S:     Supported
 F:     Documentation/admin-guide/ras.rst
 F:     Documentation/driver-api/edac.rst
@@ -8933,7 +8931,7 @@ F:        security/keys/encrypted-keys/
 
 KEYS-TRUSTED
 M:     James Bottomley <jejb@linux.ibm.com>
-M:      Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 M:     Mimi Zohar <zohar@linux.ibm.com>
 L:     linux-integrity@vger.kernel.org
 L:     keyrings@vger.kernel.org
@@ -17263,6 +17261,7 @@ F:      Documentation/power/regulator/
 F:     drivers/regulator/
 F:     include/dt-bindings/regulator/
 F:     include/linux/regulator/
+K:     regulator_get_optional
 
 VRF
 M:     David Ahern <dsa@cumulusnetworks.com>
@@ -17699,8 +17698,7 @@ F:      include/uapi/linux/dqblk_xfs.h
 F:     include/uapi/linux/fsmap.h
 
 XILINX AXI ETHERNET DRIVER
-M:     Anirudha Sarangi <anirudh@xilinx.com>
-M:     John Linn <John.Linn@xilinx.com>
+M:     Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
 S:     Maintained
 F:     drivers/net/ethernet/xilinx/xilinx_axienet*
 
index 9b08f6383a52841e75efc9d3e2a8066eb5560a29..6886f22902c9cbff2f5640f0f72bfc08d0ef4356 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc8
+EXTRAVERSION =
 NAME = Bobtail Squid
 
 # *DOCUMENTATION*
index ef28e106f24723271274b4d8a1ac57b36bf13a90..344db5244547c18b53e10e1183084839fb49960b 100644 (file)
@@ -3,7 +3,8 @@
 #ifndef __ASM_IMAGE_H
 #define __ASM_IMAGE_H
 
-#define RISCV_IMAGE_MAGIC      "RISCV"
+#define RISCV_IMAGE_MAGIC      "RISCV\0\0\0"
+#define RISCV_IMAGE_MAGIC2     "RSC\x05"
 
 #define RISCV_IMAGE_FLAG_BE_SHIFT      0
 #define RISCV_IMAGE_FLAG_BE_MASK       0x1
@@ -23,7 +24,7 @@
 #define __HEAD_FLAGS           (__HEAD_FLAG(BE))
 
 #define RISCV_HEADER_VERSION_MAJOR 0
-#define RISCV_HEADER_VERSION_MINOR 1
+#define RISCV_HEADER_VERSION_MINOR 2
 
 #define RISCV_HEADER_VERSION (RISCV_HEADER_VERSION_MAJOR << 16 | \
                              RISCV_HEADER_VERSION_MINOR)
@@ -39,9 +40,8 @@
  * @version:           version
  * @res1:              reserved
  * @res2:              reserved
- * @magic:             Magic number
- * @res3:              reserved (will be used for additional RISC-V specific
- *                     header)
+ * @magic:             Magic number (RISC-V specific; deprecated)
+ * @magic2:            Magic number 2 (to match the ARM64 'magic' field pos)
  * @res4:              reserved (will be used for PE COFF offset)
  *
  * The intention is for this header format to be shared between multiple
@@ -58,7 +58,7 @@ struct riscv_image_header {
        u32 res1;
        u64 res2;
        u64 magic;
-       u32 res3;
+       u32 magic2;
        u32 res4;
 };
 #endif /* __ASSEMBLY__ */
index 0f1ba17e476fdd08749446b0891258e7f630735b..52eec0c1bf30c11079d285f7defdf000b6583f22 100644 (file)
@@ -39,9 +39,9 @@ ENTRY(_start)
        .word RISCV_HEADER_VERSION
        .word 0
        .dword 0
-       .asciz RISCV_IMAGE_MAGIC
-       .word 0
+       .ascii RISCV_IMAGE_MAGIC
        .balign 4
+       .ascii RISCV_IMAGE_MAGIC2
        .word 0
 
 .global _start_kernel
index b5fd6e85657c2fb1fabf796f29deba382307400d..d1ccc168c0714604011f859926d256d4830edecb 100644 (file)
@@ -1961,6 +1961,16 @@ int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
        case KVM_S390_MCHK:
                irq->u.mchk.mcic = s390int->parm64;
                break;
+       case KVM_S390_INT_PFAULT_INIT:
+               irq->u.ext.ext_params = s390int->parm;
+               irq->u.ext.ext_params2 = s390int->parm64;
+               break;
+       case KVM_S390_RESTART:
+       case KVM_S390_INT_CLOCK_COMP:
+       case KVM_S390_INT_CPU_TIMER:
+               break;
+       default:
+               return -EINVAL;
        }
        return 0;
 }
index f329dcb3f44cda289d7ab9291c57a153a307d686..39cff07bf2ebef248e2f9630517e4be31ab3530c 100644 (file)
@@ -1018,6 +1018,8 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
        /* mark all the pages in active slots as dirty */
        for (slotnr = 0; slotnr < slots->used_slots; slotnr++) {
                ms = slots->memslots + slotnr;
+               if (!ms->dirty_bitmap)
+                       return -EINVAL;
                /*
                 * The second half of the bitmap is only used on x86,
                 * and would be wasted otherwise, so we put it to good
@@ -4323,7 +4325,7 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp,
        }
        case KVM_S390_INTERRUPT: {
                struct kvm_s390_interrupt s390int;
-               struct kvm_s390_irq s390irq;
+               struct kvm_s390_irq s390irq = {};
 
                if (copy_from_user(&s390int, argp, sizeof(s390int)))
                        return -EFAULT;
index ccc88926bc000b9573af14f578d74098f7c7a8ff..9f41a6f5a032da07f280c29233525694bbbf8540 100644 (file)
@@ -336,25 +336,28 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
 {
        long err;
 
+       if (!IS_ENABLED(CONFIG_SYSVIPC))
+               return -ENOSYS;
+
        /* No need for backward compatibility. We can start fresh... */
        if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
-                       err = sys_semtimedop(first, ptr,
-                                            (unsigned int)second, NULL);
+                       err = ksys_semtimedop(first, ptr,
+                                             (unsigned int)second, NULL);
                        goto out;
                case SEMTIMEDOP:
-                       err = sys_semtimedop(first, ptr, (unsigned int)second,
+                       err = ksys_semtimedop(first, ptr, (unsigned int)second,
                                (const struct __kernel_timespec __user *)
-                                            (unsigned long) fifth);
+                                             (unsigned long) fifth);
                        goto out;
                case SEMGET:
-                       err = sys_semget(first, (int)second, (int)third);
+                       err = ksys_semget(first, (int)second, (int)third);
                        goto out;
                case SEMCTL: {
-                       err = sys_semctl(first, second,
-                                        (int)third | IPC_64,
-                                        (unsigned long) ptr);
+                       err = ksys_old_semctl(first, second,
+                                             (int)third | IPC_64,
+                                             (unsigned long) ptr);
                        goto out;
                }
                default:
@@ -365,18 +368,18 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        if (call <= MSGCTL) {
                switch (call) {
                case MSGSND:
-                       err = sys_msgsnd(first, ptr, (size_t)second,
+                       err = ksys_msgsnd(first, ptr, (size_t)second,
                                         (int)third);
                        goto out;
                case MSGRCV:
-                       err = sys_msgrcv(first, ptr, (size_t)second, fifth,
+                       err = ksys_msgrcv(first, ptr, (size_t)second, fifth,
                                         (int)third);
                        goto out;
                case MSGGET:
-                       err = sys_msgget((key_t)first, (int)second);
+                       err = ksys_msgget((key_t)first, (int)second);
                        goto out;
                case MSGCTL:
-                       err = sys_msgctl(first, (int)second | IPC_64, ptr);
+                       err = ksys_old_msgctl(first, (int)second | IPC_64, ptr);
                        goto out;
                default:
                        err = -ENOSYS;
@@ -396,13 +399,13 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                        goto out;
                }
                case SHMDT:
-                       err = sys_shmdt(ptr);
+                       err = ksys_shmdt(ptr);
                        goto out;
                case SHMGET:
-                       err = sys_shmget(first, (size_t)second, (int)third);
+                       err = ksys_shmget(first, (size_t)second, (int)third);
                        goto out;
                case SHMCTL:
-                       err = sys_shmctl(first, (int)second | IPC_64, ptr);
+                       err = ksys_old_shmctl(first, (int)second | IPC_64, ptr);
                        goto out;
                default:
                        err = -ENOSYS;
index 74e88e5edd9cf42792cd6e17fa4f5f516b91eff8..bdc16b0aa7c6f8846a0c6864f3d098592542892c 100644 (file)
@@ -335,6 +335,7 @@ struct kvm_mmu_page {
        int root_count;          /* Currently serving as active root */
        unsigned int unsync_children;
        struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */
+       unsigned long mmu_valid_gen;
        DECLARE_BITMAP(unsync_child_bitmap, 512);
 
 #ifdef CONFIG_X86_32
@@ -856,6 +857,7 @@ struct kvm_arch {
        unsigned long n_requested_mmu_pages;
        unsigned long n_max_mmu_pages;
        unsigned int indirect_shadow_pages;
+       unsigned long mmu_valid_gen;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
        /*
         * Hash table of struct kvm_mmu_page.
index d63e63b7d1d9581d8036a98e439185e460eaffe8..251c795b4eb3cd75991aabd6b1cffa6b3fedb8fe 100644 (file)
@@ -21,6 +21,7 @@
 #define PCI_DEVICE_ID_AMD_17H_DF_F4    0x1464
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
 
 /* Protect the PCI config register pairs used for SMN and DF indirect access. */
 static DEFINE_MUTEX(smn_mutex);
@@ -50,6 +51,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
        {}
 };
 EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
@@ -63,6 +65,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
        {}
 };
index aa5495d0f47832fbc02d102a8fb66180a550b6e9..08fb79f377936c7725af66bf7bdeaf8f94c70c02 100644 (file)
@@ -834,6 +834,10 @@ bool __init apic_needs_pit(void)
        if (!boot_cpu_has(X86_FEATURE_APIC))
                return true;
 
+       /* Virt guests may lack ARAT, but still have DEADLINE */
+       if (!boot_cpu_has(X86_FEATURE_ARAT))
+               return true;
+
        /* Deadline timer is based on TSC so no further PIT action required */
        if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
                return false;
index 210f1f5db5f75e3f320002a9b6660c62b7806683..87bcdc6dc2f0c54048447faac2f53e5d4aa1733e 100644 (file)
@@ -107,11 +107,11 @@ static struct severity {
         */
        MCESEV(
                AO, "Action optional: memory scrubbing error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB)
+               SER, MASK(MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB)
                ),
        MCESEV(
                AO, "Action optional: last level cache writeback error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
+               SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
                ),
 
        /* ignore OVER for UCNA */
index 218b277bfda3fdd2b1dd6a7569fc360855f3cc53..a63964e7cec7bdd67f2b1886adefe98f03972185 100644 (file)
@@ -2095,6 +2095,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct
        if (!direct)
                sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
        set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
+
+       /*
+        * active_mmu_pages must be a FIFO list, as kvm_zap_obsolete_pages()
+        * depends on valid pages being added to the head of the list.  See
+        * comments in kvm_zap_obsolete_pages().
+        */
        list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
        kvm_mod_used_mmu_pages(vcpu->kvm, +1);
        return sp;
@@ -2244,7 +2250,7 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
 #define for_each_valid_sp(_kvm, _sp, _gfn)                             \
        hlist_for_each_entry(_sp,                                       \
          &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \
-               if ((_sp)->role.invalid) {    \
+               if (is_obsolete_sp((_kvm), (_sp)) || (_sp)->role.invalid) {    \
                } else
 
 #define for_each_gfn_indirect_valid_sp(_kvm, _sp, _gfn)                        \
@@ -2301,6 +2307,11 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) { }
 static void mmu_audit_disable(void) { }
 #endif
 
+static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+       return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen);
+}
+
 static bool kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
                         struct list_head *invalid_list)
 {
@@ -2525,6 +2536,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                if (level > PT_PAGE_TABLE_LEVEL && need_sync)
                        flush |= kvm_sync_pages(vcpu, gfn, &invalid_list);
        }
+       sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
        clear_page(sp->spt);
        trace_kvm_mmu_get_page(sp, true);
 
@@ -4233,6 +4245,13 @@ static bool fast_cr3_switch(struct kvm_vcpu *vcpu, gpa_t new_cr3,
                        return false;
 
                if (cached_root_available(vcpu, new_cr3, new_role)) {
+                       /*
+                        * It is possible that the cached previous root page is
+                        * obsolete because of a change in the MMU generation
+                        * number. However, changing the generation number is
+                        * accompanied by KVM_REQ_MMU_RELOAD, which will free
+                        * the root set here and allocate a new one.
+                        */
                        kvm_make_request(KVM_REQ_LOAD_CR3, vcpu);
                        if (!skip_tlb_flush) {
                                kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
@@ -5649,11 +5668,89 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
        return alloc_mmu_pages(vcpu);
 }
 
+
+static void kvm_zap_obsolete_pages(struct kvm *kvm)
+{
+       struct kvm_mmu_page *sp, *node;
+       LIST_HEAD(invalid_list);
+       int ign;
+
+restart:
+       list_for_each_entry_safe_reverse(sp, node,
+             &kvm->arch.active_mmu_pages, link) {
+               /*
+                * No obsolete valid page exists before a newly created page
+                * since active_mmu_pages is a FIFO list.
+                */
+               if (!is_obsolete_sp(kvm, sp))
+                       break;
+
+               /*
+                * Do not repeatedly zap a root page to avoid unnecessary
+                * KVM_REQ_MMU_RELOAD, otherwise we may not be able to
+                * progress:
+                *    vcpu 0                        vcpu 1
+                *                         call vcpu_enter_guest():
+                *                            1): handle KVM_REQ_MMU_RELOAD
+                *                                and require mmu-lock to
+                *                                load mmu
+                * repeat:
+                *    1): zap root page and
+                *        send KVM_REQ_MMU_RELOAD
+                *
+                *    2): if (cond_resched_lock(mmu-lock))
+                *
+                *                            2): hold mmu-lock and load mmu
+                *
+                *                            3): see KVM_REQ_MMU_RELOAD bit
+                *                                on vcpu->requests is set
+                *                                then return 1 to call
+                *                                vcpu_enter_guest() again.
+                *            goto repeat;
+                *
+                * Since we are reversely walking the list and the invalid
+                * list will be moved to the head, skip the invalid page
+                * can help us to avoid the infinity list walking.
+                */
+               if (sp->role.invalid)
+                       continue;
+
+               if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
+                       kvm_mmu_commit_zap_page(kvm, &invalid_list);
+                       cond_resched_lock(&kvm->mmu_lock);
+                       goto restart;
+               }
+
+               if (__kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list, &ign))
+                       goto restart;
+       }
+
+       kvm_mmu_commit_zap_page(kvm, &invalid_list);
+}
+
+/*
+ * Fast invalidate all shadow pages and use lock-break technique
+ * to zap obsolete pages.
+ *
+ * It's required when memslot is being deleted or VM is being
+ * destroyed, in these cases, we should ensure that KVM MMU does
+ * not use any resource of the being-deleted slot or all slots
+ * after calling the function.
+ */
+static void kvm_mmu_zap_all_fast(struct kvm *kvm)
+{
+       spin_lock(&kvm->mmu_lock);
+       kvm->arch.mmu_valid_gen++;
+
+       kvm_zap_obsolete_pages(kvm);
+       spin_unlock(&kvm->mmu_lock);
+}
+
 static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm,
                        struct kvm_memory_slot *slot,
                        struct kvm_page_track_notifier_node *node)
 {
-       kvm_mmu_zap_all(kvm);
+       kvm_mmu_zap_all_fast(kvm);
 }
 
 void kvm_mmu_init_vm(struct kvm *kvm)
index ced9fba32598d8435ef9f1d59e963f5c3e134d20..a3cba321b5c5ddb7b2730835c01635c0307e1bb1 100644 (file)
@@ -4540,6 +4540,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        int len;
        gva_t gva = 0;
        struct vmcs12 *vmcs12;
+       struct x86_exception e;
        short offset;
 
        if (!nested_vmx_check_permission(vcpu))
@@ -4588,7 +4589,8 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
                                vmx_instruction_info, true, len, &gva))
                        return 1;
                /* _system ok, nested_vmx_check_permission has verified cpl=0 */
-               kvm_write_guest_virt_system(vcpu, gva, &field_value, len, NULL);
+               if (kvm_write_guest_virt_system(vcpu, gva, &field_value, len, &e))
+                       kvm_inject_page_fault(vcpu, &e);
        }
 
        return nested_vmx_succeed(vcpu);
index 290c3c3efb8770ae7b343e227080cc4bca0859fb..91602d310a3fbf0be916d794d0eff9c3beb1b9b2 100644 (file)
@@ -5312,6 +5312,13 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
        /* kvm_write_guest_virt_system can pull in tons of pages. */
        vcpu->arch.l1tf_flush_l1d = true;
 
+       /*
+        * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED
+        * is returned, but our callers are not ready for that and they blindly
+        * call kvm_inject_page_fault.  Ensure that they at least do not leak
+        * uninitialized kernel stack memory into cr2 and error code.
+        */
+       memset(exception, 0, sizeof(*exception));
        return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
                                           PFERR_WRITE_MASK, exception);
 }
index 8901a1f89cf57bd16cbf79d6625a804274c6afe4..10fb42da0007e9d3c914143ec4e427dd1eec42f5 100644 (file)
@@ -18,37 +18,40 @@ targets += purgatory.ro
 KASAN_SANITIZE := n
 KCOV_INSTRUMENT := n
 
+# These are adjustments to the compiler flags used for objects that
+# make up the standalone purgatory.ro
+
+PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
+PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss
+
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
 # sure how to relocate those.
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_sha256.o         += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_purgatory.o      += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_string.o         += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_kexec-purgatory.o        += $(CC_FLAGS_FTRACE)
+PURGATORY_CFLAGS_REMOVE                += $(CC_FLAGS_FTRACE)
 endif
 
 ifdef CONFIG_STACKPROTECTOR
-CFLAGS_REMOVE_sha256.o         += -fstack-protector
-CFLAGS_REMOVE_purgatory.o      += -fstack-protector
-CFLAGS_REMOVE_string.o         += -fstack-protector
-CFLAGS_REMOVE_kexec-purgatory.o        += -fstack-protector
+PURGATORY_CFLAGS_REMOVE                += -fstack-protector
 endif
 
 ifdef CONFIG_STACKPROTECTOR_STRONG
-CFLAGS_REMOVE_sha256.o         += -fstack-protector-strong
-CFLAGS_REMOVE_purgatory.o      += -fstack-protector-strong
-CFLAGS_REMOVE_string.o         += -fstack-protector-strong
-CFLAGS_REMOVE_kexec-purgatory.o        += -fstack-protector-strong
+PURGATORY_CFLAGS_REMOVE                += -fstack-protector-strong
 endif
 
 ifdef CONFIG_RETPOLINE
-CFLAGS_REMOVE_sha256.o         += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_purgatory.o      += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_string.o         += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_kexec-purgatory.o        += $(RETPOLINE_CFLAGS)
+PURGATORY_CFLAGS_REMOVE                += $(RETPOLINE_CFLAGS)
 endif
 
+CFLAGS_REMOVE_purgatory.o      += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_purgatory.o             += $(PURGATORY_CFLAGS)
+
+CFLAGS_REMOVE_sha256.o         += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_sha256.o                        += $(PURGATORY_CFLAGS)
+
+CFLAGS_REMOVE_string.o         += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_string.o                        += $(PURGATORY_CFLAGS)
+
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
                $(call if_changed,ld)
 
index e5e1b3a01b1a3e9099f5f745bc0e3a04320d2ed2..e72843fe41dfeea565b2c0dc2722688561670228 100644 (file)
@@ -588,14 +588,6 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
        }
 
        map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
-       if (!map->debugfs) {
-               dev_warn(map->dev,
-                        "Failed to create %s debugfs directory\n", name);
-
-               kfree(map->debugfs_name);
-               map->debugfs_name = NULL;
-               return;
-       }
 
        debugfs_create_file("name", 0400, map->debugfs,
                            map, &regmap_name_fops);
@@ -672,10 +664,6 @@ void regmap_debugfs_initcall(void)
        struct regmap_debugfs_node *node, *tmp;
 
        regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
-       if (!regmap_debugfs_root) {
-               pr_warn("regmap: Failed to create debugfs root\n");
-               return;
-       }
 
        mutex_lock(&regmap_debugfs_early_lock);
        list_for_each_entry_safe(node, tmp, &regmap_debugfs_early_list, link) {
index c9dc70ceca5f104a9c329f0d01fd7bd6a5c9bed7..3d64c9331a82aa61cdab5be03fca8c5c08b4aea6 100644 (file)
@@ -370,7 +370,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret < 0) {
                        dev_err(map->dev, "IRQ thread failed to resume: %d\n",
                                ret);
-                       pm_runtime_put(map->dev);
                        goto exit;
                }
        }
@@ -425,8 +424,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                        dev_err(map->dev,
                                                "Failed to read IRQ status %d\n",
                                                ret);
-                                       if (chip->runtime_pm)
-                                               pm_runtime_put(map->dev);
                                        goto exit;
                                }
                        }
@@ -478,8 +475,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                dev_err(map->dev,
                                        "Failed to read IRQ status: %d\n",
                                        ret);
-                               if (chip->runtime_pm)
-                                       pm_runtime_put(map->dev);
                                goto exit;
                        }
                }
@@ -513,10 +508,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+exit:
        if (chip->runtime_pm)
                pm_runtime_put(map->dev);
 
-exit:
        if (chip->handle_post_irq)
                chip->handle_post_irq(chip->irq_drv_data);
 
index a0e84538cec88bfb7b80ee0dae4cef69282b589f..1fa58c059cbf5c6e115ccf5c3970b1165afe89b2 100644 (file)
@@ -337,7 +337,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 
        usb_free_urb(urb);
 
-       return 0;
+       return err;
 }
 
 static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
index 5cf0734eb31bf923de8c18cb8e8ad5d23a284a2f..ba41490543040a723bbdb868626225be0612846d 100644 (file)
@@ -384,6 +384,9 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x13d3, 0x3526), .driver_info = BTUSB_REALTEK },
        { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
 
+       /* Additional Realtek 8822CE Bluetooth devices */
+       { USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK },
+
        /* Silicon Wave based devices */
        { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
 
@@ -1170,10 +1173,6 @@ static int btusb_open(struct hci_dev *hdev)
        }
 
        data->intf->needs_remote_wakeup = 1;
-       /* device specific wakeup source enabled and required for USB
-        * remote wakeup while host is suspended
-        */
-       device_wakeup_enable(&data->udev->dev);
 
        if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
                goto done;
@@ -1238,7 +1237,6 @@ static int btusb_close(struct hci_dev *hdev)
                goto failed;
 
        data->intf->needs_remote_wakeup = 0;
-       device_wakeup_disable(&data->udev->dev);
        usb_autopm_put_interface(data->intf);
 
 failed:
index 9a970fd1975aab411d96912593606b5096d81180..31dec435767be3757adcfeadad1ce2cfbcad620a 100644 (file)
@@ -309,13 +309,14 @@ static void qca_wq_awake_device(struct work_struct *work)
                                            ws_awake_device);
        struct hci_uart *hu = qca->hu;
        unsigned long retrans_delay;
+       unsigned long flags;
 
        BT_DBG("hu %p wq awake device", hu);
 
        /* Vote for serial clock */
        serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
 
-       spin_lock(&qca->hci_ibs_lock);
+       spin_lock_irqsave(&qca->hci_ibs_lock, flags);
 
        /* Send wake indication to device */
        if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
@@ -327,7 +328,7 @@ static void qca_wq_awake_device(struct work_struct *work)
        retrans_delay = msecs_to_jiffies(qca->wake_retrans);
        mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
 
-       spin_unlock(&qca->hci_ibs_lock);
+       spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
 
        /* Actually send the packets */
        hci_uart_tx_wakeup(hu);
@@ -338,12 +339,13 @@ static void qca_wq_awake_rx(struct work_struct *work)
        struct qca_data *qca = container_of(work, struct qca_data,
                                            ws_awake_rx);
        struct hci_uart *hu = qca->hu;
+       unsigned long flags;
 
        BT_DBG("hu %p wq awake rx", hu);
 
        serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
 
-       spin_lock(&qca->hci_ibs_lock);
+       spin_lock_irqsave(&qca->hci_ibs_lock, flags);
        qca->rx_ibs_state = HCI_IBS_RX_AWAKE;
 
        /* Always acknowledge device wake up,
@@ -354,7 +356,7 @@ static void qca_wq_awake_rx(struct work_struct *work)
 
        qca->ibs_sent_wacks++;
 
-       spin_unlock(&qca->hci_ibs_lock);
+       spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
 
        /* Actually send the packets */
        hci_uart_tx_wakeup(hu);
index 88a3c06fc153e087640460a4c52713377729a1b5..9c37047f4b5625b8ea3fd5b3b93796729d1b4bdc 100644 (file)
@@ -164,6 +164,11 @@ config TCG_VTPM_PROXY
          /dev/vtpmX and a server-side file descriptor on which the vTPM
          can receive commands.
 
+config TCG_FTPM_TEE
+       tristate "TEE based fTPM Interface"
+       depends on TEE && OPTEE
+       help
+         This driver proxies for firmware TPM running in TEE.
 
 source "drivers/char/tpm/st33zp24/Kconfig"
 endif # TCG_TPM
index a01c4cab902a662bd842427e2708bbbfd8fbc660..c354cdff9c625fad7f813a269924053de0293a32 100644 (file)
@@ -33,3 +33,4 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/
 obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
 obj-$(CONFIG_TCG_CRB) += tpm_crb.o
 obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o
+obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o
index 4838c6a9f0f2c702e932066fba62d7a336a87f36..3d6d394a866188107f48495298dfe5a43d8e93f0 100644 (file)
@@ -287,12 +287,9 @@ static void tpm_devs_release(struct device *dev)
  * @dev: device to which the chip is associated.
  *
  * Issues a TPM2_Shutdown command prior to loss of power, as required by the
- * TPM 2.0 spec.
- * Then, calls bus- and device- specific shutdown code.
+ * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code.
  *
- * XXX: This codepath relies on the fact that sysfs is not enabled for
- * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
- * has sysfs support enabled before TPM sysfs's implicit locking is fixed.
+ * Return: always 0 (i.e. success)
  */
 static int tpm_class_shutdown(struct device *dev)
 {
index d9caedda075b2f5e690b5a34f086e1902ac774b4..edfa89160010c5cf29e1d2d4e76016323a45e306 100644 (file)
@@ -329,16 +329,9 @@ static const struct attribute_group tpm_dev_group = {
 
 void tpm_sysfs_add_device(struct tpm_chip *chip)
 {
-       /* XXX: If you wish to remove this restriction, you must first update
-        * tpm_sysfs to explicitly lock chip->ops.
-        */
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                return;
 
-       /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
-        * is called before ops is null'd and the sysfs core synchronizes this
-        * removal so that no callbacks are running or can run again
-        */
        WARN_ON(chip->groups_cnt != 0);
        chip->groups[chip->groups_cnt++] = &tpm_dev_group;
 }
diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c
new file mode 100644 (file)
index 0000000..6640a14
--- /dev/null
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation
+ *
+ * Implements a firmware TPM as described here:
+ * https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/
+ *
+ * A reference implementation is available here:
+ * https://github.com/microsoft/ms-tpm-20-ref/tree/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM
+ */
+
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/tee_drv.h>
+#include <linux/tpm.h>
+#include <linux/uuid.h>
+
+#include "tpm.h"
+#include "tpm_ftpm_tee.h"
+
+/*
+ * TA_FTPM_UUID: BC50D971-D4C9-42C4-82CB-343FB7F37896
+ *
+ * Randomly generated, and must correspond to the GUID on the TA side.
+ * Defined here in the reference implementation:
+ * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
+ */
+static const uuid_t ftpm_ta_uuid =
+       UUID_INIT(0xBC50D971, 0xD4C9, 0x42C4,
+                 0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96);
+
+/**
+ * ftpm_tee_tpm_op_recv - retrieve fTPM response.
+ * @chip:      the tpm_chip description as specified in driver/char/tpm/tpm.h.
+ * @buf:       the buffer to store data.
+ * @count:     the number of bytes to read.
+ *
+ * Return:
+ *     In case of success the number of bytes received.
+ *     On failure, -errno.
+ */
+static int ftpm_tee_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
+       size_t len;
+
+       len = pvt_data->resp_len;
+       if (count < len) {
+               dev_err(&chip->dev,
+                       "%s: Invalid size in recv: count=%zd, resp_len=%zd\n",
+                       __func__, count, len);
+               return -EIO;
+       }
+
+       memcpy(buf, pvt_data->resp_buf, len);
+       pvt_data->resp_len = 0;
+
+       return len;
+}
+
+/**
+ * ftpm_tee_tpm_op_send - send TPM commands through the TEE shared memory.
+ * @chip:      the tpm_chip description as specified in driver/char/tpm/tpm.h
+ * @buf:       the buffer to send.
+ * @len:       the number of bytes to send.
+ *
+ * Return:
+ *     In case of success, returns 0.
+ *     On failure, -errno
+ */
+static int ftpm_tee_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
+       size_t resp_len;
+       int rc;
+       u8 *temp_buf;
+       struct tpm_header *resp_header;
+       struct tee_ioctl_invoke_arg transceive_args;
+       struct tee_param command_params[4];
+       struct tee_shm *shm = pvt_data->shm;
+
+       if (len > MAX_COMMAND_SIZE) {
+               dev_err(&chip->dev,
+                       "%s: len=%zd exceeds MAX_COMMAND_SIZE supported by fTPM TA\n",
+                       __func__, len);
+               return -EIO;
+       }
+
+       memset(&transceive_args, 0, sizeof(transceive_args));
+       memset(command_params, 0, sizeof(command_params));
+       pvt_data->resp_len = 0;
+
+       /* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of fTPM TA */
+       transceive_args = (struct tee_ioctl_invoke_arg) {
+               .func = FTPM_OPTEE_TA_SUBMIT_COMMAND,
+               .session = pvt_data->session,
+               .num_params = 4,
+       };
+
+       /* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
+       command_params[0] = (struct tee_param) {
+               .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+               .u.memref = {
+                       .shm = shm,
+                       .size = len,
+                       .shm_offs = 0,
+               },
+       };
+
+       temp_buf = tee_shm_get_va(shm, 0);
+       if (IS_ERR(temp_buf)) {
+               dev_err(&chip->dev, "%s: tee_shm_get_va failed for transmit\n",
+                       __func__);
+               return PTR_ERR(temp_buf);
+       }
+       memset(temp_buf, 0, (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE));
+       memcpy(temp_buf, buf, len);
+
+       command_params[1] = (struct tee_param) {
+               .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+               .u.memref = {
+                       .shm = shm,
+                       .size = MAX_RESPONSE_SIZE,
+                       .shm_offs = MAX_COMMAND_SIZE,
+               },
+       };
+
+       rc = tee_client_invoke_func(pvt_data->ctx, &transceive_args,
+                                   command_params);
+       if ((rc < 0) || (transceive_args.ret != 0)) {
+               dev_err(&chip->dev, "%s: SUBMIT_COMMAND invoke error: 0x%x\n",
+                       __func__, transceive_args.ret);
+               return (rc < 0) ? rc : transceive_args.ret;
+       }
+
+       temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
+       if (IS_ERR(temp_buf)) {
+               dev_err(&chip->dev, "%s: tee_shm_get_va failed for receive\n",
+                       __func__);
+               return PTR_ERR(temp_buf);
+       }
+
+       resp_header = (struct tpm_header *)temp_buf;
+       resp_len = be32_to_cpu(resp_header->length);
+
+       /* sanity check resp_len */
+       if (resp_len < TPM_HEADER_SIZE) {
+               dev_err(&chip->dev, "%s: tpm response header too small\n",
+                       __func__);
+               return -EIO;
+       }
+       if (resp_len > MAX_RESPONSE_SIZE) {
+               dev_err(&chip->dev,
+                       "%s: resp_len=%zd exceeds MAX_RESPONSE_SIZE\n",
+                       __func__, resp_len);
+               return -EIO;
+       }
+
+       /* sanity checks look good, cache the response */
+       memcpy(pvt_data->resp_buf, temp_buf, resp_len);
+       pvt_data->resp_len = resp_len;
+
+       return 0;
+}
+
+static void ftpm_tee_tpm_op_cancel(struct tpm_chip *chip)
+{
+       /* not supported */
+}
+
+static u8 ftpm_tee_tpm_op_status(struct tpm_chip *chip)
+{
+       return 0;
+}
+
+static bool ftpm_tee_tpm_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return 0;
+}
+
+static const struct tpm_class_ops ftpm_tee_tpm_ops = {
+       .flags = TPM_OPS_AUTO_STARTUP,
+       .recv = ftpm_tee_tpm_op_recv,
+       .send = ftpm_tee_tpm_op_send,
+       .cancel = ftpm_tee_tpm_op_cancel,
+       .status = ftpm_tee_tpm_op_status,
+       .req_complete_mask = 0,
+       .req_complete_val = 0,
+       .req_canceled = ftpm_tee_tpm_req_canceled,
+};
+
+/*
+ * Check whether this driver supports the fTPM TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+       /*
+        * Currently this driver only support GP Complaint OPTEE based fTPM TA
+        */
+       if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
+               (ver->gen_caps & TEE_GEN_CAP_GP))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * ftpm_tee_probe - initialize the fTPM
+ * @pdev: the platform_device description.
+ *
+ * Return:
+ *     On success, 0. On failure, -errno.
+ */
+static int ftpm_tee_probe(struct platform_device *pdev)
+{
+       int rc;
+       struct tpm_chip *chip;
+       struct device *dev = &pdev->dev;
+       struct ftpm_tee_private *pvt_data = NULL;
+       struct tee_ioctl_open_session_arg sess_arg;
+
+       pvt_data = devm_kzalloc(dev, sizeof(struct ftpm_tee_private),
+                               GFP_KERNEL);
+       if (!pvt_data)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, pvt_data);
+
+       /* Open context with TEE driver */
+       pvt_data->ctx = tee_client_open_context(NULL, ftpm_tee_match, NULL,
+                                               NULL);
+       if (IS_ERR(pvt_data->ctx)) {
+               if (PTR_ERR(pvt_data->ctx) == -ENOENT)
+                       return -EPROBE_DEFER;
+               dev_err(dev, "%s: tee_client_open_context failed\n", __func__);
+               return PTR_ERR(pvt_data->ctx);
+       }
+
+       /* Open a session with fTPM TA */
+       memset(&sess_arg, 0, sizeof(sess_arg));
+       memcpy(sess_arg.uuid, ftpm_ta_uuid.b, TEE_IOCTL_UUID_LEN);
+       sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+       sess_arg.num_params = 0;
+
+       rc = tee_client_open_session(pvt_data->ctx, &sess_arg, NULL);
+       if ((rc < 0) || (sess_arg.ret != 0)) {
+               dev_err(dev, "%s: tee_client_open_session failed, err=%x\n",
+                       __func__, sess_arg.ret);
+               rc = -EINVAL;
+               goto out_tee_session;
+       }
+       pvt_data->session = sess_arg.session;
+
+       /* Allocate dynamic shared memory with fTPM TA */
+       pvt_data->shm = tee_shm_alloc(pvt_data->ctx,
+                                     MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE,
+                                     TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+       if (IS_ERR(pvt_data->shm)) {
+               dev_err(dev, "%s: tee_shm_alloc failed\n", __func__);
+               rc = -ENOMEM;
+               goto out_shm_alloc;
+       }
+
+       /* Allocate new struct tpm_chip instance */
+       chip = tpm_chip_alloc(dev, &ftpm_tee_tpm_ops);
+       if (IS_ERR(chip)) {
+               dev_err(dev, "%s: tpm_chip_alloc failed\n", __func__);
+               rc = PTR_ERR(chip);
+               goto out_chip_alloc;
+       }
+
+       pvt_data->chip = chip;
+       pvt_data->chip->flags |= TPM_CHIP_FLAG_TPM2;
+
+       /* Create a character device for the fTPM */
+       rc = tpm_chip_register(pvt_data->chip);
+       if (rc) {
+               dev_err(dev, "%s: tpm_chip_register failed with rc=%d\n",
+                       __func__, rc);
+               goto out_chip;
+       }
+
+       return 0;
+
+out_chip:
+       put_device(&pvt_data->chip->dev);
+out_chip_alloc:
+       tee_shm_free(pvt_data->shm);
+out_shm_alloc:
+       tee_client_close_session(pvt_data->ctx, pvt_data->session);
+out_tee_session:
+       tee_client_close_context(pvt_data->ctx);
+
+       return rc;
+}
+
+/**
+ * ftpm_tee_remove - remove the TPM device
+ * @pdev: the platform_device description.
+ *
+ * Return:
+ *     0 always.
+ */
+static int ftpm_tee_remove(struct platform_device *pdev)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
+
+       /* Release the chip */
+       tpm_chip_unregister(pvt_data->chip);
+
+       /* frees chip */
+       put_device(&pvt_data->chip->dev);
+
+       /* Free the shared memory pool */
+       tee_shm_free(pvt_data->shm);
+
+       /* close the existing session with fTPM TA*/
+       tee_client_close_session(pvt_data->ctx, pvt_data->session);
+
+       /* close the context with TEE driver */
+       tee_client_close_context(pvt_data->ctx);
+
+       /* memory allocated with devm_kzalloc() is freed automatically */
+
+       return 0;
+}
+
+static const struct of_device_id of_ftpm_tee_ids[] = {
+       { .compatible = "microsoft,ftpm" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
+
+static struct platform_driver ftpm_tee_driver = {
+       .driver = {
+               .name = "ftpm-tee",
+               .of_match_table = of_match_ptr(of_ftpm_tee_ids),
+       },
+       .probe = ftpm_tee_probe,
+       .remove = ftpm_tee_remove,
+};
+
+module_platform_driver(ftpm_tee_driver);
+
+MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
+MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/tpm/tpm_ftpm_tee.h b/drivers/char/tpm/tpm_ftpm_tee.h
new file mode 100644 (file)
index 0000000..f98daa7
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation
+ */
+
+#ifndef __TPM_FTPM_TEE_H__
+#define __TPM_FTPM_TEE_H__
+
+#include <linux/tee_drv.h>
+#include <linux/tpm.h>
+#include <linux/uuid.h>
+
+/* The TAFs ID implemented in this TA */
+#define FTPM_OPTEE_TA_SUBMIT_COMMAND  (0)
+#define FTPM_OPTEE_TA_EMULATE_PPI     (1)
+
+/* max. buffer size supported by fTPM  */
+#define MAX_COMMAND_SIZE       4096
+#define MAX_RESPONSE_SIZE      4096
+
+/**
+ * struct ftpm_tee_private - fTPM's private data
+ * @chip:     struct tpm_chip instance registered with tpm framework.
+ * @state:    internal state
+ * @session:  fTPM TA session identifier.
+ * @resp_len: cached response buffer length.
+ * @resp_buf: cached response buffer.
+ * @ctx:      TEE context handler.
+ * @shm:      Memory pool shared with fTPM TA in TEE.
+ */
+struct ftpm_tee_private {
+       struct tpm_chip *chip;
+       u32 session;
+       size_t resp_len;
+       u8 resp_buf[MAX_RESPONSE_SIZE];
+       struct tee_context *ctx;
+       struct tee_shm *shm;
+};
+
+#endif /* __TPM_FTPM_TEE_H__ */
index c3181ea9f27132e4013c6a1c86612d296a803c3d..270f43acbb77d485939c13c55026b9a942110bb1 100644 (file)
@@ -980,6 +980,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                        goto out_err;
                }
 
+               tpm_chip_start(chip);
+               chip->flags |= TPM_CHIP_FLAG_IRQ;
                if (irq) {
                        tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
                                                 irq);
@@ -989,6 +991,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                } else {
                        tpm_tis_probe_irq(chip, intmask);
                }
+               tpm_chip_stop(chip);
        }
 
        rc = tpm_chip_register(chip);
index 200c04ce5b0ed20361157a1c655c99bb14bee47c..2a2603bfb918547e86720dac5f0584dc57f33fdb 100644 (file)
@@ -510,4 +510,11 @@ config EDAC_ASPEED
          First, ECC must be configured in the bootloader. Then, this driver
          will expose error counters via the EDAC kernel framework.
 
+config EDAC_BLUEFIELD
+       tristate "Mellanox BlueField Memory ECC"
+       depends on ARM64 && ((MELLANOX_PLATFORM && ACPI) || COMPILE_TEST)
+       help
+         Support for error detection and correction on the
+         Mellanox BlueField SoCs.
+
 endif # EDAC
index 165ca65e1a3a55a9d0181fe5c23b71ba956704be..d265ff9311f02eb914e857d2593934da8e037f68 100644 (file)
@@ -85,3 +85,4 @@ obj-$(CONFIG_EDAC_XGENE)              += xgene_edac.o
 obj-$(CONFIG_EDAC_TI)                  += ti_edac.o
 obj-$(CONFIG_EDAC_QCOM)                        += qcom_edac.o
 obj-$(CONFIG_EDAC_ASPEED)              += aspeed_edac.o
+obj-$(CONFIG_EDAC_BLUEFIELD)           += bluefield_edac.o
index c2e693e34d434e53c801546d02700e5ee219644f..fbda4b876afd19937db8dcd7f0846006bd6b7743 100644 (file)
@@ -222,7 +222,6 @@ static unsigned long get_total_mem(void)
 static const struct of_device_id altr_sdram_ctrl_of_match[] = {
        { .compatible = "altr,sdram-edac", .data = &c5_data},
        { .compatible = "altr,sdram-edac-a10", .data = &a10_data},
-       { .compatible = "altr,sdram-edac-s10", .data = &a10_data},
        {},
 };
 MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
@@ -1170,6 +1169,24 @@ static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat)
        return 0;
 }
 
+/*********************** SDRAM EDAC Device Functions *********************/
+
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+
+static const struct edac_device_prv_data s10_sdramecc_data = {
+       .setup = altr_check_ecc_deps,
+       .ce_clear_mask = ALTR_S10_ECC_SERRPENA,
+       .ue_clear_mask = ALTR_S10_ECC_DERRPENA,
+       .ecc_enable_mask = ALTR_S10_ECC_EN,
+       .ecc_en_ofst = ALTR_S10_ECC_CTRL_SDRAM_OFST,
+       .ce_set_mask = ALTR_S10_ECC_TSERRA,
+       .ue_set_mask = ALTR_S10_ECC_TDERRA,
+       .set_err_ofst = ALTR_S10_ECC_INTTEST_OFST,
+       .ecc_irq_handler = altr_edac_a10_ecc_irq,
+       .inject_fops = &altr_edac_a10_device_inject_fops,
+};
+#endif /* CONFIG_EDAC_ALTERA_SDRAM */
+
 /*********************** OCRAM EDAC Device Functions *********************/
 
 #ifdef CONFIG_EDAC_ALTERA_OCRAM
@@ -1758,6 +1775,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = {
 #endif
 #ifdef CONFIG_EDAC_ALTERA_SDMMC
        { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data },
+#endif
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+       { .compatible = "altr,sdram-edac-s10", .data = &s10_sdramecc_data },
 #endif
        {},
 };
@@ -1866,6 +1886,7 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc)
        struct altr_arria10_edac *edac = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        int irq = irq_desc_get_irq(desc);
+       unsigned long bits;
 
        dberr = (irq == edac->db_irq) ? 1 : 0;
        sm_offset = dberr ? A10_SYSMGR_ECC_INTSTAT_DERR_OFST :
@@ -1875,7 +1896,8 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc)
 
        regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status);
 
-       for_each_set_bit(bit, (unsigned long *)&irq_status, 32) {
+       bits = irq_status;
+       for_each_set_bit(bit, &bits, 32) {
                irq = irq_linear_revmap(edac->domain, dberr * 32 + bit);
                if (irq)
                        generic_handle_irq(irq);
@@ -1889,6 +1911,10 @@ static int validate_parent_available(struct device_node *np)
        struct device_node *parent;
        int ret = 0;
 
+       /* SDRAM must be present for Linux (implied parent) */
+       if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
+               return 0;
+
        /* Ensure parent device is enabled if parent node exists */
        parent = of_parse_phandle(np, "altr,ecc-parent", 0);
        if (parent && !of_device_is_available(parent))
@@ -1898,6 +1924,22 @@ static int validate_parent_available(struct device_node *np)
        return ret;
 }
 
+static int get_s10_sdram_edac_resource(struct device_node *np,
+                                      struct resource *res)
+{
+       struct device_node *parent;
+       int ret;
+
+       parent = of_parse_phandle(np, "altr,sdr-syscon", 0);
+       if (!parent)
+               return -ENODEV;
+
+       ret = of_address_to_resource(parent, 0, res);
+       of_node_put(parent);
+
+       return ret;
+}
+
 static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
                                    struct device_node *np)
 {
@@ -1925,7 +1967,11 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
        if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
                return -ENOMEM;
 
-       rc = of_address_to_resource(np, 0, &res);
+       if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
+               rc = get_s10_sdram_edac_resource(np, &res);
+       else
+               rc = of_address_to_resource(np, 0, &res);
+
        if (rc < 0) {
                edac_printk(KERN_ERR, EDAC_DEVICE,
                            "%s: no resource address\n", ecc_name);
@@ -2231,13 +2277,15 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
                    of_device_is_compatible(child, "altr,socfpga-dma-ecc") ||
                    of_device_is_compatible(child, "altr,socfpga-usb-ecc") ||
                    of_device_is_compatible(child, "altr,socfpga-qspi-ecc") ||
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+                   of_device_is_compatible(child, "altr,sdram-edac-s10") ||
+#endif
                    of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc"))
 
                        altr_edac_a10_device_add(edac, child);
 
 #ifdef CONFIG_EDAC_ALTERA_SDRAM
-               else if ((of_device_is_compatible(child, "altr,sdram-edac-a10")) ||
-                        (of_device_is_compatible(child, "altr,sdram-edac-s10")))
+               else if (of_device_is_compatible(child, "altr,sdram-edac-a10"))
                        of_platform_populate(pdev->dev.of_node,
                                             altr_sdram_ctrl_of_match,
                                             NULL, &pdev->dev);
index 55654cc4bcdf35373517dd2c95d2af109d47de28..3727e72c8c2e70a98df2854608e1858bafb7d1fe 100644 (file)
@@ -289,6 +289,29 @@ struct altr_sdram_mc_data {
 #define ALTR_A10_ECC_INIT_WATCHDOG_10US      10000
 
 /************* Stratix10 Defines **************/
+#define ALTR_S10_ECC_CTRL_SDRAM_OFST      0x00
+#define ALTR_S10_ECC_EN                   BIT(0)
+
+#define ALTR_S10_ECC_ERRINTEN_OFST        0x10
+#define ALTR_S10_ECC_ERRINTENS_OFST       0x14
+#define ALTR_S10_ECC_ERRINTENR_OFST       0x18
+#define ALTR_S10_ECC_SERRINTEN            BIT(0)
+
+#define ALTR_S10_ECC_INTMODE_OFST         0x1C
+#define ALTR_S10_ECC_INTMODE              BIT(0)
+
+#define ALTR_S10_ECC_INTSTAT_OFST         0x20
+#define ALTR_S10_ECC_SERRPENA             BIT(0)
+#define ALTR_S10_ECC_DERRPENA             BIT(8)
+#define ALTR_S10_ECC_ERRPENA_MASK         (ALTR_S10_ECC_SERRPENA | \
+                                          ALTR_S10_ECC_DERRPENA)
+
+#define ALTR_S10_ECC_INTTEST_OFST         0x24
+#define ALTR_S10_ECC_TSERRA               BIT(0)
+#define ALTR_S10_ECC_TDERRA               BIT(8)
+#define ALTR_S10_ECC_TSERRB               BIT(16)
+#define ALTR_S10_ECC_TDERRB               BIT(24)
+
 #define ALTR_S10_DERR_ADDRA_OFST          0x2C
 
 /* Stratix10 ECC Manager Defines */
@@ -300,7 +323,7 @@ struct altr_sdram_mc_data {
 #define S10_SYSMGR_UE_ADDR_OFST           0x224
 
 #define S10_DDR0_IRQ_MASK                 BIT(16)
-#define S10_DBE_IRQ_MASK                  0x3FE
+#define S10_DBE_IRQ_MASK                  0x3FFFE
 
 /* Define ECC Block Offsets for peripherals */
 #define ECC_BLK_ADDRESS_OFST              0x40
index 873437be86d9c2d571953ef7624c06a0bb868f78..c1d4536ae466e7b3d683ecb0741baf7e7f653407 100644 (file)
@@ -788,51 +788,45 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
                 (dclr & BIT(15)) ?  "yes" : "no");
 }
 
-/*
- * The Address Mask should be a contiguous set of bits in the non-interleaved
- * case. So to check for CS interleaving, find the most- and least-significant
- * bits of the mask, generate a contiguous bitmask, and compare the two.
- */
-static bool f17_cs_interleaved(struct amd64_pvt *pvt, u8 ctrl, int cs)
+#define CS_EVEN_PRIMARY                BIT(0)
+#define CS_ODD_PRIMARY         BIT(1)
+#define CS_EVEN_SECONDARY      BIT(2)
+#define CS_ODD_SECONDARY       BIT(3)
+
+#define CS_EVEN                        (CS_EVEN_PRIMARY | CS_EVEN_SECONDARY)
+#define CS_ODD                 (CS_ODD_PRIMARY | CS_ODD_SECONDARY)
+
+static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
 {
-       u32 mask = pvt->csels[ctrl].csmasks[cs >> 1];
-       u32 msb = fls(mask) - 1, lsb = ffs(mask) - 1;
-       u32 test_mask = GENMASK(msb, lsb);
+       int cs_mode = 0;
 
-       edac_dbg(1, "mask=0x%08x test_mask=0x%08x\n", mask, test_mask);
+       if (csrow_enabled(2 * dimm, ctrl, pvt))
+               cs_mode |= CS_EVEN_PRIMARY;
 
-       return mask ^ test_mask;
+       if (csrow_enabled(2 * dimm + 1, ctrl, pvt))
+               cs_mode |= CS_ODD_PRIMARY;
+
+       /* Asymmetric dual-rank DIMM support. */
+       if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt))
+               cs_mode |= CS_ODD_SECONDARY;
+
+       return cs_mode;
 }
 
 static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
 {
-       int dimm, size0, size1, cs0, cs1;
+       int dimm, size0, size1, cs0, cs1, cs_mode;
 
        edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
 
-       for (dimm = 0; dimm < 4; dimm++) {
-               size0 = 0;
+       for (dimm = 0; dimm < 2; dimm++) {
                cs0 = dimm * 2;
-
-               if (csrow_enabled(cs0, ctrl, pvt))
-                       size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0);
-
-               size1 = 0;
                cs1 = dimm * 2 + 1;
 
-               if (csrow_enabled(cs1, ctrl, pvt)) {
-                       /*
-                        * CS interleaving is only supported if both CSes have
-                        * the same amount of memory. Because they are
-                        * interleaved, it will look like both CSes have the
-                        * full amount of memory. Save the size for both as
-                        * half the amount we found on CS0, if interleaved.
-                        */
-                       if (f17_cs_interleaved(pvt, ctrl, cs1))
-                               size1 = size0 = (size0 >> 1);
-                       else
-                               size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
-               }
+               cs_mode = f17_get_cs_mode(dimm, ctrl, pvt);
+
+               size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0);
+               size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1);
 
                amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
                                cs0,    size0,
@@ -942,89 +936,119 @@ static void prep_chip_selects(struct amd64_pvt *pvt)
        } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
                pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
                pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
+       } else if (pvt->fam >= 0x17) {
+               int umc;
+
+               for_each_umc(umc) {
+                       pvt->csels[umc].b_cnt = 4;
+                       pvt->csels[umc].m_cnt = 2;
+               }
+
        } else {
                pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
                pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
        }
 }
 
+static void read_umc_base_mask(struct amd64_pvt *pvt)
+{
+       u32 umc_base_reg, umc_base_reg_sec;
+       u32 umc_mask_reg, umc_mask_reg_sec;
+       u32 base_reg, base_reg_sec;
+       u32 mask_reg, mask_reg_sec;
+       u32 *base, *base_sec;
+       u32 *mask, *mask_sec;
+       int cs, umc;
+
+       for_each_umc(umc) {
+               umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR;
+               umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC;
+
+               for_each_chip_select(cs, umc, pvt) {
+                       base = &pvt->csels[umc].csbases[cs];
+                       base_sec = &pvt->csels[umc].csbases_sec[cs];
+
+                       base_reg = umc_base_reg + (cs * 4);
+                       base_reg_sec = umc_base_reg_sec + (cs * 4);
+
+                       if (!amd_smn_read(pvt->mc_node_id, base_reg, base))
+                               edac_dbg(0, "  DCSB%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *base, base_reg);
+
+                       if (!amd_smn_read(pvt->mc_node_id, base_reg_sec, base_sec))
+                               edac_dbg(0, "    DCSB_SEC%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *base_sec, base_reg_sec);
+               }
+
+               umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK;
+               umc_mask_reg_sec = get_umc_base(umc) + UMCCH_ADDR_MASK_SEC;
+
+               for_each_chip_select_mask(cs, umc, pvt) {
+                       mask = &pvt->csels[umc].csmasks[cs];
+                       mask_sec = &pvt->csels[umc].csmasks_sec[cs];
+
+                       mask_reg = umc_mask_reg + (cs * 4);
+                       mask_reg_sec = umc_mask_reg_sec + (cs * 4);
+
+                       if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask))
+                               edac_dbg(0, "  DCSM%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *mask, mask_reg);
+
+                       if (!amd_smn_read(pvt->mc_node_id, mask_reg_sec, mask_sec))
+                               edac_dbg(0, "    DCSM_SEC%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *mask_sec, mask_reg_sec);
+               }
+       }
+}
+
 /*
  * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
  */
 static void read_dct_base_mask(struct amd64_pvt *pvt)
 {
-       int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
+       int cs;
 
        prep_chip_selects(pvt);
 
-       if (pvt->umc) {
-               base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
-               base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
-               mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
-               mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
-       } else {
-               base_reg0 = DCSB0;
-               base_reg1 = DCSB1;
-               mask_reg0 = DCSM0;
-               mask_reg1 = DCSM1;
-       }
+       if (pvt->umc)
+               return read_umc_base_mask(pvt);
 
        for_each_chip_select(cs, 0, pvt) {
-               int reg0   = base_reg0 + (cs * 4);
-               int reg1   = base_reg1 + (cs * 4);
+               int reg0   = DCSB0 + (cs * 4);
+               int reg1   = DCSB1 + (cs * 4);
                u32 *base0 = &pvt->csels[0].csbases[cs];
                u32 *base1 = &pvt->csels[1].csbases[cs];
 
-               if (pvt->umc) {
-                       if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
-                               edac_dbg(0, "  DCSB0[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *base0, reg0);
+               if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
+                       edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base0, reg0);
 
-                       if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
-                               edac_dbg(0, "  DCSB1[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *base1, reg1);
-               } else {
-                       if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
-                               edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *base0, reg0);
-
-                       if (pvt->fam == 0xf)
-                               continue;
+               if (pvt->fam == 0xf)
+                       continue;
 
-                       if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
-                               edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *base1, (pvt->fam == 0x10) ? reg1
-                                                               : reg0);
-               }
+               if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
+                       edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base1, (pvt->fam == 0x10) ? reg1
+                                                       : reg0);
        }
 
        for_each_chip_select_mask(cs, 0, pvt) {
-               int reg0   = mask_reg0 + (cs * 4);
-               int reg1   = mask_reg1 + (cs * 4);
+               int reg0   = DCSM0 + (cs * 4);
+               int reg1   = DCSM1 + (cs * 4);
                u32 *mask0 = &pvt->csels[0].csmasks[cs];
                u32 *mask1 = &pvt->csels[1].csmasks[cs];
 
-               if (pvt->umc) {
-                       if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
-                               edac_dbg(0, "    DCSM0[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *mask0, reg0);
-
-                       if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
-                               edac_dbg(0, "    DCSM1[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *mask1, reg1);
-               } else {
-                       if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
-                               edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *mask0, reg0);
+               if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
+                       edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask0, reg0);
 
-                       if (pvt->fam == 0xf)
-                               continue;
+               if (pvt->fam == 0xf)
+                       continue;
 
-                       if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
-                               edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *mask1, (pvt->fam == 0x10) ? reg1
-                                                               : reg0);
-               }
+               if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
+                       edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask1, (pvt->fam == 0x10) ? reg1
+                                                       : reg0);
        }
 }
 
@@ -1556,18 +1580,58 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
                return ddr3_cs_size(cs_mode, false);
 }
 
-static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
+static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
                                    unsigned int cs_mode, int csrow_nr)
 {
-       u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
+       u32 addr_mask_orig, addr_mask_deinterleaved;
+       u32 msb, weight, num_zero_bits;
+       int dimm, size = 0;
 
-       /*  Each mask is used for every two base addresses. */
-       u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
+       /* No Chip Selects are enabled. */
+       if (!cs_mode)
+               return size;
 
-       /*  Register [31:1] = Address [39:9]. Size is in kBs here. */
-       u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
+       /* Requested size of an even CS but none are enabled. */
+       if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1))
+               return size;
 
-       edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask);
+       /* Requested size of an odd CS but none are enabled. */
+       if (!(cs_mode & CS_ODD) && (csrow_nr & 1))
+               return size;
+
+       /*
+        * There is one mask per DIMM, and two Chip Selects per DIMM.
+        *      CS0 and CS1 -> DIMM0
+        *      CS2 and CS3 -> DIMM1
+        */
+       dimm = csrow_nr >> 1;
+
+       /* Asymmetric dual-rank DIMM support. */
+       if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY))
+               addr_mask_orig = pvt->csels[umc].csmasks_sec[dimm];
+       else
+               addr_mask_orig = pvt->csels[umc].csmasks[dimm];
+
+       /*
+        * The number of zero bits in the mask is equal to the number of bits
+        * in a full mask minus the number of bits in the current mask.
+        *
+        * The MSB is the number of bits in the full mask because BIT[0] is
+        * always 0.
+        */
+       msb = fls(addr_mask_orig) - 1;
+       weight = hweight_long(addr_mask_orig);
+       num_zero_bits = msb - weight;
+
+       /* Take the number of zero bits off from the top of the mask. */
+       addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1);
+
+       edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm);
+       edac_dbg(1, "  Original AddrMask: 0x%x\n", addr_mask_orig);
+       edac_dbg(1, "  Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved);
+
+       /* Register [31:1] = Address [39:9]. Size is in kBs here. */
+       size = (addr_mask_deinterleaved >> 2) + 1;
 
        /* Return size in MBs. */
        return size >> 10;
@@ -2232,7 +2296,7 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
        [F17_M10H_CPUS] = {
@@ -2241,7 +2305,7 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
        [F17_M30H_CPUS] = {
@@ -2250,7 +2314,16 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
+               }
+       },
+       [F17_M70H_CPUS] = {
+               .ctl_name = "F17h_M70h",
+               .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0,
+               .f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6,
+               .ops = {
+                       .early_channel_count    = f17_early_channel_count,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
 };
@@ -2537,13 +2610,6 @@ static void decode_umc_error(int node_id, struct mce *m)
 
        err.channel = find_umc_channel(m);
 
-       if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
-               err.err_code = ERR_NORM_ADDR;
-               goto log_error;
-       }
-
-       error_address_to_page_and_offset(sys_addr, &err);
-
        if (!(m->status & MCI_STATUS_SYNDV)) {
                err.err_code = ERR_SYND;
                goto log_error;
@@ -2560,6 +2626,13 @@ static void decode_umc_error(int node_id, struct mce *m)
 
        err.csrow = m->synd & 0x7;
 
+       if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
+               err.err_code = ERR_NORM_ADDR;
+               goto log_error;
+       }
+
+       error_address_to_page_and_offset(sys_addr, &err);
+
 log_error:
        __log_ecc_error(mci, &err, ecc_type);
 }
@@ -2809,10 +2882,12 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
        int csrow_nr = csrow_nr_orig;
        u32 cs_mode, nr_pages;
 
-       if (!pvt->umc)
+       if (!pvt->umc) {
                csrow_nr >>= 1;
-
-       cs_mode = DBAM_DIMM(csrow_nr, dbam);
+               cs_mode = DBAM_DIMM(csrow_nr, dbam);
+       } else {
+               cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt);
+       }
 
        nr_pages   = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr);
        nr_pages <<= 20 - PAGE_SHIFT;
@@ -2824,6 +2899,49 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
        return nr_pages;
 }
 
+static int init_csrows_df(struct mem_ctl_info *mci)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       enum edac_type edac_mode = EDAC_NONE;
+       enum dev_type dev_type = DEV_UNKNOWN;
+       struct dimm_info *dimm;
+       int empty = 1;
+       u8 umc, cs;
+
+       if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) {
+               edac_mode = EDAC_S16ECD16ED;
+               dev_type = DEV_X16;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_S8ECD8ED) {
+               edac_mode = EDAC_S8ECD8ED;
+               dev_type = DEV_X8;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) {
+               edac_mode = EDAC_S4ECD4ED;
+               dev_type = DEV_X4;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) {
+               edac_mode = EDAC_SECDED;
+       }
+
+       for_each_umc(umc) {
+               for_each_chip_select(cs, umc, pvt) {
+                       if (!csrow_enabled(cs, umc, pvt))
+                               continue;
+
+                       empty = 0;
+                       dimm = mci->csrows[cs]->channels[umc]->dimm;
+
+                       edac_dbg(1, "MC node: %d, csrow: %d\n",
+                                       pvt->mc_node_id, cs);
+
+                       dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs);
+                       dimm->mtype = pvt->dram_type;
+                       dimm->edac_mode = edac_mode;
+                       dimm->dtype = dev_type;
+               }
+       }
+
+       return empty;
+}
+
 /*
  * Initialize the array of csrow attribute instances, based on the values
  * from pci config hardware registers.
@@ -2838,15 +2956,16 @@ static int init_csrows(struct mem_ctl_info *mci)
        int nr_pages = 0;
        u32 val;
 
-       if (!pvt->umc) {
-               amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
+       if (pvt->umc)
+               return init_csrows_df(mci);
 
-               pvt->nbcfg = val;
+       amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
 
-               edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
-                        pvt->mc_node_id, val,
-                        !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
-       }
+       pvt->nbcfg = val;
+
+       edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+                pvt->mc_node_id, val,
+                !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
        /*
         * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
@@ -2883,13 +3002,7 @@ static int init_csrows(struct mem_ctl_info *mci)
                edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
 
                /* Determine DIMM ECC mode: */
-               if (pvt->umc) {
-                       if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
-                               edac_mode = EDAC_S4ECD4ED;
-                       else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
-                               edac_mode = EDAC_SECDED;
-
-               } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
+               if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
                        edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
                                        ? EDAC_S4ECD4ED
                                        : EDAC_SECDED;
@@ -3137,12 +3250,15 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 static inline void
 f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
 {
-       u8 i, ecc_en = 1, cpk_en = 1;
+       u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1;
 
        for_each_umc(i) {
                if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
                        ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
                        cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
+
+                       dev_x4  &= !!(pvt->umc[i].dimm_cfg & BIT(6));
+                       dev_x16 &= !!(pvt->umc[i].dimm_cfg & BIT(7));
                }
        }
 
@@ -3150,8 +3266,15 @@ f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
        if (ecc_en) {
                mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
 
-               if (cpk_en)
+               if (!cpk_en)
+                       return;
+
+               if (dev_x4)
                        mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
+               else if (dev_x16)
+                       mci->edac_ctl_cap |= EDAC_FLAG_S16ECD16ED;
+               else
+                       mci->edac_ctl_cap |= EDAC_FLAG_S8ECD8ED;
        }
 }
 
@@ -3241,6 +3364,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                        fam_type = &family_types[F17_M30H_CPUS];
                        pvt->ops = &family_types[F17_M30H_CPUS].ops;
                        break;
+               } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) {
+                       fam_type = &family_types[F17_M70H_CPUS];
+                       pvt->ops = &family_types[F17_M70H_CPUS].ops;
+                       break;
                }
                /* fall through */
        case 0x18:
index 8f66472f7adc221ee5e4e6787f35547c663b8930..8c3cda81e6192b3f95600bbdd6261a280d15fe50 100644 (file)
@@ -96,6 +96,7 @@
 /* Hardware limit on ChipSelect rows per MC and processors per system */
 #define NUM_CHIPSELECTS                        8
 #define DRAM_RANGES                    8
+#define NUM_CONTROLLERS                        8
 
 #define ON true
 #define OFF false
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F6 0x1446
 
 /*
  * Function 1 - Address Map
 #define DCSM0                          0x60
 #define DCSM1                          0x160
 
-#define csrow_enabled(i, dct, pvt)     ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE)
+#define csrow_enabled(i, dct, pvt)     ((pvt)->csels[(dct)].csbases[(i)]     & DCSB_CS_ENABLE)
+#define csrow_sec_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases_sec[(i)] & DCSB_CS_ENABLE)
 
 #define DRAM_CONTROL                   0x78
 
 
 /* UMC CH register offsets */
 #define UMCCH_BASE_ADDR                        0x0
+#define UMCCH_BASE_ADDR_SEC            0x10
 #define UMCCH_ADDR_MASK                        0x20
+#define UMCCH_ADDR_MASK_SEC            0x28
 #define UMCCH_ADDR_CFG                 0x30
 #define UMCCH_DIMM_CFG                 0x80
 #define UMCCH_UMC_CFG                  0x100
@@ -285,6 +291,7 @@ enum amd_families {
        F17_CPUS,
        F17_M10H_CPUS,
        F17_M30H_CPUS,
+       F17_M70H_CPUS,
        NUM_FAMILIES,
 };
 
@@ -311,9 +318,11 @@ struct dram_range {
 /* A DCT chip selects collection */
 struct chip_select {
        u32 csbases[NUM_CHIPSELECTS];
+       u32 csbases_sec[NUM_CHIPSELECTS];
        u8 b_cnt;
 
        u32 csmasks[NUM_CHIPSELECTS];
+       u32 csmasks_sec[NUM_CHIPSELECTS];
        u8 m_cnt;
 };
 
@@ -351,8 +360,8 @@ struct amd64_pvt {
        u32 dbam0;              /* DRAM Base Address Mapping reg for DCT0 */
        u32 dbam1;              /* DRAM Base Address Mapping reg for DCT1 */
 
-       /* one for each DCT */
-       struct chip_select csels[2];
+       /* one for each DCT/UMC */
+       struct chip_select csels[NUM_CONTROLLERS];
 
        /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */
        struct dram_range ranges[DRAM_RANGES];
diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c
new file mode 100644 (file)
index 0000000..e4736eb
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bluefield-specific EDAC driver.
+ *
+ * Copyright (c) 2019 Mellanox Technologies.
+ */
+
+#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
+#include <linux/bitfield.h>
+#include <linux/edac.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "edac_module.h"
+
+#define DRIVER_NAME            "bluefield-edac"
+
+/*
+ * Mellanox BlueField EMI (External Memory Interface) register definitions.
+ */
+
+#define MLXBF_ECC_CNT 0x340
+#define MLXBF_ECC_CNT__SERR_CNT GENMASK(15, 0)
+#define MLXBF_ECC_CNT__DERR_CNT GENMASK(31, 16)
+
+#define MLXBF_ECC_ERR 0x348
+#define MLXBF_ECC_ERR__SECC BIT(0)
+#define MLXBF_ECC_ERR__DECC BIT(16)
+
+#define MLXBF_ECC_LATCH_SEL 0x354
+#define MLXBF_ECC_LATCH_SEL__START BIT(24)
+
+#define MLXBF_ERR_ADDR_0 0x358
+
+#define MLXBF_ERR_ADDR_1 0x37c
+
+#define MLXBF_SYNDROM 0x35c
+#define MLXBF_SYNDROM__DERR BIT(0)
+#define MLXBF_SYNDROM__SERR BIT(1)
+#define MLXBF_SYNDROM__SYN GENMASK(25, 16)
+
+#define MLXBF_ADD_INFO 0x364
+#define MLXBF_ADD_INFO__ERR_PRANK GENMASK(9, 8)
+
+#define MLXBF_EDAC_MAX_DIMM_PER_MC     2
+#define MLXBF_EDAC_ERROR_GRAIN         8
+
+/*
+ * Request MLNX_SIP_GET_DIMM_INFO
+ *
+ * Retrieve information about DIMM on a certain slot.
+ *
+ * Call register usage:
+ * a0: MLNX_SIP_GET_DIMM_INFO
+ * a1: (Memory controller index) << 16 | (Dimm index in memory controller)
+ * a2-7: not used.
+ *
+ * Return status:
+ * a0: MLXBF_DIMM_INFO defined below describing the DIMM.
+ * a1-3: not used.
+ */
+#define MLNX_SIP_GET_DIMM_INFO         0x82000008
+
+/* Format for the SMC response about the memory information */
+#define MLXBF_DIMM_INFO__SIZE_GB GENMASK_ULL(15, 0)
+#define MLXBF_DIMM_INFO__IS_RDIMM BIT(16)
+#define MLXBF_DIMM_INFO__IS_LRDIMM BIT(17)
+#define MLXBF_DIMM_INFO__IS_NVDIMM BIT(18)
+#define MLXBF_DIMM_INFO__RANKS GENMASK_ULL(23, 21)
+#define MLXBF_DIMM_INFO__PACKAGE_X GENMASK_ULL(31, 24)
+
+struct bluefield_edac_priv {
+       int dimm_ranks[MLXBF_EDAC_MAX_DIMM_PER_MC];
+       void __iomem *emi_base;
+       int dimm_per_mc;
+};
+
+static u64 smc_call1(u64 smc_op, u64 smc_arg)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res);
+
+       return res.a0;
+}
+
+/*
+ * Gather the ECC information from the External Memory Interface registers
+ * and report it to the edac handler.
+ */
+static void bluefield_gather_report_ecc(struct mem_ctl_info *mci,
+                                       int error_cnt,
+                                       int is_single_ecc)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       u32 dram_additional_info, err_prank, edea0, edea1;
+       u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom;
+       enum hw_event_mc_err_type ecc_type;
+       u64 ecc_dimm_addr;
+       int ecc_dimm;
+
+       ecc_type = is_single_ecc ? HW_EVENT_ERR_CORRECTED :
+                                  HW_EVENT_ERR_UNCORRECTED;
+
+       /*
+        * Tell the External Memory Interface to populate the relevant
+        * registers with information about the last ECC error occurrence.
+        */
+       ecc_latch_select = MLXBF_ECC_LATCH_SEL__START;
+       writel(ecc_latch_select, priv->emi_base + MLXBF_ECC_LATCH_SEL);
+
+       /*
+        * Verify that the ECC reported info in the registers is of the
+        * same type as the one asked to report. If not, just report the
+        * error without the detailed information.
+        */
+       dram_syndrom = readl(priv->emi_base + MLXBF_SYNDROM);
+       serr = FIELD_GET(MLXBF_SYNDROM__SERR, dram_syndrom);
+       derr = FIELD_GET(MLXBF_SYNDROM__DERR, dram_syndrom);
+       syndrom = FIELD_GET(MLXBF_SYNDROM__SYN, dram_syndrom);
+
+       if ((is_single_ecc && !serr) || (!is_single_ecc && !derr)) {
+               edac_mc_handle_error(ecc_type, mci, error_cnt, 0, 0, 0,
+                                    0, 0, -1, mci->ctl_name, "");
+               return;
+       }
+
+       dram_additional_info = readl(priv->emi_base + MLXBF_ADD_INFO);
+       err_prank = FIELD_GET(MLXBF_ADD_INFO__ERR_PRANK, dram_additional_info);
+
+       ecc_dimm = (err_prank >= 2 && priv->dimm_ranks[0] <= 2) ? 1 : 0;
+
+       edea0 = readl(priv->emi_base + MLXBF_ERR_ADDR_0);
+       edea1 = readl(priv->emi_base + MLXBF_ERR_ADDR_1);
+
+       ecc_dimm_addr = ((u64)edea1 << 32) | edea0;
+
+       edac_mc_handle_error(ecc_type, mci, error_cnt,
+                            PFN_DOWN(ecc_dimm_addr),
+                            offset_in_page(ecc_dimm_addr),
+                            syndrom, ecc_dimm, 0, 0, mci->ctl_name, "");
+}
+
+static void bluefield_edac_check(struct mem_ctl_info *mci)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       u32 ecc_count, single_error_count, double_error_count, ecc_error = 0;
+
+       /*
+        * The memory controller might not be initialized by the firmware
+        * when there isn't memory, which may lead to bad register readings.
+        */
+       if (mci->edac_cap == EDAC_FLAG_NONE)
+               return;
+
+       ecc_count = readl(priv->emi_base + MLXBF_ECC_CNT);
+       single_error_count = FIELD_GET(MLXBF_ECC_CNT__SERR_CNT, ecc_count);
+       double_error_count = FIELD_GET(MLXBF_ECC_CNT__DERR_CNT, ecc_count);
+
+       if (single_error_count) {
+               ecc_error |= MLXBF_ECC_ERR__SECC;
+
+               bluefield_gather_report_ecc(mci, single_error_count, 1);
+       }
+
+       if (double_error_count) {
+               ecc_error |= MLXBF_ECC_ERR__DECC;
+
+               bluefield_gather_report_ecc(mci, double_error_count, 0);
+       }
+
+       /* Write to clear reported errors. */
+       if (ecc_count)
+               writel(ecc_error, priv->emi_base + MLXBF_ECC_ERR);
+}
+
+/* Initialize the DIMMs information for the given memory controller. */
+static void bluefield_edac_init_dimms(struct mem_ctl_info *mci)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       int mem_ctrl_idx = mci->mc_idx;
+       struct dimm_info *dimm;
+       u64 smc_info, smc_arg;
+       int is_empty = 1, i;
+
+       for (i = 0; i < priv->dimm_per_mc; i++) {
+               dimm = mci->dimms[i];
+
+               smc_arg = mem_ctrl_idx << 16 | i;
+               smc_info = smc_call1(MLNX_SIP_GET_DIMM_INFO, smc_arg);
+
+               if (!FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info)) {
+                       dimm->mtype = MEM_EMPTY;
+                       continue;
+               }
+
+               is_empty = 0;
+
+               dimm->edac_mode = EDAC_SECDED;
+
+               if (FIELD_GET(MLXBF_DIMM_INFO__IS_NVDIMM, smc_info))
+                       dimm->mtype = MEM_NVDIMM;
+               else if (FIELD_GET(MLXBF_DIMM_INFO__IS_LRDIMM, smc_info))
+                       dimm->mtype = MEM_LRDDR4;
+               else if (FIELD_GET(MLXBF_DIMM_INFO__IS_RDIMM, smc_info))
+                       dimm->mtype = MEM_RDDR4;
+               else
+                       dimm->mtype = MEM_DDR4;
+
+               dimm->nr_pages =
+                       FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info) *
+                       (SZ_1G / PAGE_SIZE);
+               dimm->grain = MLXBF_EDAC_ERROR_GRAIN;
+
+               /* Mem controller for BlueField only supports x4, x8 and x16 */
+               switch (FIELD_GET(MLXBF_DIMM_INFO__PACKAGE_X, smc_info)) {
+               case 4:
+                       dimm->dtype = DEV_X4;
+                       break;
+               case 8:
+                       dimm->dtype = DEV_X8;
+                       break;
+               case 16:
+                       dimm->dtype = DEV_X16;
+                       break;
+               default:
+                       dimm->dtype = DEV_UNKNOWN;
+               }
+
+               priv->dimm_ranks[i] =
+                       FIELD_GET(MLXBF_DIMM_INFO__RANKS, smc_info);
+       }
+
+       if (is_empty)
+               mci->edac_cap = EDAC_FLAG_NONE;
+       else
+               mci->edac_cap = EDAC_FLAG_SECDED;
+}
+
+static int bluefield_edac_mc_probe(struct platform_device *pdev)
+{
+       struct bluefield_edac_priv *priv;
+       struct device *dev = &pdev->dev;
+       struct edac_mc_layer layers[1];
+       struct mem_ctl_info *mci;
+       struct resource *emi_res;
+       unsigned int mc_idx, dimm_count;
+       int rc, ret;
+
+       /* Read the MSS (Memory SubSystem) index from ACPI table. */
+       if (device_property_read_u32(dev, "mss_number", &mc_idx)) {
+               dev_warn(dev, "bf_edac: MSS number unknown\n");
+               return -EINVAL;
+       }
+
+       /* Read the DIMMs per MC from ACPI table. */
+       if (device_property_read_u32(dev, "dimm_per_mc", &dimm_count)) {
+               dev_warn(dev, "bf_edac: DIMMs per MC unknown\n");
+               return -EINVAL;
+       }
+
+       if (dimm_count > MLXBF_EDAC_MAX_DIMM_PER_MC) {
+               dev_warn(dev, "bf_edac: DIMMs per MC not valid\n");
+               return -EINVAL;
+       }
+
+       emi_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!emi_res)
+               return -EINVAL;
+
+       layers[0].type = EDAC_MC_LAYER_SLOT;
+       layers[0].size = dimm_count;
+       layers[0].is_virt_csrow = true;
+
+       mci = edac_mc_alloc(mc_idx, ARRAY_SIZE(layers), layers, sizeof(*priv));
+       if (!mci)
+               return -ENOMEM;
+
+       priv = mci->pvt_info;
+
+       priv->dimm_per_mc = dimm_count;
+       priv->emi_base = devm_ioremap_resource(dev, emi_res);
+       if (IS_ERR(priv->emi_base)) {
+               dev_err(dev, "failed to map EMI IO resource\n");
+               ret = PTR_ERR(priv->emi_base);
+               goto err;
+       }
+
+       mci->pdev = dev;
+       mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_RDDR4 |
+                        MEM_FLAG_LRDDR4 | MEM_FLAG_NVDIMM;
+       mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+
+       mci->mod_name = DRIVER_NAME;
+       mci->ctl_name = "BlueField_Memory_Controller";
+       mci->dev_name = dev_name(dev);
+       mci->edac_check = bluefield_edac_check;
+
+       /* Initialize mci with the actual populated DIMM information. */
+       bluefield_edac_init_dimms(mci);
+
+       platform_set_drvdata(pdev, mci);
+
+       /* Register with EDAC core */
+       rc = edac_mc_add_mc(mci);
+       if (rc) {
+               dev_err(dev, "failed to register with EDAC core\n");
+               ret = rc;
+               goto err;
+       }
+
+       /* Only POLL mode supported so far. */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       return 0;
+
+err:
+       edac_mc_free(mci);
+
+       return ret;
+
+}
+
+static int bluefield_edac_mc_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+static const struct acpi_device_id bluefield_mc_acpi_ids[] = {
+       {"MLNXBF08", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(acpi, bluefield_mc_acpi_ids);
+
+static struct platform_driver bluefield_edac_mc_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .acpi_match_table = bluefield_mc_acpi_ids,
+       },
+       .probe = bluefield_edac_mc_probe,
+       .remove = bluefield_edac_mc_remove,
+};
+
+module_platform_driver(bluefield_edac_mc_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField memory edac driver");
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_LICENSE("GPL v2");
index 64922c8fa7e3b729ea6b7919b371fcd76515491b..e6fd079783bd27f6a75da1976f8db4edeb9e6377 100644 (file)
@@ -114,8 +114,8 @@ static const struct kernel_param_ops edac_report_ops = {
 
 module_param_cb(edac_report, &edac_report_ops, &edac_report, 0644);
 
-unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
-                                unsigned len)
+unsigned int edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+                                    unsigned int len)
 {
        struct mem_ctl_info *mci = dimm->mci;
        int i, n, count = 0;
@@ -236,9 +236,9 @@ EXPORT_SYMBOL_GPL(edac_mem_types);
  * At return, the pointer 'p' will be incremented to be used on a next call
  * to this function.
  */
-void *edac_align_ptr(void **p, unsigned size, int n_elems)
+void *edac_align_ptr(void **p, unsigned int size, int n_elems)
 {
-       unsigned align, r;
+       unsigned int align, r;
        void *ptr = *p;
 
        *p += size * n_elems;
@@ -275,38 +275,37 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems)
 
 static void _edac_mc_free(struct mem_ctl_info *mci)
 {
-       int i, chn, row;
        struct csrow_info *csr;
-       const unsigned int tot_dimms = mci->tot_dimms;
-       const unsigned int tot_channels = mci->num_cschannel;
-       const unsigned int tot_csrows = mci->nr_csrows;
+       int i, chn, row;
 
        if (mci->dimms) {
-               for (i = 0; i < tot_dimms; i++)
+               for (i = 0; i < mci->tot_dimms; i++)
                        kfree(mci->dimms[i]);
                kfree(mci->dimms);
        }
+
        if (mci->csrows) {
-               for (row = 0; row < tot_csrows; row++) {
+               for (row = 0; row < mci->nr_csrows; row++) {
                        csr = mci->csrows[row];
-                       if (csr) {
-                               if (csr->channels) {
-                                       for (chn = 0; chn < tot_channels; chn++)
-                                               kfree(csr->channels[chn]);
-                                       kfree(csr->channels);
-                               }
-                               kfree(csr);
+                       if (!csr)
+                               continue;
+
+                       if (csr->channels) {
+                               for (chn = 0; chn < mci->num_cschannel; chn++)
+                                       kfree(csr->channels[chn]);
+                               kfree(csr->channels);
                        }
+                       kfree(csr);
                }
                kfree(mci->csrows);
        }
        kfree(mci);
 }
 
-struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
-                                  unsigned n_layers,
+struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
+                                  unsigned int n_layers,
                                   struct edac_mc_layer *layers,
-                                  unsigned sz_pvt)
+                                  unsigned int sz_pvt)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer *layer;
@@ -314,9 +313,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        struct rank_info *chan;
        struct dimm_info *dimm;
        u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
-       unsigned pos[EDAC_MAX_LAYERS];
-       unsigned size, tot_dimms = 1, count = 1;
-       unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
+       unsigned int pos[EDAC_MAX_LAYERS];
+       unsigned int size, tot_dimms = 1, count = 1;
+       unsigned int tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
        void *pvt, *p, *ptr = NULL;
        int i, j, row, chn, n, len, off;
        bool per_rank = false;
@@ -1235,9 +1234,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        if (p > e->location)
                *(p - 1) = '\0';
 
-       /* Report the error via the trace interface */
-       grain_bits = fls_long(e->grain) + 1;
+       /* Sanity-check driver-supplied grain value. */
+       if (WARN_ON_ONCE(!e->grain))
+               e->grain = 1;
 
+       grain_bits = fls_long(e->grain - 1);
+
+       /* Report the error via the trace interface */
        if (IS_ENABLED(CONFIG_RAS))
                trace_mc_event(type, e->msg, e->label, e->error_count,
                               mci->mc_idx, e->top_layer, e->mid_layer,
index 4165e15995ad8a16975744ac5440b2db10ca4b8e..02aac5c61d0044a89546651a9b67f697869287e3 100644 (file)
@@ -122,10 +122,10 @@ do {                                                                      \
  *     On success, return a pointer to struct mem_ctl_info pointer;
  *     %NULL otherwise
  */
-struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
-                                  unsigned n_layers,
+struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
+                                  unsigned int n_layers,
                                   struct edac_mc_layer *layers,
-                                  unsigned sz_pvt);
+                                  unsigned int sz_pvt);
 
 /**
  * edac_get_owner - Return the owner's mod_name of EDAC MC
index 4386ea4b9b5af81d069b88fb240ee721a707e4d2..32d016f1ecd1b0c5f8b4042b428952e0edb187dd 100644 (file)
@@ -131,7 +131,7 @@ static const char * const edac_caps[] = {
 
 struct dev_ch_attribute {
        struct device_attribute attr;
-       int channel;
+       unsigned int channel;
 };
 
 #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
@@ -200,7 +200,7 @@ static ssize_t channel_dimm_label_show(struct device *dev,
                                       char *data)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
 
        /* if field has not been initialized, there is nothing to send */
@@ -216,7 +216,7 @@ static ssize_t channel_dimm_label_store(struct device *dev,
                                        const char *data, size_t count)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
        size_t copy_count = count;
 
@@ -240,7 +240,7 @@ static ssize_t channel_ce_count_show(struct device *dev,
                                     struct device_attribute *mattr, char *data)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
 
        return sprintf(data, "%u\n", rank->ce_count);
@@ -278,7 +278,7 @@ static void csrow_attr_release(struct device *dev)
 {
        struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
 
-       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(csrow);
 }
 
@@ -414,14 +414,16 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
        dev_set_name(&csrow->dev, "csrow%d", index);
        dev_set_drvdata(&csrow->dev, csrow);
 
-       edac_dbg(0, "creating (virtual) csrow node %s\n",
-                dev_name(&csrow->dev));
-
        err = device_add(&csrow->dev);
-       if (err)
+       if (err) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev));
                put_device(&csrow->dev);
+               return err;
+       }
 
-       return err;
+       edac_dbg(0, "device %s created\n", dev_name(&csrow->dev));
+
+       return 0;
 }
 
 /* Create a CSROW object under specifed edac_mc_device */
@@ -435,12 +437,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
                if (!nr_pages_per_csrow(csrow))
                        continue;
                err = edac_create_csrow_object(mci, mci->csrows[i], i);
-               if (err < 0) {
-                       edac_dbg(1,
-                                "failure: create csrow objects for csrow %d\n",
-                                i);
+               if (err < 0)
                        goto error;
-               }
        }
        return 0;
 
@@ -624,7 +622,7 @@ static void dimm_attr_release(struct device *dev)
 {
        struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
 
-       edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(dimm);
 }
 
@@ -653,12 +651,21 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        pm_runtime_forbid(&mci->dev);
 
        err = device_add(&dimm->dev);
-       if (err)
+       if (err) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev));
                put_device(&dimm->dev);
+               return err;
+       }
 
-       edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev));
+       if (IS_ENABLED(CONFIG_EDAC_DEBUG)) {
+               char location[80];
 
-       return err;
+               edac_dimm_info_location(dimm, location, sizeof(location));
+               edac_dbg(0, "device %s created at location %s\n",
+                       dev_name(&dimm->dev), location);
+       }
+
+       return 0;
 }
 
 /*
@@ -901,7 +908,7 @@ static void mci_attr_release(struct device *dev)
 {
        struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
 
-       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(mci);
 }
 
@@ -933,14 +940,15 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
        dev_set_drvdata(&mci->dev, mci);
        pm_runtime_forbid(&mci->dev);
 
-       edac_dbg(0, "creating device %s\n", dev_name(&mci->dev));
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
                put_device(&mci->dev);
-               goto out;
+               return err;
        }
 
+       edac_dbg(0, "device %s created\n", dev_name(&mci->dev));
+
        /*
         * Create the dimm/rank devices
         */
@@ -950,22 +958,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
                if (!dimm->nr_pages)
                        continue;
 
-#ifdef CONFIG_EDAC_DEBUG
-               edac_dbg(1, "creating dimm%d, located at ", i);
-               if (edac_debug_level >= 1) {
-                       int lay;
-                       for (lay = 0; lay < mci->n_layers; lay++)
-                               printk(KERN_CONT "%s %d ",
-                                       edac_layer_name[mci->layers[lay].type],
-                                       dimm->location[lay]);
-                       printk(KERN_CONT "\n");
-               }
-#endif
                err = edac_create_dimm_object(mci, dimm, i);
-               if (err) {
-                       edac_dbg(1, "failure: create dimm %d obj\n", i);
+               if (err)
                        goto fail_unregister_dimm;
-               }
        }
 
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
@@ -987,7 +982,6 @@ fail_unregister_dimm:
        }
        device_unregister(&mci->dev);
 
-out:
        return err;
 }
 
@@ -1011,14 +1005,14 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
                struct dimm_info *dimm = mci->dimms[i];
                if (dimm->nr_pages == 0)
                        continue;
-               edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev));
+               edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev));
                device_unregister(&dimm->dev);
        }
 }
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
-       edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
+       edac_dbg(1, "unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
 }
 
@@ -1029,7 +1023,7 @@ static void mc_attr_release(struct device *dev)
         * parent device, used to create the /sys/devices/mc sysfs node.
         * So, there are no attributes on it.
         */
-       edac_dbg(1, "Releasing device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(dev);
 }
 
@@ -1044,10 +1038,8 @@ int __init edac_mc_sysfs_init(void)
        int err;
 
        mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
-       if (!mci_pdev) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!mci_pdev)
+               return -ENOMEM;
 
        mci_pdev->bus = edac_get_sysfs_subsys();
        mci_pdev->type = &mc_attr_type;
@@ -1055,17 +1047,15 @@ int __init edac_mc_sysfs_init(void)
        dev_set_name(mci_pdev, "mc");
 
        err = device_add(mci_pdev);
-       if (err < 0)
-               goto out_put_device;
+       if (err < 0) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev));
+               put_device(mci_pdev);
+               return err;
+       }
 
        edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
 
        return 0;
-
- out_put_device:
-       put_device(mci_pdev);
- out:
-       return err;
 }
 
 void edac_mc_sysfs_exit(void)
index 7f19f1c672c3aaf1cf8e22de6612ee26634a5b72..d413a0bdc9ad9da8637b811e79a81023c39c1906 100644 (file)
@@ -68,7 +68,7 @@ struct memdev_dmi_entry {
 
 struct ghes_edac_dimm_fill {
        struct mem_ctl_info *mci;
-       unsigned count;
+       unsigned int count;
 };
 
 static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg)
index b506eef6b146d8570f6dcba9be5205d96ad9e9f9..251f2b692785d8729d2c48e35a663dacffdadf4e 100644 (file)
@@ -417,7 +417,8 @@ static const char *i5100_err_msg(unsigned err)
 }
 
 /* convert csrow index into a rank (per channel -- 0..5) */
-static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow)
+static unsigned int i5100_csrow_to_rank(const struct mem_ctl_info *mci,
+                                       unsigned int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
@@ -425,7 +426,8 @@ static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow)
 }
 
 /* convert csrow index into a channel (0..1) */
-static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow)
+static unsigned int i5100_csrow_to_chan(const struct mem_ctl_info *mci,
+                                       unsigned int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
@@ -653,11 +655,11 @@ static struct pci_dev *pci_get_device_func(unsigned vendor,
        return ret;
 }
 
-static unsigned long i5100_npages(struct mem_ctl_info *mci, int csrow)
+static unsigned long i5100_npages(struct mem_ctl_info *mci, unsigned int csrow)
 {
        struct i5100_priv *priv = mci->pvt_info;
-       const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow);
-       const unsigned chan = i5100_csrow_to_chan(mci, csrow);
+       const unsigned int chan_rank = i5100_csrow_to_rank(mci, csrow);
+       const unsigned int chan = i5100_csrow_to_chan(mci, csrow);
        unsigned addr_lines;
 
        /* dimm present? */
@@ -852,8 +854,8 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
        for (i = 0; i < mci->tot_dimms; i++) {
                struct dimm_info *dimm;
                const unsigned long npages = i5100_npages(mci, i);
-               const unsigned chan = i5100_csrow_to_chan(mci, i);
-               const unsigned rank = i5100_csrow_to_rank(mci, i);
+               const unsigned int chan = i5100_csrow_to_chan(mci, i);
+               const unsigned int rank = i5100_csrow_to_rank(mci, i);
 
                if (!npages)
                        continue;
index ca25f8fe57ef3272ab90b0b42816bc1b0e73ebab..1ad538baaa4a95b391964e87b5b4608bbb03d9d2 100644 (file)
@@ -260,11 +260,14 @@ static u64 get_sideband_reg_base_addr(void)
        }
 }
 
+#define DNV_MCHBAR_SIZE  0x8000
+#define DNV_SB_PORT_SIZE 0x10000
 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name)
 {
        struct pci_dev *pdev;
        char *base;
        u64 addr;
+       unsigned long size;
 
        if (op == 4) {
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL);
@@ -279,15 +282,17 @@ static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *na
                        addr = get_mem_ctrl_hub_base_addr();
                        if (!addr)
                                return -ENODEV;
+                       size = DNV_MCHBAR_SIZE;
                } else {
                        /* MMIO via sideband register base address */
                        addr = get_sideband_reg_base_addr();
                        if (!addr)
                                return -ENODEV;
                        addr += (port << 16);
+                       size = DNV_SB_PORT_SIZE;
                }
 
-               base = ioremap((resource_size_t)addr, 0x10000);
+               base = ioremap((resource_size_t)addr, size);
                if (!base)
                        return -ENODEV;
 
index f1a9c0544e3f7f5fc63c8f87298c5630c3254e4b..213aedc97dc2e7d37c04194b889d95acb7763df5 100644 (file)
@@ -309,6 +309,7 @@ static const struct file_operations gpio_mockup_debugfs_ops = {
        .read = gpio_mockup_debugfs_read,
        .write = gpio_mockup_debugfs_write,
        .llseek = no_llseek,
+       .release = single_release,
 };
 
 static void gpio_mockup_debugfs_setup(struct device *dev,
index 39f2f9035c11df2b7c0d7446745a0c83cf7e0cc2..bda28eb82c3fadc70feed81beff1c540fe93d322 100644 (file)
@@ -7,6 +7,7 @@
  *          Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
+#include <linux/dmi.h>
 #include <linux/errno.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 
 #include "gpiolib.h"
 
+static int run_edge_events_on_boot = -1;
+module_param(run_edge_events_on_boot, int, 0444);
+MODULE_PARM_DESC(run_edge_events_on_boot,
+                "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
+
 /**
  * struct acpi_gpio_event - ACPI GPIO event handler data
  *
@@ -170,10 +176,13 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
        event->irq_requested = true;
 
        /* Make sure we trigger the initial state of edge-triggered IRQs */
-       value = gpiod_get_raw_value_cansleep(event->desc);
-       if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
-           ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
-               event->handler(event->irq, event);
+       if (run_edge_events_on_boot &&
+           (event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
+               value = gpiod_get_raw_value_cansleep(event->desc);
+               if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
+                   ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
+                       event->handler(event->irq, event);
+       }
 }
 
 static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
@@ -1283,3 +1292,28 @@ static int acpi_gpio_handle_deferred_request_irqs(void)
 }
 /* We must use _sync so that this runs after the first deferred_probe run */
 late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
+
+static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
+               }
+       },
+       {} /* Terminating entry */
+};
+
+static int acpi_gpio_setup_params(void)
+{
+       if (run_edge_events_on_boot < 0) {
+               if (dmi_check_system(run_edge_events_on_boot_blacklist))
+                       run_edge_events_on_boot = 0;
+               else
+                       run_edge_events_on_boot = 1;
+       }
+
+       return 0;
+}
+
+/* Directly after dmi_setup() which runs as core_initcall() */
+postcore_initcall(acpi_gpio_setup_params);
index 9762dd6d99fa85181d542703449f7f12a5432b58..9b44c49a922783d4f06e09248d8211ff50c61c48 100644 (file)
@@ -343,36 +343,27 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
 
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
-               /*
-                * -EPROBE_DEFER in our case means that we found a
-                * valid GPIO property, but no controller has been
-                * registered so far.
-                *
-                * This means we don't need to look any further for
-                * alternate name conventions, and we should really
-                * preserve the return code for our user to be able to
-                * retry probing later.
-                */
-               if (IS_ERR(desc) && PTR_ERR(desc) == -EPROBE_DEFER)
-                       return desc;
 
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+               if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT)
                        break;
        }
 
-       /* Special handling for SPI GPIOs if used */
-       if (IS_ERR(desc))
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
+               /* Special handling for SPI GPIOs if used */
                desc = of_find_spi_gpio(dev, con_id, &of_flags);
-       if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) {
+       }
+
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
                /* This quirk looks up flags and all */
                desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
                if (!IS_ERR(desc))
                        return desc;
        }
 
-       /* Special handling for regulator GPIOs if used */
-       if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
+               /* Special handling for regulator GPIOs if used */
                desc = of_find_regulator_gpio(dev, con_id, &of_flags);
+       }
 
        if (IS_ERR(desc))
                return desc;
index cca749010cd00afe966ac43ae91ae35b756092aa..d9074191edef4da533d27673660e6f357df32fe7 100644 (file)
@@ -535,6 +535,14 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
        if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
                return -EINVAL;
 
+       /*
+        * Do not allow both INPUT & OUTPUT flags to be set as they are
+        * contradictory.
+        */
+       if ((lflags & GPIOHANDLE_REQUEST_INPUT) &&
+           (lflags & GPIOHANDLE_REQUEST_OUTPUT))
+               return -EINVAL;
+
        /*
         * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
         * the hardware actually supports enabling both at the same time the
@@ -926,7 +934,9 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        }
 
        /* This is just wrong: we don't look for events on output lines */
-       if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) {
                ret = -EINVAL;
                goto out_free_label;
        }
@@ -940,10 +950,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
 
        if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
                set_bit(FLAG_ACTIVE_LOW, &desc->flags);
-       if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
-               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-       if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
-               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 
        ret = gpiod_direction_input(desc);
        if (ret)
index 0d23bf729e9fa3a4997ff1b237c473cdacb94804..c814bcef18a4007d90d5dcb85fd8abb6c69a985b 100644 (file)
@@ -1677,7 +1677,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
        return 0;
 }
 
-static const char *drm_named_modes_whitelist[] = {
+static const char * const drm_named_modes_whitelist[] = {
        "NTSC",
        "PAL",
 };
index 18e4cba767201cffbd550d0a0ea2d3245eaf5c43..8aa6a31e8ad07d8e02f4e88142e665ce20997c19 100644 (file)
@@ -128,7 +128,15 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
        limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
 
        limits.min_bpp = intel_dp_min_bpp(pipe_config);
-       limits.max_bpp = pipe_config->pipe_bpp;
+       /*
+        * FIXME: If all the streams can't fit into the link with
+        * their current pipe_bpp we should reduce pipe_bpp across
+        * the board until things start to fit. Until then we
+        * limit to <= 8bpc since that's what was hardcoded for all
+        * MST streams previously. This hack should be removed once
+        * we have the proper retry logic in place.
+        */
+       limits.max_bpp = min(pipe_config->pipe_bpp, 24);
 
        intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
 
index 2caa594322bc3f977e6d5720bf1f4a545fd89b43..528b6167833456d9fc6c5a0f8a53197c980a80d1 100644 (file)
@@ -664,15 +664,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj,
 
        for_each_sgt_page(page, sgt_iter, pages) {
                if (obj->mm.dirty)
-                       /*
-                        * As this may not be anonymous memory (e.g. shmem)
-                        * but exist on a real mapping, we have to lock
-                        * the page in order to dirty it -- holding
-                        * the page reference is not sufficient to
-                        * prevent the inode from being truncated.
-                        * Play safe and take the lock.
-                        */
-                       set_page_dirty_lock(page);
+                       set_page_dirty(page);
 
                mark_page_accessed(page);
                put_page(page);
index 98dfb086320fad58f95b6be36d11a58c7af1fc4d..99e8242194c00891698ce9659e9960efe0d39b4e 100644 (file)
@@ -308,11 +308,6 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine,
                          FLOW_CONTROL_ENABLE |
                          PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
 
-       /* Syncing dependencies between camera and graphics:skl,bxt,kbl */
-       if (!IS_COFFEELAKE(i915))
-               WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
-                                 GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
-
        /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */
        /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */
        WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
index 477c0f766663de92dfd4bf263e7e374896eef73a..b609dc030d6ca906f61ffd8bba47dce8bf1e644d 100644 (file)
@@ -342,7 +342,7 @@ int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns)
        timeout = drm_timeout_abs_to_jiffies(timeout_ns);
 
        ret = drm_gem_reservation_object_wait(file, handle, write, timeout);
-       if (ret == 0)
+       if (ret == -ETIME)
                ret = timeout ? -ETIMEDOUT : -EBUSY;
 
        return ret;
index 650dd71f9724ae605761066b75ff191dc8bd7229..2ca5668bdb626a866b9b581caa0e76af23378f28 100644 (file)
@@ -246,6 +246,16 @@ config SENSORS_ADT7475
          This driver can also be built as a module. If so, the module
          will be called adt7475.
 
+config SENSORS_AS370
+       tristate "Synaptics AS370 SoC hardware monitoring driver"
+       help
+         If you say yes here you get support for the PVT sensors of
+         the Synaptics AS370 SoC
+
+         This driver can also be built as a module. If so, the module
+         will be called as370-hwmon.
+
+
 config SENSORS_ASC7621
        tristate "Andigilog aSC7621"
        depends on I2C
@@ -1382,8 +1392,8 @@ config SENSORS_SHTC1
        tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
        depends on I2C
        help
-         If you say yes here you get support for the Sensiron SHTC1 and SHTW1
-         humidity and temperature sensors.
+         If you say yes here you get support for the Sensiron SHTC1, SHTW1,
+         and SHTC3 humidity and temperature sensors.
 
          This driver can also be built as a module. If so, the module
          will be called shtc1.
@@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818
          This driver can also be built as a module. If so, the module
          will be called adc128d818.
 
-config SENSORS_ADS1015
-       tristate "Texas Instruments ADS1015"
-       depends on I2C
-       help
-         If you say yes here you get support for Texas Instruments
-         ADS1015/ADS1115 12/16-bit 4-input ADC device.
-
-         This driver can also be built as a module. If so, the module
-         will be called ads1015.
-
 config SENSORS_ADS7828
        tristate "Texas Instruments ADS7828 and compatibles"
        depends on I2C
@@ -1834,17 +1834,12 @@ config SENSORS_W83795
          will be called w83795.
 
 config SENSORS_W83795_FANCTRL
-       bool "Include automatic fan control support (DANGEROUS)"
+       bool "Include automatic fan control support"
        depends on SENSORS_W83795
        help
          If you say yes here, support for automatic fan speed control
          will be included in the driver.
 
-         This part of the code wasn't carefully reviewed and tested yet,
-         so enabling this option is strongly discouraged on production
-         servers. Only developers and testers should enable it for the
-         time being.
-
          Please also note that this option will create sysfs attribute
          files which may change in the future, so you shouldn't rely
          on them being stable.
index 8db472ea04f00880b8aee3a303847d95fb733261..c86ce4d3d36b9e67f2173cceed38466c36051657 100644 (file)
@@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
 obj-$(CONFIG_SENSORS_ADM1029)  += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
-obj-$(CONFIG_SENSORS_ADS1015)  += ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
 obj-$(CONFIG_SENSORS_ADT7X10)  += adt7x10.o
@@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
 obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
 obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o
 obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
+obj-$(CONFIG_SENSORS_AS370)    += as370-hwmon.o
 obj-$(CONFIG_SENSORS_ASC7621)  += asc7621.o
 obj-$(CONFIG_SENSORS_ASPEED)   += aspeed-pwm-tacho.o
 obj-$(CONFIG_SENSORS_ATXP1)    += atxp1.o
index 6ba1a08253f0a3cc12a7657e4c31a0853c13b963..4cf25458f0b9515e419a6f0b88047bf35809a2e5 100644 (file)
@@ -681,8 +681,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
 
        if (resource->caps.flags & POWER_METER_CAN_CAP) {
                if (!can_cap_in_hardware()) {
-                       dev_err(&resource->acpi_dev->dev,
-                               "Ignoring unsafe software power cap!\n");
+                       dev_warn(&resource->acpi_dev->dev,
+                                "Ignoring unsafe software power cap!\n");
                        goto skip_unsafe_cap;
                }
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
deleted file mode 100644 (file)
index 3727a37..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
- * (C) Copyright 2010
- * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
- *
- * Based on the ads7828 driver by Steve Hardy.
- *
- * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-
-#include <linux/platform_data/ads1015.h>
-
-/* ADS1015 registers */
-enum {
-       ADS1015_CONVERSION = 0,
-       ADS1015_CONFIG = 1,
-};
-
-/* PGA fullscale voltages in mV */
-static const unsigned int fullscale_table[8] = {
-       6144, 4096, 2048, 1024, 512, 256, 256, 256 };
-
-/* Data rates in samples per second */
-static const unsigned int data_rate_table_1015[8] = {
-       128, 250, 490, 920, 1600, 2400, 3300, 3300
-};
-
-static const unsigned int data_rate_table_1115[8] = {
-       8, 16, 32, 64, 128, 250, 475, 860
-};
-
-#define ADS1015_DEFAULT_CHANNELS 0xff
-#define ADS1015_DEFAULT_PGA 2
-#define ADS1015_DEFAULT_DATA_RATE 4
-
-enum ads1015_chips {
-       ads1015,
-       ads1115,
-};
-
-struct ads1015_data {
-       struct device *hwmon_dev;
-       struct mutex update_lock; /* mutex protect updates */
-       struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
-       enum ads1015_chips id;
-};
-
-static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
-{
-       u16 config;
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       unsigned int pga = data->channel_data[channel].pga;
-       unsigned int data_rate = data->channel_data[channel].data_rate;
-       unsigned int conversion_time_ms;
-       const unsigned int * const rate_table = data->id == ads1115 ?
-               data_rate_table_1115 : data_rate_table_1015;
-       int res;
-
-       mutex_lock(&data->update_lock);
-
-       /* get channel parameters */
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
-       if (res < 0)
-               goto err_unlock;
-       config = res;
-       conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
-
-       /* setup and start single conversion */
-       config &= 0x001f;
-       config |= (1 << 15) | (1 << 8);
-       config |= (channel & 0x0007) << 12;
-       config |= (pga & 0x0007) << 9;
-       config |= (data_rate & 0x0007) << 5;
-
-       res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config);
-       if (res < 0)
-               goto err_unlock;
-
-       /* wait until conversion finished */
-       msleep(conversion_time_ms);
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
-       if (res < 0)
-               goto err_unlock;
-       config = res;
-       if (!(config & (1 << 15))) {
-               /* conversion not finished in time */
-               res = -EIO;
-               goto err_unlock;
-       }
-
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION);
-
-err_unlock:
-       mutex_unlock(&data->update_lock);
-       return res;
-}
-
-static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
-                            s16 reg)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       unsigned int pga = data->channel_data[channel].pga;
-       int fullscale = fullscale_table[pga];
-       const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
-
-       return DIV_ROUND_CLOSEST(reg * fullscale, mask);
-}
-
-/* sysfs callback function */
-static ssize_t in_show(struct device *dev, struct device_attribute *da,
-                      char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct i2c_client *client = to_i2c_client(dev);
-       int res;
-       int index = attr->index;
-
-       res = ads1015_read_adc(client, index);
-       if (res < 0)
-               return res;
-
-       return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res));
-}
-
-static const struct sensor_device_attribute ads1015_in[] = {
-       SENSOR_ATTR_RO(in0_input, in, 0),
-       SENSOR_ATTR_RO(in1_input, in, 1),
-       SENSOR_ATTR_RO(in2_input, in, 2),
-       SENSOR_ATTR_RO(in3_input, in, 3),
-       SENSOR_ATTR_RO(in4_input, in, 4),
-       SENSOR_ATTR_RO(in5_input, in, 5),
-       SENSOR_ATTR_RO(in6_input, in, 6),
-       SENSOR_ATTR_RO(in7_input, in, 7),
-};
-
-/*
- * Driver interface
- */
-
-static int ads1015_remove(struct i2c_client *client)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       int k;
-
-       hwmon_device_unregister(data->hwmon_dev);
-       for (k = 0; k < ADS1015_CHANNELS; ++k)
-               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       return 0;
-}
-
-#ifdef CONFIG_OF
-static int ads1015_get_channels_config_of(struct i2c_client *client)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       struct device_node *node;
-
-       if (!client->dev.of_node
-           || !of_get_next_child(client->dev.of_node, NULL))
-               return -EINVAL;
-
-       for_each_child_of_node(client->dev.of_node, node) {
-               u32 pval;
-               unsigned int channel;
-               unsigned int pga = ADS1015_DEFAULT_PGA;
-               unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
-
-               if (of_property_read_u32(node, "reg", &pval)) {
-                       dev_err(&client->dev, "invalid reg on %pOF\n", node);
-                       continue;
-               }
-
-               channel = pval;
-               if (channel >= ADS1015_CHANNELS) {
-                       dev_err(&client->dev,
-                               "invalid channel index %d on %pOF\n",
-                               channel, node);
-                       continue;
-               }
-
-               if (!of_property_read_u32(node, "ti,gain", &pval)) {
-                       pga = pval;
-                       if (pga > 6) {
-                               dev_err(&client->dev, "invalid gain on %pOF\n",
-                                       node);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!of_property_read_u32(node, "ti,datarate", &pval)) {
-                       data_rate = pval;
-                       if (data_rate > 7) {
-                               dev_err(&client->dev,
-                                       "invalid data_rate on %pOF\n", node);
-                               return -EINVAL;
-                       }
-               }
-
-               data->channel_data[channel].enabled = true;
-               data->channel_data[channel].pga = pga;
-               data->channel_data[channel].data_rate = data_rate;
-       }
-
-       return 0;
-}
-#endif
-
-static void ads1015_get_channels_config(struct i2c_client *client)
-{
-       unsigned int k;
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
-
-       /* prefer platform data */
-       if (pdata) {
-               memcpy(data->channel_data, pdata->channel_data,
-                      sizeof(data->channel_data));
-               return;
-       }
-
-#ifdef CONFIG_OF
-       if (!ads1015_get_channels_config_of(client))
-               return;
-#endif
-
-       /* fallback on default configuration */
-       for (k = 0; k < ADS1015_CHANNELS; ++k) {
-               data->channel_data[k].enabled = true;
-               data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
-               data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
-       }
-}
-
-static int ads1015_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct ads1015_data *data;
-       int err;
-       unsigned int k;
-
-       data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
-                           GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       if (client->dev.of_node)
-               data->id = (enum ads1015_chips)
-                       of_device_get_match_data(&client->dev);
-       else
-               data->id = id->driver_data;
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       /* build sysfs attribute group */
-       ads1015_get_channels_config(client);
-       for (k = 0; k < ADS1015_CHANNELS; ++k) {
-               if (!data->channel_data[k].enabled)
-                       continue;
-               err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       for (k = 0; k < ADS1015_CHANNELS; ++k)
-               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       return err;
-}
-
-static const struct i2c_device_id ads1015_id[] = {
-       { "ads1015",  ads1015},
-       { "ads1115",  ads1115},
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ads1015_id);
-
-static const struct of_device_id __maybe_unused ads1015_of_match[] = {
-       {
-               .compatible = "ti,ads1015",
-               .data = (void *)ads1015
-       },
-       {
-               .compatible = "ti,ads1115",
-               .data = (void *)ads1115
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, ads1015_of_match);
-
-static struct i2c_driver ads1015_driver = {
-       .driver = {
-               .name = "ads1015",
-               .of_match_table = of_match_ptr(ads1015_of_match),
-       },
-       .probe = ads1015_probe,
-       .remove = ads1015_remove,
-       .id_table = ads1015_id,
-};
-
-module_i2c_driver(ads1015_driver);
-
-MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
-MODULE_DESCRIPTION("ADS1015 driver");
-MODULE_LICENSE("GPL");
index c3c6031a728520d9e0035de8ff2e5e02d693d41f..6c64d50c9aae8ec175d9477fa98af6c851849d2f 100644 (file)
@@ -187,7 +187,7 @@ static const struct of_device_id __maybe_unused adt7475_of_match[] = {
 MODULE_DEVICE_TABLE(of, adt7475_of_match);
 
 struct adt7475_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex lock;
 
        unsigned long measure_updated;
@@ -212,6 +212,7 @@ struct adt7475_data {
 
        u8 vid;
        u8 vrm;
+       const struct attribute_group *groups[9];
 };
 
 static struct i2c_driver adt7475_driver;
@@ -346,8 +347,8 @@ static ssize_t voltage_store(struct device *dev,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg;
        long val;
 
@@ -440,8 +441,8 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg = 0;
        u8 out;
        int temp;
@@ -542,8 +543,7 @@ static ssize_t temp_st_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
        long val;
 
        switch (sattr->index) {
@@ -570,8 +570,8 @@ static ssize_t temp_st_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg;
        int shift, idx;
        ulong val;
@@ -647,8 +647,8 @@ static ssize_t point2_show(struct device *dev, struct device_attribute *attr,
 static ssize_t point2_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
        int temp;
        long val;
@@ -710,8 +710,8 @@ static ssize_t tach_store(struct device *dev, struct device_attribute *attr,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val))
@@ -769,8 +769,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg = 0;
        long val;
 
@@ -818,8 +818,8 @@ static ssize_t stall_disable_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+
        u8 mask = BIT(5 + sattr->index);
 
        return sprintf(buf, "%d\n", !!(data->enh_acoustics[0] & mask));
@@ -830,8 +830,8 @@ static ssize_t stall_disable_store(struct device *dev,
                                   const char *buf, size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long val;
        u8 mask = BIT(5 + sattr->index);
 
@@ -914,8 +914,8 @@ static ssize_t pwmchan_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int r;
        long val;
 
@@ -938,8 +938,8 @@ static ssize_t pwmctrl_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int r;
        long val;
 
@@ -982,8 +982,8 @@ static ssize_t pwmfreq_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int out;
        long val;
 
@@ -1022,8 +1022,8 @@ static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev,
                                        struct device_attribute *devattr,
                                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long val;
 
        if (kstrtol(buf, 10, &val))
@@ -1342,26 +1342,6 @@ static int adt7475_detect(struct i2c_client *client,
        return 0;
 }
 
-static void adt7475_remove_files(struct i2c_client *client,
-                                struct adt7475_data *data)
-{
-       sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
-       if (data->has_fan4)
-               sysfs_remove_group(&client->dev.kobj, &fan4_attr_group);
-       if (data->has_pwm2)
-               sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group);
-       if (data->has_voltage & (1 << 0))
-               sysfs_remove_group(&client->dev.kobj, &in0_attr_group);
-       if (data->has_voltage & (1 << 3))
-               sysfs_remove_group(&client->dev.kobj, &in3_attr_group);
-       if (data->has_voltage & (1 << 4))
-               sysfs_remove_group(&client->dev.kobj, &in4_attr_group);
-       if (data->has_voltage & (1 << 5))
-               sysfs_remove_group(&client->dev.kobj, &in5_attr_group);
-       if (data->has_vid)
-               sysfs_remove_group(&client->dev.kobj, &vid_attr_group);
-}
-
 static int adt7475_update_limits(struct i2c_client *client)
 {
        struct adt7475_data *data = i2c_get_clientdata(client);
@@ -1489,7 +1469,8 @@ static int adt7475_probe(struct i2c_client *client,
        };
 
        struct adt7475_data *data;
-       int i, ret = 0, revision;
+       struct device *hwmon_dev;
+       int i, ret = 0, revision, group_num = 0;
        u8 config2, config3;
 
        data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
@@ -1497,6 +1478,7 @@ static int adt7475_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mutex_init(&data->lock);
+       data->client = client;
        i2c_set_clientdata(client, data);
 
        if (client->dev.of_node)
@@ -1590,52 +1572,40 @@ static int adt7475_probe(struct i2c_client *client,
                break;
        }
 
-       ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
-       if (ret)
-               return ret;
+       data->groups[group_num++] = &adt7475_attr_group;
 
        /* Features that can be disabled individually */
        if (data->has_fan4) {
-               ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &fan4_attr_group;
        }
        if (data->has_pwm2) {
-               ret = sysfs_create_group(&client->dev.kobj, &pwm2_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &pwm2_attr_group;
        }
        if (data->has_voltage & (1 << 0)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in0_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in0_attr_group;
        }
        if (data->has_voltage & (1 << 3)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in3_attr_group;
        }
        if (data->has_voltage & (1 << 4)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in4_attr_group;
        }
        if (data->has_voltage & (1 << 5)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in5_attr_group;
        }
        if (data->has_vid) {
                data->vrm = vid_which_vrm();
-               ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num] = &vid_attr_group;
        }
 
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               ret = PTR_ERR(data->hwmon_dev);
-               goto eremove;
+       /* register device with all the acquired attributes */
+       hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+                                                          client->name, data,
+                                                          data->groups);
+
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
+               return ret;
        }
 
        dev_info(&client->dev, "%s device, revision %d\n",
@@ -1657,21 +1627,7 @@ static int adt7475_probe(struct i2c_client *client,
        /* Limits and settings, should never change update more than once */
        ret = adt7475_update_limits(client);
        if (ret)
-               goto eremove;
-
-       return 0;
-
-eremove:
-       adt7475_remove_files(client, data);
-       return ret;
-}
-
-static int adt7475_remove(struct i2c_client *client)
-{
-       struct adt7475_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       adt7475_remove_files(client, data);
+               return ret;
 
        return 0;
 }
@@ -1683,7 +1639,6 @@ static struct i2c_driver adt7475_driver = {
                .of_match_table = of_match_ptr(adt7475_of_match),
        },
        .probe          = adt7475_probe,
-       .remove         = adt7475_remove,
        .id_table       = adt7475_id,
        .detect         = adt7475_detect,
        .address_list   = normal_i2c,
@@ -1757,8 +1712,8 @@ static void adt7475_read_pwm(struct i2c_client *client, int index)
 
 static int adt7475_update_measure(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        u16 ext;
        int i;
        int ret;
@@ -1854,8 +1809,7 @@ static int adt7475_update_measure(struct device *dev)
 
 static struct adt7475_data *adt7475_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
        int ret;
 
        mutex_lock(&data->lock);
diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c
new file mode 100644 (file)
index 0000000..464244b
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Synaptics AS370 SoC Hardware Monitoring Driver
+ *
+ * Copyright (C) 2018 Synaptics Incorporated
+ * Author: Jisheng Zhang <jszhang@kernel.org>
+ */
+
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#define CTRL           0x0
+#define  PD            BIT(0)
+#define  EN            BIT(1)
+#define  T_SEL         BIT(2)
+#define  V_SEL         BIT(3)
+#define  NMOS_SEL      BIT(8)
+#define  PMOS_SEL      BIT(9)
+#define STS            0x4
+#define  BN_MASK       GENMASK(11, 0)
+#define  EOC           BIT(12)
+
+struct as370_hwmon {
+       void __iomem *base;
+};
+
+static void init_pvt(struct as370_hwmon *hwmon)
+{
+       u32 val;
+       void __iomem *addr = hwmon->base + CTRL;
+
+       val = PD;
+       writel_relaxed(val, addr);
+       val |= T_SEL;
+       writel_relaxed(val, addr);
+       val |= EN;
+       writel_relaxed(val, addr);
+       val &= ~PD;
+       writel_relaxed(val, addr);
+}
+
+static int as370_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+                           u32 attr, int channel, long *temp)
+{
+       int val;
+       struct as370_hwmon *hwmon = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_temp_input:
+               val = readl_relaxed(hwmon->base + STS) & BN_MASK;
+               *temp = DIV_ROUND_CLOSEST(val * 251802, 4096) - 85525;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static umode_t
+as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
+                      u32 attr, int channel)
+{
+       if (type != hwmon_temp)
+               return 0;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static const u32 as370_hwmon_temp_config[] = {
+       HWMON_T_INPUT,
+       0
+};
+
+static const struct hwmon_channel_info as370_hwmon_temp = {
+       .type = hwmon_temp,
+       .config = as370_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *as370_hwmon_info[] = {
+       &as370_hwmon_temp,
+       NULL
+};
+
+static const struct hwmon_ops as370_hwmon_ops = {
+       .is_visible = as370_hwmon_is_visible,
+       .read = as370_hwmon_read,
+};
+
+static const struct hwmon_chip_info as370_chip_info = {
+       .ops = &as370_hwmon_ops,
+       .info = as370_hwmon_info,
+};
+
+static int as370_hwmon_probe(struct platform_device *pdev)
+{
+       struct device *hwmon_dev;
+       struct as370_hwmon *hwmon;
+       struct device *dev = &pdev->dev;
+
+       hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+       if (!hwmon)
+               return -ENOMEM;
+
+       hwmon->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(hwmon->base))
+               return PTR_ERR(hwmon->base);
+
+       init_pvt(hwmon);
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev,
+                                                        "as370",
+                                                        hwmon,
+                                                        &as370_chip_info,
+                                                        NULL);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id as370_hwmon_match[] = {
+       { .compatible = "syna,as370-hwmon" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, as370_hwmon_match);
+
+static struct platform_driver as370_hwmon_driver = {
+       .probe = as370_hwmon_probe,
+       .driver = {
+               .name = "as370-hwmon",
+               .of_match_table = as370_hwmon_match,
+       },
+};
+module_platform_driver(as370_hwmon_driver);
+
+MODULE_AUTHOR("Jisheng Zhang<jszhang@kernel.org>");
+MODULE_DESCRIPTION("Synaptics AS370 SoC hardware monitor");
+MODULE_LICENSE("GPL v2");
index c9fa84b256783df45824abe066bdbe1cb5896422..4c609e23a4efb93d683bcefbd6e78b4ab53ea0ea 100644 (file)
@@ -706,21 +706,21 @@ static int asb100_detect_subclients(struct i2c_client *client)
                goto ERROR_SC_2;
        }
 
-       data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
-       if (!data->lm75[0]) {
+       data->lm75[0] = i2c_new_dummy_device(adapter, sc_addr[0]);
+       if (IS_ERR(data->lm75[0])) {
                dev_err(&client->dev,
                        "subclient %d registration at address 0x%x failed.\n",
                        1, sc_addr[0]);
-               err = -ENOMEM;
+               err = PTR_ERR(data->lm75[0]);
                goto ERROR_SC_2;
        }
 
-       data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
-       if (!data->lm75[1]) {
+       data->lm75[1] = i2c_new_dummy_device(adapter, sc_addr[1]);
+       if (IS_ERR(data->lm75[1])) {
                dev_err(&client->dev,
                        "subclient %d registration at address 0x%x failed.\n",
                        2, sc_addr[1]);
-               err = -ENOMEM;
+               err = PTR_ERR(data->lm75[1]);
                goto ERROR_SC_3;
        }
 
index fe6618e49dc436cafda1e5ad12f6a8cbd89ef7c6..d855c78fb8bea77d87df0fe2a16289a039bc63ed 100644 (file)
@@ -736,7 +736,7 @@ static int __init coretemp_init(void)
 
        err = platform_driver_register(&coretemp_driver);
        if (err)
-               return err;
+               goto outzone;
 
        err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
                                coretemp_cpu_online, coretemp_cpu_offline);
@@ -747,6 +747,7 @@ static int __init coretemp_init(void)
 
 outdrv:
        platform_driver_unregister(&coretemp_driver);
+outzone:
        kfree(zone_devices);
        return err;
 }
index f1c2d5faedf0d76d2074b305065cf2261e6ceb72..b85a125dd86f46a26ac817bd42a718c4ad97310c 100644 (file)
@@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
        int ret;
        struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
        struct iio_hwmon_state *state = dev_get_drvdata(dev);
+       struct iio_channel *chan = &state->channels[sattr->index];
+       enum iio_chan_type type;
+
+       ret = iio_read_channel_processed(chan, &result);
+       if (ret < 0)
+               return ret;
 
-       ret = iio_read_channel_processed(&state->channels[sattr->index],
-                                       &result);
+       ret = iio_get_channel_type(chan, &type);
        if (ret < 0)
                return ret;
 
+       if (type == IIO_POWER)
+               result *= 1000; /* mili-Watts to micro-Watts conversion */
+
        return sprintf(buf, "%d\n", result);
 }
 
@@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
        struct iio_hwmon_state *st;
        struct sensor_device_attribute *a;
        int ret, i;
-       int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
+       int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1;
        enum iio_chan_type type;
        struct iio_channel *channels;
        struct device *hwmon_dev;
@@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
                        n = curr_i++;
                        prefix = "curr";
                        break;
+               case IIO_POWER:
+                       n = power_i++;
+                       prefix = "power";
+                       break;
                case IIO_HUMIDITYRELATIVE:
                        n = humidity_i++;
                        prefix = "humidity";
index c77e89239dcd9a32c143203030362264d86f83b7..5c1dddde193c3e1ce50c539ba91e00b885a73190 100644 (file)
@@ -349,6 +349,7 @@ static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
        { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        {}
 };
index 4994c90c892986d9546765607eb7726b41adfee9..f73bd4eceb28f0e46c628b1902b3b2d6d90c0195 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/pci.h>
 #include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/processor.h>
 #define SEL_CORE       0x04
 
 struct k8temp_data {
-       struct device *hwmon_dev;
        struct mutex update_lock;
-       const char *name;
-       char valid;             /* zero until following fields are valid */
-       unsigned long last_updated;     /* in jiffies */
 
        /* registers values */
        u8 sensorsp;            /* sensor presence bits - SEL_CORE, SEL_PLACE */
-       u32 temp[2][2];         /* core, place */
        u8 swap_core_select;    /* meaning of SEL_CORE is inverted */
        u32 temp_offset;
 };
 
-static struct k8temp_data *k8temp_update_device(struct device *dev)
-{
-       struct k8temp_data *data = dev_get_drvdata(dev);
-       struct pci_dev *pdev = to_pci_dev(dev);
-       u8 tmp;
-
-       mutex_lock(&data->update_lock);
-
-       if (!data->valid
-           || time_after(jiffies, data->last_updated + HZ)) {
-               pci_read_config_byte(pdev, REG_TEMP, &tmp);
-               tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
-               pci_write_config_byte(pdev, REG_TEMP, tmp);
-               pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
-
-               if (data->sensorsp & SEL_PLACE) {
-                       tmp |= SEL_PLACE;       /* Select sensor 1, core0 */
-                       pci_write_config_byte(pdev, REG_TEMP, tmp);
-                       pci_read_config_dword(pdev, REG_TEMP,
-                                             &data->temp[0][1]);
-               }
-
-               if (data->sensorsp & SEL_CORE) {
-                       tmp &= ~SEL_PLACE;      /* Select sensor 0, core1 */
-                       tmp |= SEL_CORE;
-                       pci_write_config_byte(pdev, REG_TEMP, tmp);
-                       pci_read_config_dword(pdev, REG_TEMP,
-                                             &data->temp[1][0]);
-
-                       if (data->sensorsp & SEL_PLACE) {
-                               tmp |= SEL_PLACE; /* Select sensor 1, core1 */
-                               pci_write_config_byte(pdev, REG_TEMP, tmp);
-                               pci_read_config_dword(pdev, REG_TEMP,
-                                                     &data->temp[1][1]);
-                       }
-               }
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-       return data;
-}
-
-/*
- * Sysfs stuff
- */
-
-static ssize_t name_show(struct device *dev, struct device_attribute
-                        *devattr, char *buf)
-{
-       struct k8temp_data *data = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%s\n", data->name);
-}
-
-
-static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
-                        char *buf)
-{
-       struct sensor_device_attribute_2 *attr =
-           to_sensor_dev_attr_2(devattr);
-       int core = attr->nr;
-       int place = attr->index;
-       int temp;
-       struct k8temp_data *data = k8temp_update_device(dev);
-
-       if (data->swap_core_select && (data->sensorsp & SEL_CORE))
-               core = core ? 0 : 1;
-
-       temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
-
-       return sprintf(buf, "%d\n", temp);
-}
-
-/* core, place */
-
-static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0, 0);
-static SENSOR_DEVICE_ATTR_2_RO(temp2_input, temp, 0, 1);
-static SENSOR_DEVICE_ATTR_2_RO(temp3_input, temp, 1, 0);
-static SENSOR_DEVICE_ATTR_2_RO(temp4_input, temp, 1, 1);
-static DEVICE_ATTR_RO(name);
-
 static const struct pci_device_id k8temp_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { 0 },
 };
-
 MODULE_DEVICE_TABLE(pci, k8temp_ids);
 
 static int is_rev_g_desktop(u8 model)
@@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model)
        return 1;
 }
 
+static umode_t
+k8temp_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+                 u32 attr, int channel)
+{
+       const struct k8temp_data *data = drvdata;
+
+       if ((channel & 1) && !(data->sensorsp & SEL_PLACE))
+               return 0;
+
+       if ((channel & 2) && !(data->sensorsp & SEL_CORE))
+               return 0;
+
+       return 0444;
+}
+
+static int
+k8temp_read(struct device *dev, enum hwmon_sensor_types type,
+           u32 attr, int channel, long *val)
+{
+       struct k8temp_data *data = dev_get_drvdata(dev);
+       struct pci_dev *pdev = to_pci_dev(dev->parent);
+       int core, place;
+       u32 temp;
+       u8 tmp;
+
+       core = (channel >> 1) & 1;
+       place = channel & 1;
+
+       core ^= data->swap_core_select;
+
+       mutex_lock(&data->update_lock);
+       pci_read_config_byte(pdev, REG_TEMP, &tmp);
+       tmp &= ~(SEL_PLACE | SEL_CORE);
+       if (core)
+               tmp |= SEL_CORE;
+       if (place)
+               tmp |= SEL_PLACE;
+       pci_write_config_byte(pdev, REG_TEMP, tmp);
+       pci_read_config_dword(pdev, REG_TEMP, &temp);
+       mutex_unlock(&data->update_lock);
+
+       *val = TEMP_FROM_REG(temp) + data->temp_offset;
+
+       return 0;
+}
+
+static const struct hwmon_ops k8temp_ops = {
+       .is_visible = k8temp_is_visible,
+       .read = k8temp_read,
+};
+
+static const struct hwmon_channel_info *k8temp_info[] = {
+       HWMON_CHANNEL_INFO(temp,
+               HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT),
+       NULL
+};
+
+static const struct hwmon_chip_info k8temp_chip_info = {
+       .ops = &k8temp_ops,
+       .info = k8temp_info,
+};
+
 static int k8temp_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *id)
 {
-       int err;
        u8 scfg;
        u32 temp;
        u8 model, stepping;
        struct k8temp_data *data;
+       struct device *hwmon_dev;
 
        data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
        if (!data)
@@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev,
                        data->sensorsp &= ~SEL_CORE;
        }
 
-       data->name = "k8temp";
        mutex_init(&data->update_lock);
-       pci_set_drvdata(pdev, data);
-
-       /* Register sysfs hooks */
-       err = device_create_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       if (err)
-               goto exit_remove;
-
-       /* sensor can be changed and reports something */
-       if (data->sensorsp & SEL_PLACE) {
-               err = device_create_file(&pdev->dev,
-                                  &sensor_dev_attr_temp2_input.dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       /* core can be changed and reports something */
-       if (data->sensorsp & SEL_CORE) {
-               err = device_create_file(&pdev->dev,
-                                  &sensor_dev_attr_temp3_input.dev_attr);
-               if (err)
-                       goto exit_remove;
-               if (data->sensorsp & SEL_PLACE) {
-                       err = device_create_file(&pdev->dev,
-                                          &sensor_dev_attr_temp4_input.
-                                          dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-       }
-
-       err = device_create_file(&pdev->dev, &dev_attr_name);
-       if (err)
-               goto exit_remove;
 
-       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
+                                                        "k8temp",
+                                                        data,
+                                                        &k8temp_chip_info,
+                                                        NULL);
 
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp2_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp3_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp4_input.dev_attr);
-       device_remove_file(&pdev->dev, &dev_attr_name);
-       return err;
-}
-
-static void k8temp_remove(struct pci_dev *pdev)
-{
-       struct k8temp_data *data = pci_get_drvdata(pdev);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp2_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp3_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp4_input.dev_attr);
-       device_remove_file(&pdev->dev, &dev_attr_name);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static struct pci_driver k8temp_driver = {
        .name = "k8temp",
        .id_table = k8temp_ids,
        .probe = k8temp_probe,
-       .remove = k8temp_remove,
 };
 
 module_pci_driver(k8temp_driver);
index ce5ec403ec739c819ee8f896e5958d63380246ee..5e6392294c0351e529754bef61426dbdcd35876d 100644 (file)
@@ -16,9 +16,9 @@
 #include <linux/of_device.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
+#include <linux/util_macros.h>
 #include "lm75.h"
 
-
 /*
  * This driver handles the LM75 and compatible digital temperature sensors.
  */
@@ -36,6 +36,7 @@ enum lm75_type {              /* keep sorted in alphabetical order */
        max6626,
        max31725,
        mcp980x,
+       pct2075,
        stds75,
        stlm75,
        tcn75,
@@ -50,6 +51,41 @@ enum lm75_type {             /* keep sorted in alphabetical order */
        tmp75c,
 };
 
+/**
+ * struct lm75_params - lm75 configuration parameters.
+ * @set_mask:          Bits to set in configuration register when configuring
+ *                     the chip.
+ * @clr_mask:          Bits to clear in configuration register when configuring
+ *                     the chip.
+ * @default_resolution:        Default number of bits to represent the temperature
+ *                     value.
+ * @resolution_limits: Limit register resolution. Optional. Should be set if
+ *                     the resolution of limit registers does not match the
+ *                     resolution of the temperature register.
+ * @resolutions:       List of resolutions associated with sample times.
+ *                     Optional. Should be set if num_sample_times is larger
+ *                     than 1, and if the resolution changes with sample times.
+ *                     If set, number of entries must match num_sample_times.
+ * @default_sample_time:Sample time to be set by default.
+ * @num_sample_times:  Number of possible sample times to be set. Optional.
+ *                     Should be set if the number of sample times is larger
+ *                     than one.
+ * @sample_times:      All the possible sample times to be set. Mandatory if
+ *                     num_sample_times is larger than 1. If set, number of
+ *                     entries must match num_sample_times.
+ */
+
+struct lm75_params {
+       u8                      set_mask;
+       u8                      clr_mask;
+       u8                      default_resolution;
+       u8                      resolution_limits;
+       const u8                *resolutions;
+       unsigned int            default_sample_time;
+       u8                      num_sample_times;
+       const unsigned int      *sample_times;
+};
+
 /* Addresses scanned */
 static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
@@ -59,24 +95,231 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
 #define LM75_REG_CONF          0x01
 #define LM75_REG_HYST          0x02
 #define LM75_REG_MAX           0x03
+#define PCT2075_REG_IDLE       0x04
 
 /* Each client has this additional data */
 struct lm75_data {
-       struct i2c_client       *client;
-       struct regmap           *regmap;
-       u8                      orig_conf;
-       u8                      resolution;     /* In bits, between 9 and 16 */
-       u8                      resolution_limits;
-       unsigned int            sample_time;    /* In ms */
+       struct i2c_client               *client;
+       struct regmap                   *regmap;
+       u8                              orig_conf;
+       u8                              current_conf;
+       u8                              resolution;     /* In bits, 9 to 16 */
+       unsigned int                    sample_time;    /* In ms */
+       enum lm75_type                  kind;
+       const struct lm75_params        *params;
 };
 
 /*-----------------------------------------------------------------------*/
 
+static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
+
+#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
+
+/* The structure below stores the configuration values of the supported devices.
+ * In case of being supported multiple configurations, the default one must
+ * always be the first element of the array
+ */
+static const struct lm75_params device_params[] = {
+       [adt75] = {
+               .clr_mask = 1 << 5,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [ds1775] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 500,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 125, 250, 500, 1000 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [ds75] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 600,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 150, 300, 600, 1200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [stds75] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 600,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 150, 300, 600, 1200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [stlm75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 6,
+       },
+       [ds7505] = {
+               .set_mask = 3 << 5,     /* 12-bit mode*/
+               .default_resolution = 12,
+               .default_sample_time = 200,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 25, 50, 100, 200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [g751] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75a] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75b] = {
+               .default_resolution = 11,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [max6625] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 7,
+       },
+       [max6626] = {
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 7,
+               .resolution_limits = 9,
+       },
+       [max31725] = {
+               .default_resolution = 16,
+               .default_sample_time = MSEC_PER_SEC / 20,
+       },
+       [tcn75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 18,
+       },
+       [pct2075] = {
+               .default_resolution = 11,
+               .default_sample_time = MSEC_PER_SEC / 10,
+               .num_sample_times = 31,
+               .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600,
+               700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700,
+               1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
+               2800, 2900, 3000, 3100 },
+       },
+       [mcp980x] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .resolution_limits = 9,
+               .default_sample_time = 240,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 30, 60, 120, 240 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp100] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = 320,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 40, 80, 160, 320 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp101] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = 320,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 40, 80, 160, 320 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp105] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp112] = {
+               .set_mask = 3 << 5,     /* 8 samples / second */
+               .clr_mask = 1 << 7,     /* no one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 125,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 125, 250, 1000, 4000 },
+       },
+       [tmp175] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp275] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp75] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */
+               .clr_mask = 1 << 7 | 3 << 5,
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 37,
+               .sample_times = (unsigned int []){ MSEC_PER_SEC / 37,
+                       MSEC_PER_SEC / 18,
+                       MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 },
+               .num_sample_times = 4,
+       },
+       [tmp75c] = {
+               .clr_mask = 1 << 5,     /*not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 12,
+       }
+};
+
 static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
 {
        return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
 }
 
+static int lm75_write_config(struct lm75_data *data, u8 set_mask,
+                            u8 clr_mask)
+{
+       u8 value;
+
+       clr_mask |= LM75_SHUTDOWN;
+       value = data->current_conf & ~clr_mask;
+       value |= set_mask;
+
+       if (data->current_conf != value) {
+               s32 err;
+
+               err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF,
+                                               value);
+               if (err)
+                       return err;
+               data->current_conf = value;
+       }
+       return 0;
+}
+
 static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
                     u32 attr, int channel, long *val)
 {
@@ -120,16 +363,12 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
        return 0;
 }
 
-static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
-                     u32 attr, int channel, long temp)
+static int lm75_write_temp(struct device *dev, u32 attr, long temp)
 {
        struct lm75_data *data = dev_get_drvdata(dev);
        u8 resolution;
        int reg;
 
-       if (type != hwmon_temp)
-               return -EINVAL;
-
        switch (attr) {
        case hwmon_temp_max:
                reg = LM75_REG_MAX;
@@ -145,8 +384,8 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
         * Resolution of limit registers is assumed to be the same as the
         * temperature input register resolution unless given explicitly.
         */
-       if (data->resolution_limits)
-               resolution = data->resolution_limits;
+       if (data->params->resolution_limits)
+               resolution = data->params->resolution_limits;
        else
                resolution = data->resolution;
 
@@ -154,16 +393,88 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
        temp = DIV_ROUND_CLOSEST(temp  << (resolution - 8),
                                 1000) << (16 - resolution);
 
-       return regmap_write(data->regmap, reg, temp);
+       return regmap_write(data->regmap, reg, (u16)temp);
+}
+
+static int lm75_update_interval(struct device *dev, long val)
+{
+       struct lm75_data *data = dev_get_drvdata(dev);
+       unsigned int reg;
+       u8 index;
+       s32 err;
+
+       index = find_closest(val, data->params->sample_times,
+                            (int)data->params->num_sample_times);
+
+       switch (data->kind) {
+       default:
+               err = lm75_write_config(data, lm75_sample_set_masks[index],
+                                       LM75_SAMPLE_CLEAR_MASK);
+               if (err)
+                       return err;
+
+               data->sample_time = data->params->sample_times[index];
+               if (data->params->resolutions)
+                       data->resolution = data->params->resolutions[index];
+               break;
+       case tmp112:
+               err = regmap_read(data->regmap, LM75_REG_CONF, &reg);
+               if (err < 0)
+                       return err;
+               reg &= ~0x00c0;
+               reg |= (3 - index) << 6;
+               err = regmap_write(data->regmap, LM75_REG_CONF, reg);
+               if (err < 0)
+                       return err;
+               data->sample_time = data->params->sample_times[index];
+               break;
+       case pct2075:
+               err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE,
+                                               index + 1);
+               if (err)
+                       return err;
+               data->sample_time = data->params->sample_times[index];
+               break;
+       }
+       return 0;
+}
+
+static int lm75_write_chip(struct device *dev, u32 attr, long val)
+{
+       switch (attr) {
+       case hwmon_chip_update_interval:
+               return lm75_update_interval(dev, val);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
+                     u32 attr, int channel, long val)
+{
+       switch (type) {
+       case hwmon_chip:
+               return lm75_write_chip(dev, attr, val);
+       case hwmon_temp:
+               return lm75_write_temp(dev, attr, val);
+       default:
+               return -EINVAL;
+       }
+       return 0;
 }
 
 static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
                               u32 attr, int channel)
 {
+       const struct lm75_data *config_data = data;
+
        switch (type) {
        case hwmon_chip:
                switch (attr) {
                case hwmon_chip_update_interval:
+                       if (config_data->params->num_sample_times > 1)
+                               return 0644;
                        return 0444;
                }
                break;
@@ -208,13 +519,13 @@ static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg)
 
 static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg)
 {
-       return reg == LM75_REG_TEMP;
+       return reg == LM75_REG_TEMP || reg == LM75_REG_CONF;
 }
 
 static const struct regmap_config lm75_regmap_config = {
        .reg_bits = 8,
        .val_bits = 16,
-       .max_register = LM75_REG_MAX,
+       .max_register = PCT2075_REG_IDLE,
        .writeable_reg = lm75_is_writeable_reg,
        .volatile_reg = lm75_is_volatile_reg,
        .val_format_endian = REGMAP_ENDIAN_BIG,
@@ -238,8 +549,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        struct device *hwmon_dev;
        struct lm75_data *data;
        int status, err;
-       u8 set_mask, clr_mask;
-       int new;
        enum lm75_type kind;
 
        if (client->dev.of_node)
@@ -256,6 +565,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -ENOMEM;
 
        data->client = client;
+       data->kind = kind;
 
        data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config);
        if (IS_ERR(data->regmap))
@@ -264,113 +574,30 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
         * Then tweak to be more precise when appropriate.
         */
-       set_mask = 0;
-       clr_mask = LM75_SHUTDOWN;               /* continuous conversions */
-
-       switch (kind) {
-       case adt75:
-               clr_mask |= 1 << 5;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case ds1775:
-       case ds75:
-       case stds75:
-               clr_mask |= 3 << 5;
-               set_mask |= 2 << 5;             /* 11-bit mode */
-               data->resolution = 11;
-               data->sample_time = MSEC_PER_SEC;
-               break;
-       case stlm75:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 5;
-               break;
-       case ds7505:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case g751:
-       case lm75:
-       case lm75a:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 2;
-               break;
-       case lm75b:
-               data->resolution = 11;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max6625:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max6626:
-               data->resolution = 12;
-               data->resolution_limits = 9;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max31725:
-               data->resolution = 16;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case tcn75:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case mcp980x:
-               data->resolution_limits = 9;
-               /* fall through */
-       case tmp100:
-       case tmp101:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC;
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               break;
-       case tmp112:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case tmp105:
-       case tmp175:
-       case tmp275:
-       case tmp75:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 2;
-               break;
-       case tmp75b:  /* not one-shot mode, Conversion rate 37Hz */
-               clr_mask |= 1 << 7 | 0x3 << 5;
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 37;
-               break;
-       case tmp75c:
-               clr_mask |= 1 << 5;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       }
 
-       /* configure as specified */
+       data->params = &device_params[data->kind];
+
+       /* Save default sample time and resolution*/
+       data->sample_time = data->params->default_sample_time;
+       data->resolution = data->params->default_resolution;
+
+       /* Cache original configuration */
        status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
        if (status < 0) {
                dev_dbg(dev, "Can't read config? %d\n", status);
                return status;
        }
        data->orig_conf = status;
-       new = status & ~clr_mask;
-       new |= set_mask;
-       if (status != new)
-               i2c_smbus_write_byte_data(client, LM75_REG_CONF, new);
+       data->current_conf = status;
 
-       err = devm_add_action_or_reset(dev, lm75_remove, data);
+       err = lm75_write_config(data, data->params->set_mask,
+                               data->params->clr_mask);
        if (err)
                return err;
 
-       dev_dbg(dev, "Config %02x\n", new);
+       err = devm_add_action_or_reset(dev, lm75_remove, data);
+       if (err)
+               return err;
 
        hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
                                                         data, &lm75_chip_info,
@@ -397,6 +624,7 @@ static const struct i2c_device_id lm75_ids[] = {
        { "max31725", max31725, },
        { "max31726", max31725, },
        { "mcp980x", mcp980x, },
+       { "pct2075", pct2075, },
        { "stds75", stds75, },
        { "stlm75", stlm75, },
        { "tcn75", tcn75, },
@@ -466,6 +694,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
                .compatible = "maxim,mcp980x",
                .data = (void *)mcp980x
        },
+       {
+               .compatible = "nxp,pct2075",
+               .data = (void *)pct2075
+       },
        {
                .compatible = "st,stds75",
                .data = (void *)stds75
index f9431ad43ad3b02a0b83e3e4990d56aa2f0fcdba..53ff5051774ccc5e1a3254105da6499b1b69fed4 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/property.h>
 
 #define LTC2990_STATUS 0x00
 #define LTC2990_CONTROL        0x01
@@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
        int ret;
        struct device *hwmon_dev;
        struct ltc2990_data *data;
-       struct device_node *of_node = i2c->dev.of_node;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_WORD_DATA))
@@ -218,9 +217,10 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
 
        data->i2c = i2c;
 
-       if (of_node) {
-               ret = of_property_read_u32_array(of_node, "lltc,meas-mode",
-                                                data->mode, 2);
+       if (dev_fwnode(&i2c->dev)) {
+               ret = device_property_read_u32_array(&i2c->dev,
+                                                    "lltc,meas-mode",
+                                                    data->mode, 2);
                if (ret < 0)
                        return ret;
 
index d42bc0883a32b4ba115f113d84e6503ecd43e081..7efa6bfef06097e5d20878566a84bc9666b3f2d6 100644 (file)
@@ -20,6 +20,7 @@
  *
  * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
  * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
+ * nct6116d     9      5       5       3+3    0xd280 0xc1    0x5ca3
  * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
  * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
  * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
 
 #define USE_ALTERNATE
 
-enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
-            nct6795, nct6796, nct6797, nct6798 };
+enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
+            nct6793, nct6795, nct6796, nct6797, nct6798 };
 
 /* used to set data->name = nct6775_device_names[data->sio_kind] */
 static const char * const nct6775_device_names[] = {
        "nct6106",
+       "nct6116",
        "nct6775",
        "nct6776",
        "nct6779",
@@ -78,6 +80,7 @@ static const char * const nct6775_device_names[] = {
 
 static const char * const nct6775_sio_names[] __initconst = {
        "NCT6106D",
+       "NCT6116D",
        "NCT6775F",
        "NCT6776D/F",
        "NCT6779D",
@@ -115,6 +118,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
 #define SIO_NCT6106_ID         0xc450
+#define SIO_NCT6116_ID         0xd280
 #define SIO_NCT6775_ID         0xb470
 #define SIO_NCT6776_ID         0xc330
 #define SIO_NCT6779_ID         0xc560
@@ -825,10 +829,8 @@ static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
 
 static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
 static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
-static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
 static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
 static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
-static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
 static const u16 NCT6106_REG_TEMP_SOURCE[] = {
        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
 
@@ -896,6 +898,70 @@ static const u16 NCT6106_REG_TEMP_CRIT[32] = {
        [12] = 0x205,
 };
 
+/* NCT6112D/NCT6114D/NCT6116D specific data */
+
+static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
+static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
+static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
+static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
+
+static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
+static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
+static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
+static const u16 NCT6116_REG_TEMP_SOURCE[] = {
+       0xb0, 0xb1, 0xb2 };
+
+static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
+       0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
+static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
+       0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
+
+static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
+       0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
+static const u16 NCT6116_REG_CRITICAL_PWM[] = {
+       0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
+
+static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
+       0x114, 0x124, 0x134, 0x194, 0x1a4 };
+static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
+       0x115, 0x125, 0x135, 0x195, 0x1a5 };
+static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
+       0x116, 0x126, 0x136, 0x196, 0x1a6 };
+static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
+       0x117, 0x127, 0x137, 0x197, 0x1a7 };
+static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
+       0x118, 0x128, 0x138, 0x198, 0x1a8 };
+static const u16 NCT6116_REG_TOLERANCE_H[] = {
+       0x112, 0x122, 0x132, 0x192, 0x1a2 };
+
+static const u16 NCT6116_REG_TARGET[] = {
+       0x111, 0x121, 0x131, 0x191, 0x1a1 };
+
+static const u16 NCT6116_REG_AUTO_TEMP[] = {
+       0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
+static const u16 NCT6116_REG_AUTO_PWM[] = {
+       0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
+
+static const s8 NCT6116_ALARM_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, -1, -1, -1, -1, -1, -1,      /* in8..in9 */
+       -1,                             /* unused */
+       32, 33, 34, 35, 36,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, -1, -1, -1,         /* temp1..temp6 */
+       48, -1                          /* intrusion0, intrusion1 */
+};
+
+static const s8 NCT6116_BEEP_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, 10, 11, 12, -1, -1, -1,      /* in8..in14 */
+       32,                             /* global beep enable */
+       24, 25, 26, 27, 28,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, -1, -1, -1,         /* temp1..temp6 */
+       34, -1                          /* intrusion0, intrusion1 */
+};
+
 static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
 {
        if (mode == 0 && pwm == 255)
@@ -1294,6 +1360,11 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
                return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
                  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
                  reg == 0x111 || reg == 0x121 || reg == 0x131;
+       case nct6116:
+               return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+                 reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 ||
+                 reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 ||
+                 reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1;
        case nct6775:
                return (((reg & 0xff00) == 0x100 ||
                    (reg & 0xff00) == 0x200) &&
@@ -1673,6 +1744,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
                        data->auto_pwm[i][data->auto_pwm_num] = 0xff;
                        break;
                case nct6106:
+               case nct6116:
                case nct6779:
                case nct6791:
                case nct6792:
@@ -3109,6 +3181,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
                case nct6776:
                        break; /* always enabled, nothing to do */
                case nct6106:
+               case nct6116:
                case nct6779:
                case nct6791:
                case nct6792:
@@ -3535,6 +3608,23 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
 
                fan3pin = !(cr24 & 0x80);
                pwm3pin = cr24 & 0x08;
+       } else if (data->kind == nct6116) {
+               int cr1a = superio_inb(sioreg, 0x1a);
+               int cr1b = superio_inb(sioreg, 0x1b);
+               int cr24 = superio_inb(sioreg, 0x24);
+               int cr2a = superio_inb(sioreg, 0x2a);
+               int cr2b = superio_inb(sioreg, 0x2b);
+               int cr2f = superio_inb(sioreg, 0x2f);
+
+               fan3pin = !(cr2b & 0x10);
+               fan4pin = (cr2b & 0x80) ||                      // pin 1(2)
+                       (!(cr2f & 0x10) && (cr1a & 0x04));      // pin 65(66)
+               fan5pin = (cr2b & 0x80) ||                      // pin 126(127)
+                       (!(cr1b & 0x03) && (cr2a & 0x02));      // pin 94(96)
+
+               pwm3pin = fan3pin && (cr24 & 0x08);
+               pwm4pin = fan4pin;
+               pwm5pin = fan5pin;
        } else {
                /*
                 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
@@ -3765,7 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
                data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
-               data->REG_PWM[0] = NCT6106_REG_PWM;
+               data->REG_PWM[0] = NCT6116_REG_PWM;
                data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
                data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
                data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
@@ -3784,7 +3874,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
                data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
                data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
-               data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+               data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
                data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
                data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
                data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
@@ -3806,6 +3896,79 @@ static int nct6775_probe(struct platform_device *pdev)
                reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
                reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
 
+               break;
+       case nct6116:
+               data->in_num = 9;
+               data->pwm_num = 3;
+               data->auto_pwm_num = 4;
+               data->temp_fixed_num = 3;
+               data->num_temp_alarms = 3;
+               data->num_temp_beeps = 3;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+
+               data->temp_label = nct6776_temp_label;
+               data->temp_mask = NCT6776_TEMP_MASK;
+               data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
+
+               data->REG_VBAT = NCT6106_REG_VBAT;
+               data->REG_DIODE = NCT6106_REG_DIODE;
+               data->DIODE_MASK = NCT6106_DIODE_MASK;
+               data->REG_VIN = NCT6106_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+               data->REG_TARGET = NCT6116_REG_TARGET;
+               data->REG_FAN = NCT6116_REG_FAN;
+               data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
+               data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
+               data->REG_PWM[0] = NCT6116_REG_PWM;
+               data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
+               data->CRITICAL_PWM_ENABLE_MASK
+                 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+               data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
+               data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6106_REG_ALARM;
+               data->ALARM_BITS = NCT6116_ALARM_BITS;
+               data->REG_BEEP = NCT6106_REG_BEEP;
+               data->BEEP_BITS = NCT6116_BEEP_BITS;
+
+               reg_temp = NCT6106_REG_TEMP;
+               reg_temp_mon = NCT6106_REG_TEMP_MON;
+               num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+               num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
+               reg_temp_over = NCT6106_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+               reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+               reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+               reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
                break;
        case nct6775:
                data->in_num = 9;
@@ -4352,6 +4515,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->have_vid = (cr2a & 0x60) == 0x40;
                break;
        case nct6106:
+       case nct6116:
        case nct6779:
        case nct6791:
        case nct6792:
@@ -4381,6 +4545,7 @@ static int nct6775_probe(struct platform_device *pdev)
                                  NCT6775_REG_CR_FAN_DEBOUNCE);
                switch (data->kind) {
                case nct6106:
+               case nct6116:
                        tmp |= 0xe0;
                        break;
                case nct6775:
@@ -4576,6 +4741,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
        case SIO_NCT6106_ID:
                sio_data->kind = nct6106;
                break;
+       case SIO_NCT6116_ID:
+               sio_data->kind = nct6116;
+               break;
        case SIO_NCT6775_ID:
                sio_data->kind = nct6775;
                break;
index 710c30562fc1fe62ff14bee4122c539c3cd7ad71..95b447cfa24cb82a118fa62f3bc4c99caec33153 100644 (file)
 #define DTS_T_CTRL1_REG                0x27
 #define VT_ADC_MD_REG          0x2E
 
+#define VSEN1_HV_LL_REG                0x02    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_LV_LL_REG                0x03    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_HV_HL_REG                0x00    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_LV_HL_REG                0x01    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define SMI_STS1_REG           0xC1    /* Bank 0; SMI Status Register */
+#define SMI_STS3_REG           0xC3    /* Bank 0; SMI Status Register */
+#define SMI_STS5_REG           0xC5    /* Bank 0; SMI Status Register */
+#define SMI_STS7_REG           0xC7    /* Bank 0; SMI Status Register */
+#define SMI_STS8_REG           0xC8    /* Bank 0; SMI Status Register */
+
 #define VSEN1_HV_REG           0x40    /* Bank 0; 2 regs (HV/LV) per sensor */
 #define TEMP_CH1_HV_REG                0x42    /* Bank 0; same as VSEN2_HV */
 #define LTD_HV_REG             0x62    /* Bank 0; 2 regs in VSEN range */
+#define LTD_HV_HL_REG          0x44    /* Bank 1; 1 reg for LTD */
+#define LTD_LV_HL_REG          0x45    /* Bank 1; 1 reg for LTD */
+#define LTD_HV_LL_REG          0x46    /* Bank 1; 1 reg for LTD */
+#define LTD_LV_LL_REG          0x47    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_CH_REG                0x05    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_W_REG         0x06    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_WH_REG                0x07    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_C_REG         0x04    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_C_REG       0x90    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_CH_REG      0x91    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_W_REG       0x92    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_WH_REG      0x93    /* Bank 1; 1 reg per sensor */
 #define FANIN1_HV_REG          0x80    /* Bank 0; 2 regs (HV/LV) per sensor */
+#define FANIN1_HV_HL_REG       0x60    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define FANIN1_LV_HL_REG       0x61    /* Bank 1; 2 regs (HV/LV) per sensor */
 #define T_CPU1_HV_REG          0xA0    /* Bank 0; 2 regs (HV/LV) per sensor */
 
 #define PRTS_REG               0x03    /* Bank 2 */
@@ -58,6 +82,8 @@
 #define FANCTL1_FMR_REG                0x00    /* Bank 3; 1 reg per channel */
 #define FANCTL1_OUT_REG                0x10    /* Bank 3; 1 reg per channel */
 
+#define ENABLE_TSI     BIT(1)
+
 static const unsigned short normal_i2c[] = {
        0x2d, 0x2e, I2C_CLIENT_END
 };
@@ -72,6 +98,7 @@ struct nct7904_data {
        u8 fan_mode[FANCTL_MAX];
        u8 enable_dts;
        u8 has_dts;
+       u8 temp_mode; /* 0: TR mode, 1: TD mode */
 };
 
 /* Access functions */
@@ -170,6 +197,25 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
                        rpm = 1350000 / cnt;
                *val = rpm;
                return 0;
+       case hwmon_fan_min:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        FANIN1_HV_HL_REG + channel * 2);
+               if (ret < 0)
+                       return ret;
+               cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
+               if (cnt == 0x1fff)
+                       rpm = 0;
+               else
+                       rpm = 1350000 / cnt;
+               *val = rpm;
+               return 0;
+       case hwmon_fan_alarm:
+               ret = nct7904_read_reg(data, BANK_0,
+                                      SMI_STS5_REG + (channel >> 3));
+               if (ret < 0)
+                       return ret;
+               *val = (ret >> (channel & 0x07)) & 1;
+               return 0;
        default:
                return -EOPNOTSUPP;
        }
@@ -179,8 +225,20 @@ static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel)
 {
        const struct nct7904_data *data = _data;
 
-       if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel))
-               return 0444;
+       switch (attr) {
+       case hwmon_fan_input:
+       case hwmon_fan_alarm:
+               if (data->fanin_mask & (1 << channel))
+                       return 0444;
+               break;
+       case hwmon_fan_min:
+               if (data->fanin_mask & (1 << channel))
+                       return 0644;
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
 
@@ -211,6 +269,37 @@ static int nct7904_read_in(struct device *dev, u32 attr, int channel,
                        volt *= 6; /* 0.006V scale */
                *val = volt;
                return 0;
+       case hwmon_in_min:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        VSEN1_HV_LL_REG + index * 4);
+               if (ret < 0)
+                       return ret;
+               volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
+               if (index < 14)
+                       volt *= 2; /* 0.002V scale */
+               else
+                       volt *= 6; /* 0.006V scale */
+               *val = volt;
+               return 0;
+       case hwmon_in_max:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        VSEN1_HV_HL_REG + index * 4);
+               if (ret < 0)
+                       return ret;
+               volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
+               if (index < 14)
+                       volt *= 2; /* 0.002V scale */
+               else
+                       volt *= 6; /* 0.006V scale */
+               *val = volt;
+               return 0;
+       case hwmon_in_alarm:
+               ret = nct7904_read_reg(data, BANK_0,
+                                      SMI_STS1_REG + (index >> 3));
+               if (ret < 0)
+                       return ret;
+               *val = (ret >> (index & 0x07)) & 1;
+               return 0;
        default:
                return -EOPNOTSUPP;
        }
@@ -221,9 +310,20 @@ static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel)
        const struct nct7904_data *data = _data;
        int index = nct7904_chan_to_index[channel];
 
-       if (channel > 0 && attr == hwmon_in_input &&
-           (data->vsen_mask & BIT(index)))
-               return 0444;
+       switch (attr) {
+       case hwmon_in_input:
+       case hwmon_in_alarm:
+               if (channel > 0 && (data->vsen_mask & BIT(index)))
+                       return 0444;
+               break;
+       case hwmon_in_min:
+       case hwmon_in_max:
+               if (channel > 0 && (data->vsen_mask & BIT(index)))
+                       return 0644;
+               break;
+       default:
+               break;
+       }
 
        return 0;
 }
@@ -233,6 +333,7 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
 {
        struct nct7904_data *data = dev_get_drvdata(dev);
        int ret, temp;
+       unsigned int reg1, reg2, reg3;
 
        switch (attr) {
        case hwmon_temp_input:
@@ -250,16 +351,106 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
                temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
                *val = sign_extend32(temp, 10) * 125;
                return 0;
+       case hwmon_temp_alarm:
+               if (channel == 4) {
+                       ret = nct7904_read_reg(data, BANK_0,
+                                              SMI_STS3_REG);
+                       if (ret < 0)
+                               return ret;
+                       *val = (ret >> 1) & 1;
+               } else if (channel < 4) {
+                       ret = nct7904_read_reg(data, BANK_0,
+                                              SMI_STS1_REG);
+                       if (ret < 0)
+                               return ret;
+                       *val = (ret >> (((channel * 2) + 1) & 0x07)) & 1;
+               } else {
+                       if ((channel - 5) < 4) {
+                               ret = nct7904_read_reg(data, BANK_0,
+                                                      SMI_STS7_REG +
+                                                      ((channel - 5) >> 3));
+                               if (ret < 0)
+                                       return ret;
+                               *val = (ret >> ((channel - 5) & 0x07)) & 1;
+                       } else {
+                               ret = nct7904_read_reg(data, BANK_0,
+                                                      SMI_STS8_REG +
+                                                      ((channel - 5) >> 3));
+                               if (ret < 0)
+                                       return ret;
+                               *val = (ret >> (((channel - 5) & 0x07) - 4))
+                                                       & 1;
+                       }
+               }
+               return 0;
+       case hwmon_temp_type:
+               if (channel < 5) {
+                       if ((data->tcpu_mask >> channel) & 0x01) {
+                               if ((data->temp_mode >> channel) & 0x01)
+                                       *val = 3; /* TD */
+                               else
+                                       *val = 4; /* TR */
+                       } else {
+                               *val = 0;
+                       }
+               } else {
+                       if ((data->has_dts >> (channel - 5)) & 0x01) {
+                               if (data->enable_dts & ENABLE_TSI)
+                                       *val = 5; /* TSI */
+                               else
+                                       *val = 6; /* PECI */
+                       } else {
+                               *val = 0;
+                       }
+               }
+               return 0;
+       case hwmon_temp_max:
+               reg1 = LTD_HV_LL_REG;
+               reg2 = TEMP_CH1_W_REG;
+               reg3 = DTS_T_CPU1_W_REG;
+               break;
+       case hwmon_temp_max_hyst:
+               reg1 = LTD_LV_LL_REG;
+               reg2 = TEMP_CH1_WH_REG;
+               reg3 = DTS_T_CPU1_WH_REG;
+               break;
+       case hwmon_temp_crit:
+               reg1 = LTD_HV_HL_REG;
+               reg2 = TEMP_CH1_C_REG;
+               reg3 = DTS_T_CPU1_C_REG;
+               break;
+       case hwmon_temp_crit_hyst:
+               reg1 = LTD_LV_HL_REG;
+               reg2 = TEMP_CH1_CH_REG;
+               reg3 = DTS_T_CPU1_CH_REG;
+               break;
        default:
                return -EOPNOTSUPP;
        }
+
+       if (channel == 4)
+               ret = nct7904_read_reg(data, BANK_1, reg1);
+       else if (channel < 5)
+               ret = nct7904_read_reg(data, BANK_1,
+                                      reg2 + channel * 8);
+       else
+               ret = nct7904_read_reg(data, BANK_1,
+                                      reg3 + (channel - 5) * 4);
+
+       if (ret < 0)
+               return ret;
+       *val = ret * 1000;
+       return 0;
 }
 
 static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
 {
        const struct nct7904_data *data = _data;
 
-       if (attr == hwmon_temp_input) {
+       switch (attr) {
+       case hwmon_temp_input:
+       case hwmon_temp_alarm:
+       case hwmon_temp_type:
                if (channel < 5) {
                        if (data->tcpu_mask & BIT(channel))
                                return 0444;
@@ -267,6 +458,21 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
                        if (data->has_dts & BIT(channel - 5))
                                return 0444;
                }
+               break;
+       case hwmon_temp_max:
+       case hwmon_temp_max_hyst:
+       case hwmon_temp_crit:
+       case hwmon_temp_crit_hyst:
+               if (channel < 5) {
+                       if (data->tcpu_mask & BIT(channel))
+                               return 0644;
+               } else {
+                       if (data->has_dts & BIT(channel - 5))
+                               return 0644;
+               }
+               break;
+       default:
+               break;
        }
 
        return 0;
@@ -297,6 +503,137 @@ static int nct7904_read_pwm(struct device *dev, u32 attr, int channel,
        }
 }
 
+static int nct7904_write_temp(struct device *dev, u32 attr, int channel,
+                             long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret;
+       unsigned int reg1, reg2, reg3;
+
+       val = clamp_val(val / 1000, -128, 127);
+
+       switch (attr) {
+       case hwmon_temp_max:
+               reg1 = LTD_HV_LL_REG;
+               reg2 = TEMP_CH1_W_REG;
+               reg3 = DTS_T_CPU1_W_REG;
+               break;
+       case hwmon_temp_max_hyst:
+               reg1 = LTD_LV_LL_REG;
+               reg2 = TEMP_CH1_WH_REG;
+               reg3 = DTS_T_CPU1_WH_REG;
+               break;
+       case hwmon_temp_crit:
+               reg1 = LTD_HV_HL_REG;
+               reg2 = TEMP_CH1_C_REG;
+               reg3 = DTS_T_CPU1_C_REG;
+               break;
+       case hwmon_temp_crit_hyst:
+               reg1 = LTD_LV_HL_REG;
+               reg2 = TEMP_CH1_CH_REG;
+               reg3 = DTS_T_CPU1_CH_REG;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       if (channel == 4)
+               ret = nct7904_write_reg(data, BANK_1, reg1, val);
+       else if (channel < 5)
+               ret = nct7904_write_reg(data, BANK_1,
+                                       reg2 + channel * 8, val);
+       else
+               ret = nct7904_write_reg(data, BANK_1,
+                                       reg3 + (channel - 5) * 4, val);
+
+       return ret;
+}
+
+static int nct7904_write_fan(struct device *dev, u32 attr, int channel,
+                            long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret;
+       u8 tmp;
+
+       switch (attr) {
+       case hwmon_fan_min:
+               if (val <= 0)
+                       return -EINVAL;
+
+               val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), 1, 0x1fff);
+               tmp = (val >> 5) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       FANIN1_HV_HL_REG + channel * 2, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = val & 0x1f;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       FANIN1_LV_HL_REG + channel * 2, tmp);
+               return ret;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int nct7904_write_in(struct device *dev, u32 attr, int channel,
+                           long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret, index, tmp;
+
+       index = nct7904_chan_to_index[channel];
+
+       if (index < 14)
+               val = val / 2; /* 0.002V scale */
+       else
+               val = val / 6; /* 0.006V scale */
+
+       val = clamp_val(val, 0, 0x7ff);
+
+       switch (attr) {
+       case hwmon_in_min:
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_LV_LL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp &= ~0x7;
+               tmp |= val & 0x7;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_LV_LL_REG + index * 4, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_HV_LL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp = (val >> 3) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_HV_LL_REG + index * 4, tmp);
+               return ret;
+       case hwmon_in_max:
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_LV_HL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp &= ~0x7;
+               tmp |= val & 0x7;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_LV_HL_REG + index * 4, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_HV_HL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp = (val >> 3) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_HV_HL_REG + index * 4, tmp);
+               return ret;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static int nct7904_write_pwm(struct device *dev, u32 attr, int channel,
                             long val)
 {
@@ -354,8 +691,14 @@ static int nct7904_write(struct device *dev, enum hwmon_sensor_types type,
                         u32 attr, int channel, long val)
 {
        switch (type) {
+       case hwmon_in:
+               return nct7904_write_in(dev, attr, channel, val);
+       case hwmon_fan:
+               return nct7904_write_fan(dev, attr, channel, val);
        case hwmon_pwm:
                return nct7904_write_pwm(dev, attr, channel, val);
+       case hwmon_temp:
+               return nct7904_write_temp(dev, attr, channel, val);
        default:
                return -EOPNOTSUPP;
        }
@@ -404,51 +747,91 @@ static int nct7904_detect(struct i2c_client *client,
 
 static const struct hwmon_channel_info *nct7904_info[] = {
        HWMON_CHANNEL_INFO(in,
-                          HWMON_I_INPUT, /* dummy, skipped in is_visible */
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT),
+                          /* dummy, skipped in is_visible */
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM),
        HWMON_CHANNEL_INFO(fan,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT),
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM),
        HWMON_CHANNEL_INFO(pwm,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
        HWMON_CHANNEL_INFO(temp,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT),
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST),
        NULL
 };
 
@@ -530,11 +913,14 @@ static int nct7904_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
+       data->temp_mode = 0;
        for (i = 0; i < 4; i++) {
                val = (ret & (0x03 << i)) >> (i * 2);
                bit = (1 << i);
                if (val == 0)
                        data->tcpu_mask &= ~bit;
+               else if (val == 0x1 || val == 0x2)
+                       data->temp_mode |= bit;
        }
 
        /* PECI */
@@ -557,7 +943,7 @@ static int nct7904_probe(struct i2c_client *client,
                if (ret < 0)
                        return ret;
                data->has_dts = ret & 0xF;
-               if (data->enable_dts & 0x2) {
+               if (data->enable_dts & ENABLE_TSI) {
                        ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
                        if (ret < 0)
                                return ret;
index 09aaefa6fdb8c192e561d720dab6cc7d65a40138..11a28609da3c769343fd83c976a6ffdc13050bc5 100644 (file)
@@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
                spin_lock_init(&data->fan_lock[i]);
 
                data->fan_irq[i] = platform_get_irq(pdev, i);
-               if (data->fan_irq[i] < 0) {
-                       dev_err(dev, "get IRQ fan%d failed\n", i);
+               if (data->fan_irq[i] < 0)
                        return data->fan_irq[i];
-               }
 
                sprintf(name, "NPCM7XX-FAN-MD%d", i);
                ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr,
index b6588483fae125a28562df82e90b2fb1446f29ea..d62d69bb7e490412b72ec7e6eb4e2ad612add115 100644 (file)
@@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS
          This driver can also be built as a module. If so, the module will
          be called ibm-cffps.
 
+config SENSORS_INSPUR_IPSPS
+       tristate "INSPUR Power System Power Supply"
+       help
+         If you say yes here you get hardware monitoring support for the INSPUR
+         Power System power supply.
+
+         This driver can also be built as a module. If so, the module will
+         be called inspur-ipsps.
+
 config SENSORS_IR35221
        tristate "Infineon IR35221"
        help
index c950ea9a5d003e0645be173a871303875cc6a47b..03bacfcfd6607dbb2365b6d1e912489f3838f92b 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS)             += pmbus_core.o
 obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
 obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
 obj-$(CONFIG_SENSORS_IBM_CFFPS)        += ibm-cffps.o
+obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
 obj-$(CONFIG_SENSORS_IR35221)  += ir35221.o
 obj-$(CONFIG_SENSORS_IR38064)  += ir38064.o
 obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
index ee2ee9e3ffd739ab06116b6d6ef9db1867980665..d44745e498e76b0d847caaff878118e711a571d0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/of_device.h>
 #include <linux/pmbus.h>
 
 #include "pmbus.h"
@@ -20,8 +21,9 @@
 #define CFFPS_PN_CMD                           0x9B
 #define CFFPS_SN_CMD                           0x9E
 #define CFFPS_CCIN_CMD                         0xBD
-#define CFFPS_FW_CMD_START                     0xFA
-#define CFFPS_FW_NUM_BYTES                     4
+#define CFFPS_FW_CMD                           0xFA
+#define CFFPS1_FW_NUM_BYTES                    4
+#define CFFPS2_FW_NUM_WORDS                    3
 #define CFFPS_SYS_CONFIG_CMD                   0xDA
 
 #define CFFPS_INPUT_HISTORY_CMD                        0xD6
@@ -52,6 +54,8 @@ enum {
        CFFPS_DEBUGFS_NUM_ENTRIES
 };
 
+enum versions { cffps1, cffps2 };
+
 struct ibm_cffps_input_history {
        struct mutex update_lock;
        unsigned long last_update;
@@ -61,6 +65,7 @@ struct ibm_cffps_input_history {
 };
 
 struct ibm_cffps {
+       enum versions version;
        struct i2c_client *client;
 
        struct ibm_cffps_input_history input_history;
@@ -132,6 +137,8 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
        struct ibm_cffps *psu = to_psu(idxp, idx);
        char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
 
+       pmbus_set_page(psu->client, 0);
+
        switch (idx) {
        case CFFPS_DEBUGFS_INPUT_HISTORY:
                return ibm_cffps_read_input_history(psu, buf, count, ppos);
@@ -152,16 +159,36 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
                rc = snprintf(data, 5, "%04X", rc);
                goto done;
        case CFFPS_DEBUGFS_FW:
-               for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) {
-                       rc = i2c_smbus_read_byte_data(psu->client,
-                                                     CFFPS_FW_CMD_START + i);
-                       if (rc < 0)
-                               return rc;
+               switch (psu->version) {
+               case cffps1:
+                       for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
+                               rc = i2c_smbus_read_byte_data(psu->client,
+                                                             CFFPS_FW_CMD +
+                                                               i);
+                               if (rc < 0)
+                                       return rc;
+
+                               snprintf(&data[i * 2], 3, "%02X", rc);
+                       }
 
-                       snprintf(&data[i * 2], 3, "%02X", rc);
-               }
+                       rc = i * 2;
+                       break;
+               case cffps2:
+                       for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) {
+                               rc = i2c_smbus_read_word_data(psu->client,
+                                                             CFFPS_FW_CMD +
+                                                               i);
+                               if (rc < 0)
+                                       return rc;
+
+                               snprintf(&data[i * 4], 5, "%04X", rc);
+                       }
 
-               rc = i * 2;
+                       rc = i * 4;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
                goto done;
        default:
                return -EINVAL;
@@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
                        psu->led_state = CFFPS_LED_ON;
        }
 
+       pmbus_set_page(psu->client, 0);
+
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       psu->led_state);
        if (rc < 0)
@@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
        if (led_cdev->brightness == LED_OFF)
                return 0;
 
+       pmbus_set_page(psu->client, 0);
+
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       CFFPS_LED_BLINK);
        if (rc < 0)
@@ -328,15 +359,32 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
                dev_warn(dev, "failed to register led class: %d\n", rc);
 }
 
-static struct pmbus_driver_info ibm_cffps_info = {
-       .pages = 1,
-       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
-               PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
-               PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
-               PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
-               PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
-       .read_byte_data = ibm_cffps_read_byte_data,
-       .read_word_data = ibm_cffps_read_word_data,
+static struct pmbus_driver_info ibm_cffps_info[] = {
+       [cffps1] = {
+               .pages = 1,
+               .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
+                       PMBUS_HAVE_STATUS_FAN12,
+               .read_byte_data = ibm_cffps_read_byte_data,
+               .read_word_data = ibm_cffps_read_word_data,
+       },
+       [cffps2] = {
+               .pages = 2,
+               .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
+                       PMBUS_HAVE_STATUS_FAN12,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
+               .read_byte_data = ibm_cffps_read_byte_data,
+               .read_word_data = ibm_cffps_read_word_data,
+       },
 };
 
 static struct pmbus_platform_data ibm_cffps_pdata = {
@@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
        int i, rc;
+       enum versions vs;
        struct dentry *debugfs;
        struct dentry *ibm_cffps_dir;
        struct ibm_cffps *psu;
+       const void *md = of_device_get_match_data(&client->dev);
+
+       if (md)
+               vs = (enum versions)md;
+       else if (id)
+               vs = (enum versions)id->driver_data;
+       else
+               vs = cffps1;
 
        client->dev.platform_data = &ibm_cffps_pdata;
-       rc = pmbus_do_probe(client, id, &ibm_cffps_info);
+       rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
        if (rc)
                return rc;
 
@@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
        if (!psu)
                return 0;
 
+       psu->version = vs;
        psu->client = client;
        mutex_init(&psu->input_history.update_lock);
        psu->input_history.last_update = jiffies - HZ;
@@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id ibm_cffps_id[] = {
-       { "ibm_cffps1", 1 },
+       { "ibm_cffps1", cffps1 },
+       { "ibm_cffps2", cffps2 },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
 
 static const struct of_device_id ibm_cffps_of_match[] = {
-       { .compatible = "ibm,cffps1" },
+       {
+               .compatible = "ibm,cffps1",
+               .data = (void *)cffps1
+       },
+       {
+               .compatible = "ibm,cffps2",
+               .data = (void *)cffps2
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c
new file mode 100644 (file)
index 0000000..42e0154
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Inspur Corp.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pmbus.h>
+#include <linux/hwmon-sysfs.h>
+
+#include "pmbus.h"
+
+#define IPSPS_REG_VENDOR_ID    0x99
+#define IPSPS_REG_MODEL                0x9A
+#define IPSPS_REG_FW_VERSION   0x9B
+#define IPSPS_REG_PN           0x9C
+#define IPSPS_REG_SN           0x9E
+#define IPSPS_REG_HW_VERSION   0xB0
+#define IPSPS_REG_MODE         0xFC
+
+#define MODE_ACTIVE            0x55
+#define MODE_STANDBY           0x0E
+#define MODE_REDUNDANCY                0x00
+
+#define MODE_ACTIVE_STRING             "active"
+#define MODE_STANDBY_STRING            "standby"
+#define MODE_REDUNDANCY_STRING         "redundancy"
+
+enum ipsps_index {
+       vendor,
+       model,
+       fw_version,
+       part_number,
+       serial_number,
+       hw_version,
+       mode,
+       num_regs,
+};
+
+static const u8 ipsps_regs[num_regs] = {
+       [vendor] = IPSPS_REG_VENDOR_ID,
+       [model] = IPSPS_REG_MODEL,
+       [fw_version] = IPSPS_REG_FW_VERSION,
+       [part_number] = IPSPS_REG_PN,
+       [serial_number] = IPSPS_REG_SN,
+       [hw_version] = IPSPS_REG_HW_VERSION,
+       [mode] = IPSPS_REG_MODE,
+};
+
+static ssize_t ipsps_string_show(struct device *dev,
+                                struct device_attribute *devattr,
+                                char *buf)
+{
+       u8 reg;
+       int rc;
+       char *p;
+       char data[I2C_SMBUS_BLOCK_MAX + 1];
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_block_data(client, reg, data);
+       if (rc < 0)
+               return rc;
+
+       /* filled with printable characters, ending with # */
+       p = memscan(data, '#', rc);
+       *p = '\0';
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", data);
+}
+
+static ssize_t ipsps_fw_version_show(struct device *dev,
+                                    struct device_attribute *devattr,
+                                    char *buf)
+{
+       u8 reg;
+       int rc;
+       u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 };
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_block_data(client, reg, data);
+       if (rc < 0)
+               return rc;
+
+       if (rc != 6)
+               return -EPROTO;
+
+       return snprintf(buf, PAGE_SIZE, "%u.%02u%u-%u.%02u\n",
+                       data[1], data[2]/* < 100 */, data[3]/*< 10*/,
+                       data[4], data[5]/* < 100 */);
+}
+
+static ssize_t ipsps_mode_show(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       u8 reg;
+       int rc;
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_byte_data(client, reg);
+       if (rc < 0)
+               return rc;
+
+       switch (rc) {
+       case MODE_ACTIVE:
+               return snprintf(buf, PAGE_SIZE, "[%s] %s %s\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       case MODE_STANDBY:
+               return snprintf(buf, PAGE_SIZE, "%s [%s] %s\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       case MODE_REDUNDANCY:
+               return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       default:
+               return snprintf(buf, PAGE_SIZE, "unspecified\n");
+       }
+}
+
+static ssize_t ipsps_mode_store(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       u8 reg;
+       int rc;
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       if (sysfs_streq(MODE_STANDBY_STRING, buf)) {
+               rc = i2c_smbus_write_byte_data(client, reg,
+                                              MODE_STANDBY);
+               if (rc < 0)
+                       return rc;
+               return count;
+       } else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) {
+               rc = i2c_smbus_write_byte_data(client, reg,
+                                              MODE_ACTIVE);
+               if (rc < 0)
+                       return rc;
+               return count;
+       }
+
+       return -EINVAL;
+}
+
+static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor);
+static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model);
+static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number);
+static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number);
+static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version);
+static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version);
+static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode);
+
+static struct attribute *ipsps_attrs[] = {
+       &sensor_dev_attr_vendor.dev_attr.attr,
+       &sensor_dev_attr_model.dev_attr.attr,
+       &sensor_dev_attr_part_number.dev_attr.attr,
+       &sensor_dev_attr_serial_number.dev_attr.attr,
+       &sensor_dev_attr_hw_version.dev_attr.attr,
+       &sensor_dev_attr_fw_version.dev_attr.attr,
+       &sensor_dev_attr_mode.dev_attr.attr,
+       NULL,
+};
+
+ATTRIBUTE_GROUPS(ipsps);
+
+static struct pmbus_driver_info ipsps_info = {
+       .pages = 1,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+               PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN |
+               PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
+               PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
+               PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
+               PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
+       .groups = ipsps_groups,
+};
+
+static struct pmbus_platform_data ipsps_pdata = {
+       .flags = PMBUS_SKIP_STATUS_CHECK,
+};
+
+static int ipsps_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       client->dev.platform_data = &ipsps_pdata;
+       return pmbus_do_probe(client, id, &ipsps_info);
+}
+
+static const struct i2c_device_id ipsps_id[] = {
+       { "ipsps1", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ipsps_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ipsps_of_match[] = {
+       { .compatible = "inspur,ipsps1" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ipsps_of_match);
+#endif
+
+static struct i2c_driver ipsps_driver = {
+       .driver = {
+               .name = "inspur-ipsps",
+               .of_match_table = of_match_ptr(ipsps_of_match),
+       },
+       .probe = ipsps_probe,
+       .remove = pmbus_do_remove,
+       .id_table = ipsps_id,
+};
+
+module_i2c_driver(ipsps_driver);
+
+MODULE_AUTHOR("John Wang");
+MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
+MODULE_LICENSE("GPL");
index 69d9029ea410d03581515b954a74a5264f2a6f20..254b0f98c7552024dad65835e3805342b9147ba4 100644 (file)
@@ -244,8 +244,6 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
 #define MAX31785_VOUT_FUNCS \
        (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
 
-#define MAX37185_NUM_FAN_PAGES 6
-
 static const struct pmbus_driver_info max31785_info = {
        .pages = MAX31785_NR_PAGES,
 
index c846759bc1c0866d3954f5fd9b895e315275a800..a9229c6b0e84dcc7435d18bd9e19bef9a60227ae 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/pmbus.h>
-#include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include "pmbus.h"
 
index efe4bb1ff221c871d99c1c6697690cf870cdeea7..d3a64a35f7a9af2d11fe31de0d37b5abb7c2301a 100644 (file)
@@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = {
 };
 module_platform_driver(rpi_hwmon_driver);
 
-MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
+MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>");
 MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:raspberrypi-hwmon");
index 83fe08185ac7d9a9a1a92338277b742fa0547919..a0078ccede03f9302db615deab5e0d65df75fdcc 100644 (file)
@@ -24,19 +24,33 @@ static const unsigned char shtc1_cmd_measure_blocking_lpm[]    = { 0x64, 0x58 };
 static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
 
 /* command for reading the ID register */
-static const unsigned char shtc1_cmd_read_id_reg[]            = { 0xef, 0xc8 };
+static const unsigned char shtc1_cmd_read_id_reg[]             = { 0xef, 0xc8 };
 
-/* constants for reading the ID register */
-#define SHTC1_ID         0x07
-#define SHTC1_ID_REG_MASK 0x1f
+/*
+ * constants for reading the ID register
+ * SHTC1: 0x0007 with mask 0x003f
+ * SHTW1: 0x0007 with mask 0x003f
+ * SHTC3: 0x0807 with mask 0x083f
+ */
+#define SHTC3_ID      0x0807
+#define SHTC3_ID_MASK 0x083f
+#define SHTC1_ID      0x0007
+#define SHTC1_ID_MASK 0x003f
 
 /* delays for non-blocking i2c commands, both in us */
 #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
 #define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
+#define SHTC3_NONBLOCKING_WAIT_TIME_HPM  12100
+#define SHTC3_NONBLOCKING_WAIT_TIME_LPM    800
 
 #define SHTC1_CMD_LENGTH      2
 #define SHTC1_RESPONSE_LENGTH 6
 
+enum shtcx_chips {
+       shtc1,
+       shtc3,
+};
+
 struct shtc1_data {
        struct i2c_client *client;
        struct mutex update_lock;
@@ -47,6 +61,7 @@ struct shtc1_data {
        unsigned int nonblocking_wait_time; /* in us */
 
        struct shtc1_platform_data setup;
+       enum shtcx_chips chip;
 
        int temperature; /* 1000 * temperature in dgr C */
        int humidity; /* 1000 * relative humidity in %RH */
@@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data)
                data->command = data->setup.blocking_io ?
                                shtc1_cmd_measure_blocking_hpm :
                                shtc1_cmd_measure_nonblocking_hpm;
-               data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM;
-
+               data->nonblocking_wait_time = (data->chip == shtc1) ?
+                               SHTC1_NONBLOCKING_WAIT_TIME_HPM :
+                               SHTC3_NONBLOCKING_WAIT_TIME_HPM;
        } else {
                data->command = data->setup.blocking_io ?
                                shtc1_cmd_measure_blocking_lpm :
                                shtc1_cmd_measure_nonblocking_lpm;
-               data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM;
+               data->nonblocking_wait_time = (data->chip == shtc1) ?
+                               SHTC1_NONBLOCKING_WAIT_TIME_LPM :
+                               SHTC3_NONBLOCKING_WAIT_TIME_LPM;
        }
 }
 
@@ -171,9 +189,11 @@ static int shtc1_probe(struct i2c_client *client,
                       const struct i2c_device_id *id)
 {
        int ret;
-       char id_reg[2];
+       u16 id_reg;
+       char id_reg_buf[2];
        struct shtc1_data *data;
        struct device *hwmon_dev;
+       enum shtcx_chips chip = id->driver_data;
        struct i2c_adapter *adap = client->adapter;
        struct device *dev = &client->dev;
 
@@ -187,13 +207,20 @@ static int shtc1_probe(struct i2c_client *client,
                dev_err(dev, "could not send read_id_reg command: %d\n", ret);
                return ret < 0 ? ret : -ENODEV;
        }
-       ret = i2c_master_recv(client, id_reg, sizeof(id_reg));
-       if (ret != sizeof(id_reg)) {
+       ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
+       if (ret != sizeof(id_reg_buf)) {
                dev_err(dev, "could not read ID register: %d\n", ret);
                return -ENODEV;
        }
-       if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) {
-               dev_err(dev, "ID register doesn't match\n");
+
+       id_reg = be16_to_cpup((__be16 *)id_reg_buf);
+       if (chip == shtc3) {
+               if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {
+                       dev_err(dev, "SHTC3 ID register does not match\n");
+                       return -ENODEV;
+               }
+       } else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {
+               dev_err(dev, "SHTC1 ID register does not match\n");
                return -ENODEV;
        }
 
@@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client,
        data->setup.blocking_io = false;
        data->setup.high_precision = true;
        data->client = client;
+       data->chip = chip;
 
        if (client->dev.platform_data)
                data->setup = *(struct shtc1_platform_data *)dev->platform_data;
@@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client,
 
 /* device ID table */
 static const struct i2c_device_id shtc1_id[] = {
-       { "shtc1", 0 },
-       { "shtw1", 0 },
+       { "shtc1", shtc1 },
+       { "shtw1", shtc1 },
+       { "shtc3", shtc3 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, shtc1_id);
index d8c91c2cb8cf5eab77498c81cd465033597bc2dd..6eff14fe395d3466ba944b1b81a37fffc0c87b19 100644 (file)
@@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client,
 
        data->client = client;
        data->type = id->driver_data;
-       data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK)
+       data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK)
                                     | SMM665_CMDREG_BASE);
-       if (!data->cmdreg)
-               return -ENOMEM;
+       if (IS_ERR(data->cmdreg))
+               return PTR_ERR(data->cmdreg);
 
        switch (data->type) {
        case smm465:
index d2c04b6a3f2b7cfd7974b8cf19ae1f21ad80ed69..015f1ea319669eff7932daf49456a6638b9a7add 100644 (file)
@@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client)
        }
 
        for (i = 0; i < num_sc; i++) {
-               data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
-               if (!data->lm75[i]) {
+               data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]);
+               if (IS_ERR(data->lm75[i])) {
                        dev_err(&new_client->dev,
                                "Subclient %d registration at address 0x%x failed.\n",
                                i, sc_addr[i]);
-                       err = -ENOMEM;
+                       err = PTR_ERR(data->lm75[i]);
                        if (i == 1)
                                goto ERROR_SC_3;
                        goto ERROR_SC_2;
index 050ad42016914803181eb5e6f306185039f4eac8..aad8d4da5802be02cf981778ea68642075706f4a 100644 (file)
@@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
        struct i2c_adapter *adapter = client->adapter;
        struct w83791d_data *data = i2c_get_clientdata(client);
        int address = client->addr;
-       int i, id, err;
+       int i, id;
        u8 val;
 
        id = i2c_adapter_id(adapter);
@@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
                                        "invalid subclient "
                                        "address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -ENODEV;
-                               goto error_sc_0;
+                               return -ENODEV;
                        }
                }
                w83791d_write(client, W83791D_REG_I2C_SUBADDR,
@@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client)
 
        val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
        if (!(val & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + (val & 0x7));
        if (!(val & 0x80)) {
-               if ((data->lm75[0] != NULL) &&
+               if (!IS_ERR(data->lm75[0]) &&
                                ((val & 0x7) == ((val >> 4) & 0x7))) {
                        dev_err(&client->dev,
                                "duplicate addresses 0x%x, "
                                "use force_subclient\n",
                                data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto error_sc_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((val >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + ((val >> 4) & 0x7));
        }
 
        return 0;
-
-/* Undo inits in case of errors */
-
-error_sc_1:
-       i2c_unregister_device(data->lm75[0]);
-error_sc_0:
-       return err;
 }
 
 
@@ -1394,7 +1386,7 @@ static int w83791d_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &w83791d_group);
        if (err)
-               goto error3;
+               return err;
 
        /* Check if pins of fan/pwm 4-5 are in use as GPIO */
        has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10;
@@ -1419,9 +1411,6 @@ error5:
                sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
 error4:
        sysfs_remove_group(&client->dev.kobj, &w83791d_group);
-error3:
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
        return err;
 }
 
@@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &w83791d_group);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        return 0;
 }
 
index da8a6d62aa2347c9c7fd8dac5aae66193082b3f5..7fc8a1160c8f95269a8c29e07db0ff3e92c962d9 100644 (file)
@@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
 static int
 w83792d_detect_subclients(struct i2c_client *new_client)
 {
-       int i, id, err;
+       int i, id;
        int address = new_client->addr;
        u8 val;
        struct i2c_adapter *adapter = new_client->adapter;
@@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client)
                                dev_err(&new_client->dev,
                                        "invalid subclient address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -ENODEV;
-                               goto ERROR_SC_0;
+                               return -ENODEV;
                        }
                }
                w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
@@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client)
 
        val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
        if (!(val & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
+                                                         0x48 + (val & 0x7));
        if (!(val & 0x80)) {
-               if ((data->lm75[0] != NULL) &&
+               if (!IS_ERR(data->lm75[0]) &&
                        ((val & 0x7) == ((val >> 4) & 0x7))) {
                        dev_err(&new_client->dev,
                                "duplicate addresses 0x%x, use force_subclient\n",
                                data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto ERROR_SC_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((val >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
+                                                         0x48 + ((val >> 4) & 0x7));
        }
 
        return 0;
-
-/* Undo inits in case of errors */
-
-ERROR_SC_1:
-       i2c_unregister_device(data->lm75[0]);
-ERROR_SC_0:
-       return err;
 }
 
 static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
@@ -1396,7 +1388,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Register sysfs hooks */
        err = sysfs_create_group(&dev->kobj, &w83792d_group);
        if (err)
-               goto exit_i2c_unregister;
+               return err;
 
        /*
         * Read GPIO enable register to check if pins for fan 4,5 are used as
@@ -1441,9 +1433,6 @@ exit_remove_files:
        sysfs_remove_group(&dev->kobj, &w83792d_group);
        for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
                sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
-exit_i2c_unregister:
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
        return err;
 }
 
@@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client)
                sysfs_remove_group(&client->dev.kobj,
                                   &w83792d_group_fan[i]);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        return 0;
 }
 
index 46f5dfec8d0a29ef6ff40b151d19f4e3024320fd..9df48b70c70c7381fbcba60119182a39edb2a2cd 100644 (file)
@@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client)
        for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
                device_remove_file(dev, &w83793_temp[i].dev_attr);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        /* Decrease data reference counter */
        mutex_lock(&watchdog_data_mutex);
        kref_put(&data->kref, w83793_release_resources);
@@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client)
 static int
 w83793_detect_subclients(struct i2c_client *client)
 {
-       int i, id, err;
+       int i, id;
        int address = client->addr;
        u8 tmp;
        struct i2c_adapter *adapter = client->adapter;
@@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client)
                                        "invalid subclient "
                                        "address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -EINVAL;
-                               goto ERROR_SC_0;
+                               return -EINVAL;
                        }
                }
                w83793_write_value(client, W83793_REG_I2C_SUBADDR,
@@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client)
 
        tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
        if (!(tmp & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + (tmp & 0x7));
        if (!(tmp & 0x80)) {
-               if ((data->lm75[0] != NULL)
+               if (!IS_ERR(data->lm75[0])
                    && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
                        dev_err(&client->dev,
                                "duplicate addresses 0x%x, "
                                "use force_subclients\n", data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto ERROR_SC_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((tmp >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + ((tmp >> 4) & 0x7));
        }
 
        return 0;
-
-       /* Undo inits in case of errors */
-
-ERROR_SC_1:
-       i2c_unregister_device(data->lm75[0]);
-ERROR_SC_0:
-       return err;
 }
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
@@ -1945,9 +1934,6 @@ exit_remove:
 
        for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
                device_remove_file(dev, &w83793_temp[i].dev_attr);
-
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
 free_mem:
        kfree(data);
 exit:
index 7e3286265a3845346d11b82d7d8c2b3fe72042fe..f0af3a42f53cf6d605b3c1ad413468bcdd9138dd 100644 (file)
@@ -958,7 +958,7 @@ config TI_ADC161S626
 
 config TI_ADS1015
        tristate "Texas Instruments ADS1015 ADC"
-       depends on I2C && !SENSORS_ADS1015
+       depends on I2C
        select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
index 3c3ad42f22bfd29da879255593fe3cb7a21e1b3e..c92b405b7646cfbceaed3b6544fb71d145c9bb42 100644 (file)
@@ -688,6 +688,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        if (!cdev->ap.applid)
                return -ENODEV;
 
+       if (count < CAPIMSG_BASELEN)
+               return -EINVAL;
+
        skb = alloc_skb(count, GFP_USER);
        if (!skb)
                return -ENOMEM;
@@ -698,7 +701,8 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        }
        mlen = CAPIMSG_LEN(skb->data);
        if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
-               if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
+               if (count < CAPI_DATA_B3_REQ_LEN ||
+                   (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
                        kfree_skb(skb);
                        return -EINVAL;
                }
@@ -711,6 +715,10 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
 
        if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
+               if (count < CAPI_DISCONNECT_B3_RESP_LEN) {
+                       kfree_skb(skb);
+                       return -EINVAL;
+               }
                mutex_lock(&cdev->lock);
                capincci_free(cdev, CAPIMSG_NCCI(skb->data));
                mutex_unlock(&cdev->lock);
index 7e0d3a49c06d8ec443f0b8493c617411efbf7af8..bb31e13648d6577d47c5b0bd268a7cf0ccc80d5a 100644 (file)
@@ -597,7 +597,7 @@ static void bcm2835_finish_request(struct bcm2835_host *host)
        struct dma_chan *terminate_chan = NULL;
        struct mmc_request *mrq;
 
-       cancel_delayed_work_sync(&host->timeout_work);
+       cancel_delayed_work(&host->timeout_work);
 
        mrq = host->mrq;
 
index 64d3b5fb7fe563e0c958dc21e2a8090ce3e0d2d2..4a2872f49a6079445c339fa3c52f6111f1f63b16 100644 (file)
@@ -774,8 +774,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
        /* All SDHI have SDIO status bits which must be 1 */
        mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
 
-       pm_runtime_enable(&pdev->dev);
-
        ret = renesas_sdhi_clk_enable(host);
        if (ret)
                goto efree;
@@ -856,8 +854,6 @@ edisclk:
 efree:
        tmio_mmc_host_free(host);
 
-       pm_runtime_disable(&pdev->dev);
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
@@ -869,8 +865,6 @@ int renesas_sdhi_remove(struct platform_device *pdev)
        tmio_mmc_host_remove(host);
        renesas_sdhi_clk_disable(host);
 
-       pm_runtime_disable(&pdev->dev);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
index 9dc4548271b4b25d95c82f035b98f4f62f1e3c29..19944b0049db0d4b8778c00a4b2fa93535f029a9 100644 (file)
@@ -432,7 +432,6 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
                                        mmc_hostname(host->mmc));
                                host->flags &= ~SDHCI_SIGNALING_330;
                                host->flags |= SDHCI_SIGNALING_180;
-                               host->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
                                host->mmc->caps2 |= MMC_CAP2_NO_SD;
                                host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
                                pci_write_config_dword(chip->pdev,
@@ -682,6 +681,7 @@ static const struct sdhci_ops sdhci_pci_o2_ops = {
 const struct sdhci_pci_fixes sdhci_o2 = {
        .probe = sdhci_pci_o2_probe,
        .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD,
        .probe_slot = sdhci_pci_o2_probe_slot,
 #ifdef CONFIG_PM_SLEEP
        .resume = sdhci_pci_o2_resume,
index 8539e10784b4096186024319c18f0df4e555e435..93e83ad25976e756bdb04408b51c506925b02534 100644 (file)
@@ -172,8 +172,6 @@ static int tmio_mmc_probe(struct platform_device *pdev)
        host->mmc->f_max = pdata->hclk;
        host->mmc->f_min = pdata->hclk / 512;
 
-       pm_runtime_enable(&pdev->dev);
-
        ret = tmio_mmc_host_probe(host);
        if (ret)
                goto host_free;
@@ -193,7 +191,6 @@ host_remove:
        tmio_mmc_host_remove(host);
 host_free:
        tmio_mmc_host_free(host);
-       pm_runtime_disable(&pdev->dev);
 cell_disable:
        if (cell->disable)
                cell->disable(pdev);
@@ -210,8 +207,6 @@ static int tmio_mmc_remove(struct platform_device *pdev)
        if (cell->disable)
                cell->disable(pdev);
 
-       pm_runtime_disable(&pdev->dev);
-
        return 0;
 }
 
index c5ba13fae39920e656de9737412804e2f5155a77..2f0b092d6dcc64d199b75ec7563600f1954502dd 100644 (file)
@@ -163,6 +163,7 @@ struct tmio_mmc_host {
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
        bool                    native_hotplug;
+       bool                    runtime_synced;
        bool                    sdio_irq_enabled;
 
        /* Mandatory callback */
index 2cb3f951c3e2b793761726feb2bfa7a3ac45a980..9b6e1001e77c3acdc5c959b43bb397853f2d9eb2 100644 (file)
@@ -1153,15 +1153,6 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
 
-/**
- * tmio_mmc_host_probe() - Common probe for all implementations
- * @_host: Host to probe
- *
- * Perform tasks common to all implementations probe functions.
- *
- * The caller should have called pm_runtime_enable() prior to calling
- * the common probe function.
- */
 int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 {
        struct platform_device *pdev = _host->pdev;
@@ -1257,19 +1248,22 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       pm_runtime_set_active(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        ret = mmc_add_host(mmc);
        if (ret)
                goto remove_host;
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
+       pm_runtime_put(&pdev->dev);
 
        return 0;
 
 remove_host:
+       pm_runtime_put_noidle(&pdev->dev);
        tmio_mmc_host_remove(_host);
        return ret;
 }
@@ -1280,12 +1274,11 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        struct platform_device *pdev = host->pdev;
        struct mmc_host *mmc = host->mmc;
 
+       pm_runtime_get_sync(&pdev->dev);
+
        if (host->pdata->flags & TMIO_MMC_SDIO_IRQ)
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
 
-       if (!host->native_hotplug)
-               pm_runtime_get_sync(&pdev->dev);
-
        dev_pm_qos_hide_latency_limit(&pdev->dev);
 
        mmc_remove_host(mmc);
@@ -1294,7 +1287,10 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        tmio_mmc_release_dma(host);
 
        pm_runtime_dont_use_autosuspend(&pdev->dev);
+       if (host->native_hotplug)
+               pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
 
@@ -1337,6 +1333,11 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 {
        struct tmio_mmc_host *host = dev_get_drvdata(dev);
 
+       if (!host->runtime_synced) {
+               host->runtime_synced = true;
+               return 0;
+       }
+
        tmio_mmc_clk_enable(host);
        tmio_mmc_hw_reset(host->mmc);
 
index 49aad9a79c18d24aba0d45340964d24b5656aeb9..91a2be41edf6196bd9fc7f73262ab206efa46d1f 100644 (file)
@@ -631,7 +631,6 @@ static int uniphier_sd_probe(struct platform_device *pdev)
        host->clk_disable = uniphier_sd_clk_disable;
        host->set_clock = uniphier_sd_set_clock;
 
-       pm_runtime_enable(&pdev->dev);
        ret = uniphier_sd_clk_enable(host);
        if (ret)
                goto free_host;
@@ -653,7 +652,6 @@ static int uniphier_sd_probe(struct platform_device *pdev)
 
 free_host:
        tmio_mmc_host_free(host);
-       pm_runtime_disable(&pdev->dev);
 
        return ret;
 }
@@ -664,7 +662,6 @@ static int uniphier_sd_remove(struct platform_device *pdev)
 
        tmio_mmc_host_remove(host);
        uniphier_sd_clk_disable(host);
-       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index 0a7243825e7bae6d52f0b441e3174eeed61968f8..85a3b062371df881d7184e1733803e59c58259f2 100644 (file)
@@ -98,7 +98,7 @@ static const struct hclge_hw_error hclge_igu_egu_tnl_int[] = {
          .reset_level = HNAE3_GLOBAL_RESET },
        { .int_msk = BIT(1), .msg = "rx_stp_fifo_overflow",
          .reset_level = HNAE3_GLOBAL_RESET },
-       { .int_msk = BIT(2), .msg = "rx_stp_fifo_undeflow",
+       { .int_msk = BIT(2), .msg = "rx_stp_fifo_underflow",
          .reset_level = HNAE3_GLOBAL_RESET },
        { .int_msk = BIT(3), .msg = "tx_buf_overflow",
          .reset_level = HNAE3_GLOBAL_RESET },
index fa4bb940665c2fccd1933d7e4db9289d0d550cbc..5cb55ea671e3535ba1e23099f2b722a18f91b2af 100644 (file)
@@ -1984,8 +1984,11 @@ static void __ibmvnic_reset(struct work_struct *work)
        rwi = get_next_rwi(adapter);
        while (rwi) {
                if (adapter->state == VNIC_REMOVING ||
-                   adapter->state == VNIC_REMOVED)
-                       goto out;
+                   adapter->state == VNIC_REMOVED) {
+                       kfree(rwi);
+                       rc = EBUSY;
+                       break;
+               }
 
                if (adapter->force_reset_recovery) {
                        adapter->force_reset_recovery = false;
@@ -2011,7 +2014,7 @@ static void __ibmvnic_reset(struct work_struct *work)
                netdev_dbg(adapter->netdev, "Reset failed\n");
                free_all_rwi(adapter);
        }
-out:
+
        adapter->resetting = false;
        if (we_lock_rtnl)
                rtnl_unlock();
index 7882148abb4320ccf3a979b565fa93990366f991..51c696b6bf644d2a902cd0de495bdb792c23e6e0 100644 (file)
@@ -36,6 +36,7 @@
 #include <net/vxlan.h>
 #include <net/mpls.h>
 #include <net/xdp_sock.h>
+#include <net/xfrm.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
@@ -2621,7 +2622,7 @@ adjust_by_size:
                /* 16K ints/sec to 9.2K ints/sec */
                avg_wire_size *= 15;
                avg_wire_size += 11452;
-       } else if (avg_wire_size <= 1980) {
+       } else if (avg_wire_size < 1968) {
                /* 9.2K ints/sec to 8K ints/sec */
                avg_wire_size *= 5;
                avg_wire_size += 22420;
@@ -2654,6 +2655,8 @@ adjust_by_size:
        case IXGBE_LINK_SPEED_2_5GB_FULL:
        case IXGBE_LINK_SPEED_1GB_FULL:
        case IXGBE_LINK_SPEED_10_FULL:
+               if (avg_wire_size > 8064)
+                       avg_wire_size = 8064;
                itr += DIV_ROUND_UP(avg_wire_size,
                                    IXGBE_ITR_ADAPTIVE_MIN_INC * 64) *
                       IXGBE_ITR_ADAPTIVE_MIN_INC;
@@ -8695,7 +8698,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
 #endif /* IXGBE_FCOE */
 
 #ifdef CONFIG_IXGBE_IPSEC
-       if (secpath_exists(skb) &&
+       if (xfrm_offload(skb) &&
            !ixgbe_ipsec_tx(tx_ring, first, &ipsec_tx))
                goto out_drop;
 #endif
index 6b609553329fa98647b78f4e1e5d3e9223a8aa7a..a3b6d8c89127f1a2fcfdfb84a1824dbbedc019e6 100644 (file)
@@ -633,19 +633,17 @@ static void ixgbe_clean_xdp_tx_buffer(struct ixgbe_ring *tx_ring,
 bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
                            struct ixgbe_ring *tx_ring, int napi_budget)
 {
+       u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use;
        unsigned int total_packets = 0, total_bytes = 0;
-       u32 i = tx_ring->next_to_clean, xsk_frames = 0;
-       unsigned int budget = q_vector->tx.work_limit;
        struct xdp_umem *umem = tx_ring->xsk_umem;
        union ixgbe_adv_tx_desc *tx_desc;
        struct ixgbe_tx_buffer *tx_bi;
-       bool xmit_done;
+       u32 xsk_frames = 0;
 
-       tx_bi = &tx_ring->tx_buffer_info[i];
-       tx_desc = IXGBE_TX_DESC(tx_ring, i);
-       i -= tx_ring->count;
+       tx_bi = &tx_ring->tx_buffer_info[ntc];
+       tx_desc = IXGBE_TX_DESC(tx_ring, ntc);
 
-       do {
+       while (ntc != ntu) {
                if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
                        break;
 
@@ -661,22 +659,18 @@ bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
 
                tx_bi++;
                tx_desc++;
-               i++;
-               if (unlikely(!i)) {
-                       i -= tx_ring->count;
+               ntc++;
+               if (unlikely(ntc == tx_ring->count)) {
+                       ntc = 0;
                        tx_bi = tx_ring->tx_buffer_info;
                        tx_desc = IXGBE_TX_DESC(tx_ring, 0);
                }
 
                /* issue prefetch for next Tx descriptor */
                prefetch(tx_desc);
+       }
 
-               /* update budget accounting */
-               budget--;
-       } while (likely(budget));
-
-       i += tx_ring->count;
-       tx_ring->next_to_clean = i;
+       tx_ring->next_to_clean = ntc;
 
        u64_stats_update_begin(&tx_ring->syncp);
        tx_ring->stats.bytes += total_bytes;
@@ -688,8 +682,7 @@ bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
        if (xsk_frames)
                xsk_umem_complete_tx(umem, xsk_frames);
 
-       xmit_done = ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit);
-       return budget > 0 && xmit_done;
+       return ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit);
 }
 
 int ixgbe_xsk_async_xmit(struct net_device *dev, u32 qid)
index d2b41f9f87f80513a793eafe5e65899464488a9c..72872d6ca80c4992bfe2594bfdd273385a3b331c 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/bpf.h>
 #include <linux/bpf_trace.h>
 #include <linux/atomic.h>
+#include <net/xfrm.h>
 
 #include "ixgbevf.h"
 
@@ -4161,7 +4162,7 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb,
        first->protocol = vlan_get_protocol(skb);
 
 #ifdef CONFIG_IXGBEVF_IPSEC
-       if (secpath_exists(skb) && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx))
+       if (xfrm_offload(skb) && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx))
                goto out_drop;
 #endif
        tso = ixgbevf_tso(tx_ring, first, &hdr_len, &ipsec_tx);
index 1f6e16d5ea6be56b5cc663ec1f480e827ece7ae9..309470ec02190471476744602f98be74ab02f57b 100644 (file)
@@ -2240,7 +2240,7 @@ static int mlx4_validate_optimized_steering(struct mlx4_dev *dev)
        for (i = 1; i <= dev->caps.num_ports; i++) {
                if (mlx4_dev_port(dev, i, &port_cap)) {
                        mlx4_err(dev,
-                                "QUERY_DEV_CAP command failed, can't veify DMFS high rate steering.\n");
+                                "QUERY_DEV_CAP command failed, can't verify DMFS high rate steering.\n");
                } else if ((dev->caps.dmfs_high_steer_mode !=
                            MLX4_STEERING_DMFS_A0_DEFAULT) &&
                           (port_cap.dmfs_optimized_state ==
index d0a01e8f000aee71413425d94efc921856a062f7..b339125b2f097fcfdafd7e45f9ee8c5eeac5190a 100644 (file)
@@ -232,9 +232,9 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
        if (!laddr) {
-               printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
-               dev_kfree_skb(skb);
-               return NETDEV_TX_BUSY;
+               pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name);
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
        }
 
        sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0);       /* clear status */
index d5bbe3d6048bf3cec01fc5aadce5c75cc0d5f066..05981b54eaab7dccd70d0f90dd90508c230481ad 100644 (file)
@@ -260,9 +260,6 @@ nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
 
        type = cmsg_hdr->type;
        switch (type) {
-       case NFP_FLOWER_CMSG_TYPE_PORT_REIFY:
-               nfp_flower_cmsg_portreify_rx(app, skb);
-               break;
        case NFP_FLOWER_CMSG_TYPE_PORT_MOD:
                nfp_flower_cmsg_portmod_rx(app, skb);
                break;
@@ -328,8 +325,7 @@ nfp_flower_queue_ctl_msg(struct nfp_app *app, struct sk_buff *skb, int type)
        struct nfp_flower_priv *priv = app->priv;
        struct sk_buff_head *skb_head;
 
-       if (type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY ||
-           type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
+       if (type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
                skb_head = &priv->cmsg_skbs_high;
        else
                skb_head = &priv->cmsg_skbs_low;
@@ -368,6 +364,10 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
        } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH) {
                /* Acks from the NFP that the route is added - ignore. */
                dev_consume_skb_any(skb);
+       } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY) {
+               /* Handle REIFY acks outside wq to prevent RTNL conflict. */
+               nfp_flower_cmsg_portreify_rx(app, skb);
+               dev_consume_skb_any(skb);
        } else {
                nfp_flower_queue_ctl_msg(app, skb, cmsg_hdr->type);
        }
index b327b29f5d577a3f72bbeb3b744ecda2cb27219f..a6b4bfae4684fbbfdc1d83125c11cf55d920a9b0 100644 (file)
@@ -713,6 +713,21 @@ struct nv_skb_map {
        struct nv_skb_map *next_tx_ctx;
 };
 
+struct nv_txrx_stats {
+       u64 stat_rx_packets;
+       u64 stat_rx_bytes; /* not always available in HW */
+       u64 stat_rx_missed_errors;
+       u64 stat_rx_dropped;
+       u64 stat_tx_packets; /* not always available in HW */
+       u64 stat_tx_bytes;
+       u64 stat_tx_dropped;
+};
+
+#define nv_txrx_stats_inc(member) \
+               __this_cpu_inc(np->txrx_stats->member)
+#define nv_txrx_stats_add(member, count) \
+               __this_cpu_add(np->txrx_stats->member, (count))
+
 /*
  * SMP locking:
  * All hardware access under netdev_priv(dev)->lock, except the performance
@@ -797,10 +812,7 @@ struct fe_priv {
 
        /* RX software stats */
        struct u64_stats_sync swstats_rx_syncp;
-       u64 stat_rx_packets;
-       u64 stat_rx_bytes; /* not always available in HW */
-       u64 stat_rx_missed_errors;
-       u64 stat_rx_dropped;
+       struct nv_txrx_stats __percpu *txrx_stats;
 
        /* media detection workaround.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
@@ -826,9 +838,6 @@ struct fe_priv {
 
        /* TX software stats */
        struct u64_stats_sync swstats_tx_syncp;
-       u64 stat_tx_packets; /* not always available in HW */
-       u64 stat_tx_bytes;
-       u64 stat_tx_dropped;
 
        /* msi/msi-x fields */
        u32 msi_flags;
@@ -1721,6 +1730,39 @@ static void nv_update_stats(struct net_device *dev)
        }
 }
 
+static void nv_get_stats(int cpu, struct fe_priv *np,
+                        struct rtnl_link_stats64 *storage)
+{
+       struct nv_txrx_stats *src = per_cpu_ptr(np->txrx_stats, cpu);
+       unsigned int syncp_start;
+       u64 rx_packets, rx_bytes, rx_dropped, rx_missed_errors;
+       u64 tx_packets, tx_bytes, tx_dropped;
+
+       do {
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
+               rx_packets       = src->stat_rx_packets;
+               rx_bytes         = src->stat_rx_bytes;
+               rx_dropped       = src->stat_rx_dropped;
+               rx_missed_errors = src->stat_rx_missed_errors;
+       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
+
+       storage->rx_packets       += rx_packets;
+       storage->rx_bytes         += rx_bytes;
+       storage->rx_dropped       += rx_dropped;
+       storage->rx_missed_errors += rx_missed_errors;
+
+       do {
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
+               tx_packets  = src->stat_tx_packets;
+               tx_bytes    = src->stat_tx_bytes;
+               tx_dropped  = src->stat_tx_dropped;
+       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
+
+       storage->tx_packets += tx_packets;
+       storage->tx_bytes   += tx_bytes;
+       storage->tx_dropped += tx_dropped;
+}
+
 /*
  * nv_get_stats64: dev->ndo_get_stats64 function
  * Get latest stats value from the nic.
@@ -1733,7 +1775,7 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
        __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
-       unsigned int syncp_start;
+       int cpu;
 
        /*
         * Note: because HW stats are not always available and for
@@ -1746,20 +1788,8 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
         */
 
        /* software stats */
-       do {
-               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
-               storage->rx_packets       = np->stat_rx_packets;
-               storage->rx_bytes         = np->stat_rx_bytes;
-               storage->rx_dropped       = np->stat_rx_dropped;
-               storage->rx_missed_errors = np->stat_rx_missed_errors;
-       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
-
-       do {
-               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
-               storage->tx_packets = np->stat_tx_packets;
-               storage->tx_bytes   = np->stat_tx_bytes;
-               storage->tx_dropped = np->stat_tx_dropped;
-       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
+       for_each_online_cpu(cpu)
+               nv_get_stats(cpu, np, storage);
 
        /* If the nic supports hw counters then retrieve latest values */
        if (np->driver_data & DEV_HAS_STATISTICS_V123) {
@@ -1827,7 +1857,7 @@ static int nv_alloc_rx(struct net_device *dev)
                } else {
 packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_dropped++;
+                       nv_txrx_stats_inc(stat_rx_dropped);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
                }
@@ -1869,7 +1899,7 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                } else {
 packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_dropped++;
+                       nv_txrx_stats_inc(stat_rx_dropped);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
                }
@@ -2013,7 +2043,7 @@ static void nv_drain_tx(struct net_device *dev)
                }
                if (nv_release_txskb(np, &np->tx_skb[i])) {
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                }
                np->tx_skb[i].dma = 0;
@@ -2227,7 +2257,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* on DMA mapping error - drop the packet */
                        dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                        return NETDEV_TX_OK;
                }
@@ -2273,7 +2303,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_dropped++;
+                               nv_txrx_stats_inc(stat_tx_dropped);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                                return NETDEV_TX_OK;
                        }
@@ -2384,7 +2414,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                        /* on DMA mapping error - drop the packet */
                        dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                        return NETDEV_TX_OK;
                }
@@ -2431,7 +2461,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                                dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_dropped++;
+                               nv_txrx_stats_inc(stat_tx_dropped);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                                return NETDEV_TX_OK;
                        }
@@ -2560,9 +2590,12 @@ static int nv_tx_done(struct net_device *dev, int limit)
                                            && !(flags & NV_TX_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
+                                       unsigned int len;
+
                                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                                       np->stat_tx_packets++;
-                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_inc(stat_tx_packets);
+                                       len = np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_add(stat_tx_bytes, len);
                                        u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                bytes_compl += np->get_tx_ctx->skb->len;
@@ -2577,9 +2610,12 @@ static int nv_tx_done(struct net_device *dev, int limit)
                                            && !(flags & NV_TX2_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
+                                       unsigned int len;
+
                                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                                       np->stat_tx_packets++;
-                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_inc(stat_tx_packets);
+                                       len = np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_add(stat_tx_bytes, len);
                                        u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                bytes_compl += np->get_tx_ctx->skb->len;
@@ -2627,9 +2663,12 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
                                                nv_legacybackoff_reseed(dev);
                                }
                        } else {
+                               unsigned int len;
+
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_packets++;
-                               np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                               nv_txrx_stats_inc(stat_tx_packets);
+                               len = np->get_tx_ctx->skb->len;
+                               nv_txrx_stats_add(stat_tx_bytes, len);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                        }
 
@@ -2806,6 +2845,15 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
        }
 }
 
+static void rx_missing_handler(u32 flags, struct fe_priv *np)
+{
+       if (flags & NV_RX_MISSEDFRAME) {
+               u64_stats_update_begin(&np->swstats_rx_syncp);
+               nv_txrx_stats_inc(stat_rx_missed_errors);
+               u64_stats_update_end(&np->swstats_rx_syncp);
+       }
+}
+
 static int nv_rx_process(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
@@ -2848,11 +2896,7 @@ static int nv_rx_process(struct net_device *dev, int limit)
                                        }
                                        /* the rest are hard errors */
                                        else {
-                                               if (flags & NV_RX_MISSEDFRAME) {
-                                                       u64_stats_update_begin(&np->swstats_rx_syncp);
-                                                       np->stat_rx_missed_errors++;
-                                                       u64_stats_update_end(&np->swstats_rx_syncp);
-                                               }
+                                               rx_missing_handler(flags, np);
                                                dev_kfree_skb(skb);
                                                goto next_pkt;
                                        }
@@ -2896,8 +2940,8 @@ static int nv_rx_process(struct net_device *dev, int limit)
                skb->protocol = eth_type_trans(skb, dev);
                napi_gro_receive(&np->napi, skb);
                u64_stats_update_begin(&np->swstats_rx_syncp);
-               np->stat_rx_packets++;
-               np->stat_rx_bytes += len;
+               nv_txrx_stats_inc(stat_rx_packets);
+               nv_txrx_stats_add(stat_rx_bytes, len);
                u64_stats_update_end(&np->swstats_rx_syncp);
 next_pkt:
                if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
@@ -2982,8 +3026,8 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                        }
                        napi_gro_receive(&np->napi, skb);
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_packets++;
-                       np->stat_rx_bytes += len;
+                       nv_txrx_stats_inc(stat_rx_packets);
+                       nv_txrx_stats_add(stat_rx_bytes, len);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                } else {
                        dev_kfree_skb(skb);
@@ -5651,6 +5695,12 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        SET_NETDEV_DEV(dev, &pci_dev->dev);
        u64_stats_init(&np->swstats_rx_syncp);
        u64_stats_init(&np->swstats_tx_syncp);
+       np->txrx_stats = alloc_percpu(struct nv_txrx_stats);
+       if (!np->txrx_stats) {
+               pr_err("np->txrx_stats, alloc memory error.\n");
+               err = -ENOMEM;
+               goto out_alloc_percpu;
+       }
 
        timer_setup(&np->oom_kick, nv_do_rx_refill, 0);
        timer_setup(&np->nic_poll, nv_do_nic_poll, 0);
@@ -6060,6 +6110,8 @@ out_relreg:
 out_disable:
        pci_disable_device(pci_dev);
 out_free:
+       free_percpu(np->txrx_stats);
+out_alloc_percpu:
        free_netdev(dev);
 out:
        return err;
@@ -6105,6 +6157,9 @@ static void nv_restore_mac_addr(struct pci_dev *pci_dev)
 static void nv_remove(struct pci_dev *pci_dev)
 {
        struct net_device *dev = pci_get_drvdata(pci_dev);
+       struct fe_priv *np = netdev_priv(dev);
+
+       free_percpu(np->txrx_stats);
 
        unregister_netdev(dev);
 
index 4083019c547a4b1b04509738ac4a6cb4ee0808e5..f97a4096f8fc8e44ef2456e822952a885e48de83 100644 (file)
@@ -873,7 +873,12 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
        int ret;
        u32 reg, val;
 
-       regmap_field_read(gmac->regmap_field, &val);
+       ret = regmap_field_read(gmac->regmap_field, &val);
+       if (ret) {
+               dev_err(priv->device, "Fail to read from regmap field.\n");
+               return ret;
+       }
+
        reg = gmac->variant->default_syscon_value;
        if (reg != val)
                dev_warn(priv->device,
index 331c16d30d5df02d1a00bca2c4871362e5dbfeb6..23281aeeb2226ee4dc9d7655aebc247c94c94def 100644 (file)
@@ -344,10 +344,10 @@ static void sp_bump(struct sixpack *sp, char cmd)
 
        sp->dev->stats.rx_bytes += count;
 
-       if ((skb = dev_alloc_skb(count)) == NULL)
+       if ((skb = dev_alloc_skb(count + 1)) == NULL)
                goto out_mem;
 
-       ptr = skb_put(skb, count);
+       ptr = skb_put(skb, count + 1);
        *ptr++ = cmd;   /* KISS command */
 
        memcpy(ptr, sp->cooked_buf + 1, count);
index a45c5de96ab1c9688c0ed1eaa99f60fef3294230..a5a57ca94c1ac541092867b685fe7d616218f96b 100644 (file)
@@ -376,8 +376,8 @@ static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_stat
  *  Local device  Link partner
  *  Pause AsymDir Pause AsymDir Result
  *    1     X       1     X     TX+RX
- *    0     1       1     1     RX
- *    1     1       0     1     TX
+ *    0     1       1     1     TX
+ *    1     1       0     1     RX
  */
 static void phylink_resolve_flow(struct phylink *pl,
                                 struct phylink_link_state *state)
@@ -398,7 +398,7 @@ static void phylink_resolve_flow(struct phylink *pl,
                        new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
                else if (pause & MLO_PAUSE_ASYM)
                        new_pause = state->pause & MLO_PAUSE_SYM ?
-                                MLO_PAUSE_RX : MLO_PAUSE_TX;
+                                MLO_PAUSE_TX : MLO_PAUSE_RX;
        } else {
                new_pause = pl->link_config.pause & MLO_PAUSE_TXRX_MASK;
        }
index db16d7a13e00c197574b1f9f70044775648bbd72..aab0be40d4430ab1c1fed92782f4a263f38020bd 100644 (file)
@@ -787,7 +787,8 @@ static void tun_detach_all(struct net_device *dev)
 }
 
 static int tun_attach(struct tun_struct *tun, struct file *file,
-                     bool skip_filter, bool napi, bool napi_frags)
+                     bool skip_filter, bool napi, bool napi_frags,
+                     bool publish_tun)
 {
        struct tun_file *tfile = file->private_data;
        struct net_device *dev = tun->dev;
@@ -870,7 +871,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
         * initialized tfile; otherwise we risk using half-initialized
         * object.
         */
-       rcu_assign_pointer(tfile->tun, tun);
+       if (publish_tun)
+               rcu_assign_pointer(tfile->tun, tun);
        rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
        tun->numqueues++;
        tun_set_real_num_queues(tun);
@@ -2730,7 +2732,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER,
                                 ifr->ifr_flags & IFF_NAPI,
-                                ifr->ifr_flags & IFF_NAPI_FRAGS);
+                                ifr->ifr_flags & IFF_NAPI_FRAGS, true);
                if (err < 0)
                        return err;
 
@@ -2829,13 +2831,17 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
-                                ifr->ifr_flags & IFF_NAPI_FRAGS);
+                                ifr->ifr_flags & IFF_NAPI_FRAGS, false);
                if (err < 0)
                        goto err_free_flow;
 
                err = register_netdevice(tun->dev);
                if (err < 0)
                        goto err_detach;
+               /* free_netdev() won't check refcnt, to aovid race
+                * with dev_put() we need publish tun after registration.
+                */
+               rcu_assign_pointer(tfile->tun, tun);
        }
 
        netif_carrier_on(tun->dev);
@@ -2978,7 +2984,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
                if (ret < 0)
                        goto unlock;
                ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI,
-                                tun->flags & IFF_NAPI_FRAGS);
+                                tun->flags & IFF_NAPI_FRAGS, true);
        } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
                tun = rtnl_dereference(tfile->tun);
                if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)
index 8458e88c18e9e017f579128c36a9707b1232ab97..32f53de5b1fe7abff0eb2882240bcd295977af08 100644 (file)
@@ -206,7 +206,15 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                goto bad_desc;
        }
 skip:
-       if (rndis && header.usb_cdc_acm_descriptor &&
+       /* Communcation class functions with bmCapabilities are not
+        * RNDIS.  But some Wireless class RNDIS functions use
+        * bmCapabilities for their own purpose. The failsafe is
+        * therefore applied only to Communication class RNDIS
+        * functions.  The rndis test is redundant, but a cheap
+        * optimization.
+        */
+       if (rndis && is_rndis(&intf->cur_altsetting->desc) &&
+           header.usb_cdc_acm_descriptor &&
            header.usb_cdc_acm_descriptor->bmCapabilities) {
                dev_dbg(&intf->dev,
                        "ACM capabilities %02x, not really RNDIS?\n",
index d74349628db2209e99ed5c4e24c172bf1603ed23..0e6a51525d9134d18a87a69362a9af7cdfc32790 100644 (file)
@@ -1115,7 +1115,7 @@ static void lmc_running_reset (struct net_device *dev) /*fold00*/
     sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
     LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
 
-    lmc_trace(dev, "lmc_runnin_reset_out");
+    lmc_trace(dev, "lmc_running_reset_out");
 }
 
 
index 6642bcb27761d63e8545865c1e2c91097cf9e5c2..8efb493ceec2fc96cda43cb56cde5e6d19e91015 100644 (file)
@@ -127,6 +127,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev,
                        "%d\n", result);
        result = 0;
 error_cmd:
+       kfree(cmd);
        kfree_skb(ack_skb);
 error_msg_to_dev:
 error_alloc:
index d9ed53b7c768d631cb67c519f4c898a0e9152e70..3b12e7ad35e1dd06b36c6a5ff9c8b20fba5bfbc8 100644 (file)
@@ -1070,18 +1070,18 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* same thing for QuZ... */
        if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QUZ) {
-               if (cfg == &iwl_ax101_cfg_qu_hr)
-                       cfg = &iwl_ax101_cfg_quz_hr;
-               else if (cfg == &iwl_ax201_cfg_qu_hr)
-                       cfg = &iwl_ax201_cfg_quz_hr;
-               else if (cfg == &iwl9461_2ac_cfg_qu_b0_jf_b0)
-                       cfg = &iwl9461_2ac_cfg_quz_a0_jf_b0_soc;
-               else if (cfg == &iwl9462_2ac_cfg_qu_b0_jf_b0)
-                       cfg = &iwl9462_2ac_cfg_quz_a0_jf_b0_soc;
-               else if (cfg == &iwl9560_2ac_cfg_qu_b0_jf_b0)
-                       cfg = &iwl9560_2ac_cfg_quz_a0_jf_b0_soc;
-               else if (cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
-                       cfg = &iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc;
+               if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax101_cfg_quz_hr;
+               else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax201_cfg_quz_hr;
+               else if (iwl_trans->cfg == &iwl9461_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9461_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9462_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9462_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9560_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc;
        }
 
 #endif
index 653d347a9a19d3e77eb3fbd1ad5d7da3278d6d4a..580387f9f12a9af3b2f64e5ea760ea1607dafe29 100644 (file)
@@ -241,6 +241,9 @@ static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
                }
 
                vs_ie = (struct ieee_types_header *)vendor_ie;
+               if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
+                       IEEE_MAX_IE_SIZE)
+                       return -EINVAL;
                memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
                       vs_ie, vs_ie->len + 2);
                le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2);
index 18f7d9bf30b28edc19acef376675b15d726bcc00..0939a8c8f3ab5cf74a55ae08c3feadc1c486f3ca 100644 (file)
@@ -265,6 +265,8 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
 
        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
        if (rate_ie) {
+               if (rate_ie->len > MWIFIEX_SUPPORTED_RATES)
+                       return;
                memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
                rate_len = rate_ie->len;
        }
@@ -272,8 +274,11 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
                                           params->beacon.tail,
                                           params->beacon.tail_len);
-       if (rate_ie)
+       if (rate_ie) {
+               if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len)
+                       return;
                memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
+       }
 
        return;
 }
@@ -391,6 +396,8 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv,
                                            params->beacon.tail_len);
        if (vendor_ie) {
                wmm_ie = vendor_ie;
+               if (*(wmm_ie + 1) > sizeof(struct mwifiex_types_wmm_info))
+                       return;
                memcpy(&bss_cfg->wmm_info, wmm_ie +
                       sizeof(struct ieee_types_header), *(wmm_ie + 1));
                priv->wmm_enabled = 1;
index 40c0d536e20d04468569bdaa4575c74cb0aee40c..9d4426f6905f29591b9f66a613a3830acf88ccf1 100644 (file)
@@ -59,6 +59,11 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
                dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
        }
 
+       if (is_mt7630(dev)) {
+               dev->mt76.cap.has_5ghz = false;
+               dev_dbg(dev->mt76.dev, "mask out 5GHz support\n");
+       }
+
        if (!mt76x02_field_valid(nic_conf1 & 0xff))
                nic_conf1 &= 0xff00;
 
index 4585e1b756c2096d93321e9d3aa8da1f2ff25d49..6117e6ca08cb7cf6cedb6b46b9a426f1bd0d0b10 100644 (file)
@@ -62,6 +62,19 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
        mt76x0e_stop_hw(dev);
 }
 
+static int
+mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+               struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+               struct ieee80211_key_conf *key)
+{
+       struct mt76x02_dev *dev = hw->priv;
+
+       if (is_mt7630(dev))
+               return -EOPNOTSUPP;
+
+       return mt76x02_set_key(hw, cmd, vif, sta, key);
+}
+
 static void
 mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
              u32 queues, bool drop)
@@ -78,7 +91,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
        .configure_filter = mt76x02_configure_filter,
        .bss_info_changed = mt76x02_bss_info_changed,
        .sta_state = mt76_sta_state,
-       .set_key = mt76x02_set_key,
+       .set_key = mt76x0e_set_key,
        .conf_tx = mt76x02_conf_tx,
        .sw_scan_start = mt76x02_sw_scan,
        .sw_scan_complete = mt76x02_sw_scan_complete,
index ecbe78b8027b689ea831826713173364b3941a73..f1cdcd61c54a5eeec18fc349e63a5cd832cb17fa 100644 (file)
@@ -1654,13 +1654,18 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
 
        offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
 
-       rt2800_register_multiread(rt2x00dev, offset,
-                                 &iveiv_entry, sizeof(iveiv_entry));
-       if ((crypto->cipher == CIPHER_TKIP) ||
-           (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
-           (crypto->cipher == CIPHER_AES))
-               iveiv_entry.iv[3] |= 0x20;
-       iveiv_entry.iv[3] |= key->keyidx << 6;
+       if (crypto->cmd == SET_KEY) {
+               rt2800_register_multiread(rt2x00dev, offset,
+                                         &iveiv_entry, sizeof(iveiv_entry));
+               if ((crypto->cipher == CIPHER_TKIP) ||
+                   (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
+                   (crypto->cipher == CIPHER_AES))
+                       iveiv_entry.iv[3] |= 0x20;
+               iveiv_entry.iv[3] |= key->keyidx << 6;
+       } else {
+               memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+       }
+
        rt2800_register_multiwrite(rt2x00dev, offset,
                                   &iveiv_entry, sizeof(iveiv_entry));
 }
@@ -4237,24 +4242,18 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        switch (rt2x00dev->default_ant.rx_chain_num) {
        case 3:
                /* Turn on tertiary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN, 1);
                /* fall-through */
        case 2:
                /* Turn on secondary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
                /* fall-through */
        case 1:
                /* Turn on primary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
                break;
        }
 
index f5048d4b8cb6d3d32ba0f44f271023cc15544601..760eaffeebd64a100392f5d97da43ae303428520 100644 (file)
@@ -645,7 +645,6 @@ fail_rx:
        kfree(rsi_dev->tx_buffer);
 
 fail_eps:
-       kfree(rsi_dev);
 
        return status;
 }
index e42850095892d41fbbf43dc797d28efd5a3d3537..7eda62a9e0dfa3d95616c85e3339570725b01cd8 100644 (file)
@@ -316,7 +316,7 @@ static int st95hf_echo_command(struct st95hf_context *st95context)
                                          &echo_response);
        if (result) {
                dev_err(&st95context->spicontext.spidev->dev,
-                       "err: echo response receieve error = 0x%x\n", result);
+                       "err: echo response receive error = 0x%x\n", result);
                return result;
        }
 
index ba6438ac4d72a0623da3abd65a03f57d326224b8..ff84d1afd229d34f50be3564277222221342582a 100644 (file)
@@ -2552,7 +2552,7 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
                        if (IS_ERR(map))
                                return map;
                } else
-                       map = ERR_PTR(-ENODEV);
+                       return ERR_PTR(-ENODEV);
 
                ctx->maps[ASPEED_IP_LPC] = map;
                dev_dbg(ctx->dev, "Acquired LPC regmap");
@@ -2562,6 +2562,33 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
        return ERR_PTR(-EINVAL);
 }
 
+static int aspeed_g5_sig_expr_eval(struct aspeed_pinmux_data *ctx,
+                                  const struct aspeed_sig_expr *expr,
+                                  bool enabled)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < expr->ndescs; i++) {
+               const struct aspeed_sig_desc *desc = &expr->descs[i];
+               struct regmap *map;
+
+               map = aspeed_g5_acquire_regmap(ctx, desc->ip);
+               if (IS_ERR(map)) {
+                       dev_err(ctx->dev,
+                               "Failed to acquire regmap for IP block %d\n",
+                               desc->ip);
+                       return PTR_ERR(map);
+               }
+
+               ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]);
+               if (ret <= 0)
+                       return ret;
+       }
+
+       return 1;
+}
+
 /**
  * Configure a pin's signal by applying an expression's descriptor state for
  * all descriptors in the expression.
@@ -2647,6 +2674,7 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx,
 }
 
 static const struct aspeed_pinmux_ops aspeed_g5_ops = {
+       .eval = aspeed_g5_sig_expr_eval,
        .set = aspeed_g5_sig_expr_set,
 };
 
index 839c01b7953f2b845f1e0db64f4269feb0bb2131..57305ca838a7c800fb93cf5377bf1ecb5a9bc562 100644 (file)
@@ -78,11 +78,14 @@ int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
  * neither the enabled nor disabled state. Thus we must explicitly test for
  * either condition as required.
  */
-int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+int aspeed_sig_expr_eval(struct aspeed_pinmux_data *ctx,
                         const struct aspeed_sig_expr *expr, bool enabled)
 {
-       int i;
        int ret;
+       int i;
+
+       if (ctx->ops->eval)
+               return ctx->ops->eval(ctx, expr, enabled);
 
        for (i = 0; i < expr->ndescs; i++) {
                const struct aspeed_sig_desc *desc = &expr->descs[i];
index 52d299b59ce2fe20bebe72a491f66ce59a0e567d..db3457c86f48c5f0314ce917b6c6136560975e86 100644 (file)
@@ -702,6 +702,8 @@ struct aspeed_pin_function {
 struct aspeed_pinmux_data;
 
 struct aspeed_pinmux_ops {
+       int (*eval)(struct aspeed_pinmux_data *ctx,
+                   const struct aspeed_sig_expr *expr, bool enabled);
        int (*set)(struct aspeed_pinmux_data *ctx,
                   const struct aspeed_sig_expr *expr, bool enabled);
 };
@@ -722,9 +724,8 @@ struct aspeed_pinmux_data {
 int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled,
                         struct regmap *map);
 
-int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
-                        const struct aspeed_sig_expr *expr,
-                        bool enabled);
+int aspeed_sig_expr_eval(struct aspeed_pinmux_data *ctx,
+                        const struct aspeed_sig_expr *expr, bool enabled);
 
 static inline int aspeed_sig_expr_set(struct aspeed_pinmux_data *ctx,
                                      const struct aspeed_sig_expr *expr,
index ef6777e14d3df080b5d5afa14d0169e38e8ad621..6f0404f501071b37200119fe7d4f90d3c73cf49a 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_RAS)      += ras.o debugfs.o
+obj-$(CONFIG_RAS)      += ras.o
+obj-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_RAS_CEC)  += cec.o
index 5d545806d930372ce02c5637d230b77e03dd2f5a..c09cf55e2d2040031b0688d827d806f57db9df13 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/mm.h>
 #include <linux/gfp.h>
+#include <linux/ras.h>
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
 
index 9c1b717efad861d332460d32663d82bae3894d3a..0d4f985afbf37f92e9f0f54531f2dd58248ee877 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/debugfs.h>
+#include <linux/ras.h>
+#include "debugfs.h"
 
 struct dentry *ras_debugfs_dir;
 
index b57093d7c01f660ff65da897f64133944f5058e1..3ee63531f6d5c36d36ffd24b2e7477cf1290e439 100644 (file)
@@ -83,6 +83,7 @@ config REGULATOR_88PM8607
 config REGULATOR_ACT8865
        tristate "Active-semi act8865 voltage regulator"
        depends on I2C
+       depends on POWER_SUPPLY
        select REGMAP_I2C
        help
          This driver controls a active-semi act8865 voltage output
@@ -618,6 +619,15 @@ config REGULATOR_MT6323
          This driver supports the control of different power rails of device
          through regulator interface.
 
+config REGULATOR_MT6358
+       tristate "MediaTek MT6358 PMIC"
+       depends on MFD_MT6397 && BROKEN
+       help
+         Say y here to select this option to enable the power regulator of
+         MediaTek MT6358 PMIC.
+         This driver supports the control of different power rails of device
+         through regulator interface.
+
 config REGULATOR_MT6380
        tristate "MediaTek MT6380 PMIC"
        depends on MTK_PMIC_WRAP
@@ -906,6 +916,13 @@ config REGULATOR_SY8106A
        help
          This driver supports SY8106A single output regulator.
 
+config REGULATOR_SY8824X
+       tristate "Silergy SY8824C/SY8824E regulator"
+       depends on I2C && (OF || COMPILE_TEST)
+       select REGMAP_I2C
+       help
+         This driver supports SY8824C single output regulator.
+
 config REGULATOR_TPS51632
        tristate "TI TPS51632 Power Regulator"
        depends on I2C
index eef73b5a35a4dd1e467a26e6f07e4f7e8b8f6635..2210ba56f9bd115e6229e02861d7009358d977dd 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
+obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
@@ -111,6 +112,7 @@ obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
 obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
+obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
index cf72d7c6b8c9fb75eb06cdf0575cf85945a939c5..0fa97f934df49b0f3998fd7ee51287085ae9f2f5 100644 (file)
 #include <linux/regulator/act8865.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/power_supply.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regmap.h>
+#include <dt-bindings/regulator/active-semi,8865-regulator.h>
 
 /*
  * ACT8600 Global Register Map.
  */
 #define        ACT8865_SYS_MODE        0x00
 #define        ACT8865_SYS_CTRL        0x01
+#define        ACT8865_SYS_UNLK_REGS   0x0b
 #define        ACT8865_DCDC1_VSET1     0x20
 #define        ACT8865_DCDC1_VSET2     0x21
 #define        ACT8865_DCDC1_CTRL      0x22
+#define        ACT8865_DCDC1_SUS       0x24
 #define        ACT8865_DCDC2_VSET1     0x30
 #define        ACT8865_DCDC2_VSET2     0x31
 #define        ACT8865_DCDC2_CTRL      0x32
+#define        ACT8865_DCDC2_SUS       0x34
 #define        ACT8865_DCDC3_VSET1     0x40
 #define        ACT8865_DCDC3_VSET2     0x41
 #define        ACT8865_DCDC3_CTRL      0x42
+#define        ACT8865_DCDC3_SUS       0x44
 #define        ACT8865_LDO1_VSET       0x50
 #define        ACT8865_LDO1_CTRL       0x51
+#define        ACT8865_LDO1_SUS        0x52
 #define        ACT8865_LDO2_VSET       0x54
 #define        ACT8865_LDO2_CTRL       0x55
+#define        ACT8865_LDO2_SUS        0x56
 #define        ACT8865_LDO3_VSET       0x60
 #define        ACT8865_LDO3_CTRL       0x61
+#define        ACT8865_LDO3_SUS        0x62
 #define        ACT8865_LDO4_VSET       0x64
 #define        ACT8865_LDO4_CTRL       0x65
+#define        ACT8865_LDO4_SUS        0x66
 #define        ACT8865_MSTROFF         0x20
 
 /*
  * Field Definitions.
  */
 #define        ACT8865_ENA             0x80    /* ON - [7] */
+#define        ACT8865_DIS             0x40    /* DIS - [6] */
+
 #define        ACT8865_VSEL_MASK       0x3F    /* VSET - [5:0] */
 
 
 #define ACT8600_LDO10_ENA              0x40    /* ON - [6] */
 #define ACT8600_SUDCDC_VSEL_MASK       0xFF    /* SUDCDC VSET - [7:0] */
 
+#define ACT8600_APCH_CHG_ACIN          BIT(7)
+#define ACT8600_APCH_CHG_USB           BIT(6)
+#define ACT8600_APCH_CSTATE0           BIT(5)
+#define ACT8600_APCH_CSTATE1           BIT(4)
+
 /*
  * ACT8865 voltage number
  */
@@ -217,6 +234,171 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0),
 };
 
+static int act8865_set_suspend_state(struct regulator_dev *rdev, bool enable)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev->desc->id, reg, val;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_SUS;
+               val = 0xe8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (enable)
+               val |= BIT(4);
+
+       /*
+        * Ask the PMIC to enable/disable this output when entering hibernate
+        * mode.
+        */
+       return regmap_write(regmap, reg, val);
+}
+
+static int act8865_set_suspend_enable(struct regulator_dev *rdev)
+{
+       return act8865_set_suspend_state(rdev, true);
+}
+
+static int act8865_set_suspend_disable(struct regulator_dev *rdev)
+{
+       return act8865_set_suspend_state(rdev, false);
+}
+
+static unsigned int act8865_of_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case ACT8865_REGULATOR_MODE_FIXED:
+               return REGULATOR_MODE_FAST;
+       case ACT8865_REGULATOR_MODE_NORMAL:
+               return REGULATOR_MODE_NORMAL;
+       case ACT8865_REGULATOR_MODE_LOWPOWER:
+               return REGULATOR_MODE_STANDBY;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static int act8865_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev_get_id(rdev);
+       int reg, val = 0;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_CTRL;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_CTRL;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_CTRL;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_CTRL;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_CTRL;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_CTRL;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_CTRL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+       case REGULATOR_MODE_NORMAL:
+               if (id <= ACT8865_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               if (id > ACT8865_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(regmap, reg, BIT(5), val);
+}
+
+static unsigned int act8865_get_mode(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev_get_id(rdev);
+       int reg, ret, val = 0;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_CTRL;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_CTRL;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_CTRL;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_CTRL;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_CTRL;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_CTRL;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_CTRL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_read(regmap, reg, &val);
+       if (ret)
+               return ret;
+
+       if (id <= ACT8865_ID_DCDC3 && (val & BIT(5)))
+               return REGULATOR_MODE_FAST;
+       else if (id > ACT8865_ID_DCDC3 && !(val & BIT(5)))
+               return REGULATOR_MODE_NORMAL;
+       else
+               return REGULATOR_MODE_STANDBY;
+}
+
 static const struct regulator_ops act8865_ops = {
        .list_voltage           = regulator_list_voltage_linear_range,
        .map_voltage            = regulator_map_voltage_linear_range,
@@ -224,24 +406,44 @@ static const struct regulator_ops act8865_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
+       .set_mode               = act8865_set_mode,
+       .get_mode               = act8865_get_mode,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_enable     = act8865_set_suspend_enable,
+       .set_suspend_disable    = act8865_set_suspend_disable,
 };
 
 static const struct regulator_ops act8865_ldo_ops = {
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .set_mode               = act8865_set_mode,
+       .get_mode               = act8865_get_mode,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_enable     = act8865_set_suspend_enable,
+       .set_suspend_disable    = act8865_set_suspend_disable,
+       .set_pull_down          = regulator_set_pull_down_regmap,
+};
+
+static const struct regulator_ops act8865_fixed_ldo_ops = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
 };
 
-#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply)           \
+#define ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, _ops)    \
        [_family##_ID_##_id] = {                                        \
                .name                   = _name,                        \
                .of_match               = of_match_ptr(_name),          \
+               .of_map_mode            = act8865_of_map_mode,          \
                .regulators_node        = of_match_ptr("regulators"),   \
                .supply_name            = _supply,                      \
                .id                     = _family##_ID_##_id,           \
                .type                   = REGULATOR_VOLTAGE,            \
-               .ops                    = &act8865_ops,                 \
+               .ops                    = _ops,                         \
                .n_voltages             = ACT8865_VOLTAGE_NUM,          \
                .linear_ranges          = act8865_voltage_ranges,       \
                .n_linear_ranges        = ARRAY_SIZE(act8865_voltage_ranges), \
@@ -249,9 +451,17 @@ static const struct regulator_ops act8865_ldo_ops = {
                .vsel_mask              = ACT8865_VSEL_MASK,            \
                .enable_reg             = _family##_##_id##_CTRL,       \
                .enable_mask            = ACT8865_ENA,                  \
+               .pull_down_reg          = _family##_##_id##_CTRL,       \
+               .pull_down_mask         = ACT8865_DIS,                  \
                .owner                  = THIS_MODULE,                  \
        }
 
+#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \
+       ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ops)
+
+#define ACT88xx_LDO(_name, _family, _id, _vsel_reg, _supply) \
+       ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ldo_ops)
+
 static const struct regulator_desc act8600_regulators[] = {
        ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"),
        ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"),
@@ -281,7 +491,7 @@ static const struct regulator_desc act8600_regulators[] = {
                .of_match = of_match_ptr("LDO_REG9"),
                .regulators_node = of_match_ptr("regulators"),
                .id = ACT8600_ID_LDO9,
-               .ops = &act8865_ldo_ops,
+               .ops = &act8865_fixed_ldo_ops,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = 1,
                .fixed_uV = 3300000,
@@ -294,7 +504,7 @@ static const struct regulator_desc act8600_regulators[] = {
                .of_match = of_match_ptr("LDO_REG10"),
                .regulators_node = of_match_ptr("regulators"),
                .id = ACT8600_ID_LDO10,
-               .ops = &act8865_ldo_ops,
+               .ops = &act8865_fixed_ldo_ops,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = 1,
                .fixed_uV = 1200000,
@@ -323,20 +533,20 @@ static const struct regulator_desc act8865_regulators[] = {
        ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"),
        ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"),
        ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"),
-       ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
-       ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
 };
 
 static const struct regulator_desc act8865_alt_regulators[] = {
        ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"),
        ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"),
        ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"),
-       ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
-       ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
 };
 
 #ifdef CONFIG_OF
@@ -372,6 +582,75 @@ static void act8865_power_off(void)
        while (1);
 }
 
+static int act8600_charger_get_status(struct regmap *map)
+{
+       unsigned int val;
+       int ret;
+       u8 state0, state1;
+
+       ret = regmap_read(map, ACT8600_APCH_STAT, &val);
+       if (ret < 0)
+               return ret;
+
+       state0 = val & ACT8600_APCH_CSTATE0;
+       state1 = val & ACT8600_APCH_CSTATE1;
+
+       if (state0 && !state1)
+               return POWER_SUPPLY_STATUS_CHARGING;
+       if (!state0 && state1)
+               return POWER_SUPPLY_STATUS_NOT_CHARGING;
+       if (!state0 && !state1)
+               return POWER_SUPPLY_STATUS_DISCHARGING;
+
+       return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static int act8600_charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct regmap *map = power_supply_get_drvdata(psy);
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = act8600_charger_get_status(map);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum power_supply_property act8600_charger_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+};
+
+static const struct power_supply_desc act8600_charger_desc = {
+       .name = "act8600-charger",
+       .type = POWER_SUPPLY_TYPE_BATTERY,
+       .properties = act8600_charger_properties,
+       .num_properties = ARRAY_SIZE(act8600_charger_properties),
+       .get_property = act8600_charger_get_property,
+};
+
+static int act8600_charger_probe(struct device *dev, struct regmap *regmap)
+{
+       struct power_supply *charger;
+       struct power_supply_config cfg = {
+               .drv_data = regmap,
+               .of_node = dev->of_node,
+       };
+
+       charger = devm_power_supply_register(dev, &act8600_charger_desc, &cfg);
+
+       return PTR_ERR_OR_ZERO(charger);
+}
+
 static int act8865_pmic_probe(struct i2c_client *client,
                              const struct i2c_device_id *i2c_id)
 {
@@ -483,9 +762,20 @@ static int act8865_pmic_probe(struct i2c_client *client,
                }
        }
 
+       if (type == ACT8600) {
+               ret = act8600_charger_probe(dev, act8865->regmap);
+               if (ret < 0) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "Failed to probe charger");
+                       return ret;
+               }
+       }
+
        i2c_set_clientdata(client, act8865);
 
-       return 0;
+       /* Unlock expert registers for ACT8865. */
+       return type != ACT8865 ? 0 : regmap_write(act8865->regmap,
+                                                 ACT8865_SYS_UNLK_REGS, 0xef);
 }
 
 static const struct i2c_device_id act8865_ids[] = {
index 584284938ac9b23584e25bfa67a8456311093371..d2f804dbc785da98d871984c1e3c7e392426b46b 100644 (file)
@@ -169,16 +169,16 @@ static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
                reg = ACT8945A_DCDC3_CTRL;
                break;
        case ACT8945A_ID_LDO1:
-               reg = ACT8945A_LDO1_SUS;
+               reg = ACT8945A_LDO1_CTRL;
                break;
        case ACT8945A_ID_LDO2:
-               reg = ACT8945A_LDO2_SUS;
+               reg = ACT8945A_LDO2_CTRL;
                break;
        case ACT8945A_ID_LDO3:
-               reg = ACT8945A_LDO3_SUS;
+               reg = ACT8945A_LDO3_CTRL;
                break;
        case ACT8945A_ID_LDO4:
-               reg = ACT8945A_LDO4_SUS;
+               reg = ACT8945A_LDO4_CTRL;
                break;
        default:
                return -EINVAL;
index e0c0cf462004958635420a95d11ca00eb2b9d472..afe94470b67f7588a28930731d3a4ab6f4d2a331 100644 (file)
@@ -381,12 +381,16 @@ static struct device_node *of_get_child_regulator(struct device_node *parent,
                if (!regnode) {
                        regnode = of_get_child_regulator(child, prop_name);
                        if (regnode)
-                               return regnode;
+                               goto err_node_put;
                } else {
-                       return regnode;
+                       goto err_node_put;
                }
        }
        return NULL;
+
+err_node_put:
+       of_node_put(child);
+       return regnode;
 }
 
 /**
@@ -564,13 +568,15 @@ static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
-       ssize_t ret;
+       int uV;
 
        regulator_lock(rdev);
-       ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev));
+       uV = regulator_get_voltage_rdev(rdev);
        regulator_unlock(rdev);
 
-       return ret;
+       if (uV < 0)
+               return uV;
+       return sprintf(buf, "%d\n", uV);
 }
 static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
 
@@ -5640,7 +5646,7 @@ static int __init regulator_init(void)
 /* init early to allow our consumers to complete system booting */
 core_initcall(regulator_init);
 
-static int __init regulator_late_cleanup(struct device *dev, void *data)
+static int regulator_late_cleanup(struct device *dev, void *data)
 {
        struct regulator_dev *rdev = dev_to_rdev(dev);
        const struct regulator_ops *ops = rdev->desc->ops;
@@ -5689,17 +5695,8 @@ unlock:
        return 0;
 }
 
-static int __init regulator_init_complete(void)
+static void regulator_init_complete_work_function(struct work_struct *work)
 {
-       /*
-        * Since DT doesn't provide an idiomatic mechanism for
-        * enabling full constraints and since it's much more natural
-        * with DT to provide them just assume that a DT enabled
-        * system has full constraints.
-        */
-       if (of_have_populated_dt())
-               has_full_constraints = true;
-
        /*
         * Regulators may had failed to resolve their input supplies
         * when were registered, either because the input supply was
@@ -5717,6 +5714,35 @@ static int __init regulator_init_complete(void)
         */
        class_for_each_device(&regulator_class, NULL, NULL,
                              regulator_late_cleanup);
+}
+
+static DECLARE_DELAYED_WORK(regulator_init_complete_work,
+                           regulator_init_complete_work_function);
+
+static int __init regulator_init_complete(void)
+{
+       /*
+        * Since DT doesn't provide an idiomatic mechanism for
+        * enabling full constraints and since it's much more natural
+        * with DT to provide them just assume that a DT enabled
+        * system has full constraints.
+        */
+       if (of_have_populated_dt())
+               has_full_constraints = true;
+
+       /*
+        * We punt completion for an arbitrary amount of time since
+        * systems like distros will load many drivers from userspace
+        * so consumers might not always be ready yet, this is
+        * particularly an issue with laptops where this might bounce
+        * the display off then on.  Ideally we'd get a notification
+        * from userspace when this happens but we don't so just wait
+        * a bit and hope we waited long enough.  It'd be better if
+        * we'd only do this on systems that need it, and a kernel
+        * command line option might be useful.
+        */
+       schedule_delayed_work(&regulator_init_complete_work,
+                             msecs_to_jiffies(30000));
 
        return 0;
 }
index 2ffc64622451e0cdacae463f62a7dd27b5207276..56f3f72d77075e01e61beb9592acbbc221750fd7 100644 (file)
@@ -1032,10 +1032,8 @@ static int da9062_regulator_probe(struct platform_device *pdev)
 
        /* LDOs overcurrent event support */
        irq = platform_get_irq_byname(pdev, "LDO_LIM");
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ.\n");
+       if (irq < 0)
                return irq;
-       }
        regulators->irq_ldo_lim = irq;
 
        ret = devm_request_threaded_irq(&pdev->dev, irq,
index 02f816318fba9762862af0536b401a3818118ba5..28b1b20f45bd1a1fbcedc92143ea6650fd510830 100644 (file)
@@ -863,10 +863,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)
 
        /* LDOs overcurrent event support */
        irq = platform_get_irq_byname(pdev, "LDO_LIM");
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ.\n");
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_threaded_irq(&pdev->dev, irq,
                                NULL, da9063_ldo_lim_event,
index 0309823d2c726035b0598b09b3add990c35a8363..bf80748f1ccc2a80ab014ae84bde52696e117a41 100644 (file)
@@ -285,7 +285,7 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
                pdata->reg_node[n] = da9211_matches[i].of_node;
                pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
                                  da9211_matches[i].of_node,
-                                 "enable",
+                                 "enable-gpios",
                                  0,
                                  GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
                                  "da9211-enable");
index 999547dde99d2726e01b17ff7252393686326abe..d90a6fd8cbc7468f67324322443254388eff2d17 100644 (file)
 #include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
+#include <linux/clk.h>
+
 
 struct fixed_voltage_data {
        struct regulator_desc desc;
        struct regulator_dev *dev;
+
+       struct clk *enable_clock;
+       unsigned int clk_enable_counter;
 };
 
+struct fixed_dev_type {
+       bool has_enable_clock;
+};
+
+static const struct fixed_dev_type fixed_voltage_data = {
+       .has_enable_clock = false,
+};
+
+static const struct fixed_dev_type fixed_clkenable_data = {
+       .has_enable_clock = true,
+};
+
+static int reg_clock_enable(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       ret = clk_prepare_enable(priv->enable_clock);
+       if (ret)
+               return ret;
+
+       priv->clk_enable_counter++;
+
+       return ret;
+}
+
+static int reg_clock_disable(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+
+       clk_disable_unprepare(priv->enable_clock);
+       priv->clk_enable_counter--;
+
+       return 0;
+}
+
+static int reg_clock_is_enabled(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+
+       return priv->clk_enable_counter > 0;
+}
+
 
 /**
  * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
@@ -84,10 +133,19 @@ of_get_fixed_voltage_config(struct device *dev,
 static struct regulator_ops fixed_voltage_ops = {
 };
 
+static struct regulator_ops fixed_voltage_clkenabled_ops = {
+       .enable = reg_clock_enable,
+       .disable = reg_clock_disable,
+       .is_enabled = reg_clock_is_enabled,
+};
+
 static int reg_fixed_voltage_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct fixed_voltage_config *config;
        struct fixed_voltage_data *drvdata;
+       const struct fixed_dev_type *drvtype =
+               of_match_device(dev->driver->of_match_table, dev)->data;
        struct regulator_config cfg = { };
        enum gpiod_flags gflags;
        int ret;
@@ -118,7 +176,18 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
        }
        drvdata->desc.type = REGULATOR_VOLTAGE;
        drvdata->desc.owner = THIS_MODULE;
-       drvdata->desc.ops = &fixed_voltage_ops;
+
+       if (drvtype->has_enable_clock) {
+               drvdata->desc.ops = &fixed_voltage_clkenabled_ops;
+
+               drvdata->enable_clock = devm_clk_get(dev, NULL);
+               if (IS_ERR(drvdata->enable_clock)) {
+                       dev_err(dev, "Cant get enable-clock from devicetree\n");
+                       return -ENOENT;
+               }
+       } else {
+               drvdata->desc.ops = &fixed_voltage_ops;
+       }
 
        drvdata->desc.enable_time = config->startup_delay;
 
@@ -191,8 +260,16 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 
 #if defined(CONFIG_OF)
 static const struct of_device_id fixed_of_match[] = {
-       { .compatible = "regulator-fixed", },
-       {},
+       {
+               .compatible = "regulator-fixed",
+               .data = &fixed_voltage_data,
+       },
+       {
+               .compatible = "regulator-fixed-clock",
+               .data = &fixed_clkenable_data,
+       },
+       {
+       },
 };
 MODULE_DEVICE_TABLE(of, fixed_of_match);
 #endif
index 4986cc5064a1fbed266ada36b54303814d628693..ca3dc3f3bb292c679e8521d12b082b5e82447349 100644 (file)
@@ -860,3 +860,24 @@ int regulator_get_current_limit_regmap(struct regulator_dev *rdev)
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(regulator_get_current_limit_regmap);
+
+/**
+ * regulator_bulk_set_supply_names - initialize the 'supply' fields in an array
+ *                                   of regulator_bulk_data structs
+ *
+ * @consumers: array of regulator_bulk_data entries to initialize
+ * @supply_names: array of supply name strings
+ * @num_supplies: number of supply names to initialize
+ *
+ * Note: the 'consumers' array must be the size of 'num_supplies'.
+ */
+void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                                    const char *const *supply_names,
+                                    unsigned int num_supplies)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_supplies; i++)
+               consumers[i].supply = supply_names[i];
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_set_supply_names);
index 5647e2f97ff8d5fca78b9ef610055bf61bb96b7e..4b9f618b07e971682a5704c83f78e5632952b6f8 100644 (file)
 
 /* LM3632 */
 #define LM3632_BOOST_VSEL_MAX          0x26
-#define LM3632_LDO_VSEL_MAX            0x29
+#define LM3632_LDO_VSEL_MAX            0x28
 #define LM3632_VBOOST_MIN              4500000
 #define LM3632_VLDO_MIN                        4000000
 
 /* LM36274 */
 #define LM36274_BOOST_VSEL_MAX         0x3f
-#define LM36274_LDO_VSEL_MAX           0x34
+#define LM36274_LDO_VSEL_MAX           0x32
 #define LM36274_VOLTAGE_MIN            4000000
 
 /* Common */
@@ -226,7 +226,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vboost",
                .id             = LM36274_BOOST,
                .ops            = &lm363x_boost_voltage_table_ops,
-               .n_voltages     = LM36274_BOOST_VSEL_MAX,
+               .n_voltages     = LM36274_BOOST_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
@@ -239,7 +239,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vpos",
                .id             = LM36274_LDO_POS,
                .ops            = &lm363x_regulator_voltage_table_ops,
-               .n_voltages     = LM36274_LDO_VSEL_MAX,
+               .n_voltages     = LM36274_LDO_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
@@ -254,7 +254,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vneg",
                .id             = LM36274_LDO_NEG,
                .ops            = &lm363x_regulator_voltage_table_ops,
-               .n_voltages     = LM36274_LDO_VSEL_MAX,
+               .n_voltages     = LM36274_LDO_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
index 0c440c5e28327c80b596f0996c3ef6b122021a6d..4ae12ac1f4c64452368034cd672b7f7eeea9172b 100644 (file)
@@ -65,7 +65,6 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev,
                                       int ramp_delay)
 {
        int id = rdev_get_id(rdev);
-       struct lp87565 *lp87565 = rdev_get_drvdata(rdev);
        unsigned int reg;
        int ret;
 
@@ -86,11 +85,11 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev,
        else
                reg = 0;
 
-       ret = regmap_update_bits(lp87565->regmap, regulators[id].ctrl2_reg,
+       ret = regmap_update_bits(rdev->regmap, regulators[id].ctrl2_reg,
                                 LP87565_BUCK_CTRL_2_SLEW_RATE,
                                 reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE));
        if (ret) {
-               dev_err(lp87565->dev, "SLEW RATE write failed: %d\n", ret);
+               dev_err(&rdev->dev, "SLEW RATE write failed: %d\n", ret);
                return ret;
        }
 
index 1b00f363899660d08926ac8ec02a83d7617283af..00e9bb92c326b223a769328713e533010f87bb3b 100644 (file)
@@ -464,7 +464,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
 {
        struct lp8788 *lp = ldo->lp;
        enum lp8788_ext_ldo_en_id enable_id;
-       u8 en_mask[] = {
+       static const u8 en_mask[] = {
                [EN_ALDO1]   = LP8788_EN_SEL_ALDO1_M,
                [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M,
                [EN_ALDO5]   = LP8788_EN_SEL_ALDO5_M,
index 8020eb57374a1b32d3a1c322483c5a0bb308c514..c8e579e993160d9ac8424ee1f63a11461d3e1732 100644 (file)
@@ -257,7 +257,7 @@ static int max77686_of_parse_cb(struct device_node *np,
        case MAX77686_BUCK9:
        case MAX77686_LDO20 ... MAX77686_LDO22:
                config->ena_gpiod = gpiod_get_from_of_node(np,
-                               "maxim,ena",
+                               "maxim,ena-gpios",
                                0,
                                GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
                                "max77686-regulator");
index 4bca54446287363464c92af84c2347865ebd6271..347043a5a9a7df999722fd73870cda070123abbd 100644 (file)
@@ -485,7 +485,6 @@ static int max8660_probe(struct i2c_client *client,
                rdev = devm_regulator_register(&client->dev,
                                                  &max8660_reg[id], &config);
                if (IS_ERR(rdev)) {
-                       ret = PTR_ERR(rdev);
                        dev_err(&client->dev, "failed to register %s\n",
                                max8660_reg[id].name);
                        return PTR_ERR(rdev);
diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c
new file mode 100644 (file)
index 0000000..ba42682
--- /dev/null
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2019 MediaTek Inc.
+
+#include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6358-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6358_BUCK_MODE_AUTO  0
+#define MT6358_BUCK_MODE_FORCE_PWM     1
+
+/*
+ * MT6358 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ */
+struct mt6358_regulator_info {
+       struct regulator_desc desc;
+       u32 status_reg;
+       u32 qi;
+       const u32 *index_table;
+       unsigned int n_table;
+       u32 vsel_shift;
+       u32 da_vsel_reg;
+       u32 da_vsel_mask;
+       u32 da_vsel_shift;
+       u32 modeset_reg;
+       u32 modeset_mask;
+       u32 modeset_shift;
+};
+
+#define MT6358_BUCK(match, vreg, min, max, step,               \
+       volt_ranges, vosel_mask, _da_vsel_reg, _da_vsel_mask,   \
+       _da_vsel_shift, _modeset_reg, _modeset_shift)           \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_range_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg,         \
+               .owner = THIS_MODULE,           \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .linear_ranges = volt_ranges,           \
+               .n_linear_ranges = ARRAY_SIZE(volt_ranges),     \
+               .vsel_reg = MT6358_BUCK_##vreg##_ELR0,  \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = MT6358_BUCK_##vreg##_CON0,        \
+               .enable_mask = BIT(0),  \
+               .of_map_mode = mt6358_map_mode, \
+       },      \
+       .status_reg = MT6358_BUCK_##vreg##_DBG1,        \
+       .qi = BIT(0),   \
+       .da_vsel_reg = _da_vsel_reg,    \
+       .da_vsel_mask = _da_vsel_mask,  \
+       .da_vsel_shift = _da_vsel_shift,        \
+       .modeset_reg = _modeset_reg,    \
+       .modeset_mask = BIT(_modeset_shift),    \
+       .modeset_shift = _modeset_shift \
+}
+
+#define MT6358_LDO(match, vreg, ldo_volt_table,        \
+       ldo_index_table, enreg, enbit, vosel,   \
+       vosel_mask, vosel_shift)        \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_table_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = ARRAY_SIZE(ldo_volt_table),       \
+               .volt_table = ldo_volt_table,   \
+               .vsel_reg = vosel,      \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = enreg,    \
+               .enable_mask = BIT(enbit),      \
+       },      \
+       .status_reg = MT6358_LDO_##vreg##_CON1, \
+       .qi = BIT(15),  \
+       .index_table = ldo_index_table, \
+       .n_table = ARRAY_SIZE(ldo_index_table), \
+       .vsel_shift = vosel_shift,      \
+}
+
+#define MT6358_LDO1(match, vreg, min, max, step,       \
+       volt_ranges, _da_vsel_reg, _da_vsel_mask,       \
+       _da_vsel_shift, vosel, vosel_mask)      \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_range_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .linear_ranges = volt_ranges,   \
+               .n_linear_ranges = ARRAY_SIZE(volt_ranges),     \
+               .vsel_reg = vosel,      \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = MT6358_LDO_##vreg##_CON0, \
+               .enable_mask = BIT(0),  \
+       },      \
+       .da_vsel_reg = _da_vsel_reg,    \
+       .da_vsel_mask = _da_vsel_mask,  \
+       .da_vsel_shift = _da_vsel_shift,        \
+       .status_reg = MT6358_LDO_##vreg##_DBG1, \
+       .qi = BIT(0),   \
+}
+
+#define MT6358_REG_FIXED(match, vreg,  \
+       enreg, enbit, volt)     \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_fixed_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = 1,        \
+               .enable_reg = enreg,    \
+               .enable_mask = BIT(enbit),      \
+               .min_uV = volt, \
+       },      \
+       .status_reg = MT6358_LDO_##vreg##_CON1, \
+       .qi = BIT(15),                                                  \
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const struct regulator_linear_range buck_volt_range4[] = {
+       REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500),
+};
+
+static const u32 vdram2_voltages[] = {
+       600000, 1800000,
+};
+
+static const u32 vsim_voltages[] = {
+       1700000, 1800000, 2700000, 3000000, 3100000,
+};
+
+static const u32 vibr_voltages[] = {
+       1200000, 1300000, 1500000, 1800000,
+       2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 vusb_voltages[] = {
+       3000000, 3100000,
+};
+
+static const u32 vcamd_voltages[] = {
+       900000, 1000000, 1100000, 1200000,
+       1300000, 1500000, 1800000,
+};
+
+static const u32 vefuse_voltages[] = {
+       1700000, 1800000, 1900000,
+};
+
+static const u32 vmch_vemc_voltages[] = {
+       2900000, 3000000, 3300000,
+};
+
+static const u32 vcama_voltages[] = {
+       1800000, 2500000, 2700000,
+       2800000, 2900000, 3000000,
+};
+
+static const u32 vcn33_bt_wifi_voltages[] = {
+       3300000, 3400000, 3500000,
+};
+
+static const u32 vmc_voltages[] = {
+       1800000, 2900000, 3000000, 3300000,
+};
+
+static const u32 vldo28_voltages[] = {
+       2800000, 3000000,
+};
+
+static const u32 vdram2_idx[] = {
+       0, 12,
+};
+
+static const u32 vsim_idx[] = {
+       3, 4, 8, 11, 12,
+};
+
+static const u32 vibr_idx[] = {
+       0, 1, 2, 4, 5, 9, 11, 13,
+};
+
+static const u32 vusb_idx[] = {
+       3, 4,
+};
+
+static const u32 vcamd_idx[] = {
+       3, 4, 5, 6, 7, 9, 12,
+};
+
+static const u32 vefuse_idx[] = {
+       11, 12, 13,
+};
+
+static const u32 vmch_vemc_idx[] = {
+       2, 3, 5,
+};
+
+static const u32 vcama_idx[] = {
+       0, 7, 9, 10, 11, 12,
+};
+
+static const u32 vcn33_bt_wifi_idx[] = {
+       1, 2, 3,
+};
+
+static const u32 vmc_idx[] = {
+       4, 10, 11, 13,
+};
+
+static const u32 vldo28_idx[] = {
+       1, 3,
+};
+
+static unsigned int mt6358_map_mode(unsigned int mode)
+{
+       return mode == MT6358_BUCK_MODE_AUTO ?
+               REGULATOR_MODE_NORMAL : REGULATOR_MODE_FAST;
+}
+
+static int mt6358_set_voltage_sel(struct regulator_dev *rdev,
+                                 unsigned int selector)
+{
+       int idx, ret;
+       const u32 *pvol;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       pvol = info->index_table;
+
+       idx = pvol[selector];
+       ret = regmap_update_bits(rdev->regmap, info->desc.vsel_reg,
+                                info->desc.vsel_mask,
+                                idx << info->vsel_shift);
+
+       return ret;
+}
+
+static int mt6358_get_voltage_sel(struct regulator_dev *rdev)
+{
+       int idx, ret;
+       u32 selector;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       const u32 *pvol;
+
+       ret = regmap_read(rdev->regmap, info->desc.vsel_reg, &selector);
+       if (ret != 0) {
+               dev_info(&rdev->dev,
+                        "Failed to get mt6358 %s vsel reg: %d\n",
+                        info->desc.name, ret);
+               return ret;
+       }
+
+       selector = (selector & info->desc.vsel_mask) >> info->vsel_shift;
+       pvol = info->index_table;
+       for (idx = 0; idx < info->desc.n_voltages; idx++) {
+               if (pvol[idx] == selector)
+                       return idx;
+       }
+
+       return -EINVAL;
+}
+
+static int mt6358_get_buck_voltage_sel(struct regulator_dev *rdev)
+{
+       int ret, regval;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->da_vsel_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to get mt6358 Buck %s vsel reg: %d\n",
+                       info->desc.name, ret);
+               return ret;
+       }
+
+       ret = (regval >> info->da_vsel_shift) & info->da_vsel_mask;
+
+       return ret;
+}
+
+static int mt6358_get_status(struct regulator_dev *rdev)
+{
+       int ret;
+       u32 regval;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->status_reg, &regval);
+       if (ret != 0) {
+               dev_info(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+               return ret;
+       }
+
+       return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6358_regulator_set_mode(struct regulator_dev *rdev,
+                                    unsigned int mode)
+{
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       int val;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               val = MT6358_BUCK_MODE_FORCE_PWM;
+               break;
+       case REGULATOR_MODE_NORMAL:
+               val = MT6358_BUCK_MODE_AUTO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(&rdev->dev, "mt6358 buck set_mode %#x, %#x, %#x, %#x\n",
+               info->modeset_reg, info->modeset_mask,
+               info->modeset_shift, val);
+
+       val <<= info->modeset_shift;
+
+       return regmap_update_bits(rdev->regmap, info->modeset_reg,
+                                 info->modeset_mask, val);
+}
+
+static unsigned int mt6358_regulator_get_mode(struct regulator_dev *rdev)
+{
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret, regval;
+
+       ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to get mt6358 buck mode: %d\n", ret);
+               return ret;
+       }
+
+       switch ((regval & info->modeset_mask) >> info->modeset_shift) {
+       case MT6358_BUCK_MODE_AUTO:
+               return REGULATOR_MODE_NORMAL;
+       case MT6358_BUCK_MODE_FORCE_PWM:
+               return REGULATOR_MODE_FAST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct regulator_ops mt6358_volt_range_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = mt6358_get_buck_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+       .set_mode = mt6358_regulator_set_mode,
+       .get_mode = mt6358_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6358_volt_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .set_voltage_sel = mt6358_set_voltage_sel,
+       .get_voltage_sel = mt6358_get_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+};
+
+static const struct regulator_ops mt6358_volt_fixed_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+};
+
+/* The array is indexed by id(MT6358_ID_XXX) */
+static struct mt6358_regulator_info mt6358_regulators[] = {
+       MT6358_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500,
+                   buck_volt_range2, 0x7f, MT6358_BUCK_VDRAM1_DBG0, 0x7f,
+                   0, MT6358_VDRAM1_ANA_CON0, 8),
+       MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f,
+                   0, MT6358_VCORE_VGPU_ANA_CON0, 1),
+       MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+                   buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, 0,
+                   MT6358_VPA_ANA_CON0, 3),
+       MT6358_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VPROC11_DBG0, 0x7f,
+                   0, MT6358_VPROC_ANA_CON0, 1),
+       MT6358_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VPROC12_DBG0, 0x7f,
+                   0, MT6358_VPROC_ANA_CON0, 2),
+       MT6358_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, 0,
+                   MT6358_VCORE_VGPU_ANA_CON0, 2),
+       MT6358_BUCK("buck_vs2", VS2, 500000, 2087500, 12500,
+                   buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, 0,
+                   MT6358_VS2_ANA_CON0, 8),
+       MT6358_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VMODEM_DBG0, 0x7f,
+                   0, MT6358_VMODEM_ANA_CON0, 8),
+       MT6358_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500,
+                   buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, 0,
+                   MT6358_VS1_ANA_CON0, 8),
+       MT6358_REG_FIXED("ldo_vrf12", VRF12,
+                        MT6358_LDO_VRF12_CON0, 0, 1200000),
+       MT6358_REG_FIXED("ldo_vio18", VIO18,
+                        MT6358_LDO_VIO18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vcamio", VCAMIO,
+                        MT6358_LDO_VCAMIO_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vcn18", VCN18, MT6358_LDO_VCN18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vfe28", VFE28, MT6358_LDO_VFE28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vcn28", VCN28, MT6358_LDO_VCN28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vxo22", VXO22, MT6358_LDO_VXO22_CON0, 0, 2200000),
+       MT6358_REG_FIXED("ldo_vaux18", VAUX18,
+                        MT6358_LDO_VAUX18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vbif28", VBIF28,
+                        MT6358_LDO_VBIF28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vio28", VIO28, MT6358_LDO_VIO28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_va12", VA12, MT6358_LDO_VA12_CON0, 0, 1200000),
+       MT6358_REG_FIXED("ldo_vrf18", VRF18, MT6358_LDO_VRF18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vaud28", VAUD28,
+                        MT6358_LDO_VAUD28_CON0, 0, 2800000),
+       MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx,
+                  MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0),
+       MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx,
+                  MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx,
+                  MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx,
+                  MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcamd", VCAMD, vcamd_voltages, vcamd_idx,
+                  MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx,
+                  MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vmch", VMCH, vmch_vemc_voltages, vmch_vemc_idx,
+                  MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcama1", VCAMA1, vcama_voltages, vcama_idx,
+                  MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vemc", VEMC, vmch_vemc_voltages, vmch_vemc_idx,
+                  MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_wifi_voltages,
+                  vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_0,
+                  0, MT6358_VCN33_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_bt_wifi_voltages,
+                  vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_1,
+                  0, MT6358_VCN33_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vcama2", VCAMA2, vcama_voltages, vcama_idx,
+                  MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx,
+                  MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vldo28", VLDO28, vldo28_voltages, vldo28_idx,
+                  MT6358_LDO_VLDO28_CON0_0, 0,
+                  MT6358_VLDO28_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vsim2", VSIM2, vsim_voltages, vsim_idx,
+                  MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00, 8),
+       MT6358_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON0, 0x7f),
+       MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON2, 0x7f),
+       MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON3, 0x7f),
+       MT6358_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON1, 0x7f),
+};
+
+static int mt6358_regulator_probe(struct platform_device *pdev)
+{
+       struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = {};
+       struct regulator_dev *rdev;
+       int i;
+
+       for (i = 0; i < MT6358_MAX_REGULATOR; i++) {
+               config.dev = &pdev->dev;
+               config.driver_data = &mt6358_regulators[i];
+               config.regmap = mt6397->regmap;
+
+               rdev = devm_regulator_register(&pdev->dev,
+                                              &mt6358_regulators[i].desc,
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "failed to register %s\n",
+                               mt6358_regulators[i].desc.name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id mt6358_platform_ids[] = {
+       {"mt6358-regulator", 0},
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6358_platform_ids);
+
+static struct platform_driver mt6358_regulator_driver = {
+       .driver = {
+               .name = "mt6358-regulator",
+       },
+       .probe = mt6358_regulator_probe,
+       .id_table = mt6358_platform_ids,
+};
+
+module_platform_driver(mt6358_regulator_driver);
+
+MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6358 PMIC");
+MODULE_LICENSE("GPL");
index b2c2d01d1637060192f0d1554f201d276ef1b901..db6c085da65ecf742daeca83824072ab70a3834b 100644 (file)
@@ -50,6 +50,20 @@ enum rpmh_regulator_type {
 #define PMIC4_BOB_MODE_AUTO                    2
 #define PMIC4_BOB_MODE_PWM                     3
 
+#define PMIC5_LDO_MODE_RETENTION               3
+#define PMIC5_LDO_MODE_LPM                     4
+#define PMIC5_LDO_MODE_HPM                     7
+
+#define PMIC5_SMPS_MODE_RETENTION              3
+#define PMIC5_SMPS_MODE_PFM                    4
+#define PMIC5_SMPS_MODE_AUTO                   6
+#define PMIC5_SMPS_MODE_PWM                    7
+
+#define PMIC5_BOB_MODE_PASS                    2
+#define PMIC5_BOB_MODE_PFM                     4
+#define PMIC5_BOB_MODE_AUTO                    6
+#define PMIC5_BOB_MODE_PWM                     7
+
 /**
  * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
  * @regulator_type:            RPMh accelerator type used to manage this
@@ -488,6 +502,14 @@ static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = -EINVAL,
 };
 
+static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = PMIC5_LDO_MODE_RETENTION,
+       [REGULATOR_MODE_IDLE]    = PMIC5_LDO_MODE_LPM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_LDO_MODE_HPM,
+       [REGULATOR_MODE_FAST]    = -EINVAL,
+};
+
 static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
 {
        unsigned int mode;
@@ -518,6 +540,14 @@ static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = PMIC4_SMPS_MODE_PWM,
 };
 
+static const int pmic_mode_map_pmic5_smps[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = PMIC5_SMPS_MODE_RETENTION,
+       [REGULATOR_MODE_IDLE]    = PMIC5_SMPS_MODE_PFM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_SMPS_MODE_AUTO,
+       [REGULATOR_MODE_FAST]    = PMIC5_SMPS_MODE_PWM,
+};
+
 static unsigned int
 rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
 {
@@ -552,6 +582,14 @@ static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = PMIC4_BOB_MODE_PWM,
 };
 
+static const int pmic_mode_map_pmic5_bob[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = -EINVAL,
+       [REGULATOR_MODE_IDLE]    = PMIC5_BOB_MODE_PFM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_BOB_MODE_AUTO,
+       [REGULATOR_MODE_FAST]    = PMIC5_BOB_MODE_PWM,
+};
+
 static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
 {
        unsigned int mode;
@@ -637,6 +675,72 @@ static const struct rpmh_vreg_hw_data pmic4_lvs = {
        /* LVS hardware does not support voltage or mode configuration. */
 };
 
+static const struct rpmh_vreg_hw_data pmic5_pldo = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+       .n_voltages = 256,
+       .hpm_min_load_uA = 10000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
+       .n_voltages = 63,
+       .hpm_min_load_uA = 10000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_nldo = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000),
+       .n_voltages = 124,
+       .hpm_min_load_uA = 30000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+       .n_voltages = 216,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
+       .n_voltages = 264,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(2800000, 0, 4, 1600),
+       .n_voltages = 5,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_bob = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_bypass_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 135, 32000),
+       .n_voltages = 136,
+       .pmic_mode_map = pmic_mode_map_pmic5_bob,
+       .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
 #define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
 { \
        .name           = _name, \
@@ -705,6 +809,75 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
        {},
 };
 
+static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_ftsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_ftsmps510, "vdd-s2"),
+       RPMH_VREG("smps3",  "smp%s3",  &pmic5_ftsmps510, "vdd-s3"),
+       RPMH_VREG("smps4",  "smp%s4",  &pmic5_hfsmps510,   "vdd-s4"),
+       RPMH_VREG("smps5",  "smp%s5",  &pmic5_hfsmps510,   "vdd-s5"),
+       RPMH_VREG("smps6",  "smp%s6",  &pmic5_ftsmps510, "vdd-s6"),
+       RPMH_VREG("smps7",  "smp%s7",  &pmic5_ftsmps510, "vdd-s7"),
+       RPMH_VREG("smps8",  "smp%s8",  &pmic5_ftsmps510, "vdd-s8"),
+       RPMH_VREG("smps9",  "smp%s9",  &pmic5_ftsmps510, "vdd-s9"),
+       RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_pldo,      "vdd-l2-l10"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_nldo,      "vdd-l6-l9"),
+       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo,      "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_nldo,      "vdd-l6-l9"),
+       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_pldo,      "vdd-l2-l10"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo12",  "ldo%s12", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo13",  "ldo%s13", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo14",  "ldo%s14", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo15",  "ldo%s15", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo16",  "ldo%s16", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo18",  "ldo%s18", &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       {},
+};
+
+static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_ftsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_ftsmps510, "vdd-s2"),
+       RPMH_VREG("smps3",  "smp%s3",  &pmic5_ftsmps510, "vdd-s3"),
+       RPMH_VREG("smps4",  "smp%s4",  &pmic5_ftsmps510, "vdd-s4"),
+       RPMH_VREG("smps5",  "smp%s5",  &pmic5_ftsmps510, "vdd-s5"),
+       RPMH_VREG("smps6",  "smp%s6",  &pmic5_ftsmps510, "vdd-s6"),
+       RPMH_VREG("smps7",  "smp%s7",  &pmic5_ftsmps510, "vdd-s7"),
+       RPMH_VREG("smps8",  "smp%s8",  &pmic5_hfsmps510, "vdd-s8"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_pldo_lv,   "vdd-l1-l8"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo,      "vdd-l2-l3"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l2-l3"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo,      "vdd-l7-l11"),
+       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_pldo_lv,   "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_pldo,      "vdd-l9-l10"),
+       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_pldo,      "vdd-l9-l10"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_pldo,      "vdd-l7-l11"),
+       RPMH_VREG("bob",    "bob%s1",  &pmic5_bob,       "vdd-bob"),
+       {},
+};
+
+static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_hfsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_hfsmps515, "vdd-s2"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo,      "vdd-l1"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo,      "vdd-l2"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l3"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo,      "vdd-l4"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,      "vdd-l5-l6"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo,      "vdd-l5-l6"),
+       RPMH_VREG("ldo7",   "ldo%s6",  &pmic5_pldo_lv,   "vdd-l7"),
+       {},
+};
+
 static int rpmh_regulator_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -743,6 +916,22 @@ static int rpmh_regulator_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id rpmh_regulator_match_table[] = {
+       {
+               .compatible = "qcom,pm8005-rpmh-regulators",
+               .data = pm8005_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8009-rpmh-regulators",
+               .data = pm8009_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8150-rpmh-regulators",
+               .data = pm8150_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8150l-rpmh-regulators",
+               .data = pm8150l_vreg_data,
+       },
        {
                .compatible = "qcom,pm8998-rpmh-regulators",
                .data = pm8998_vreg_data,
@@ -751,10 +940,6 @@ static const struct of_device_id rpmh_regulator_match_table[] = {
                .compatible = "qcom,pmi8998-rpmh-regulators",
                .data = pmi8998_vreg_data,
        },
-       {
-               .compatible = "qcom,pm8005-rpmh-regulators",
-               .data = pm8005_vreg_data,
-       },
        {}
 };
 MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
index e7af0c53d4496f5ddafdfad971ff1c9aa66dc4dc..61bd5ef0806c22f4eba2f530a9264d9ee7fdd26b 100644 (file)
@@ -606,7 +606,7 @@ static unsigned int rk8xx_regulator_of_map_mode(unsigned int mode)
        case 2:
                return REGULATOR_MODE_NORMAL;
        default:
-               return -EINVAL;
+               return REGULATOR_MODE_INVALID;
        }
 }
 
index 054baaadfdfddc39c83f7ffd1fa58c6a29f2eb7f..5bc00884cf512d4ebecfe470603a97f9a3827a43 100644 (file)
@@ -1226,7 +1226,7 @@ common_reg:
                        goto out;
                }
 
-               if (s2mps11->ext_control_gpiod[i]) {
+               if (config.ena_gpiod) {
                        ret = s2mps14_pmic_enable_ext_control(s2mps11,
                                        regulator);
                        if (ret < 0) {
index 04b732991d6955f3cf917644725be7fff756acd3..a0565daecacef3bbf9971f23286e7f0151bea89a 100644 (file)
@@ -205,7 +205,7 @@ static int slg51000_of_parse_cb(struct device_node *np,
        ena_gpiod = devm_gpiod_get_from_of_node(chip->dev, np,
                                                "enable-gpios", 0,
                                                gflags, "gpio-en-ldo");
-       if (ena_gpiod) {
+       if (!IS_ERR(ena_gpiod)) {
                config->ena_gpiod = ena_gpiod;
                devm_gpiod_unhinge(chip->dev, config->ena_gpiod);
        }
@@ -447,18 +447,19 @@ static int slg51000_i2c_probe(struct i2c_client *client,
 {
        struct device *dev = &client->dev;
        struct slg51000 *chip;
-       struct gpio_desc *cs_gpiod = NULL;
+       struct gpio_desc *cs_gpiod;
        int error, ret;
 
        chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node,
-                                              "dlg,cs-gpios", 0,
-                                              GPIOD_OUT_HIGH
-                                              | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
-                                              "slg51000-cs");
+       cs_gpiod = devm_gpiod_get_optional(dev, "dlg,cs",
+                                          GPIOD_OUT_HIGH |
+                                               GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+       if (IS_ERR(cs_gpiod))
+               return PTR_ERR(cs_gpiod);
+
        if (cs_gpiod) {
                dev_info(dev, "Found chip selector property\n");
                chip->cs_gpiod = cs_gpiod;
index 2a897666c65064b42ac69f49c32be3f1d5a21454..03f162ffd1440f7b0aad52b62dbdd52b75b6f56b 100644 (file)
@@ -20,7 +20,6 @@
 #define STM32MP1_SYSCFG_EN_BOOSTER_MASK        BIT(8)
 
 static const struct regulator_ops stm32h7_booster_ops = {
-       .list_voltage   = regulator_list_voltage_linear,
        .enable         = regulator_enable_regmap,
        .disable        = regulator_disable_regmap,
        .is_enabled     = regulator_is_enabled_regmap,
@@ -31,7 +30,6 @@ static const struct regulator_desc stm32h7_booster_desc = {
        .supply_name = "vdda",
        .n_voltages = 1,
        .type = REGULATOR_VOLTAGE,
-       .min_uV = 3300000,
        .fixed_uV = 3300000,
        .ramp_delay = 66000, /* up to 50us to stabilize */
        .ops = &stm32h7_booster_ops,
@@ -53,7 +51,6 @@ static int stm32mp1_booster_disable(struct regulator_dev *rdev)
 }
 
 static const struct regulator_ops stm32mp1_booster_ops = {
-       .list_voltage   = regulator_list_voltage_linear,
        .enable         = stm32mp1_booster_enable,
        .disable        = stm32mp1_booster_disable,
        .is_enabled     = regulator_is_enabled_regmap,
@@ -64,7 +61,6 @@ static const struct regulator_desc stm32mp1_booster_desc = {
        .supply_name = "vdda",
        .n_voltages = 1,
        .type = REGULATOR_VOLTAGE,
-       .min_uV = 3300000,
        .fixed_uV = 3300000,
        .ramp_delay = 66000,
        .ops = &stm32mp1_booster_ops,
diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c
new file mode 100644 (file)
index 0000000..92adb4f
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// SY8824C/SY8824E regulator driver
+//
+// Copyright (C) 2019 Synaptics Incorporated
+//
+// Author: Jisheng Zhang <jszhang@kernel.org>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SY8824C_BUCK_EN                (1 << 7)
+#define SY8824C_MODE           (1 << 6)
+
+struct sy8824_config {
+       /* registers */
+       unsigned int vol_reg;
+       unsigned int mode_reg;
+       unsigned int enable_reg;
+       /* Voltage range and step(linear) */
+       unsigned int vsel_min;
+       unsigned int vsel_step;
+       unsigned int vsel_count;
+};
+
+struct sy8824_device_info {
+       struct device *dev;
+       struct regulator_desc desc;
+       struct regulator_init_data *regulator;
+       const struct sy8824_config *cfg;
+};
+
+static int sy8824_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct sy8824_device_info *di = rdev_get_drvdata(rdev);
+       const struct sy8824_config *cfg = di->cfg;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               regmap_update_bits(rdev->regmap, cfg->mode_reg,
+                                  SY8824C_MODE, SY8824C_MODE);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               regmap_update_bits(rdev->regmap, cfg->mode_reg,
+                                  SY8824C_MODE, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static unsigned int sy8824_get_mode(struct regulator_dev *rdev)
+{
+       struct sy8824_device_info *di = rdev_get_drvdata(rdev);
+       const struct sy8824_config *cfg = di->cfg;
+       u32 val;
+       int ret = 0;
+
+       ret = regmap_read(rdev->regmap, cfg->mode_reg, &val);
+       if (ret < 0)
+               return ret;
+       if (val & SY8824C_MODE)
+               return REGULATOR_MODE_FAST;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static const struct regulator_ops sy8824_regulator_ops = {
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .map_voltage = regulator_map_voltage_linear,
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_mode = sy8824_set_mode,
+       .get_mode = sy8824_get_mode,
+};
+
+static int sy8824_regulator_register(struct sy8824_device_info *di,
+                       struct regulator_config *config)
+{
+       struct regulator_desc *rdesc = &di->desc;
+       const struct sy8824_config *cfg = di->cfg;
+       struct regulator_dev *rdev;
+
+       rdesc->name = "sy8824-reg";
+       rdesc->supply_name = "vin";
+       rdesc->ops = &sy8824_regulator_ops;
+       rdesc->type = REGULATOR_VOLTAGE;
+       rdesc->n_voltages = cfg->vsel_count;
+       rdesc->enable_reg = cfg->enable_reg;
+       rdesc->enable_mask = SY8824C_BUCK_EN;
+       rdesc->min_uV = cfg->vsel_min;
+       rdesc->uV_step = cfg->vsel_step;
+       rdesc->vsel_reg = cfg->vol_reg;
+       rdesc->vsel_mask = cfg->vsel_count - 1;
+       rdesc->owner = THIS_MODULE;
+
+       rdev = devm_regulator_register(di->dev, &di->desc, config);
+       return PTR_ERR_OR_ZERO(rdev);
+}
+
+static const struct regmap_config sy8824_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int sy8824_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device_node *np = dev->of_node;
+       struct sy8824_device_info *di;
+       struct regulator_config config = { };
+       struct regmap *regmap;
+       int ret;
+
+       di = devm_kzalloc(dev, sizeof(struct sy8824_device_info), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
+       if (!di->regulator) {
+               dev_err(dev, "Platform data not found!\n");
+               return -EINVAL;
+       }
+
+       di->dev = dev;
+       di->cfg = of_device_get_match_data(dev);
+
+       regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to allocate regmap!\n");
+               return PTR_ERR(regmap);
+       }
+       i2c_set_clientdata(client, di);
+
+       config.dev = di->dev;
+       config.init_data = di->regulator;
+       config.regmap = regmap;
+       config.driver_data = di;
+       config.of_node = np;
+
+       ret = sy8824_regulator_register(di, &config);
+       if (ret < 0)
+               dev_err(dev, "Failed to register regulator!\n");
+       return ret;
+}
+
+static const struct sy8824_config sy8824c_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x00,
+       .enable_reg = 0x00,
+       .vsel_min = 762500,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct sy8824_config sy8824e_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x00,
+       .enable_reg = 0x00,
+       .vsel_min = 700000,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct sy8824_config sy20276_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x01,
+       .enable_reg = 0x01,
+       .vsel_min = 600000,
+       .vsel_step = 10000,
+       .vsel_count = 128,
+};
+
+static const struct sy8824_config sy20278_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x01,
+       .enable_reg = 0x01,
+       .vsel_min = 762500,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct of_device_id sy8824_dt_ids[] = {
+       {
+               .compatible = "silergy,sy8824c",
+               .data = &sy8824c_cfg
+       },
+       {
+               .compatible = "silergy,sy8824e",
+               .data = &sy8824e_cfg
+       },
+       {
+               .compatible = "silergy,sy20276",
+               .data = &sy20276_cfg
+       },
+       {
+               .compatible = "silergy,sy20278",
+               .data = &sy20278_cfg
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sy8824_dt_ids);
+
+static const struct i2c_device_id sy8824_id[] = {
+       { "sy8824", },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, sy8824_id);
+
+static struct i2c_driver sy8824_regulator_driver = {
+       .driver = {
+               .name = "sy8824-regulator",
+               .of_match_table = of_match_ptr(sy8824_dt_ids),
+       },
+       .probe = sy8824_i2c_probe,
+       .id_table = sy8824_id,
+};
+module_i2c_driver(sy8824_regulator_driver);
+
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver");
+MODULE_LICENSE("GPL v2");
index 6e22f5ebba2e84358839731452e6b61d5549620e..e302bd01a0849e261e40b5024ff6836f449557ea 100644 (file)
@@ -138,7 +138,7 @@ static int tps65132_of_parse_cb(struct device_node *np,
 
        rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev,
                                        "enable", 0, &np->fwnode, 0, "enable");
-       if (IS_ERR(rpdata->en_gpiod)) {
+       if (IS_ERR_OR_NULL(rpdata->en_gpiod)) {
                ret = PTR_ERR(rpdata->en_gpiod);
 
                /* Ignore the error other than probe defer */
@@ -150,7 +150,7 @@ static int tps65132_of_parse_cb(struct device_node *np,
        rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child(
                                        tps->dev, "active-discharge", 0,
                                        &np->fwnode, 0, "active-discharge");
-       if (IS_ERR(rpdata->act_dis_gpiod)) {
+       if (IS_ERR_OR_NULL(rpdata->act_dis_gpiod)) {
                ret = PTR_ERR(rpdata->act_dis_gpiod);
 
                /* Ignore the error other than probe defer */
index 6fa15b2d6fb33ef7353a8e5c3b37fe0f61ab825b..866b4dd01da9ea0911da113969f3c2a453aff6d0 100644 (file)
@@ -359,6 +359,17 @@ static const u16 VINTANA2_VSEL_table[] = {
        2500, 2750,
 };
 
+/* 600mV to 1450mV in 12.5 mV steps */
+static const struct regulator_linear_range VDD1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 68, 12500)
+};
+
+/* 600mV to 1450mV in 12.5 mV steps, everything above = 1500mV */
+static const struct regulator_linear_range VDD2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 68, 12500),
+       REGULATOR_LINEAR_RANGE(1500000, 69, 69, 12500)
+};
+
 static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
@@ -427,6 +438,8 @@ static int twl4030smps_get_voltage(struct regulator_dev *rdev)
 }
 
 static const struct regulator_ops twl4030smps_ops = {
+       .list_voltage   = regulator_list_voltage_linear_range,
+
        .set_voltage    = twl4030smps_set_voltage,
        .get_voltage    = twl4030smps_get_voltage,
 };
@@ -466,7 +479,8 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
                }, \
        }
 
-#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
+#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf, \
+               n_volt) \
 static const struct twlreg_info TWL4030_INFO_##label = { \
        .base = offset, \
        .id = num, \
@@ -479,6 +493,9 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
                .owner = THIS_MODULE, \
                .enable_time = turnon_delay, \
                .of_map_mode = twl4030reg_map_mode, \
+               .n_voltages = n_volt, \
+               .n_linear_ranges = ARRAY_SIZE(label ## _ranges), \
+               .linear_ranges = label ## _ranges, \
                }, \
        }
 
@@ -518,8 +535,8 @@ TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00);
 TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08);
 TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08);
 TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08);
-TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08);
-TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08);
+TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08, 68);
+TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08, 69);
 /* VUSBCP is managed *only* by the USB subchip */
 TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
 TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
index 5fe208b381eb26ab8ae55d2f6be3c0fc656c45ce..b8100c3cedad3fc91bebe9c2f09fb09b85d15b28 100644 (file)
@@ -57,6 +57,9 @@ struct twlreg_info {
 #define VREG_BC_PROC           3
 #define VREG_BC_CLK_RST                4
 
+/* TWL6030 LDO register values for VREG_VOLTAGE */
+#define TWL6030_VREG_VOLTAGE_WR_S   BIT(7)
+
 /* TWL6030 LDO register values for CFG_STATE */
 #define TWL6030_CFG_STATE_OFF  0x00
 #define TWL6030_CFG_STATE_ON   0x01
@@ -68,9 +71,10 @@ struct twlreg_info {
 #define TWL6030_CFG_STATE_APP(v)       (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
                                                TWL6030_CFG_STATE_APP_SHIFT)
 
-/* Flags for SMPS Voltage reading */
+/* Flags for SMPS Voltage reading and LDO reading*/
 #define SMPS_OFFSET_EN         BIT(0)
 #define SMPS_EXTENDED_EN       BIT(1)
+#define TWL_6030_WARM_RESET    BIT(3)
 
 /* twl6032 SMPS EPROM values */
 #define TWL6030_SMPS_OFFSET            0xB0
@@ -250,6 +254,9 @@ twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
 
+       if (info->flags & TWL_6030_WARM_RESET)
+               selector |= TWL6030_VREG_VOLTAGE_WR_S;
+
        return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
                            selector);
 }
@@ -259,6 +266,9 @@ static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev)
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE);
 
+       if (info->flags & TWL_6030_WARM_RESET)
+               vsel &= ~TWL6030_VREG_VOLTAGE_WR_S;
+
        return vsel;
 }
 
@@ -665,14 +675,14 @@ static int twlreg_probe(struct platform_device *pdev)
        struct regulation_constraints   *c;
        struct regulator_dev            *rdev;
        struct regulator_config         config = { };
+       struct device_node              *np = pdev->dev.of_node;
 
        template = of_device_get_match_data(&pdev->dev);
        if (!template)
                return -ENODEV;
 
        id = template->desc.id;
-       initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
-                                               &template->desc);
+       initdata = of_get_regulator_init_data(&pdev->dev, np, &template->desc);
        if (!initdata)
                return -EINVAL;
 
@@ -710,10 +720,13 @@ static int twlreg_probe(struct platform_device *pdev)
                break;
        }
 
+       if (of_get_property(np, "ti,retain-on-reset", NULL))
+               info->flags |= TWL_6030_WARM_RESET;
+
        config.dev = &pdev->dev;
        config.init_data = initdata;
        config.driver_data = info;
-       config.of_node = pdev->dev.of_node;
+       config.of_node = np;
 
        rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
        if (IS_ERR(rdev)) {
index 9026d5a3e964811cd1c7108903dc850c81b7e6ed..2311924c31039423652b71150614a617c0031504 100644 (file)
@@ -185,6 +185,10 @@ static const struct of_device_id uniphier_regulator_match[] = {
                .compatible = "socionext,uniphier-pro4-usb3-regulator",
                .data = &uniphier_pro4_usb3_data,
        },
+       {
+               .compatible = "socionext,uniphier-pro5-usb3-regulator",
+               .data = &uniphier_pro4_usb3_data,
+       },
        {
                .compatible = "socionext,uniphier-pxs2-usb3-regulator",
                .data = &uniphier_pxs2_usb3_data,
index 5dc174ac8cacdebbc26801aff68bd6e27a479c93..36ca2cf419bfebf475021d995640f383b154ee5e 100644 (file)
@@ -2178,7 +2178,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
                /* If this is an input descriptor, increment that count. */
                if (access == VHOST_ACCESS_WO) {
                        *in_num += ret;
-                       if (unlikely(log)) {
+                       if (unlikely(log && ret)) {
                                log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
                                log[*log_num].len = vhost32_to_cpu(vq, desc.len);
                                ++*log_num;
@@ -2319,7 +2319,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                        /* If this is an input descriptor,
                         * increment that count. */
                        *in_num += ret;
-                       if (unlikely(log)) {
+                       if (unlikely(log && ret)) {
                                log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
                                log[*log_num].len = vhost32_to_cpu(vq, desc.len);
                                ++*log_num;
index c8be1c4f5b5566929d9dc1601bd8b05b6552402e..bdc08244a648dbf0ee58fe8b9dc4e5e36c15dcb8 100644 (file)
@@ -566,13 +566,17 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
 
 unmap_release:
        err_idx = i;
-       i = head;
+
+       if (indirect)
+               i = 0;
+       else
+               i = head;
 
        for (n = 0; n < total_sg; n++) {
                if (i == err_idx)
                        break;
                vring_unmap_one_split(vq, &desc[i]);
-               i = virtio16_to_cpu(_vq->vdev, vq->split.vring.desc[i].next);
+               i = virtio16_to_cpu(_vq->vdev, desc[i].next);
        }
 
        if (indirect)
index 1ff438fd5bc2906499a0eb075e8c38740e64be7b..eeb75281894ed6a3ad41dfe53d9f1fa7df2d84dc 100644 (file)
@@ -3628,6 +3628,13 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
                       TASK_UNINTERRUPTIBLE);
 }
 
+static void end_extent_buffer_writeback(struct extent_buffer *eb)
+{
+       clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
+       smp_mb__after_atomic();
+       wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
+}
+
 /*
  * Lock eb pages and flush the bio if we can't the locks
  *
@@ -3699,8 +3706,11 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
 
                if (!trylock_page(p)) {
                        if (!flush) {
-                               ret = flush_write_bio(epd);
-                               if (ret < 0) {
+                               int err;
+
+                               err = flush_write_bio(epd);
+                               if (err < 0) {
+                                       ret = err;
                                        failed_page_nr = i;
                                        goto err_unlock;
                                }
@@ -3715,16 +3725,23 @@ err_unlock:
        /* Unlock already locked pages */
        for (i = 0; i < failed_page_nr; i++)
                unlock_page(eb->pages[i]);
+       /*
+        * Clear EXTENT_BUFFER_WRITEBACK and wake up anyone waiting on it.
+        * Also set back EXTENT_BUFFER_DIRTY so future attempts to this eb can
+        * be made and undo everything done before.
+        */
+       btrfs_tree_lock(eb);
+       spin_lock(&eb->refs_lock);
+       set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
+       end_extent_buffer_writeback(eb);
+       spin_unlock(&eb->refs_lock);
+       percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len,
+                                fs_info->dirty_metadata_batch);
+       btrfs_clear_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+       btrfs_tree_unlock(eb);
        return ret;
 }
 
-static void end_extent_buffer_writeback(struct extent_buffer *eb)
-{
-       clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
-       smp_mb__after_atomic();
-       wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
-}
-
 static void set_btree_ioerr(struct page *page)
 {
        struct extent_buffer *eb = (struct extent_buffer *)page->private;
index 6c8297bcfeb7caa63bc2b39bdd06b5a1f7708489..1bfd7e34f31e33709f0e937f83c6d978d74564c6 100644 (file)
@@ -4985,7 +4985,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                                                      BTRFS_I(inode),
                                                      LOG_OTHER_INODE_ALL,
                                                      0, LLONG_MAX, ctx);
-                                       iput(inode);
+                                       btrfs_add_delayed_iput(inode);
                                }
                        }
                        continue;
@@ -5000,7 +5000,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
                                      LOG_OTHER_INODE, 0, LLONG_MAX, ctx);
                if (ret) {
-                       iput(inode);
+                       btrfs_add_delayed_iput(inode);
                        continue;
                }
 
@@ -5009,7 +5009,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                key.offset = 0;
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0) {
-                       iput(inode);
+                       btrfs_add_delayed_iput(inode);
                        continue;
                }
 
@@ -5056,7 +5056,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                        }
                        path->slots[0]++;
                }
-               iput(inode);
+               btrfs_add_delayed_iput(inode);
        }
 
        return ret;
@@ -5689,7 +5689,7 @@ process_leaf:
                        }
 
                        if (btrfs_inode_in_log(BTRFS_I(di_inode), trans->transid)) {
-                               iput(di_inode);
+                               btrfs_add_delayed_iput(di_inode);
                                break;
                        }
 
@@ -5701,7 +5701,7 @@ process_leaf:
                        if (!ret &&
                            btrfs_must_commit_transaction(trans, BTRFS_I(di_inode)))
                                ret = 1;
-                       iput(di_inode);
+                       btrfs_add_delayed_iput(di_inode);
                        if (ret)
                                goto next_dir_inode;
                        if (ctx->log_new_dentries) {
@@ -5848,7 +5848,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
                        if (!ret && ctx && ctx->log_new_dentries)
                                ret = log_new_dir_dentries(trans, root,
                                                   BTRFS_I(dir_inode), ctx);
-                       iput(dir_inode);
+                       btrfs_add_delayed_iput(dir_inode);
                        if (ret)
                                goto out;
                }
@@ -5891,7 +5891,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
                        ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
                                              LOG_INODE_EXISTS,
                                              0, LLONG_MAX, ctx);
-               iput(inode);
+               btrfs_add_delayed_iput(inode);
                if (ret)
                        return ret;
 
index 420fe3deed39702b93a5567dbebe77a8e4b6b992..006b7a2070bf6869d2f7c42500eea135919def74 100644 (file)
@@ -4586,7 +4586,6 @@ static int __ext4_get_inode_loc(struct inode *inode,
        struct buffer_head      *bh;
        struct super_block      *sb = inode->i_sb;
        ext4_fsblk_t            block;
-       struct blk_plug         plug;
        int                     inodes_per_block, inode_offset;
 
        iloc->bh = NULL;
@@ -4675,7 +4674,6 @@ make_io:
                 * If we need to do any I/O, try to pre-readahead extra
                 * blocks from the inode table.
                 */
-               blk_start_plug(&plug);
                if (EXT4_SB(sb)->s_inode_readahead_blks) {
                        ext4_fsblk_t b, end, table;
                        unsigned num;
@@ -4706,7 +4704,6 @@ make_io:
                get_bh(bh);
                bh->b_end_io = end_buffer_read_sync;
                submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh);
-               blk_finish_plug(&plug);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        EXT4_ERROR_INODE_BLOCK(inode, block,
diff --git a/include/dt-bindings/regulator/active-semi,8865-regulator.h b/include/dt-bindings/regulator/active-semi,8865-regulator.h
new file mode 100644 (file)
index 0000000..15473db
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device Tree binding constants for the ACT8865 PMIC regulators
+ */
+
+#ifndef _DT_BINDINGS_REGULATOR_ACT8865_H
+#define _DT_BINDINGS_REGULATOR_ACT8865_H
+
+/*
+ * These constants should be used to specify regulator modes in device tree for
+ * ACT8865 regulators as follows:
+ * ACT8865_REGULATOR_MODE_FIXED:       It is specific to DCDC regulators and it
+ *                                     specifies the usage of fixed-frequency
+ *                                     PWM.
+ *
+ * ACT8865_REGULATOR_MODE_NORMAL:      It is specific to LDO regulators and it
+ *                                     specifies the usage of normal mode.
+ *
+ * ACT8865_REGULATOR_MODE_LOWPOWER:    For DCDC and LDO regulators; it specify
+ *                                     the usage of proprietary power-saving
+ *                                     mode.
+ */
+
+#define ACT8865_REGULATOR_MODE_FIXED           1
+#define ACT8865_REGULATOR_MODE_NORMAL          2
+#define ACT8865_REGULATOR_MODE_LOWPOWER        3
+
+#endif
index 342dabda9c7ef23cdeb4f7da161bb648de423c84..c19483b900794cd8a478f265a6873bea054ac712 100644 (file)
@@ -440,7 +440,7 @@ struct dimm_info {
        char label[EDAC_MC_LABEL_LEN + 1];      /* DIMM label on motherboard */
 
        /* Memory location data */
-       unsigned location[EDAC_MAX_LAYERS];
+       unsigned int location[EDAC_MAX_LAYERS];
 
        struct mem_ctl_info *mci;       /* the parent */
 
@@ -451,7 +451,7 @@ struct dimm_info {
 
        u32 nr_pages;                   /* number of pages on this dimm */
 
-       unsigned csrow, cschannel;      /* Points to the old API data */
+       unsigned int csrow, cschannel;  /* Points to the old API data */
 
        u16 smbios_handle;              /* Handle for SMBIOS type 17 */
 };
@@ -597,7 +597,7 @@ struct mem_ctl_info {
                                           unsigned long page);
        int mc_idx;
        struct csrow_info **csrows;
-       unsigned nr_csrows, num_cschannel;
+       unsigned int nr_csrows, num_cschannel;
 
        /*
         * Memory Controller hierarchy
@@ -608,14 +608,14 @@ struct mem_ctl_info {
         * of the recent drivers enumerate memories per DIMM, instead.
         * When the memory controller is per rank, csbased is true.
         */
-       unsigned n_layers;
+       unsigned int n_layers;
        struct edac_mc_layer *layers;
        bool csbased;
 
        /*
         * DIMM info. Will eventually remove the entire csrows_info some day
         */
-       unsigned tot_dimms;
+       unsigned int tot_dimms;
        struct dimm_info **dimms;
 
        /*
index c842735a4f45a41d4ce305d236d08a8b2d0ef3b6..4b97f427cc929972de59bcd4b1de5531ea56e16a 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_DF_F3    0x1463
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
 #define PCI_DEVICE_ID_AMD_CNB17H_F3    0x1703
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
index 1e5d86ebdaeb54cb5718ff10c8a8f74adc3a8efc..52bc8e487ef7d3442b562ffd9907027e53a310c4 100644 (file)
@@ -11,6 +11,7 @@ struct fixed_phy_status {
 };
 
 struct device_node;
+struct gpio_desc;
 
 #if IS_ENABLED(CONFIG_FIXED_PHY)
 extern int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier);
index 2a83e434db9d080667bd8f3465552c797e814c10..9645b1194c9812adc23c62b9518c305c3dcacf40 100644 (file)
@@ -72,6 +72,10 @@ extern struct pid init_struct_pid;
 
 extern const struct file_operations pidfd_fops;
 
+struct file;
+
+extern struct pid *pidfd_pid(const struct file *file);
+
 static inline struct pid *get_pid(struct pid *pid)
 {
        if (pid)
index 815983419375a28fb5db6d87843d7acc2d193501..337a463915278cc000cbdb0d47b40ea4e5645a7d 100644 (file)
@@ -281,6 +281,12 @@ void devm_regulator_unregister_notifier(struct regulator *regulator,
 void *regulator_get_drvdata(struct regulator *regulator);
 void regulator_set_drvdata(struct regulator *regulator, void *data);
 
+/* misc helpers */
+
+void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                                    const char *const *supply_names,
+                                    unsigned int num_supplies);
+
 #else
 
 /*
@@ -580,6 +586,13 @@ static inline int regulator_list_voltage(struct regulator *regulator, unsigned s
        return -EINVAL;
 }
 
+static inline void
+regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                               const char *const *supply_names,
+                               unsigned int num_supplies)
+{
+}
+
 #endif
 
 static inline int regulator_set_voltage_triplet(struct regulator *regulator,
diff --git a/include/linux/regulator/mt6358-regulator.h b/include/linux/regulator/mt6358-regulator.h
new file mode 100644 (file)
index 0000000..1cc3049
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6358_H
+#define __LINUX_REGULATOR_MT6358_H
+
+enum {
+       MT6358_ID_VDRAM1 = 0,
+       MT6358_ID_VCORE,
+       MT6358_ID_VPA,
+       MT6358_ID_VPROC11,
+       MT6358_ID_VPROC12,
+       MT6358_ID_VGPU,
+       MT6358_ID_VS2,
+       MT6358_ID_VMODEM,
+       MT6358_ID_VS1,
+       MT6358_ID_VDRAM2 = 9,
+       MT6358_ID_VSIM1,
+       MT6358_ID_VIBR,
+       MT6358_ID_VRF12,
+       MT6358_ID_VIO18,
+       MT6358_ID_VUSB,
+       MT6358_ID_VCAMIO,
+       MT6358_ID_VCAMD,
+       MT6358_ID_VCN18,
+       MT6358_ID_VFE28,
+       MT6358_ID_VSRAM_PROC11,
+       MT6358_ID_VCN28,
+       MT6358_ID_VSRAM_OTHERS,
+       MT6358_ID_VSRAM_GPU,
+       MT6358_ID_VXO22,
+       MT6358_ID_VEFUSE,
+       MT6358_ID_VAUX18,
+       MT6358_ID_VMCH,
+       MT6358_ID_VBIF28,
+       MT6358_ID_VSRAM_PROC12,
+       MT6358_ID_VCAMA1,
+       MT6358_ID_VEMC,
+       MT6358_ID_VIO28,
+       MT6358_ID_VA12,
+       MT6358_ID_VRF18,
+       MT6358_ID_VCN33_BT,
+       MT6358_ID_VCN33_WIFI,
+       MT6358_ID_VCAMA2,
+       MT6358_ID_VMC,
+       MT6358_ID_VLDO28,
+       MT6358_ID_VAUD28,
+       MT6358_ID_VSIM2,
+       MT6358_ID_RG_MAX,
+};
+
+#define MT6358_MAX_REGULATOR   MT6358_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6358_H */
index 88145da7d14078ff4af7594271d7411d7c8eba61..f7c561c4dcdd5fa5d1376ac0d75fad959729c48e 100644 (file)
@@ -1402,4 +1402,23 @@ static inline unsigned int ksys_personality(unsigned int personality)
        return old;
 }
 
+/* for __ARCH_WANT_SYS_IPC */
+long ksys_semtimedop(int semid, struct sembuf __user *tsops,
+                    unsigned int nsops,
+                    const struct __kernel_timespec __user *timeout);
+long ksys_semget(key_t key, int nsems, int semflg);
+long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
+long ksys_msgget(key_t key, int msgflg);
+long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
+long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
+                long msgtyp, int msgflg);
+long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
+                int msgflg);
+long ksys_shmget(key_t key, size_t size, int shmflg);
+long ksys_shmdt(char __user *shmaddr);
+long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
+long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
+                           unsigned int nsops,
+                           const struct old_timespec32 __user *timeout);
+
 #endif
index 4c81846ccce8c2e16e3effd0ab4573e07887255c..ab1ca9e238d2726507596b8a5408bc97a9f5e3d0 100644 (file)
@@ -513,7 +513,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
                          struct netlink_callback *cb);
 
 int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh,
-                    unsigned char *flags, bool skip_oif);
+                    u8 rt_family, unsigned char *flags, bool skip_oif);
 int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh,
-                   int nh_weight);
+                   int nh_weight, u8 rt_family);
 #endif  /* _NET_FIB_H */
index 95f766c31c907fff2427de084e517fd1c3740073..331ebbc94fe7846ed3563b6050c1d24e0d9a150c 100644 (file)
@@ -161,7 +161,8 @@ struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
 }
 
 static inline
-int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
+int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
+                           u8 rt_family)
 {
        struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
        int i;
@@ -172,7 +173,7 @@ int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
                struct fib_nh_common *nhc = &nhi->fib_nhc;
                int weight = nhg->nh_entries[i].weight;
 
-               if (fib_add_nexthop(skb, nhc, weight) < 0)
+               if (fib_add_nexthop(skb, nhc, weight, rt_family) < 0)
                        return -EMSGSIZE;
        }
 
index b22db30c3d887818fdd20657ef073760f902aa83..aa08a7a5f6ac5836524dd34115cd57e2675e574d 100644 (file)
@@ -983,7 +983,6 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
 void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
 
 struct xfrm_if_parms {
-       char name[IFNAMSIZ];    /* name of XFRM device */
        int link;               /* ifindex of underlying L2 interface */
        u32 if_id;              /* interface identifyer */
 };
@@ -991,7 +990,6 @@ struct xfrm_if_parms {
 struct xfrm_if {
        struct xfrm_if __rcu *next;     /* next interface in list */
        struct net_device *dev;         /* virtual device associated with interface */
-       struct net_device *phydev;      /* physical device */
        struct net *net;                /* netns for packet i/o */
        struct xfrm_if_parms p;         /* interface parms */
 
index 1be0e798e36218c1d1bbbf9b46b42b7deb9c9e57..1fc8faa6e97306dfa95335ecba91b3777a843aa9 100644 (file)
@@ -569,7 +569,7 @@ __SYSCALL(__NR_semget, sys_semget)
 __SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl)
 #if defined(__ARCH_WANT_TIME32_SYSCALLS) || __BITS_PER_LONG != 32
 #define __NR_semtimedop 192
-__SC_COMP(__NR_semtimedop, sys_semtimedop, sys_semtimedop_time32)
+__SC_3264(__NR_semtimedop, sys_semtimedop_time32, sys_semtimedop)
 #endif
 #define __NR_semop 193
 __SYSCALL(__NR_semop, sys_semop)
index 4941628a4fb9b919720d3fd9a949828f2c397fc0..5ec88e7548a9f55e19c1b90f990f2f617ca3c723 100644 (file)
@@ -16,6 +16,7 @@
 #define CAPI_MSG_BASELEN               8
 #define CAPI_DATA_B3_REQ_LEN           (CAPI_MSG_BASELEN+4+4+2+2+2)
 #define CAPI_DATA_B3_RESP_LEN          (CAPI_MSG_BASELEN+4+2)
+#define CAPI_DISCONNECT_B3_RESP_LEN    (CAPI_MSG_BASELEN+4)
 
 /*----- CAPI commands -----*/
 #define CAPI_ALERT                 0x01
index ac49a220cf2ad8ee3fa1bfa2b72c9b232c1cf0d6..85b809fc9f118414a33eb730c21b62c35a91dd12 100644 (file)
@@ -17,6 +17,7 @@
 #define P_ALL          0
 #define P_PID          1
 #define P_PGID         2
+#define P_PIDFD                3
 
 
 #endif /* _UAPI_LINUX_WAIT_H */
index 0fcf8e719b7647fe7e59141c153b2485c95c4399..5766c61aed0e538f2b255480c28e8b41333736af 100644 (file)
@@ -276,29 +276,7 @@ static inline int compat_ipc_parse_version(int *cmd)
        *cmd &= ~IPC_64;
        return version;
 }
-#endif
 
-/* for __ARCH_WANT_SYS_IPC */
-long ksys_semtimedop(int semid, struct sembuf __user *tsops,
-                    unsigned int nsops,
-                    const struct __kernel_timespec __user *timeout);
-long ksys_semget(key_t key, int nsems, int semflg);
-long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
-long ksys_msgget(key_t key, int msgflg);
-long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
-long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
-                long msgtyp, int msgflg);
-long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
-                int msgflg);
-long ksys_shmget(key_t key, size_t size, int shmflg);
-long ksys_shmdt(char __user *shmaddr);
-long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
-
-/* for CONFIG_ARCH_WANT_OLD_COMPAT_IPC */
-long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
-                           unsigned int nsops,
-                           const struct old_timespec32 __user *timeout);
-#ifdef CONFIG_COMPAT
 long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg);
 long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr);
 long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
@@ -306,6 +284,7 @@ long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
 long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
                       compat_ssize_t msgsz, int msgflg);
 long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr);
-#endif /* CONFIG_COMPAT */
+
+#endif
 
 #endif
index b5c14c9d7b9870c1e122e6debe275d9fe4a5b5b8..c36a719fee6d34a18af09ac4d1e7d0b8c58d377f 100644 (file)
@@ -1772,16 +1772,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno,
                bitmap_from_u64(mask, stack_mask);
                for_each_set_bit(i, mask, 64) {
                        if (i >= func->allocated_stack / BPF_REG_SIZE) {
-                               /* This can happen if backtracking
-                                * is propagating stack precision where
-                                * caller has larger stack frame
-                                * than callee, but backtrack_insn() should
-                                * have returned -ENOTSUPP.
+                               /* the sequence of instructions:
+                                * 2: (bf) r3 = r10
+                                * 3: (7b) *(u64 *)(r3 -8) = r0
+                                * 4: (79) r4 = *(u64 *)(r10 -8)
+                                * doesn't contain jmps. It's backtracked
+                                * as a single block.
+                                * During backtracking insn 3 is not recognized as
+                                * stack access, so at the end of backtracking
+                                * stack slot fp-8 is still marked in stack_mask.
+                                * However the parent state may not have accessed
+                                * fp-8 and it's "unallocated" stack space.
+                                * In such case fallback to conservative.
                                 */
-                               verbose(env, "BUG spi %d stack_size %d\n",
-                                       i, func->allocated_stack);
-                               WARN_ONCE(1, "verifier backtracking bug");
-                               return -EFAULT;
+                               mark_all_scalars_precise(env, st);
+                               return 0;
                        }
 
                        if (func->stack[i].slot_type[0] != STACK_SPILL) {
index 753afbca549fdaeba9c133c192c1927d1d9c6f3c..8be1da1ebd9a4f3d4ee3f6038a85e18e8d5fa685 100644 (file)
@@ -5255,8 +5255,16 @@ static struct cgroup *cgroup_create(struct cgroup *parent)
         * if the parent has to be frozen, the child has too.
         */
        cgrp->freezer.e_freeze = parent->freezer.e_freeze;
-       if (cgrp->freezer.e_freeze)
+       if (cgrp->freezer.e_freeze) {
+               /*
+                * Set the CGRP_FREEZE flag, so when a process will be
+                * attached to the child cgroup, it will become frozen.
+                * At this point the new cgroup is unpopulated, so we can
+                * consider it frozen immediately.
+                */
+               set_bit(CGRP_FREEZE, &cgrp->flags);
                set_bit(CGRP_FROZEN, &cgrp->flags);
+       }
 
        spin_lock_irq(&css_set_lock);
        for (tcgrp = cgrp; tcgrp; tcgrp = cgroup_parent(tcgrp)) {
index c5cd852fe86bb4e6eda1466330d7d6ea5f5a5fac..3cc8416ec844a46cb967becb21de903bc019824f 100644 (file)
@@ -413,7 +413,7 @@ static int hw_breakpoint_parse(struct perf_event *bp,
 
 int register_perf_hw_breakpoint(struct perf_event *bp)
 {
-       struct arch_hw_breakpoint hw;
+       struct arch_hw_breakpoint hw = { };
        int err;
 
        err = reserve_bp_slot(bp);
@@ -461,7 +461,7 @@ int
 modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr,
                                bool check)
 {
-       struct arch_hw_breakpoint hw;
+       struct arch_hw_breakpoint hw = { };
        int err;
 
        err = hw_breakpoint_parse(bp, attr, &hw);
index 5b4a5dcce8f8328dd173ead148f4dc6a5fa0d8c4..22ab6a4bdc513ce04c059b81bad920dd0308b2c9 100644 (file)
@@ -1554,6 +1554,23 @@ end:
        return retval;
 }
 
+static struct pid *pidfd_get_pid(unsigned int fd)
+{
+       struct fd f;
+       struct pid *pid;
+
+       f = fdget(fd);
+       if (!f.file)
+               return ERR_PTR(-EBADF);
+
+       pid = pidfd_pid(f.file);
+       if (!IS_ERR(pid))
+               get_pid(pid);
+
+       fdput(f);
+       return pid;
+}
+
 static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
                          int options, struct rusage *ru)
 {
@@ -1576,19 +1593,32 @@ static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
                type = PIDTYPE_PID;
                if (upid <= 0)
                        return -EINVAL;
+
+               pid = find_get_pid(upid);
                break;
        case P_PGID:
                type = PIDTYPE_PGID;
-               if (upid <= 0)
+               if (upid < 0)
+                       return -EINVAL;
+
+               if (upid)
+                       pid = find_get_pid(upid);
+               else
+                       pid = get_task_pid(current, PIDTYPE_PGID);
+               break;
+       case P_PIDFD:
+               type = PIDTYPE_PID;
+               if (upid < 0)
                        return -EINVAL;
+
+               pid = pidfd_get_pid(upid);
+               if (IS_ERR(pid))
+                       return PTR_ERR(pid);
                break;
        default:
                return -EINVAL;
        }
 
-       if (type < PIDTYPE_MAX)
-               pid = find_get_pid(upid);
-
        wo.wo_type      = type;
        wo.wo_pid       = pid;
        wo.wo_flags     = options;
index 2852d0e76ea3b905693a454f36e21524c14a8b54..0ad65a932936d62ea5dd82f2e48c74bc31b2ffc6 100644 (file)
@@ -1690,6 +1690,14 @@ static inline void rcu_copy_process(struct task_struct *p)
 #endif /* #ifdef CONFIG_TASKS_RCU */
 }
 
+struct pid *pidfd_pid(const struct file *file)
+{
+       if (file->f_op == &pidfd_fops)
+               return file->private_data;
+
+       return ERR_PTR(-EBADF);
+}
+
 static int pidfd_release(struct inode *inode, struct file *file)
 {
        struct pid *pid = file->private_data;
@@ -2338,6 +2346,8 @@ struct mm_struct *copy_init_mm(void)
  *
  * It copies the process, and if successful kick-starts
  * it and waits for it to finish using the VM if required.
+ *
+ * args->exit_signal is expected to be checked for sanity by the caller.
  */
 long _do_fork(struct kernel_clone_args *args)
 {
@@ -2562,6 +2572,14 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
        if (copy_from_user(&args, uargs, size))
                return -EFAULT;
 
+       /*
+        * Verify that higher 32bits of exit_signal are unset and that
+        * it is a valid signal
+        */
+       if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) ||
+                    !valid_signal(args.exit_signal)))
+               return -EINVAL;
+
        *kargs = (struct kernel_clone_args){
                .flags          = args.flags,
                .pidfd          = u64_to_user_ptr(args.pidfd),
index 95414ad3506a919e21561d057e54ba27b8eb53c2..98c04ca5fa43d6a4515fff52a2d956c250777083 100644 (file)
@@ -36,6 +36,8 @@ static void resend_irqs(unsigned long arg)
                irq = find_first_bit(irqs_resend, nr_irqs);
                clear_bit(irq, irqs_resend);
                desc = irq_to_desc(irq);
+               if (!desc)
+                       continue;
                local_irq_disable();
                desc->handle_irq(desc);
                local_irq_enable();
index 534fec266a334b299846034e878c271619fe5c71..c4da1ef56fdfcd7a522e403600c9786efc26bd94 100644 (file)
@@ -3678,8 +3678,11 @@ static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
 
 static struct pid *pidfd_to_pid(const struct file *file)
 {
-       if (file->f_op == &pidfd_fops)
-               return file->private_data;
+       struct pid *pid;
+
+       pid = pidfd_pid(file);
+       if (!IS_ERR(pid))
+               return pid;
 
        return tgid_pidfd_to_pid(file);
 }
index f33d66fc0e86d5741e42b352bcb9e3a94d944412..4e6b1c3e4c9814405922d47ee2d9ffe1eb3c5d3d 100644 (file)
@@ -631,6 +631,9 @@ config SBITMAP
 config PARMAN
        tristate "parman" if COMPILE_TEST
 
+config OBJAGG
+       tristate "objagg" if COMPILE_TEST
+
 config STRING_SELFTEST
        tristate "Test string functions"
 
@@ -653,6 +656,3 @@ config GENERIC_LIB_CMPDI2
 
 config GENERIC_LIB_UCMPDI2
        bool
-
-config OBJAGG
-       tristate "objagg" if COMPILE_TEST
index cdb00c2ef242387c0d6824e0ec07c3a19b85eb8f..c1d3a303d97fbda890e546755535199af0420d2e 100644 (file)
@@ -5660,11 +5660,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_UNKNOWN_CONN_ID);
 
-       if (min < hcon->le_conn_min_interval ||
-           max > hcon->le_conn_max_interval)
-               return send_conn_param_neg_reply(hdev, handle,
-                                                HCI_ERROR_INVALID_LL_PARAMS);
-
        if (hci_check_conn_params(min, max, latency, timeout))
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_INVALID_LL_PARAMS);
index dfc1edb168b78b2ed43575cdd6087c45b75a0f82..da7fdbdf9c41af026969f6045513d3e7685434bc 100644 (file)
@@ -5305,14 +5305,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
        memset(&rsp, 0, sizeof(rsp));
 
-       if (min < hcon->le_conn_min_interval ||
-           max > hcon->le_conn_max_interval) {
-               BT_DBG("requested connection interval exceeds current bounds.");
-               err = -EINVAL;
-       } else {
-               err = hci_check_conn_params(min, max, latency, to_multiplier);
-       }
-
+       err = hci_check_conn_params(min, max, latency, to_multiplier);
        if (err)
                rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
        else
index bf6acd34234daa8a1da4aff928c169837bcf58c1..63f9c08625f055b7779dd471707f16cf6f7b4ba1 100644 (file)
@@ -437,7 +437,7 @@ static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
        struct nlmsghdr *nlh;
        struct nlattr *nest;
 
-       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), 0);
        if (!nlh)
                return -EMSGSIZE;
 
index d3f9592f4ff8d8435861cd95dd0d130e8fa22fbb..af7800103e51e5aee724ff314697d17ec583aeba 100644 (file)
@@ -496,6 +496,10 @@ static unsigned int br_nf_pre_routing(void *priv,
                if (!brnet->call_ip6tables &&
                    !br_opt_get(br, BROPT_NF_CALL_IP6TABLES))
                        return NF_ACCEPT;
+               if (!ipv6_mod_enabled()) {
+                       pr_warn_once("Module ipv6 is disabled, so call_ip6tables is not supported.");
+                       return NF_DROP;
+               }
 
                nf_bridge_pull_encap_header_rcsum(skb);
                return br_nf_pre_routing_ipv6(priv, skb, state);
index 0891f499c1bb7cdb85490a681b21895f2206bcba..5156c0edebe8097403c6b78f711df5a373fd2e6d 100644 (file)
@@ -8758,6 +8758,8 @@ int register_netdevice(struct net_device *dev)
        ret = notifier_to_errno(ret);
        if (ret) {
                rollback_registered(dev);
+               rcu_barrier();
+
                dev->reg_state = NETREG_UNREGISTERED;
        }
        /*
index 0338820ee0ec67ce5b399b629984a0d05033e8c5..982d8d12830e411a2f262da3dffbc407ab40ff64 100644 (file)
@@ -3664,6 +3664,25 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
        int pos;
        int dummy;
 
+       if (list_skb && !list_skb->head_frag && skb_headlen(list_skb) &&
+           (skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY)) {
+               /* gso_size is untrusted, and we have a frag_list with a linear
+                * non head_frag head.
+                *
+                * (we assume checking the first list_skb member suffices;
+                * i.e if either of the list_skb members have non head_frag
+                * head, then the first one has too).
+                *
+                * If head_skb's headlen does not fit requested gso_size, it
+                * means that the frag_list members do NOT terminate on exact
+                * gso_size boundaries. Hence we cannot perform skb_frag_t page
+                * sharing. Therefore we must fallback to copying the frag_list
+                * skbs; we do so by disabling SG.
+                */
+               if (mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb))
+                       features &= ~NETIF_F_SG;
+       }
+
        __skb_push(head_skb, doffset);
        proto = skb_network_protocol(head_skb, &dummy);
        if (unlikely(!proto))
index 1330a7442e5b1e54d80d0b675f7356742bcdfbec..50916f9bc4f2e5b7814943e7528f46d5df44b502 100644 (file)
@@ -656,6 +656,7 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
                                   struct sock *sk, u64 flags)
 {
        struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        u32 key_size = map->key_size, hash;
        struct bpf_htab_elem *elem, *elem_new;
        struct bpf_htab_bucket *bucket;
@@ -666,6 +667,8 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
        WARN_ON_ONCE(!rcu_read_lock_held());
        if (unlikely(flags > BPF_EXIST))
                return -EINVAL;
+       if (unlikely(icsk->icsk_ulp_data))
+               return -EINVAL;
 
        link = sk_psock_init_link();
        if (!link)
index 2db089e10ba0ee524ce50cec26c19137002a9992..0913a090b2bf4232d82b6294051d4924052f66b1 100644 (file)
@@ -1582,7 +1582,7 @@ failure:
 }
 
 int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
-                    unsigned char *flags, bool skip_oif)
+                    u8 rt_family, unsigned char *flags, bool skip_oif)
 {
        if (nhc->nhc_flags & RTNH_F_DEAD)
                *flags |= RTNH_F_DEAD;
@@ -1613,7 +1613,7 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
                /* if gateway family does not match nexthop family
                 * gateway is encoded as RTA_VIA
                 */
-               if (nhc->nhc_gw_family != nhc->nhc_family) {
+               if (rt_family != nhc->nhc_gw_family) {
                        int alen = sizeof(struct in6_addr);
                        struct nlattr *nla;
                        struct rtvia *via;
@@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(fib_nexthop_info);
 
 #if IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) || IS_ENABLED(CONFIG_IPV6)
 int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
-                   int nh_weight)
+                   int nh_weight, u8 rt_family)
 {
        const struct net_device *dev = nhc->nhc_dev;
        struct rtnexthop *rtnh;
@@ -1667,7 +1667,7 @@ int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
        rtnh->rtnh_hops = nh_weight - 1;
        rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
 
-       if (fib_nexthop_info(skb, nhc, &flags, true) < 0)
+       if (fib_nexthop_info(skb, nhc, rt_family, &flags, true) < 0)
                goto nla_put_failure;
 
        rtnh->rtnh_flags = flags;
@@ -1693,13 +1693,14 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi)
                goto nla_put_failure;
 
        if (unlikely(fi->nh)) {
-               if (nexthop_mpath_fill_node(skb, fi->nh) < 0)
+               if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0)
                        goto nla_put_failure;
                goto mp_end;
        }
 
        for_nexthops(fi) {
-               if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight) < 0)
+               if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight,
+                                   AF_INET) < 0)
                        goto nla_put_failure;
 #ifdef CONFIG_IP_ROUTE_CLASSID
                if (nh->nh_tclassid &&
@@ -1775,7 +1776,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
                const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
                unsigned char flags = 0;
 
-               if (fib_nexthop_info(skb, nhc, &flags, false) < 0)
+               if (fib_nexthop_info(skb, nhc, AF_INET, &flags, false) < 0)
                        goto nla_put_failure;
 
                rtm->rtm_flags = flags;
index c21e8a22fb3bb39d06eb3ee7eb4cfae5066b6f48..8a1cd93dbb09d2f06ff6e2f39b496ca28341093f 100644 (file)
@@ -266,7 +266,7 @@ static void tcp_ecn_accept_cwr(struct sock *sk, const struct sk_buff *skb)
 
 static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp)
 {
-       tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
+       tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
 }
 
 static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb)
index 87d2d8c1db7cc86940d6216b50d3bdadfb588937..98ac32b49d8c9a4fe6158d8c9e7b759373483709 100644 (file)
@@ -223,7 +223,7 @@ static int __net_init ping_v6_proc_init_net(struct net *net)
        return 0;
 }
 
-static void __net_init ping_v6_proc_exit_net(struct net *net)
+static void __net_exit ping_v6_proc_exit_net(struct net *net)
 {
        remove_proc_entry("icmp6", net->proc_net);
 }
index fd059e08785abb0d06320da870ffe8dd9499f8f9..546088e50815158a81ebe953a3a1ec820243c367 100644 (file)
@@ -4388,13 +4388,14 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
        struct fib6_config cfg = {
                .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
                .fc_ifindex = idev->dev->ifindex,
-               .fc_flags = RTF_UP | RTF_ADDRCONF | RTF_NONEXTHOP,
+               .fc_flags = RTF_UP | RTF_NONEXTHOP,
                .fc_dst = *addr,
                .fc_dst_len = 128,
                .fc_protocol = RTPROT_KERNEL,
                .fc_nlinfo.nl_net = net,
                .fc_ignore_dev_down = true,
        };
+       struct fib6_info *f6i;
 
        if (anycast) {
                cfg.fc_type = RTN_ANYCAST;
@@ -4404,7 +4405,10 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
                cfg.fc_flags |= RTF_LOCAL;
        }
 
-       return ip6_route_info_create(&cfg, gfp_flags, NULL);
+       f6i = ip6_route_info_create(&cfg, gfp_flags, NULL);
+       if (!IS_ERR(f6i))
+               f6i->dst_nocount = true;
+       return f6i;
 }
 
 /* remove deleted ip from prefsrc entries */
@@ -5325,11 +5329,11 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
        if (nexthop_is_multipath(nh)) {
                struct nlattr *mp;
 
-               mp = nla_nest_start(skb, RTA_MULTIPATH);
+               mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
                if (!mp)
                        goto nla_put_failure;
 
-               if (nexthop_mpath_fill_node(skb, nh))
+               if (nexthop_mpath_fill_node(skb, nh, AF_INET6))
                        goto nla_put_failure;
 
                nla_nest_end(skb, mp);
@@ -5337,7 +5341,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
                struct fib6_nh *fib6_nh;
 
                fib6_nh = nexthop_fib6_nh(nh);
-               if (fib_nexthop_info(skb, &fib6_nh->nh_common,
+               if (fib_nexthop_info(skb, &fib6_nh->nh_common, AF_INET6,
                                     flags, false) < 0)
                        goto nla_put_failure;
        }
@@ -5466,13 +5470,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
                        goto nla_put_failure;
 
                if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common,
-                                   rt->fib6_nh->fib_nh_weight) < 0)
+                                   rt->fib6_nh->fib_nh_weight, AF_INET6) < 0)
                        goto nla_put_failure;
 
                list_for_each_entry_safe(sibling, next_sibling,
                                         &rt->fib6_siblings, fib6_siblings) {
                        if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
-                                           sibling->fib6_nh->fib_nh_weight) < 0)
+                                           sibling->fib6_nh->fib_nh_weight,
+                                           AF_INET6) < 0)
                                goto nla_put_failure;
                }
 
@@ -5489,7 +5494,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
 
                rtm->rtm_flags |= nh_flags;
        } else {
-               if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common,
+               if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6,
                                     &nh_flags, false) < 0)
                        goto nla_put_failure;
 
index 111c400199ec569c00275f644f7e99964e8c4bbf..4105c97c7ba1f4bbae8bd66c977047992a648a4c 100644 (file)
@@ -1529,7 +1529,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
        int err;
-       int layer2_update;
 
        if (params->vlan) {
                sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
@@ -1573,18 +1572,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
            test_sta_flag(sta, WLAN_STA_ASSOC))
                rate_control_rate_init(sta);
 
-       layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-               sdata->vif.type == NL80211_IFTYPE_AP;
-
        err = sta_info_insert_rcu(sta);
        if (err) {
                rcu_read_unlock();
                return err;
        }
 
-       if (layer2_update)
-               cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
-
        rcu_read_unlock();
 
        return 0;
@@ -1682,10 +1675,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                sta->sdata = vlansdata;
                ieee80211_check_fast_xmit(sta);
 
-               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
                        ieee80211_vif_inc_num_mcast(sta->sdata);
-
-               cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
+                       cfg80211_send_layer2_update(sta->sdata->dev,
+                                                   sta->sta.addr);
+               }
        }
 
        err = sta_apply_parameters(local, sta, params);
index 95eb8220e2e47def69ad381539330ec1d47bd599..5fb368cc26338dc048212367c6233a6018f5b091 100644 (file)
@@ -1979,6 +1979,10 @@ int sta_info_move_state(struct sta_info *sta,
                        ieee80211_check_fast_xmit(sta);
                        ieee80211_check_fast_rx(sta);
                }
+               if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sta->sdata->vif.type == NL80211_IFTYPE_AP)
+                       cfg80211_send_layer2_update(sta->sdata->dev,
+                                                   sta->sta.addr);
                break;
        default:
                break;
index 6aa01eb6fe99ce8cdb62dec08c2b37a3701a6218..e2d13cd1887562c80361042c7fe72ad50b8034d5 100644 (file)
@@ -553,10 +553,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
                goto nla_put_failure;
 
        if (ctnetlink_dump_status(skb, ct) < 0 ||
-           ctnetlink_dump_timeout(skb, ct) < 0 ||
            ctnetlink_dump_acct(skb, ct, type) < 0 ||
            ctnetlink_dump_timestamp(skb, ct) < 0 ||
-           ctnetlink_dump_protoinfo(skb, ct) < 0 ||
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
            ctnetlink_dump_secctx(skb, ct) < 0 ||
@@ -568,6 +566,11 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
            ctnetlink_dump_ct_synproxy(skb, ct) < 0)
                goto nla_put_failure;
 
+       if (!test_bit(IPS_OFFLOAD_BIT, &ct->status) &&
+           (ctnetlink_dump_timeout(skb, ct) < 0 ||
+            ctnetlink_dump_protoinfo(skb, ct) < 0))
+               goto nla_put_failure;
+
        nlmsg_end(skb, nlh);
        return skb->len;
 
index 80a8f9ae4c93118d651f6b27f97f1f89bda77cfe..a0b4bf654de2d75765bc27b4ea61c130f32a14a1 100644 (file)
@@ -217,7 +217,7 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
                return err;
        }
 
-       flow->timeout = (u32)jiffies;
+       flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
        return 0;
 }
 EXPORT_SYMBOL_GPL(flow_offload_add);
index 2cf3f32fe6d2543fd338b0a545aca3fd975ec04f..a2e726ae7f07737b8dc5d420cacbf00885a90ba0 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables_core.h>
 #include <net/netfilter/nf_tables.h>
+#include <net/ipv6.h>
 
 #include <net/netfilter/nft_fib.h>
 
@@ -34,6 +35,8 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
                }
                break;
        case ETH_P_IPV6:
+               if (!ipv6_mod_enabled())
+                       break;
                switch (priv->result) {
                case NFT_FIB_RESULT_OIF:
                case NFT_FIB_RESULT_OIFNAME:
index d7f3776dfd719d402ae178890107db8ebd1627f2..637ce3e8c575ce1b95dfcd340347176772cdff2d 100644 (file)
@@ -47,9 +47,6 @@ static void nft_socket_eval(const struct nft_expr *expr,
                return;
        }
 
-       /* So that subsequent socket matching not to require other lookups. */
-       skb->sk = sk;
-
        switch(priv->key) {
        case NFT_SOCKET_TRANSPARENT:
                nft_reg_store8(dest, inet_sk_transparent(sk));
@@ -66,6 +63,9 @@ static void nft_socket_eval(const struct nft_expr *expr,
                WARN_ON(1);
                regs->verdict.code = NFT_BREAK;
        }
+
+       if (sk != skb->sk)
+               sock_gen_put(sk);
 }
 
 static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
index ccff1e544c2183ba709d488c80015b8932370fbc..e35869e81766ea6660176c94fa910dbe2614bf61 100644 (file)
@@ -84,11 +84,14 @@ static ssize_t qrtr_tun_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (!kbuf)
                return -ENOMEM;
 
-       if (!copy_from_iter_full(kbuf, len, from))
+       if (!copy_from_iter_full(kbuf, len, from)) {
+               kfree(kbuf);
                return -EFAULT;
+       }
 
        ret = qrtr_endpoint_post(&tun->ep, kbuf, len);
 
+       kfree(kbuf);
        return ret < 0 ? ret : len;
 }
 
index 0f4398e7f2a7add7c20b6fdd333c40af4e719c92..05464fd7c17afcc708eec3e4305ca85d039048d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -239,34 +239,30 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        }
 
-       sock_set_flag(sk, SOCK_RCU_FREE);
-       ret = rds_add_bound(rs, binding_addr, &port, scope_id);
-       if (ret)
-               goto out;
-
-       if (rs->rs_transport) { /* previously bound */
+       /* The transport can be set using SO_RDS_TRANSPORT option before the
+        * socket is bound.
+        */
+       if (rs->rs_transport) {
                trans = rs->rs_transport;
                if (trans->laddr_check(sock_net(sock->sk),
                                       binding_addr, scope_id) != 0) {
                        ret = -ENOPROTOOPT;
-                       rds_remove_bound(rs);
-               } else {
-                       ret = 0;
+                       goto out;
                }
-               goto out;
-       }
-       trans = rds_trans_get_preferred(sock_net(sock->sk), binding_addr,
-                                       scope_id);
-       if (!trans) {
-               ret = -EADDRNOTAVAIL;
-               rds_remove_bound(rs);
-               pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
-                                   __func__, binding_addr);
-               goto out;
+       } else {
+               trans = rds_trans_get_preferred(sock_net(sock->sk),
+                                               binding_addr, scope_id);
+               if (!trans) {
+                       ret = -EADDRNOTAVAIL;
+                       pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
+                                           __func__, binding_addr);
+                       goto out;
+               }
+               rs->rs_transport = trans;
        }
 
-       rs->rs_transport = trans;
-       ret = 0;
+       sock_set_flag(sk, SOCK_RCU_FREE);
+       ret = rds_add_bound(rs, binding_addr, &port, scope_id);
 
 out:
        release_sock(sk);
index d122c53c869734ee00ad628fd53c3ae49d143849..157be1ff8697be438a7ee6636e37671169fff3df 100644 (file)
@@ -1262,8 +1262,8 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
 
                        if (nskb != skb) {
                                rxrpc_eaten_skb(skb, rxrpc_skb_received);
-                               rxrpc_new_skb(skb, rxrpc_skb_unshared);
                                skb = nskb;
+                               rxrpc_new_skb(skb, rxrpc_skb_unshared);
                                sp = rxrpc_skb(skb);
                        }
                }
index 04faee7ccbce64354618365b1c304d7c76f6bb06..1047825d9f48d546fe1339a25f3f86979e7ac801 100644 (file)
@@ -1920,6 +1920,8 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
        cl = cops->find(q, portid);
        if (!cl)
                return;
+       if (!cops->tcf_block)
+               return;
        block = cops->tcf_block(q, cl, NULL);
        if (!block)
                return;
index 137db1cbde8538e124133c6e148acc3e92e56a74..ac28f6a5d70e0b38ae8ce7858f08e9d15778c22f 100644 (file)
@@ -46,6 +46,8 @@ EXPORT_SYMBOL(default_qdisc_ops);
  * - updates to tree and tree walking are only done under the rtnl mutex.
  */
 
+#define SKB_XOFF_MAGIC ((struct sk_buff *)1UL)
+
 static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q)
 {
        const struct netdev_queue *txq = q->dev_queue;
@@ -71,7 +73,7 @@ static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q)
                                q->q.qlen--;
                        }
                } else {
-                       skb = NULL;
+                       skb = SKB_XOFF_MAGIC;
                }
        }
 
@@ -253,8 +255,11 @@ validate:
                return skb;
 
        skb = qdisc_dequeue_skb_bad_txq(q);
-       if (unlikely(skb))
+       if (unlikely(skb)) {
+               if (skb == SKB_XOFF_MAGIC)
+                       return NULL;
                goto bulk;
+       }
        skb = q->dequeue(q);
        if (skb) {
 bulk:
index cee6971c1c8249a68dd6b953948fa1fef21fce04..23cd1c873a2cfc24b907a8177e71dd68b0939701 100644 (file)
@@ -531,7 +531,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt,
                new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]);
 
        non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight;
-       if (non_hh_quantum > INT_MAX)
+       if (non_hh_quantum == 0 || non_hh_quantum > INT_MAX)
                return -EINVAL;
 
        sch_tree_lock(sch);
index 2d47adcb4cbe002f655a937ab89ffc0c603d3015..53746ffeeca355026dfb0e7712d2ec36c47811f1 100644 (file)
@@ -1336,7 +1336,7 @@ static int __net_init sctp_ctrlsock_init(struct net *net)
        return status;
 }
 
-static void __net_init sctp_ctrlsock_exit(struct net *net)
+static void __net_exit sctp_ctrlsock_exit(struct net *net)
 {
        /* Free the control endpoint.  */
        inet_ctl_sock_destroy(net->sctp.ctl_sock);
index 1cf5bb5b73c412cadf1b3d7240bb8c200edb77a5..e52b2128e43b8706ddbec3d6b77388e24402c1c9 100644 (file)
@@ -547,7 +547,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_cmd_seq *commands,
        if (net->sctp.pf_enable &&
           (transport->state == SCTP_ACTIVE) &&
           (transport->error_count < transport->pathmaxrxt) &&
-          (transport->error_count > asoc->pf_retrans)) {
+          (transport->error_count > transport->pf_retrans)) {
 
                sctp_assoc_control_transport(asoc, transport,
                                             SCTP_TRANSPORT_PF,
index 9d1f83b10c0a6c5ab0ca2736c8a9f8491e44c310..b083d4e66230b1e365fc983a0d82eb6f76d0bedd 100644 (file)
@@ -309,7 +309,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)
        return retval;
 }
 
-static long sctp_get_port_local(struct sock *, union sctp_addr *);
+static int sctp_get_port_local(struct sock *, union sctp_addr *);
 
 /* Verify this is a valid sockaddr. */
 static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
@@ -399,9 +399,8 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
         * detection.
         */
        addr->v4.sin_port = htons(snum);
-       if ((ret = sctp_get_port_local(sk, addr))) {
+       if (sctp_get_port_local(sk, addr))
                return -EADDRINUSE;
-       }
 
        /* Refresh ephemeral port.  */
        if (!bp->port)
@@ -413,11 +412,13 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len,
                                 SCTP_ADDR_SRC, GFP_ATOMIC);
 
-       /* Copy back into socket for getsockname() use. */
-       if (!ret) {
-               inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
-               sp->pf->to_sk_saddr(addr, sk);
+       if (ret) {
+               sctp_put_port(sk);
+               return ret;
        }
+       /* Copy back into socket for getsockname() use. */
+       inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
+       sp->pf->to_sk_saddr(addr, sk);
 
        return ret;
 }
@@ -7173,7 +7174,7 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
                val.spt_pathmaxrxt = trans->pathmaxrxt;
                val.spt_pathpfthld = trans->pf_retrans;
 
-               return 0;
+               goto out;
        }
 
        asoc = sctp_id2assoc(sk, val.spt_assoc_id);
@@ -7191,6 +7192,7 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
                val.spt_pathmaxrxt = sp->pathmaxrxt;
        }
 
+out:
        if (put_user(len, optlen) || copy_to_user(optval, &val, len))
                return -EFAULT;
 
@@ -7998,7 +8000,7 @@ static void sctp_unhash(struct sock *sk)
 static struct sctp_bind_bucket *sctp_bucket_create(
        struct sctp_bind_hashbucket *head, struct net *, unsigned short snum);
 
-static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
+static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
        struct sctp_sock *sp = sctp_sk(sk);
        bool reuse = (sk->sk_reuse || sp->reuse);
@@ -8108,7 +8110,7 @@ pp_found:
 
                        if (sctp_bind_addr_conflict(&ep2->base.bind_addr,
                                                    addr, sp2, sp)) {
-                               ret = (long)sk2;
+                               ret = 1;
                                goto fail_unlock;
                        }
                }
@@ -8180,7 +8182,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
        addr.v4.sin_port = htons(snum);
 
        /* Note: sk->sk_num gets filled in if ephemeral port request. */
-       return !!sctp_get_port_local(sk, &addr);
+       return sctp_get_port_local(sk, &addr);
 }
 
 /*
index 44abc8e9c99024df9932d151fdc32ce4d4aa2820..241ed22744739dc5d2167ce7c4f108c2e1200b01 100644 (file)
@@ -223,7 +223,8 @@ static void tipc_publ_purge(struct net *net, struct publication *publ, u32 addr)
                       publ->key);
        }
 
-       kfree_rcu(p, rcu);
+       if (p)
+               kfree_rcu(p, rcu);
 }
 
 /**
index 74868f9d81fb2b2c0fdd98522544eabfad3689fe..2ab4859df55ac08fec69b81a2a8f1cac6585195f 100644 (file)
@@ -145,8 +145,6 @@ static int xfrmi_create(struct net_device *dev)
        if (err < 0)
                goto out;
 
-       strcpy(xi->p.name, dev->name);
-
        dev_hold(dev);
        xfrmi_link(xfrmn, xi);
 
@@ -177,7 +175,6 @@ static void xfrmi_dev_uninit(struct net_device *dev)
        struct xfrmi_net *xfrmn = net_generic(xi->net, xfrmi_net_id);
 
        xfrmi_unlink(xfrmn, xi);
-       dev_put(xi->phydev);
        dev_put(dev);
 }
 
@@ -294,7 +291,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        if (tdev == dev) {
                stats->collisions++;
                net_warn_ratelimited("%s: Local routing loop detected!\n",
-                                    xi->p.name);
+                                    dev->name);
                goto tx_err_dst_release;
        }
 
@@ -364,7 +361,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_err;
        }
 
-       fl.flowi_oif = xi->phydev->ifindex;
+       fl.flowi_oif = xi->p.link;
 
        ret = xfrmi_xmit2(skb, dev, &fl);
        if (ret < 0)
@@ -505,7 +502,7 @@ static int xfrmi_change(struct xfrm_if *xi, const struct xfrm_if_parms *p)
 
 static int xfrmi_update(struct xfrm_if *xi, struct xfrm_if_parms *p)
 {
-       struct net *net = dev_net(xi->dev);
+       struct net *net = xi->net;
        struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
        int err;
 
@@ -550,7 +547,7 @@ static int xfrmi_get_iflink(const struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
 
-       return xi->phydev->ifindex;
+       return xi->p.link;
 }
 
 
@@ -576,12 +573,14 @@ static void xfrmi_dev_setup(struct net_device *dev)
        dev->needs_free_netdev  = true;
        dev->priv_destructor    = xfrmi_dev_free;
        netif_keep_dst(dev);
+
+       eth_broadcast_addr(dev->broadcast);
 }
 
 static int xfrmi_dev_init(struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net_device *phydev = xi->phydev;
+       struct net_device *phydev = __dev_get_by_index(xi->net, xi->p.link);
        int err;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
@@ -596,13 +595,19 @@ static int xfrmi_dev_init(struct net_device *dev)
 
        dev->features |= NETIF_F_LLTX;
 
-       dev->needed_headroom = phydev->needed_headroom;
-       dev->needed_tailroom = phydev->needed_tailroom;
+       if (phydev) {
+               dev->needed_headroom = phydev->needed_headroom;
+               dev->needed_tailroom = phydev->needed_tailroom;
 
-       if (is_zero_ether_addr(dev->dev_addr))
-               eth_hw_addr_inherit(dev, phydev);
-       if (is_zero_ether_addr(dev->broadcast))
-               memcpy(dev->broadcast, phydev->broadcast, dev->addr_len);
+               if (is_zero_ether_addr(dev->dev_addr))
+                       eth_hw_addr_inherit(dev, phydev);
+               if (is_zero_ether_addr(dev->broadcast))
+                       memcpy(dev->broadcast, phydev->broadcast,
+                              dev->addr_len);
+       } else {
+               eth_hw_addr_random(dev);
+               eth_broadcast_addr(dev->broadcast);
+       }
 
        return 0;
 }
@@ -638,12 +643,6 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
        int err;
 
        xfrmi_netlink_parms(data, &p);
-
-       if (!tb[IFLA_IFNAME])
-               return -EINVAL;
-
-       nla_strlcpy(p.name, tb[IFLA_IFNAME], IFNAMSIZ);
-
        xi = xfrmi_locate(net, &p);
        if (xi)
                return -EEXIST;
@@ -652,13 +651,8 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
        xi->p = p;
        xi->net = net;
        xi->dev = dev;
-       xi->phydev = dev_get_by_index(net, p.link);
-       if (!xi->phydev)
-               return -ENODEV;
 
        err = xfrmi_create(dev);
-       if (err < 0)
-               dev_put(xi->phydev);
        return err;
 }
 
@@ -672,11 +666,11 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
                           struct netlink_ext_ack *extack)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net *net = dev_net(dev);
-
-       xfrmi_netlink_parms(data, &xi->p);
+       struct net *net = xi->net;
+       struct xfrm_if_parms p;
 
-       xi = xfrmi_locate(net, &xi->p);
+       xfrmi_netlink_parms(data, &p);
+       xi = xfrmi_locate(net, &p);
        if (!xi) {
                xi = netdev_priv(dev);
        } else {
@@ -684,7 +678,7 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
                        return -EEXIST;
        }
 
-       return xfrmi_update(xi, &xi->p);
+       return xfrmi_update(xi, &p);
 }
 
 static size_t xfrmi_get_size(const struct net_device *dev)
@@ -715,7 +709,7 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
 
-       return dev_net(xi->phydev);
+       return xi->net;
 }
 
 static const struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
index ec94f5795ea4b3b5bce37736a46131f728b987a5..21e939235b3908ba3c363e2a570f41acd316173e 100644 (file)
@@ -912,6 +912,7 @@ restart:
                } else if (delta > 0) {
                        p = &parent->rb_right;
                } else {
+                       bool same_prefixlen = node->prefixlen == n->prefixlen;
                        struct xfrm_policy *tmp;
 
                        hlist_for_each_entry(tmp, &n->hhead, bydst) {
@@ -919,9 +920,11 @@ restart:
                                hlist_del_rcu(&tmp->bydst);
                        }
 
+                       node->prefixlen = prefixlen;
+
                        xfrm_policy_inexact_list_reinsert(net, node, family);
 
-                       if (node->prefixlen == n->prefixlen) {
+                       if (same_prefixlen) {
                                kfree_rcu(n, rcu);
                                return;
                        }
@@ -929,7 +932,6 @@ restart:
                        rb_erase(*p, new);
                        kfree_rcu(n, rcu);
                        n = node;
-                       n->prefixlen = prefixlen;
                        goto restart;
                }
        }
index 8219a30853d283fa65baa1be4f16036d7cf542a8..0fc1b6d4b0f9c4db9084158fd22b755e7b53482f 100644 (file)
@@ -447,6 +447,59 @@ cleanup:
        return ret;
 }
 
+/*
+ * The test creates a cgroups and freezes it. Then it creates a child cgroup
+ * and populates it with a task. After that it checks that the child cgroup
+ * is frozen and the parent cgroup remains frozen too.
+ */
+static int test_cgfreezer_mkdir(const char *root)
+{
+       int ret = KSFT_FAIL;
+       char *parent, *child = NULL;
+       int pid;
+
+       parent = cg_name(root, "cg_test_mkdir_A");
+       if (!parent)
+               goto cleanup;
+
+       child = cg_name(parent, "cg_test_mkdir_B");
+       if (!child)
+               goto cleanup;
+
+       if (cg_create(parent))
+               goto cleanup;
+
+       if (cg_freeze_wait(parent, true))
+               goto cleanup;
+
+       if (cg_create(child))
+               goto cleanup;
+
+       pid = cg_run_nowait(child, child_fn, NULL);
+       if (pid < 0)
+               goto cleanup;
+
+       if (cg_wait_for_proc_count(child, 1))
+               goto cleanup;
+
+       if (cg_check_frozen(child, true))
+               goto cleanup;
+
+       if (cg_check_frozen(parent, true))
+               goto cleanup;
+
+       ret = KSFT_PASS;
+
+cleanup:
+       if (child)
+               cg_destroy(child);
+       free(child);
+       if (parent)
+               cg_destroy(parent);
+       free(parent);
+       return ret;
+}
+
 /*
  * The test creates two nested cgroups, freezes the parent
  * and removes the child. Then it checks that the parent cgroup
@@ -815,6 +868,7 @@ struct cgfreezer_test {
        T(test_cgfreezer_simple),
        T(test_cgfreezer_tree),
        T(test_cgfreezer_forkbomb),
+       T(test_cgfreezer_mkdir),
        T(test_cgfreezer_rmdir),
        T(test_cgfreezer_migrate),
        T(test_cgfreezer_ptrace),
index c5c93d5fb3ade4fbd24d668d227281712ae9894b..f9ebeac1e6f20e8fcafba752a916c87d61dfb7ca 100755 (executable)
@@ -212,6 +212,8 @@ check_output()
                        printf "        ${out}\n"
                        printf "    Expected:\n"
                        printf "        ${expected}\n\n"
+               else
+                       echo "      WARNING: Unexpected route entry"
                fi
        fi
 
@@ -274,7 +276,7 @@ ipv6_fcnal()
 
        run_cmd "$IP nexthop get id 52"
        log_test $? 0 "Get nexthop by id"
-       check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1"
+       check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1 scope link"
 
        run_cmd "$IP nexthop del id 52"
        log_test $? 0 "Delete nexthop by id"
@@ -479,12 +481,12 @@ ipv6_fcnal_runtime()
        run_cmd "$IP -6 nexthop add id 85 dev veth1"
        run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 85"
        log_test $? 0 "IPv6 route with device only nexthop"
-       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1"
+       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1 metric 1024 pref medium"
 
        run_cmd "$IP nexthop add id 123 group 81/85"
        run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 123"
        log_test $? 0 "IPv6 multipath route with nexthop mix - dev only + gw"
-       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 nexthop via 2001:db8:91::2 dev veth1 nexthop dev veth1"
+       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 123 metric 1024 nexthop via 2001:db8:91::2 dev veth1 weight 1 nexthop dev veth1 weight 1 pref medium"
 
        #
        # IPv6 route with v4 nexthop - not allowed
@@ -538,7 +540,7 @@ ipv4_fcnal()
 
        run_cmd "$IP nexthop get id 12"
        log_test $? 0 "Get nexthop by id"
-       check_nexthop "id 12" "id 12 via 172.16.1.2 src 172.16.1.1 dev veth1 scope link"
+       check_nexthop "id 12" "id 12 via 172.16.1.2 dev veth1 scope link"
 
        run_cmd "$IP nexthop del id 12"
        log_test $? 0 "Delete nexthop by id"
@@ -685,7 +687,7 @@ ipv4_withv6_fcnal()
        set +e
        run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
-       check_route "172.16.101.1" "172.16.101.1 nhid 11 via ${lladdr} dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 11 via inet6 ${lladdr} dev veth1"
 
        set -e
        run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
@@ -694,11 +696,11 @@ ipv4_withv6_fcnal()
        run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
 
-       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
 
        run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
        log_test $? 0 "IPv4 route with IPv6 gateway"
-       check_route "172.16.101.1" "172.16.101.1 via ${lladdr} dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 via inet6 ${lladdr} dev veth1"
 
        run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
        log_test $? 2 "IPv4 route with invalid IPv6 gateway"
@@ -785,10 +787,10 @@ ipv4_fcnal_runtime()
        log_test $? 0 "IPv4 route with device only nexthop"
        check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
 
-       run_cmd "$IP nexthop add id 122 group 21/85"
-       run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
+       run_cmd "$IP nexthop add id 123 group 21/85"
+       run_cmd "$IP ro replace 172.16.101.1/32 nhid 123"
        log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
-       check_route "172.16.101.1" "172.16.101.1 nhid 85 nexthop via 172.16.1.2 dev veth1 nexthop dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 123 nexthop via 172.16.1.2 dev veth1 weight 1 nexthop dev veth1 weight 1"
 
        #
        # IPv4 with IPv6
@@ -820,7 +822,7 @@ ipv4_fcnal_runtime()
        run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
        log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
 
-       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
 
        run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
index 5445943bf07f222acaba83a253668ec06db032e5..7a1bf94c5bd38bc9837b87911a082a1ef287eee8 100755 (executable)
@@ -106,6 +106,13 @@ do_overlap()
     #
     # 10.0.0.0/24 and 10.0.1.0/24 nodes have been merged as 10.0.0.0/23.
     ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/23 dir fwd priority 200 action block
+
+    # similar to above: add policies (with partially random address), with shrinking prefixes.
+    for p in 29 28 27;do
+      for k in $(seq 1 32); do
+       ip -net $ns xfrm policy add src 10.253.1.$((RANDOM%255))/$p dst 10.254.1.$((RANDOM%255))/$p dir fwd priority $((200+k)) action block 2>/dev/null
+      done
+    done
 }
 
 do_esp_policy_get_check() {
index 16d84d117bc04c3f2ebf962c7cb684d84f691e6f..8d069490e17be4d84d1ff1178099d5b9de095dc0 100644 (file)
@@ -1,2 +1,4 @@
 pidfd_open_test
+pidfd_poll_test
 pidfd_test
+pidfd_wait
index 720b2d884b3c52560d86078c704b1696a89c5a9d..464c9b76148f1538643fd512e35461f327ea1249 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 CFLAGS += -g -I../../../../usr/include/ -lpthread
 
-TEST_GEN_PROGS := pidfd_test pidfd_open_test
+TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_poll_test pidfd_wait
 
 include ../lib.mk
 
index 8452e910463f692282e040c6e29682678ac287e7..c6bc68329f4b66e5da2f6720c1f8fcd33d80ce48 100644 (file)
 
 #include "../kselftest.h"
 
+#ifndef P_PIDFD
+#define P_PIDFD 3
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000
+#endif
+
+#ifndef __NR_pidfd_open
+#define __NR_pidfd_open -1
+#endif
+
+#ifndef __NR_pidfd_send_signal
+#define __NR_pidfd_send_signal -1
+#endif
+
+#ifndef __NR_clone3
+#define __NR_clone3 -1
+#endif
+
 /*
  * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
  * That means, when it wraps around any pid < 300 will be skipped.
@@ -53,5 +73,15 @@ again:
        return WEXITSTATUS(status);
 }
 
+static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
+{
+       return syscall(__NR_pidfd_open, pid, flags);
+}
+
+static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
+                                       unsigned int flags)
+{
+       return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
+}
 
 #endif /* __PIDFD_H */
index 0377133dd6dceab6748b206a6c6cfa55cfa32472..b9fe75fc3e517b75d9a70c9ac3f1d60f492392a0 100644 (file)
 #include "pidfd.h"
 #include "../kselftest.h"
 
-static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
-{
-       return syscall(__NR_pidfd_open, pid, flags);
-}
-
 static int safe_int(const char *numstr, int *converted)
 {
        char *err = NULL;
diff --git a/tools/testing/selftests/pidfd/pidfd_poll_test.c b/tools/testing/selftests/pidfd/pidfd_poll_test.c
new file mode 100644 (file)
index 0000000..4b11544
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "pidfd.h"
+#include "../kselftest.h"
+
+static bool timeout;
+
+static void handle_alarm(int sig)
+{
+       timeout = true;
+}
+
+int main(int argc, char **argv)
+{
+       struct pollfd fds;
+       int iter, nevents;
+       int nr_iterations = 10000;
+
+       fds.events = POLLIN;
+
+       if (argc > 2)
+               ksft_exit_fail_msg("Unexpected command line argument\n");
+
+       if (argc == 2) {
+               nr_iterations = atoi(argv[1]);
+               if (nr_iterations <= 0)
+                       ksft_exit_fail_msg("invalid input parameter %s\n",
+                                       argv[1]);
+       }
+
+       ksft_print_msg("running pidfd poll test for %d iterations\n",
+               nr_iterations);
+
+       for (iter = 0; iter < nr_iterations; iter++) {
+               int pidfd;
+               int child_pid = fork();
+
+               if (child_pid < 0) {
+                       if (errno == EAGAIN) {
+                               iter--;
+                               continue;
+                       }
+                       ksft_exit_fail_msg(
+                               "%s - failed to fork a child process\n",
+                               strerror(errno));
+               }
+
+               if (child_pid == 0) {
+                       /* Child process just sleeps for a min and exits */
+                       sleep(60);
+                       exit(EXIT_SUCCESS);
+               }
+
+               /* Parent kills the child and waits for its death */
+               pidfd = sys_pidfd_open(child_pid, 0);
+               if (pidfd < 0)
+                       ksft_exit_fail_msg("%s - pidfd_open failed\n",
+                                       strerror(errno));
+
+               /* Setup 3 sec alarm - plenty of time */
+               if (signal(SIGALRM, handle_alarm) == SIG_ERR)
+                       ksft_exit_fail_msg("%s - signal failed\n",
+                                       strerror(errno));
+               alarm(3);
+
+               /* Send SIGKILL to the child */
+               if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0))
+                       ksft_exit_fail_msg("%s - pidfd_send_signal failed\n",
+                                       strerror(errno));
+
+               /* Wait for the death notification */
+               fds.fd = pidfd;
+               nevents = poll(&fds, 1, -1);
+
+               /* Check for error conditions */
+               if (nevents < 0)
+                       ksft_exit_fail_msg("%s - poll failed\n",
+                                       strerror(errno));
+
+               if (nevents != 1)
+                       ksft_exit_fail_msg("unexpected poll result: %d\n",
+                                       nevents);
+
+               if (!(fds.revents & POLLIN))
+                       ksft_exit_fail_msg(
+                               "unexpected event type received: 0x%x\n",
+                               fds.revents);
+
+               if (timeout)
+                       ksft_exit_fail_msg(
+                               "death notification wait timeout\n");
+
+               close(pidfd);
+               /* Wait for child to prevent zombies */
+               if (waitpid(child_pid, NULL, 0) < 0)
+                       ksft_exit_fail_msg("%s - waitpid failed\n",
+                                       strerror(errno));
+
+       }
+
+       ksft_test_result_pass("pidfd poll test: pass\n");
+       return ksft_exit_pass();
+}
index b632965e60eb0758a1197faedd44f0b3e7d5c829..7aff2d3b42c078217e4f85b392645a308237fb9b 100644 (file)
 #include "pidfd.h"
 #include "../kselftest.h"
 
-#ifndef __NR_pidfd_send_signal
-#define __NR_pidfd_send_signal -1
-#endif
-
 #define str(s) _str(s)
 #define _str(s) #s
 #define CHILD_THREAD_MIN_WAIT 3 /* seconds */
 
 #define MAX_EVENTS 5
 
-#ifndef CLONE_PIDFD
-#define CLONE_PIDFD 0x00001000
-#endif
-
 static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
 {
        size_t stack_size = 1024;
@@ -47,12 +39,6 @@ static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
 #endif
 }
 
-static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
-                                       unsigned int flags)
-{
-       return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
-}
-
 static int signal_received;
 
 static void set_signal_received_on_sigusr1(int sig)
diff --git a/tools/testing/selftests/pidfd/pidfd_wait.c b/tools/testing/selftests/pidfd/pidfd_wait.c
new file mode 100644 (file)
index 0000000..7079f8e
--- /dev/null
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "pidfd.h"
+#include "../kselftest.h"
+
+#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
+
+static pid_t sys_clone3(struct clone_args *args)
+{
+       return syscall(__NR_clone3, args, sizeof(struct clone_args));
+}
+
+static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
+                     struct rusage *ru)
+{
+       return syscall(__NR_waitid, which, pid, info, options, ru);
+}
+
+static int test_pidfd_wait_simple(void)
+{
+       const char *test_name = "pidfd wait simple";
+       int pidfd = -1, status = 0;
+       pid_t parent_tid = -1;
+       struct clone_args args = {
+               .parent_tid = ptr_to_u64(&parent_tid),
+               .pidfd = ptr_to_u64(&pidfd),
+               .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
+               .exit_signal = SIGCHLD,
+       };
+       int ret;
+       pid_t pid;
+       siginfo_t info = {
+               .si_signo = 0,
+       };
+
+       pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+       if (pidfd < 0)
+               ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n",
+                                  test_name, strerror(errno));
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid == 0)
+               ksft_exit_fail_msg(
+                       "%s test: succeeded to wait on invalid pidfd %s\n",
+                       test_name, strerror(errno));
+       close(pidfd);
+       pidfd = -1;
+
+       pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+       if (pidfd == 0)
+               ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n",
+                                  test_name, strerror(errno));
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid == 0)
+               ksft_exit_fail_msg(
+                       "%s test: succeeded to wait on invalid pidfd %s\n",
+                       test_name, strerror(errno));
+       close(pidfd);
+       pidfd = -1;
+
+       pid = sys_clone3(&args);
+       if (pid < 0)
+               ksft_exit_fail_msg("%s test: failed to create new process %s\n",
+                                  test_name, strerror(errno));
+
+       if (pid == 0)
+               exit(EXIT_SUCCESS);
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status))
+               ksft_exit_fail_msg(
+                       "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+       close(pidfd);
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_EXITED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ksft_test_result_pass("%s test: Passed\n", test_name);
+       return 0;
+}
+
+static int test_pidfd_wait_states(void)
+{
+       const char *test_name = "pidfd wait states";
+       int pidfd = -1, status = 0;
+       pid_t parent_tid = -1;
+       struct clone_args args = {
+               .parent_tid = ptr_to_u64(&parent_tid),
+               .pidfd = ptr_to_u64(&pidfd),
+               .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
+               .exit_signal = SIGCHLD,
+       };
+       int ret;
+       pid_t pid;
+       siginfo_t info = {
+               .si_signo = 0,
+       };
+
+       pid = sys_clone3(&args);
+       if (pid < 0)
+               ksft_exit_fail_msg("%s test: failed to create new process %s\n",
+                                  test_name, strerror(errno));
+
+       if (pid == 0) {
+               kill(getpid(), SIGSTOP);
+               kill(getpid(), SIGSTOP);
+               exit(EXIT_SUCCESS);
+       }
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_STOPPED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_CONTINUED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_STOPPED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_KILLED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       close(pidfd);
+
+       ksft_test_result_pass("%s test: Passed\n", test_name);
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       ksft_print_header();
+       ksft_set_plan(2);
+
+       test_pidfd_wait_simple();
+       test_pidfd_wait_states();
+
+       return ksft_exit_pass();
+}