Merge "msm: kgsl: Don't read stale crashdumper data"
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index d4a352b..18386ab 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -39,6 +39,8 @@
- System Trace Macrocell:
"arm,coresight-stm", "arm,primecell"; [1]
+ - Trigger Generation Unit:
+ "arm,primecell";
* reg: physical base address and length of the register
set(s) of the component.
@@ -86,6 +88,16 @@
* qcom,dummy-sink: Configure the device as sink.
+* Additional required property for coresight-tgu devices:
+ * tgu-steps: must be present. Indicates number of steps supported
+ by the TGU.
+ * tgu-conditions: must be present. Indicates the number of conditions
+ supported by the TGU.
+ * tgu-regs: must be present. Indicates the number of regs supported
+ by the TGU.
+ * tgu-timer-counters: must be present. Indicates the number of timers and
+ counters available in the TGU to do a comparision.
+
* Optional properties for all components:
* reg-names: names corresponding to each reg property value.
@@ -388,7 +400,7 @@
};
};
-4. CTIs
+5. CTIs
cti0: cti@6010000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x6010000 0x1000>;
@@ -400,5 +412,21 @@
clock-names = "apb_pclk";
};
+6. TGUs
+ ipcb_tgu: tgu@6b0c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b999>;
+ reg = <0x06B0C000 0x1000>;
+ reg-names = "tgu-base";
+ tgu-steps = <3>;
+ tgu-conditions = <4>;
+ tgu-regs = <4>;
+ tgu-timer-counters = <8>;
+
+ coresight-name = "coresight-tgu-ipcb";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
[1]. There is currently two version of STM: STM32 and STM500. Both
have the same HW interface and as such don't need an explicit binding name.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index bc82bdc..765b5e4 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -92,6 +92,12 @@
- SDM670
compatible = "qcom,sdm670"
+- QCS605
+ compatible = "qcom,qcs605"
+
+- SDA670
+ compatible = "qcom,sda670"
+
- MSM8952
compatible = "qcom,msm8952"
@@ -276,6 +282,10 @@
compatible = "qcom,sdm670-rumi"
compatible = "qcom,sdm670-cdp"
compatible = "qcom,sdm670-mtp"
+compatible = "qcom,qcs605-cdp"
+compatible = "qcom,qcs605-mtp"
+compatible = "qcom,sda670-cdp"
+compatible = "qcom,sda670-mtp"
compatible = "qcom,msm8952-rumi"
compatible = "qcom,msm8952-sim"
compatible = "qcom,msm8952-qrd"
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 2e233a1..b18d573 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -211,19 +211,22 @@
and pagetable walk.
- cache-slices: phandle to the system LLC driver, cache slice index.
+
+GPU coresight info:
The following properties are optional as collecting data via coresight might
not be supported for every chipset. The documentation for coresight
properties can be found in:
Documentation/devicetree/bindings/coresight/coresight.txt
-- coresight-id Unique integer identifier for the bus.
-- coresight-name Unique descriptive name of the bus.
-- coresight-nr-inports Number of input ports on the bus.
-- coresight-outports List of output port numbers on the bus.
-- coresight-child-list List of phandles pointing to the children of this
+- qcom,gpu-coresights: Container for sets of GPU coresight sources.
+- coresight-id: Unique integer identifier for the bus.
+- coresight-name: Unique descriptive name of the bus.
+- coresight-nr-inports: Number of input ports on the bus.
+- coresight-outports: List of output port numbers on the bus.
+- coresight-child-list: List of phandles pointing to the children of this
component.
-- coresight-child-ports List of input port numbers of the children.
-- coresight-atid The unique ATID value of the coresight device
+- coresight-child-ports: List of input port numbers of the children.
+- coresight-atid: The unique ATID value of the coresight device
Example of A330 GPU in MSM8916:
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 0f8dc27..8fcdd82 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -96,6 +96,10 @@
retention. No cache invalidation operations involving asid
may be used.
+- qcom,disable-atos:
+ Some hardware may not have full support for atos debugging
+ in tandem with other features like power collapse.
+
- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
disable in ms. In case of unmap call, regulator is
enabled/disabled. This may introduce additional delay. For
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index d61606a..f0549cb 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -7,9 +7,11 @@
- compatible : one of:
- "qcom,msm-vidc"
- "qcom,sdm845-vidc" : Invokes driver specific data for SDM845.
+ - "qcom,sdm670-vidc" : Invokes driver specific data for SDM670.
Optional properties:
- reg : offset and length of the register set for the device.
+- sku-index : sku version of the hardware.
- interrupts : should contain the vidc interrupt.
- qcom,reg-presets : list of offset-value pairs for registers to be written.
The offsets are from the base offset specified in 'reg'. This is mainly
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 24c75e2..d3098be 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -85,6 +85,7 @@
On certain chipsets, coming out of the CX Power Collapse event, the SDCC registers
contents will not be retained. It is software responsibility to restore the
SDCC registers before resuming to normal operation.
+ - qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 271703f..85b0fe9 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -67,6 +67,9 @@
service.
- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem.
- qcom,override-acc: Boolean- Present if we need to override the default ACC settings
+- qcom,mss_pdc_offset: Integer- Mandatory if PDC register is specified. It is
+ used to specify which bit in the PDC register
+ corresponds to the modem.
- qcom,ahb-clk-vote: Boolean- Present if we need to remove the vote for the mss_cfg_ahb
clock after the modem boots up
- qcom,pnoc-clk-vote: Boolean- Present if the modem needs the PNOC bus to be
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 4901fa0..c3e2cab 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -23,6 +23,8 @@
with "phys" attribute, provides phandle to UFS PHY node
- vdd-hba-supply : phandle to UFS host controller supply regulator node
- vcc-supply : phandle to VCC supply regulator node
+- vcc-voltage-level : specifies voltage levels for VCC supply.
+ Should be specified in pairs (min, max), units uV.
- vccq-supply : phandle to VCCQ supply regulator node
- vccq2-supply : phandle to VCCQ2 supply regulator node
- vcc-supply-1p8 : For embedded UFS devices, valid VCC range is 1.7-1.95V
diff --git a/Makefile b/Makefile
index 3849d63..a8d289a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 41
+SUBLEVEL = 48
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/alpha/include/asm/types.h b/arch/alpha/include/asm/types.h
index 4cb4b6d..0bc66e1 100644
--- a/arch/alpha/include/asm/types.h
+++ b/arch/alpha/include/asm/types.h
@@ -1,6 +1,6 @@
#ifndef _ALPHA_TYPES_H
#define _ALPHA_TYPES_H
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
#endif /* _ALPHA_TYPES_H */
diff --git a/arch/alpha/include/uapi/asm/types.h b/arch/alpha/include/uapi/asm/types.h
index 9fd3cd4..8d1024d 100644
--- a/arch/alpha/include/uapi/asm/types.h
+++ b/arch/alpha/include/uapi/asm/types.h
@@ -9,8 +9,18 @@
* need to be careful to avoid a name clashes.
*/
-#ifndef __KERNEL__
+/*
+ * This is here because we used to use l64 for alpha
+ * and we don't want to impact user mode with our change to ll64
+ * in the kernel.
+ *
+ * However, some user programs are fine with this. They can
+ * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here.
+ */
+#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__)
#include <asm-generic/int-l64.h>
+#else
+#include <asm-generic/int-ll64.h>
#endif
#endif /* _UAPI_ALPHA_TYPES_H */
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index b3410ff..4fd6272 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -89,7 +89,9 @@
#define ARC_REG_SLC_FLUSH 0x904
#define ARC_REG_SLC_INVALIDATE 0x905
#define ARC_REG_SLC_RGN_START 0x914
+#define ARC_REG_SLC_RGN_START1 0x915
#define ARC_REG_SLC_RGN_END 0x916
+#define ARC_REG_SLC_RGN_END1 0x917
/* Bit val in SLC_CONTROL */
#define SLC_CTRL_IM 0x040
diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c
index 8147583..bbdfeb3 100644
--- a/arch/arc/mm/cache.c
+++ b/arch/arc/mm/cache.c
@@ -562,6 +562,7 @@
static DEFINE_SPINLOCK(lock);
unsigned long flags;
unsigned int ctrl;
+ phys_addr_t end;
spin_lock_irqsave(&lock, flags);
@@ -591,8 +592,16 @@
* END needs to be setup before START (latter triggers the operation)
* END can't be same as START, so add (l2_line_sz - 1) to sz
*/
- write_aux_reg(ARC_REG_SLC_RGN_END, (paddr + sz + l2_line_sz - 1));
- write_aux_reg(ARC_REG_SLC_RGN_START, paddr);
+ end = paddr + sz + l2_line_sz - 1;
+ if (is_pae40_enabled())
+ write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end));
+
+ write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end));
+
+ if (is_pae40_enabled())
+ write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr));
+
+ write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr));
while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index 895fa6c..563901e 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -75,7 +75,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pca0_pins>;
interrupt-parent = <&gpio0>;
- interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
@@ -87,7 +87,7 @@
compatible = "nxp,pca9555";
pinctrl-names = "default";
interrupt-parent = <&gpio0>;
- interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
new file mode 100644
index 0000000..f9ad6f4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
@@ -0,0 +1,109 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+ qcom,smp2p-modem@17811008 {
+ compatible = "qcom,smp2p";
+ reg = <0x17811008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ /* ssr - inbound entry from mss */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 2ef277f..d538efe 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -34,6 +34,13 @@
reg = <0x8fd00000 0x300000>;
label = "peripheral2_mem";
};
+
+ mss_mem: mss_region@87800000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x87800000 0x8000000>;
+ label = "mss_mem";
+ };
};
cpus {
@@ -324,8 +331,134 @@
#interrupt-cells = <4>;
cell-index = <0>;
};
+
+ qcom,ipc-spinlock@1f40000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x1f40000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@8fe40000 {
+ compatible = "qcom,smem";
+ reg = <0x8fe40000 0xc0000>,
+ <0x17811008 0x4>,
+ <0x1fd4000 0x8>;
+ reg-names = "smem", "irq-reg-base",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+ };
+
+ qcom,glink-smem-native-xprt-modem@8fe40000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x8fe40000 0xc0000>,
+ <0x17811008 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x1000>;
+ interrupts = <GIC_SPI 111 IRQ_TYPE_EDGE_RISING>;
+ label = "mpss";
+ };
+
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "mpss";
+ qcom,glink-xprt = "smem";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ qcom,glink_pkt {
+ compatible = "qcom,glinkpkt";
+
+ qcom,glinkpkt-at-mdm0 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DS";
+ qcom,glinkpkt-dev-name = "at_mdm0";
+ };
+
+ qcom,glinkpkt-loopback_cntl {
+ qcom,glinkpkt-transport = "lloop";
+ qcom,glinkpkt-edge = "local";
+ qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT";
+ qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl";
+ };
+
+ qcom,glinkpkt-loopback_data {
+ qcom,glinkpkt-transport = "lloop";
+ qcom,glinkpkt-edge = "local";
+ qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT";
+ qcom,glinkpkt-dev-name = "glink_pkt_loopback";
+ };
+
+ qcom,glinkpkt-data40-cntl {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA40_CNTL";
+ qcom,glinkpkt-dev-name = "smdcntl8";
+ };
+
+ qcom,glinkpkt-data1 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA1";
+ qcom,glinkpkt-dev-name = "smd7";
+ };
+
+ qcom,glinkpkt-data4 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA4";
+ qcom,glinkpkt-dev-name = "smd8";
+ };
+
+ qcom,glinkpkt-data11 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA11";
+ qcom,glinkpkt-dev-name = "smd11";
+ };
+ };
+
+ pil_modem: qcom,mss@4080000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x4080000 0x100>;
+ interrupts = <0 250 1>;
+
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ vdd_cx-supply = <&pmxpoorwills_s5_level>;
+ qcom,proxy-reg-names = "vdd_cx";
+
+ qcom,pas-id = <0>;
+ qcom,smem-id = <421>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,firmware-name = "modem";
+ memory-region = <&mss_mem>;
+ status = "ok";
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ };
};
#include "pmxpoorwills.dtsi"
#include "sdxpoorwills-regulator.dtsi"
+#include "sdxpoorwills-smp2p.dtsi"
#include "sdxpoorwills-usb.dtsi"
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
index 5ea4915..10d3074 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
@@ -56,7 +56,7 @@
};
&pio {
- mmc2_pins_nrst: mmc2@0 {
+ mmc2_pins_nrst: mmc2-rst-pin {
allwinner,pins = "PC16";
allwinner,function = "gpio_out";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
diff --git a/arch/arm/boot/dts/tango4-vantage-1172.dts b/arch/arm/boot/dts/tango4-vantage-1172.dts
index 4cab64c..e3a51e3 100644
--- a/arch/arm/boot/dts/tango4-vantage-1172.dts
+++ b/arch/arm/boot/dts/tango4-vantage-1172.dts
@@ -21,7 +21,7 @@
};
ð0 {
- phy-connection-type = "rgmii";
+ phy-connection-type = "rgmii-id";
phy-handle = <ð0_phy>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index ff8a523..1826b6f 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -195,6 +195,7 @@
CONFIG_INPUT_GPIO=m
CONFIG_SERIO_LIBPS2=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
@@ -276,13 +277,19 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_USB_BAM=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
CONFIG_TRACER_PKT=y
CONFIG_MSM_SMP2P=y
CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 6965607..ce61464 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -189,9 +189,11 @@
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -203,6 +205,7 @@
CONFIG_POWER_SUPPLY=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS=y
+CONFIG_MFD_SYSCON=y
CONFIG_MSM_CDC_PINCTRL=y
CONFIG_MSM_CDC_SUPPLY=y
CONFIG_REGULATOR=y
@@ -260,6 +263,7 @@
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_RTC_CLASS=y
CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
CONFIG_UIO=y
CONFIG_STAGING=y
CONFIG_GSI=y
@@ -270,13 +274,20 @@
CONFIG_IPA_UT=y
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
-CONFIG_HWSPINLOCK_QCOM=y
-CONFIG_QCOM_SMEM=y
-CONFIG_QCOM_SMD=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index bfe2a2f..22b7311 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -54,6 +54,24 @@
#define ftrace_return_address(n) return_address(n)
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+
+static inline bool arch_syscall_match_sym_name(const char *sym,
+ const char *name)
+{
+ if (!strcmp(sym, "sys_mmap2"))
+ sym = "sys_mmap_pgoff";
+ else if (!strcmp(sym, "sys_statfs64_wrapper"))
+ sym = "sys_statfs64";
+ else if (!strcmp(sym, "sys_fstatfs64_wrapper"))
+ sym = "sys_fstatfs64";
+ else if (!strcmp(sym, "sys_arm_fadvise64_64"))
+ sym = "sys_fadvise64_64";
+
+ /* Ignore case since sym may start with "SyS" instead of "sys" */
+ return !strcasecmp(sym, name);
+}
+
#endif /* ifndef __ASSEMBLY__ */
#endif /* _ASM_ARM_FTRACE */
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 332ce3b..2206e0e 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -829,22 +829,22 @@
* Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
* underlying level-2 and level-3 tables before freeing the actual level-1 table
* and setting the struct pointer to NULL.
- *
- * Note we don't need locking here as this is only called when the VM is
- * destroyed, which can only be done once.
*/
void kvm_free_stage2_pgd(struct kvm *kvm)
{
- if (kvm->arch.pgd == NULL)
- return;
+ void *pgd = NULL;
spin_lock(&kvm->mmu_lock);
- unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+ if (kvm->arch.pgd) {
+ unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+ pgd = READ_ONCE(kvm->arch.pgd);
+ kvm->arch.pgd = NULL;
+ }
spin_unlock(&kvm->mmu_lock);
/* Free the HW pgd, one page at a time */
- free_pages_exact(kvm->arch.pgd, S2_PGD_SIZE);
- kvm->arch.pgd = NULL;
+ if (pgd)
+ free_pages_exact(pgd, S2_PGD_SIZE);
}
static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
@@ -1664,12 +1664,16 @@
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
{
+ if (!kvm->arch.pgd)
+ return 0;
trace_kvm_age_hva(start, end);
return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
}
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
{
+ if (!kvm->arch.pgd)
+ return 0;
trace_kvm_test_age_hva(hva);
return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL);
}
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index f96fba6..e1454fb 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -139,6 +139,15 @@
This enables support for the SDM670 chipset. If you do not
wish to build a kernel that runs on this chipset, say 'N' here.
+config ARCH_MSM8953
+ bool "Enable Support for Qualcomm Technologies Inc. MSM8953"
+ depends on ARCH_QCOM
+ select COMMON_CLK_QCOM
+ select QCOM_GDSC
+ help
+ This enables support for the MSM8953 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
config ARCH_ROCKCHIP
bool "Rockchip Platforms"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 954738a..276e09c 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -28,9 +28,7 @@
sda845-v2-qrd-overlay.dtbo \
sda845-v2-4k-panel-mtp-overlay.dtbo \
sda845-v2-4k-panel-cdp-overlay.dtbo \
- sda845-v2-4k-panel-qrd-overlay.dtbo \
- sdm845-interposer-sdm670-cdp-overlay.dtbo \
- sdm845-interposer-sdm670-mtp-overlay.dtbo
+ sda845-v2-4k-panel-qrd-overlay.dtbo
sdm845-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
@@ -58,8 +56,6 @@
sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
-sdm845-interposer-sdm670-cdp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
-sdm845-interposer-sdm670-mtp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
@@ -84,19 +80,77 @@
sdm670-mtp-overlay.dtbo \
sdm670-rumi-overlay.dtbo \
sdm670-pm660a-cdp-overlay.dtbo \
- sdm670-pm660a-mtp-overlay.dtbo
+ sdm670-pm660a-mtp-overlay.dtbo \
+ sdm670-external-codec-cdp-overlay.dtbo \
+ sdm670-external-codec-mtp-overlay.dtbo \
+ sdm670-external-codec-pm660a-cdp-overlay.dtbo \
+ sdm670-external-codec-pm660a-mtp-overlay.dtbo \
+ sdm670-usbc-cdp-overlay.dtbo \
+ sdm670-usbc-mtp-overlay.dtbo \
+ sdm670-usbc-pm660a-cdp-overlay.dtbo \
+ sdm670-usbc-pm660a-mtp-overlay.dtbo \
+ sdm670-usbc-external-codec-cdp-overlay.dtbo \
+ sdm670-usbc-external-codec-mtp-overlay.dtbo \
+ sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo \
+ sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo \
+ sda670-cdp-overlay.dtbo \
+ sda670-mtp-overlay.dtbo \
+ sda670-pm660a-cdp-overlay.dtbo \
+ sda670-pm660a-mtp-overlay.dtbo \
+ qcs605-cdp-overlay.dtbo \
+ qcs605-mtp-overlay.dtbo \
+ qcs605-external-codec-mtp-overlay.dtbo
sdm670-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-mtp-overlay.dtbo-base := sdm670.dtb
sdm670-rumi-overlay.dtbo-base := sdm670.dtb
sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sda670-cdp-overlay.dtbo-base := sda670.dtb
+sda670-mtp-overlay.dtbo-base := sda670.dtb
+sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb
+sda670-pm660a-mtp-overlay.dtbo-base := sda670.dtb
+qcs605-cdp-overlay.dtbo-base := qcs605.dtb
+qcs605-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
+
else
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
sdm670-mtp.dtb \
sdm670-cdp.dtb \
sdm670-pm660a-mtp.dtb \
- sdm670-pm660a-cdp.dtb
+ sdm670-pm660a-cdp.dtb \
+ sdm670-external-codec-cdp.dtb \
+ sdm670-external-codec-mtp.dtb \
+ sdm670-external-codec-pm660a-cdp.dtb \
+ sdm670-external-codec-pm660a-mtp.dtb \
+ sdm670-usbc-cdp.dtb \
+ sdm670-usbc-external-codec-cdp.dtb \
+ sdm670-usbc-external-codec-mtp.dtb \
+ sdm670-usbc-external-codec-pm660a-cdp.dtb \
+ sdm670-usbc-external-codec-pm660a-mtp.dtb \
+ sdm670-usbc-mtp.dtb \
+ sdm670-usbc-pm660a-cdp.dtb \
+ sdm670-usbc-pm660a-mtp.dtb \
+ sda670-mtp.dtb \
+ sda670-cdp.dtb \
+ sda670-pm660a-mtp.dtb \
+ sda670-pm660a-cdp.dtb \
+ qcs605-mtp.dtb \
+ qcs605-cdp.dtb \
+ qcs605-external-codec-mtp.dtb
endif
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index 0d0e7f7..c83fd87 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -29,7 +29,6 @@
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
- qcom,cmd-sync-wait-broadcast;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>;
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 5de0e44..2156a5d 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -21,6 +21,7 @@
#iommu-cells = <1>;
qcom,dynamic;
qcom,use-3-lvl-tables;
+ qcom,disable-atos;
#global-interrupts = <2>;
qcom,regulator-names = "vdd";
vdd-supply = <&gpu_cx_gdsc>;
@@ -62,6 +63,7 @@
qcom,skip-init;
qcom,use-3-lvl-tables;
qcom,no-asid-retention;
+ qcom,disable-atos;
#global-interrupts = <1>;
#size-cells = <1>;
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 48d68a7..1fdb3f6 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -12,6 +12,7 @@
#include <dt-bindings/spmi/spmi.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
&spmi_bus {
pm660_0: qcom,pm660@0 {
@@ -58,13 +59,14 @@
};
};
- qcom,temp-alarm@2400 {
+ pm660_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm660_tz";
qcom,channel-num = <6>;
qcom,temp_alarm-vadc = <&pm660_vadc>;
+ #thermal-sensor-cells = <0>;
};
pm660_gpios: pinctrl@c000 {
@@ -249,6 +251,8 @@
compatible = "qcom,qpnp-pdphy";
reg = <0x1700 0x100>;
vdd-pdphy-supply = <&pm660l_l7>;
+ vbus-supply = <0>;
+ vconn-supply = <0>;
interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
@@ -349,27 +353,23 @@
};
};
- pm660_rradc: rradc@4500 {
- compatible = "qcom,rradc";
- reg = <0x4500 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- #io-channel-cells = <1>;
- qcom,pmic-revid = <&pm660_revid>;
- };
-
- bcl@4200 {
+ bcl_sensor: bcl@4200 {
compatible = "qcom,msm-bcl-lmh";
reg = <0x4200 0xff>,
<0x4300 0xff>;
reg-names = "fg_user_adc",
"fg_lmh";
interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>,
- <0x0 0x42 0x2 IRQ_TYPE_NONE>;
- interrupt-names = "bcl-high-ibat-int",
- "bcl-low-vbat-int";
- qcom,vbat-polling-delay-ms = <100>;
- qcom,ibat-polling-delay-ms = <100>;
+ <0x0 0x42 0x1 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x2 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x3 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x4 IRQ_TYPE_NONE>;
+ interrupt-names = "bcl-high-ibat",
+ "bcl-very-high-ibat",
+ "bcl-low-vbat",
+ "bcl-very-low-vbat",
+ "bcl-crit-low-vbat";
+ #thermal-sensor-cells = <1>;
};
};
@@ -456,4 +456,243 @@
};
};
};
+
+ ibat-high {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 0>;
+
+ trips {
+ ibat-high {
+ temperature = <4200>;
+ hysteresis = <200>;
+ type = "passive";
+ };
+ };
+ };
+
+ ibat-vhigh {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 1>;
+
+ trips {
+ ibat-vhigh {
+ temperature = <4300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+
+ vbat_adc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 2>;
+ tracks-low;
+
+ trips {
+ pm660_vbat_adc: vbat-adc {
+ temperature = <3300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ vbat_map6 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map7 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ vbat_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 3>;
+ tracks-low;
+
+ trips {
+ vbat-low {
+ temperature = <3100>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ vbat_too_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 4>;
+ tracks-low;
+
+ trips {
+ vbat-too-low {
+ temperature = <2900>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ soc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 5>;
+ tracks-low;
+
+ trips {
+ pm660_low_soc: low-soc {
+ temperature = <10>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ soc_map6 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map7 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ pm660_temp_alarm: pm660_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pm660_tz>;
+
+ trips {
+ pm660_trip0: pm660-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660_trip1: pm660-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660_trip2: pm660-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ cooling-maps {
+ trip0_cpu0 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU0 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu1 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU1 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu2 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU2 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu3 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU3 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu4 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU4 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu5 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU5 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu6 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU6 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu7 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU7 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip1_cpu1 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu2 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu3 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu4 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu5 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu6 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu7 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
new file mode 100644
index 0000000..fe7a027
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L CDP";
+ compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp";
+ qcom,msm-id = <347 0x0>;
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
new file mode 100644
index 0000000..7b38a58
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "qcs605.dtsi"
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L CDP";
+ compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..1f439ae
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,msm-id = <347 0x0>;
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
new file mode 100644
index 0000000..abc3f2d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "qcs605.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts
new file mode 100644
index 0000000..7327440
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,msm-id = <347 0x0>;
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-mtp.dts
new file mode 100644
index 0000000..bc7b376
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-mtp.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "qcs605.dtsi"
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dts b/arch/arm64/boot/dts/qcom/qcs605.dts
new file mode 100644
index 0000000..28c417f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "qcs605.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 SoC";
+ compatible = "qcom,qcs605";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
new file mode 100644
index 0000000..12da650
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sda670.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605";
+ qcom,msm-id = <347 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts
new file mode 100644
index 0000000..141ed59
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L CDP";
+ compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp";
+ qcom,msm-id = <337 0x0>;
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-cdp.dts b/arch/arm64/boot/dts/qcom/sda670-cdp.dts
new file mode 100644
index 0000000..fcb340e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-cdp.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda670.dtsi"
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L CDP";
+ compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts
new file mode 100644
index 0000000..af8e8f1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L MTP";
+ compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp";
+ qcom,msm-id = <337 0x0>;
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-mtp.dts b/arch/arm64/boot/dts/qcom/sda670-mtp.dts
new file mode 100644
index 0000000..2123b44
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-mtp.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda670.dtsi"
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L MTP";
+ compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..3e1365d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A CDP";
+ compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp";
+ qcom,msm-id = <337 0x0>;
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts
new file mode 100644
index 0000000..6cbf224
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A CDP";
+ compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..9855b11
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A MTP";
+ compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp";
+ qcom,msm-id = <337 0x0>;
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts
new file mode 100644
index 0000000..ffb6aa3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A MTP";
+ compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670.dts b/arch/arm64/boot/dts/qcom/sda670.dts
new file mode 100644
index 0000000..8852e30
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sda670.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670 SoC";
+ compatible = "qcom,sda670";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda670.dtsi b/arch/arm64/boot/dts/qcom/sda670.dtsi
new file mode 100644
index 0000000..d19aac3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda670.dtsi
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm670.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA670";
+ qcom,msm-id = <337 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 4bc99a0..00f454c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -94,3 +94,38 @@
status = "ok";
};
+
+&pm660_charger {
+ qcom,batteryless-platform;
+};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&tlmm 91 0>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&tlmm 92 0>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 16efb4c..6cbfb57 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -400,15 +400,6 @@
};
port@4 {
- reg = <5>;
- tpda_in_funnel_lpass: endpoint {
- slave-mode;
- remote-endpoint =
- <&funnel_lpass_out_tpda>;
- };
- };
-
- port@5 {
reg = <6>;
tpda_in_funnel_turing: endpoint {
slave-mode;
@@ -417,7 +408,7 @@
};
};
- port@6 {
+ port@5 {
reg = <7>;
tpda_in_tpdm_vsense: endpoint {
slave-mode;
@@ -426,7 +417,7 @@
};
};
- port@7 {
+ port@6 {
reg = <10>;
tpda_in_tpdm_qm: endpoint {
slave-mode;
@@ -435,7 +426,7 @@
};
};
- port@8 {
+ port@7 {
reg = <11>;
tpda_in_tpdm_north: endpoint {
slave-mode;
@@ -444,7 +435,7 @@
};
};
- port@9 {
+ port@8 {
reg = <13>;
tpda_in_tpdm_pimem: endpoint {
slave-mode;
@@ -545,67 +536,6 @@
};
};
- funnel_lpass: funnel@6845000 {
- compatible = "arm,primecell";
- arm,primecell-periphid = <0x0003b908>;
-
- reg = <0x6845000 0x1000>;
- reg-names = "funnel-base";
-
- coresight-name = "coresight-funnel-lpass";
-
- clocks = <&clock_aop QDSS_CLK>;
- clock-names = "apb_pclk";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- funnel_lpass_out_tpda: endpoint {
- remote-endpoint =
- <&tpda_in_funnel_lpass>;
- };
- };
-
- port@1 {
- reg = <0>;
- funnel_lpass_in_tpdm_lpass: endpoint {
- slave-mode;
- remote-endpoint =
- <&tpdm_lpass_out_funnel_lpass>;
- };
- };
-
- port@2 {
- reg = <1>;
- funnel_lpass_in_audio_etm0: endpoint {
- slave-mode;
- remote-endpoint =
- <&audio_etm0_out_funnel_lpass>;
- };
- };
- };
- };
-
- tpdm_lpass: tpdm@6844000 {
- compatible = "arm,primecell";
- reg = <0x6844000 0x1000>;
- reg-names = "tpdm-base";
-
- coresight-name = "coresight-tpdm-lpass";
-
- clocks = <&clock_aop QDSS_CLK>;
- clock-names = "apb_pclk";
-
- port {
- tpdm_lpass_out_funnel_lpass: endpoint {
- remote-endpoint = <&funnel_lpass_in_tpdm_lpass>;
- };
- };
- };
-
tpdm_center: tpdm@6c28000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b968>;
@@ -1652,19 +1582,6 @@
};
};
- audio_etm0 {
- compatible = "qcom,coresight-remote-etm";
-
- coresight-name = "coresight-audio-etm0";
- qcom,inst-id = <5>;
-
- port {
- audio_etm0_out_funnel_lpass: endpoint {
- remote-endpoint = <&funnel_lpass_in_audio_etm0>;
- };
- };
- };
-
funnel_apss_merg: funnel@7810000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
new file mode 100644
index 0000000..32a8580
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
new file mode 100644
index 0000000..6a87d3a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..970209ca
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
new file mode 100644
index 0000000..87ac190
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..48a6066
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
@@ -0,0 +1,35 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
new file mode 100644
index 0000000..e64d13b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..8715ddc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
new file mode 100644
index 0000000..0beaddb3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
new file mode 100644
index 0000000..6ea92ee
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
@@ -0,0 +1,11 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 4bc99a0..320a1f2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -94,3 +94,47 @@
status = "ok";
};
+
+&vendor {
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-itech-3000mah.dtsi"
+ #include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+ #include "fg-gen3-batterydata-demo-6000mah.dtsi"
+ };
+};
+
+&pm660_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&tlmm 91 0>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&tlmm 92 0>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index a080db4..2a2b6d8 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1451,5 +1451,27 @@
};
};
};
+
+ /* Pinctrl setting for CAMERA GPIO key */
+ key_cam_snapshot {
+ key_cam_snapshot_default: key_cam_snapshot_default {
+ pins = "gpio91";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ key_cam_focus {
+ key_cam_focus_default: key_cam_focus_default {
+ pins = "gpio92";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 24d92eb..aa6be24 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -156,6 +156,15 @@
};
};
+ pm660_rradc: rradc@4500 {
+ compatible = "qcom,rradc";
+ reg = <0x4500 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ qcom,pmic-revid = <&pm660_revid>;
+ };
+
pm660_fg: qpnp,fg {
compatible = "qcom,fg-gen3";
#address-cells = <1>;
@@ -366,3 +375,7 @@
vbus-supply = <&smb2_vbus>;
vconn-supply = <&smb2_vconn>;
};
+
+&usb0 {
+ extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 23792b1..24b8dd6 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -642,4 +642,14 @@
qcom,init-voltage = <3312000>;
};
};
+
+ refgen: refgen-regulator@ff1000 {
+ compatible = "qcom,refgen-regulator";
+ reg = <0xff1000 0x60>;
+ regulator-name = "refgen";
+ regulator-enable-ramp-delay = <5>;
+ proxy-supply = <&refgen>;
+ qcom,proxy-consumer-enable;
+ regulator-always-on;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index bd35cf2..6a69e29 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -17,10 +17,19 @@
/delete-node/ ssusb@a800000;
/delete-node/ qusb@88e3000;
/delete-node/ ssphy@88eb000;
+ /delete-node/ usb_audio_qmi_dev;
+ usb_audio_qmi_dev {
+ compatible = "qcom,usb-audio-qmi-dev";
+ iommus = <&apps_smmu 0x180f 0x0>;
+ qcom,usb-audio-stream-id = <0xf>;
+ qcom,usb-audio-intr-num = <2>;
+ };
};
&usb0 {
- extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+ /delete-property/ iommus;
+ /delete-property/ qcom,smmu-s1-bypass;
+ extcon = <0>, <0>, <0> /* <&eud> */;
};
&qusb_phy0 {
@@ -30,6 +39,6 @@
};
&usb_qmp_dp_phy {
- vdd-supply = <&pm660_l1>;
- core-supply = <&pm660l_l1>;
+ vdd-supply = <&pm660l_l1>; /* 0.88v */
+ core-supply = <&pm660_l1>; /* 1.2v */
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
new file mode 100644
index 0000000..190b32f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
new file mode 100644
index 0000000..45ff83f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
new file mode 100644
index 0000000..226c2ae
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
new file mode 100644
index 0000000..8928f80
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..78d1dfa
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
new file mode 100644
index 0000000..5628e92
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..c1891a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
@@ -0,0 +1,35 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
new file mode 100644
index 0000000..c059113
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..c54e299
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
new file mode 100644
index 0000000..d09b5e5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
new file mode 100644
index 0000000..d8c4102
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
@@ -0,0 +1,32 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
new file mode 100644
index 0000000..b9bb3ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..95df620
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
new file mode 100644
index 0000000..5e33308
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..226a46b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
new file mode 100644
index 0000000..ca99736
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
new file mode 100644
index 0000000..a74f9d8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
@@ -0,0 +1,214 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/clock/qcom,videocc-sdm845.h>
+
+&soc {
+ msm_vidc0: qcom,vidc0 {
+ compatible = "qcom,msm-vidc", "qcom,sdm670-vidc";
+ status = "ok";
+ sku-index = <0>;
+ reg = <0xaa00000 0x200000>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* Supply */
+ venus-supply = <&venus_gdsc>;
+ venus-core0-supply = <&vcodec0_gdsc>;
+ venus-core1-supply = <&vcodec1_gdsc>;
+
+ /* Clocks */
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "core0_clk", "core0_bus_clk",
+ "core1_clk", "core1_bus_clk";
+ clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC1_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC1_AXI_CLK>;
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "core0_clk", "core0_bus_clk",
+ "core1_clk", "core1_bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
+ qcom,allowed-clock-rates = <100000000 200000000 320000000
+ 380000000 444000000 533000000>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "msm-vidc-ddr";
+ qcom,bus-range-kbps = <1000 3388000>;
+ };
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&apps_smmu 0x10a0 0x8>,
+ <&apps_smmu 0x10b0 0x0>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x6f800000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus =
+ <&apps_smmu 0x10a1 0x8>,
+ <&apps_smmu 0x10a5 0x8>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus =
+ <&apps_smmu 0x10a3 0x8>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus =
+ <&apps_smmu 0x10a4 0x8>,
+ <&apps_smmu 0x10b4 0x0>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+
+ msm_vidc1: qcom,vidc1 {
+ compatible = "qcom,msm-vidc", "qcom,sdm670-vidc";
+ status = "ok";
+ sku-index = <1>;
+ reg = <0xaa00000 0x200000>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* Supply */
+ venus-supply = <&venus_gdsc>;
+ venus-core0-supply = <&vcodec0_gdsc>;
+
+ /* Clocks */
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "core0_clk", "core0_bus_clk";
+ clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>;
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "core0_clk", "core0_bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>;
+ qcom,allowed-clock-rates = <100000000 200000000 320000000
+ 364800000>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "msm-vidc-ddr";
+ qcom,bus-range-kbps = <1000 2128000>;
+ };
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&apps_smmu 0x10a0 0x8>,
+ <&apps_smmu 0x10b0 0x0>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x6f800000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus =
+ <&apps_smmu 0x10a1 0x8>,
+ <&apps_smmu 0x10a5 0x8>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus =
+ <&apps_smmu 0x10a3 0x8>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus =
+ <&apps_smmu 0x10a4 0x8>,
+ <&apps_smmu 0x10b4 0x0>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 9d58b9d..02f0a58 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -53,6 +53,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_0>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_0: l2-cache {
@@ -88,6 +89,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_100>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_100: l2-cache {
@@ -118,6 +120,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_200>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_200: l2-cache {
@@ -148,6 +151,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_300>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_300: l2-cache {
@@ -178,6 +182,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_400>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_400: l2-cache {
@@ -208,6 +213,7 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_500>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
qcom,lmh-dcvs = <&lmh_dcvs0>;
#cooling-cells = <2>;
L2_500: l2-cache {
@@ -238,6 +244,7 @@
cache-size = <0x10000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_600>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
qcom,lmh-dcvs = <&lmh_dcvs1>;
#cooling-cells = <2>;
L2_600: l2-cache {
@@ -268,6 +275,7 @@
cache-size = <0x10000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_700>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
qcom,lmh-dcvs = <&lmh_dcvs1>;
#cooling-cells = <2>;
L2_700: l2-cache {
@@ -327,6 +335,129 @@
};
};
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 300000 14
+ 403200 18
+ 480000 21
+ 576000 25
+ 652800 27
+ 748800 31
+ 825600 40
+ 902400 43
+ 979200 46
+ 1056000 50
+ 1132800 53
+ 1228800 57
+ 1324800 84
+ 1420800 90
+ 1516800 96
+ 1612800 114
+ 1689600 135
+ 1766400 141
+ >;
+ idle-cost-data = <
+ 12 10 8 6
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 300000 256
+ 403200 271
+ 480000 282
+ 576000 296
+ 652800 307
+ 748800 321
+ 825600 332
+ 902400 369
+ 979200 382
+ 1056000 395
+ 1132800 408
+ 1209600 421
+ 1286400 434
+ 1363200 448
+ 1459200 567
+ 1536000 586
+ 1612800 604
+ 1689600 622
+ 1766400 641
+ 1843200 659
+ 1920000 678
+ 1996800 696
+ 2092800 876
+ 2169600 900
+ 2246400 924
+ 2323200 948
+ 2400000 1170
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 300000 5
+ 403200 7
+ 480000 7
+ 576000 7
+ 652800 8
+ 748800 8
+ 825600 9
+ 902400 9
+ 979200 9
+ 1056000 10
+ 1132800 10
+ 1228800 10
+ 1324800 13
+ 1420800 14
+ 1516800 15
+ 1612800 16
+ 1689600 19
+ 1766400 19
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 300000 25
+ 403200 27
+ 480000 28
+ 576000 29
+ 652800 30
+ 748800 32
+ 825600 33
+ 902400 36
+ 979200 38
+ 1056000 39
+ 1132800 40
+ 1209600 42
+ 1286400 43
+ 1363200 44
+ 1459200 56
+ 1536000 58
+ 1612800 60
+ 1689600 62
+ 1766400 64
+ 1843200 65
+ 1920000 67
+ 1996800 69
+ 2092800 87
+ 2169600 90
+ 2246400 92
+ 2323200 94
+ 2400000 117
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
+
psci {
compatible = "arm,psci-1.0";
method = "smc";
@@ -455,6 +586,12 @@
size = <0 0x5c00000>;
};
+ dump_mem: mem_dump_region {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x2400000>;
+ };
+
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
@@ -474,6 +611,9 @@
#include "sdm670-qupv3.dtsi"
#include "sdm670-coresight.dtsi"
+
+#include "sdm670-vidc.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -506,6 +646,14 @@
qcom,pipe-attr-ee;
};
+ qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clock-frequency = <25000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&tlmm 122 0>;
+ };
+
thermal_zones: thermal-zones {};
tsens0: tsens@c222000 {
@@ -693,7 +841,7 @@
};
clock_aop: qcom,aopclk {
- compatible = "qcom,aop-qmp-clk-v2";
+ compatible = "qcom,aop-qmp-clk-v1";
#clock-cells = <1>;
mboxes = <&qmp_aop 0>;
mbox-names = "qdss_clk";
@@ -934,6 +1082,61 @@
};
};
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xec>;
+ };
+
+ rpm_sw_dump {
+ qcom,dump-size = <0x28000>;
+ qcom,dump-id = <0xea>;
+ };
+
+ pmic_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xe4>;
+ };
+
+ tmc_etf_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xf0>;
+ };
+
+ tmc_etf_swao_dump {
+ qcom,dump-size = <0x8400>;
+ qcom,dump-id = <0xf1>;
+ };
+
+ tmc_etr_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x100>;
+ };
+
+ tmc_etf_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x101>;
+ };
+
+ tmc_etf_swao_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x102>;
+ };
+
+ misc_data_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0xe8>;
+ };
+
+ power_regs_data_dump {
+ qcom,dump-size = <0x100000>;
+ qcom,dump-id = <0xed>;
+ };
+ };
+
kryo3xx-erp {
compatible = "arm,arm64-kryo3xx-cpu-erp";
interrupts = <1 6 4>,
@@ -1196,6 +1399,15 @@
interrupts = <0 17 0>;
};
+ eud: qcom,msm-eud@88e0000 {
+ compatible = "qcom,msm-eud";
+ interrupt-names = "eud_irq";
+ interrupts = <GIC_SPI 492 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x88e0000 0x2000>;
+ reg-names = "eud_base";
+ status = "disabled";
+ };
+
qcom,llcc@1100000 {
compatible = "qcom,llcc-core", "syscon", "simple-mfd";
reg = <0x1100000 0x250000>;
@@ -1424,6 +1636,13 @@
status = "ok";
};
+ qcom,rmtfs_sharedmem@0 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0 0x200000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
qcom,rmnet-ipa {
compatible = "qcom,rmnet-ipa3";
qcom,rmnet-ipa-ssr;
@@ -1464,17 +1683,17 @@
<90 512 80000 640000>,
<90 585 80000 640000>,
<1 676 80000 80000>,
- <143 777 0 150000>,
+ <143 777 0 150>, /* IB defined for IPA clk in MHz*/
/* NOMINAL */
<90 512 206000 960000>,
<90 585 206000 960000>,
<1 676 206000 160000>,
- <143 777 0 300000>,
+ <143 777 0 300>, /* IB defined for IPA clk in MHz*/
/* TURBO */
<90 512 206000 3600000>,
<90 585 206000 3600000>,
<1 676 206000 300000>,
- <143 777 0 355333>;
+ <143 777 0 355>; /* IB defined for IPA clk in MHz*/
qcom,bus-vector-names = "MIN", "SVS", "NOMINAL", "TURBO";
/* IPA RAM mmap */
@@ -1629,6 +1848,7 @@
qcom,ssctl-instance-id = <0x12>;
qcom,override-acc;
qcom,qdsp6v65-1-0;
+ qcom,mss_pdc_offset = <8>;
status = "ok";
memory-region = <&pil_modem_mem>;
qcom,mem-protect-id = <0xF>;
@@ -1839,6 +2059,235 @@
dma-coherent;
};
};
+
+ qcom,icnss@18800000 {
+ status = "disabled";
+ compatible = "qcom,icnss";
+ reg = <0x18800000 0x800000>;
+ interrupts = <0 414 0 /* CE0 */ >,
+ <0 415 0 /* CE1 */ >,
+ <0 416 0 /* CE2 */ >,
+ <0 417 0 /* CE3 */ >,
+ <0 418 0 /* CE4 */ >,
+ <0 419 0 /* CE5 */ >,
+ <0 420 0 /* CE6 */ >,
+ <0 421 0 /* CE7 */ >,
+ <0 422 0 /* CE8 */ >,
+ <0 423 0 /* CE9 */ >,
+ <0 424 0 /* CE10 */ >,
+ <0 425 0 /* CE11 */ >;
+ qcom,wlan-msa-memory = <0x100000>;
+ qcom,smmu-s1-bypass;
+ };
+
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "performance";
+ qcom,src-dst-ports =
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 1144 /* 150 MHz */ >,
+ < 2288 /* 300 MHz */ >,
+ < 3555 /* 466 MHz */ >,
+ < 4577 /* 600 MHz */ >,
+ < 6149 /* 806 MHz */ >,
+ < 7118 /* 933 MHz */ >;
+ };
+
+ bwmon: qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon4";
+ reg = <0x1436400 0x300>, <0x1436300 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 581 4>;
+ qcom,mport = <0>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ llccbw: qcom,llccbw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports =
+ <MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ llcc_bwmon: qcom,llcc-bwmon {
+ compatible = "qcom,bimc-bwmon5";
+ reg = <0x0114a000 0x1000>;
+ reg-names = "base";
+ interrupts = <GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&llccbw>;
+ qcom,count-unit = <0x200000>;
+ qcom,byte-mid-mask = <0xe000>;
+ qcom,byte-mid-match = <0xe000>;
+ };
+
+ memlat_cpu0: qcom,memlat-cpu0 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ memlat_cpu4: qcom,memlat-cpu4 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ status = "ok";
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq_memlat_0: qcom,cpu0-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&memlat_cpu0>;
+ qcom,cachemiss-ev = <0x24>;
+ qcom,core-dev-table =
+ < 748800 1144 >,
+ < 998400 1720 >,
+ < 1209600 2086 >,
+ < 1497600 2929 >,
+ < 1728000 3879 >;
+ };
+
+ devfreq_memlat_4: qcom,cpu4-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&memlat_cpu4>;
+ qcom,cachemiss-ev = <0x24>;
+ qcom,core-dev-table =
+ < 787200 1144 >,
+ < 1113600 2086 >,
+ < 1344000 3879 >,
+ < 1900800 5931 >,
+ < 2438400 6881 >;
+ };
+
+ l3_cpu0: qcom,l3-cpu0 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
+ governor = "performance";
+ };
+
+ l3_cpu4: qcom,l3-cpu4 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
+ governor = "performance";
+ };
+
+ devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&l3_cpu0>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 748800 566400000 >,
+ < 998400 787200000 >,
+ < 1209660 940800000 >,
+ < 1497600 1190400000 >,
+ < 1612800 1382400000 >,
+ < 1728000 1440000000 >;
+ };
+
+ devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&l3_cpu4>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 1113600 566400000 >,
+ < 1344000 787200000 >,
+ < 1728000 940800000 >,
+ < 1900800 1190400000 >,
+ < 2438400 1440000000 >;
+ };
+
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 748800 1144 >,
+ < 1209600 1720 >,
+ < 1612000 2086 >,
+ < 1728000 2929 >;
+ cpu-to-dev-map-4 =
+ < 1113600 1144 >,
+ < 1344000 2086 >,
+ < 1728000 2929 >,
+ < 1900800 3879 >,
+ < 2438400 6881 >;
+ };
+ };
+
+ gpu_gx_domain_addr: syscon@0x5091508 {
+ compatible = "syscon";
+ reg = <0x5091508 0x4>;
+ };
+
+ gpu_gx_sw_reset: syscon@0x5091008 {
+ compatible = "syscon";
+ reg = <0x5091008 0x4>;
+ };
};
#include "sdm670-pinctrl.dtsi"
@@ -1915,6 +2364,9 @@
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&pm660l_s2_level>;
+ domain-addr = <&gpu_gx_domain_addr>;
+ sw-reset = <&gpu_gx_sw_reset>;
+ qcom,reset-aon-logic;
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
index 9bd1d54..cb11a9e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
@@ -175,7 +175,7 @@
compatible = "qcom,wcd-spi-v2";
qcom,master-bus-num = <0>;
qcom,chip-select = <0>;
- qcom,max-frequency = <9600000>;
+ qcom,max-frequency = <24000000>;
qcom,mem-base-addr = <0x100000>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 646dbad..cf7ccae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -903,7 +903,7 @@
qcom,bus-dev = <&fab_mem_noc>;
qcom,bcms = <&bcm_sh3>;
qcom,ap-owned;
- qcom,prio = <6>;
+ qcom,prio = <7>;
};
mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index dddf1fb..fe19658 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -110,6 +110,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -146,6 +147,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 3cfcddb..568213b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -522,6 +522,58 @@
};
};
+ port@5 {
+ reg = <6>;
+ funnel_in2_in_funnel_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_gfx_out_funnel_in2>;
+ };
+ };
+ };
+ };
+
+ funnel_gfx: funnel@0x6943000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6943000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-gfx";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_gfx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_funnel_gfx>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_in2_in_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_out_funnel_in2>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_in2_in_gfx_cx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_cx_out_funnel_in2>;
+ };
+ };
};
};
@@ -1883,6 +1935,22 @@
clock-names = "apb_pclk";
};
+ ipcb_tgu: tgu@6b0c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b999>;
+ reg = <0x06B0C000 0x1000>;
+ reg-names = "tgu-base";
+ tgu-steps = <3>;
+ tgu-conditions = <4>;
+ tgu-regs = <4>;
+ tgu-timer-counters = <8>;
+
+ coresight-name = "coresight-tgu-ipcb";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
turing_etm0 {
compatible = "qcom,coresight-remote-etm";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index c02a0a6..f800b4e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -122,6 +122,36 @@
cache-slice-names = "gpu", "gpuhtw";
cache-slices = <&llcc 12>, <&llcc 11>;
+ qcom,gpu-coresights {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-coresight";
+
+ qcom,gpu-coresight@0 {
+ reg = <0>;
+ coresight-name = "coresight-gfx";
+ coresight-atid = <50>;
+ port {
+ gfx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_gfx>;
+ };
+ };
+ };
+
+ qcom,gpu-coresight@1 {
+ reg = <1>;
+ coresight-name = "coresight-gfx-cx";
+ coresight-atid = <51>;
+ port {
+ gfx_cx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_gfx_cx>;
+ };
+ };
+ };
+ };
+
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index e36a759e..5578ece 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -216,11 +216,11 @@
&clock_gpucc {
/delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mx-supply;
};
&clock_gfx {
/delete-property/ vdd_gfx-supply;
- /delete-property/ vdd_mx-supply;
};
&pil_modem {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index c6abee1..3756197 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -198,6 +198,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -234,6 +235,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
index 000d65e7..2ac313d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
@@ -32,6 +32,9 @@
smb2_vconn: qcom,smb2-vconn {
regulator-name = "smb2-vconn";
};
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
+ };
};
&usb0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 8993ff9..02f30fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -115,6 +115,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -151,6 +152,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index 6ea92ee..7bc4d89 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -9,3 +9,35 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+
+&pmi8998_pdphy {
+ vbus-supply = <&smb2_vbus>;
+};
+
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l20>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index f50df47..d22c28a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -1389,12 +1389,24 @@
compatible = "qcom,rpmh-vrm-regulator";
mboxes = <&apps_rsc 0>;
qcom,resource-name = "bobb1";
+ qcom,send-defaults;
+
pmi8998_bob: regulator-bob {
regulator-name = "pmi8998_bob";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_PASS>;
+ };
+
+ pmi8998_bob_ao: regulator-bob-ao {
+ regulator-name = "pmi8998_bob_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_AUTO>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index e7fd8a0..99004bf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -33,6 +33,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -157,6 +158,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 08e68cd..80ef35f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -57,7 +57,7 @@
qcom,cpr-saw-use-unit-mV;
qcom,saw-avs-ctrl = <0x101C031>;
- qcom,saw-avs-limit = <0x3B803B8>;
+ qcom,saw-avs-limit = <0x3E803E8>;
qcom,cpr-enable;
qcom,cpr-hw-closed-loop;
@@ -85,9 +85,9 @@
regulator-max-microvolt = <18>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <18 18>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <18 18 18>;
qcom,cpr-corners = <18>;
qcom,cpr-corner-fmax-map = <6 12 15 18>;
@@ -133,10 +133,62 @@
1950 2632>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
- < 0 0 12000 12000>;
+ /* Speed bin 0 */
+ < 0 0 12000 12000>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ /* Speed bin 1 */
+ < 0 0 12000 12000>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ /* Speed bin 2 */
+ < 0 0 12000 12000>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>,
+ <(-15000) (-15000) (-3000) (-3000)>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- < 0 0 12000 10000>;
+ /* Speed bin 0 */
+ < 0 0 12000 10000>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ /* Speed bin 1 */
+ < 0 0 12000 10000>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ /* Speed bin 2 */
+ < 0 0 12000 10000>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>,
+ <(-15000) (-15000) (-3000) (-5000)>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
@@ -149,6 +201,8 @@
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -168,19 +222,23 @@
regulator-max-microvolt = <15>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <14 15>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <14 15 15>;
qcom,cpr-corners =
/* Speed bin 0 */
<14 14 14 14 14 14 14 14>,
/* Speed bin 1 */
+ <15 15 15 15 15 15 15 15>,
+ /* Speed bin 2 */
<15 15 15 15 15 15 15 15>;
qcom,cpr-corner-fmax-map =
/* Speed bin 0 */
<4 8 11 14>,
/* Speed bin 1 */
+ <4 8 11 15>,
+ /* Speed bin 2 */
<4 8 11 15>;
qcom,cpr-voltage-ceiling =
@@ -192,6 +250,11 @@
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 932000 932000 1000000
+ 1000000>,
+ /* Speed bin 2 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 932000 932000 1000000
1000000>;
qcom,cpr-voltage-floor =
@@ -203,6 +266,11 @@
<568000 568000 568000 568000 568000
568000 568000 568000 568000 568000
568000 568000 568000 568000
+ 568000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000
568000>;
qcom,cpr-floor-to-ceiling-max-range =
@@ -213,6 +281,10 @@
/* Speed bin 1 */
<32000 32000 32000 32000 32000
32000 32000 32000 32000 32000
+ 32000 32000 32000 40000 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
32000 32000 32000 40000 40000>;
qcom,corner-frequencies =
@@ -227,6 +299,12 @@
576000000 652800000 748800000
844800000 940800000 1036800000
1132800000 1209600000 1305600000
+ 1401600000 1497600000 1593600000>,
+ /* Speed bin 2 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 844800000 940800000 1036800000
+ 1132800000 1209600000 1305600000
1401600000 1497600000 1593600000>;
qcom,cpr-ro-scaling-factor =
@@ -244,22 +322,76 @@
2501 2095>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
- < 8000 16000 16000 12000>;
+ /* Speed bin 0 */
+ < 8000 16000 16000 12000>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ /* Speed bin 1 */
+ < 8000 16000 16000 12000>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ /* Speed bin 2 */
+ < 8000 16000 16000 12000>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>,
+ < (-7000) 1000 1000 (-3000)>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- < 6000 14000 16000 12000>;
+ /* Speed bin 0 */
+ < 6000 14000 16000 12000>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ /* Speed bin 1 */
+ < 6000 14000 16000 12000>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ /* Speed bin 2 */
+ < 6000 14000 16000 12000>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>,
+ < (-9000) (-1000) 1000 (-3000)>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <14 15>;
+ qcom,cpr-aging-ref-corner = <14 15 15>;
qcom,cpr-aging-ro-scaling-factor = <1620>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -302,7 +434,7 @@
qcom,cpr-saw-use-unit-mV;
qcom,saw-avs-ctrl = <0x101C031>;
- qcom,saw-avs-limit = <0x4700470>;
+ qcom,saw-avs-limit = <0x4880488>;
qcom,cpr-enable;
qcom,cpr-hw-closed-loop;
@@ -312,7 +444,7 @@
qcom,cpr-panic-reg-name-list =
"APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
- qcom,cpr-aging-ref-voltage = <1136000>;
+ qcom,cpr-aging-ref-voltage = <1160000>;
vdd-supply = <&pm8998_s12>;
thread@0 {
@@ -325,23 +457,27 @@
apc1_perfcl_vreg: regulator {
regulator-name = "apc1_perfcl_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <33>;
+ regulator-max-microvolt = <35>;
qcom,cpr-fuse-corners = <5>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <28 31>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <28 31 33>;
qcom,cpr-corners =
/* Speed bin 0 */
<28 28 28 28 28 28 28 28>,
/* Speed bin 1 */
- <31 31 31 31 31 31 31 31>;
+ <31 31 31 31 31 31 31 31>,
+ /* Speed bin 2 */
+ <33 33 33 33 33 33 33 33>;
qcom,cpr-corner-fmax-map =
/* Speed bin 0 */
<7 14 22 27 28>,
/* Speed bin 1 */
- <7 14 22 27 31>;
+ <7 14 22 27 31>,
+ /* Speed bin 2 */
+ <7 14 22 30 33>;
qcom,cpr-voltage-ceiling =
/* Speed bin 0 */
@@ -350,15 +486,23 @@
828000 828000 828000 828000 828000
828000 828000 828000 932000 932000
932000 932000 1104000 1104000 1104000
- 1104000 1136000 1136000>,
+ 1104000 1160000 1160000>,
/* Speed bin 1 */
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 828000 932000 932000
932000 932000 1104000 1104000 1104000
- 1104000 1136000 1136000 1136000 1136000
- 1136000>;
+ 1104000 1160000 1160000 1160000 1160000
+ 1160000>,
+ /* Speed bin 2 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 932000 932000
+ 932000 932000 1104000 1104000 1104000
+ 1104000 1160000 1160000 1160000 1160000
+ 1160000 1160000 1160000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -375,7 +519,15 @@
568000 568000 568000 568000 568000
568000 568000 568000 568000 568000
568000 568000 568000 568000 568000
- 568000>;
+ 568000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 568000>;
qcom,cpr-floor-to-ceiling-max-range =
/* Speed bin 0 */
@@ -392,7 +544,15 @@
32000 32000 32000 32000 32000
32000 32000 32000 32000 32000
32000 32000 40000 40000 40000
- 40000>;
+ 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 40000 40000 40000
+ 40000 40000 40000>;
qcom,corner-frequencies =
/* Speed bin 0 */
@@ -417,7 +577,19 @@
1996800000 2092800000 2169600000
2246400000 2323200000 2400000000
2476800000 2553600000 2649600000
- 2707200000>;
+ 2707200000>,
+ /* Speed bin 2 */
+ <300000000 403200000 480000000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1459200000
+ 1536000000 1612800000 1689600000
+ 1766400000 1843200000 1920000000
+ 1996800000 2092800000 2169600000
+ 2246400000 2323200000 2400000000
+ 2476800000 2553600000 2649600000
+ 2707200000 2726400000 2745600000>;
qcom,cpr-ro-scaling-factor =
<2857 3056 2828 2952 2699 2796 2447
@@ -437,28 +609,76 @@
2003 1675>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
- /* Speed bin 0 */
- < 8000 8000 8000 0 0>,
- /* Speed bin 1 */
- < 8000 8000 8000 0 16000>;
+ /* Speed bin 0 */
+ < 8000 8000 8000 0 0>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ < (-7000) (-7000) (-7000) (-15000) (-15000)>,
+ /* Speed bin 1 */
+ < 8000 8000 8000 0 16000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ /* Speed bin 2 */
+ < 8000 8000 8000 0 16000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>,
+ < (-7000) (-7000) (-7000) (-15000) 1000>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- /* Speed bin 0 */
- < 6000 6000 8000 0 0>,
- /* Speed bin 1 */
- < 6000 6000 8000 0 16000>;
+ /* Speed bin 0 */
+ < 6000 6000 8000 0 0>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ < (-9000) (-9000) (-7000) (-15000) (-15000)>,
+ /* Speed bin 1 */
+ < 6000 6000 8000 0 16000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ /* Speed bin 2 */
+ < 6000 6000 8000 0 16000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>,
+ < (-9000) (-9000) (-7000) (-15000) 1000>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <27 31>;
+ qcom,cpr-aging-ref-corner = <27 31 33>;
qcom,cpr-aging-ro-scaling-factor = <1700>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -477,6 +697,10 @@
};
};
+&pil_modem {
+ qcom,mss_pdc_offset = <9>;
+};
+
/* VDD_APC0 */
&pm8998_s13 {
regulator-min-microvolt = <568000>;
@@ -486,7 +710,7 @@
/* VDD_APC1 */
&pm8998_s12 {
regulator-min-microvolt = <568000>;
- regulator-max-microvolt = <1136000>;
+ regulator-max-microvolt = <1160000>;
};
&clock_cpucc {
@@ -529,6 +753,23 @@
< 1497600000 0x403c0d4e 0x00003e3e 0x2 14 >,
< 1593600000 0x403c0e53 0x00004242 0x2 15 >;
+ qcom,l3-speedbin2-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 844800000 0x4024062c 0x00002323 0x2 7 >,
+ < 940800000 0x40240731 0x00002727 0x2 8 >,
+ < 1036800000 0x40240836 0x00002b2b 0x2 9 >,
+ < 1132800000 0x402c093b 0x00002f2f 0x2 10 >,
+ < 1209600000 0x402c0a3f 0x00003232 0x2 11 >,
+ < 1305600000 0x40340b44 0x00003636 0x2 12 >,
+ < 1401600000 0x40340c49 0x00003a3a 0x2 13 >,
+ < 1497600000 0x403c0d4e 0x00003e3e 0x2 14 >,
+ < 1593600000 0x403c0e53 0x00004242 0x2 15 >;
+
qcom,pwrcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
< 403200000 0x500c0115 0x00002020 0x1 2 >,
@@ -569,6 +810,26 @@
< 1689600000 0x40441058 0x00004646 0x2 17 >,
< 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+ qcom,pwrcl-speedbin2-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+ < 1228800000 0x402c0b40 0x00003333 0x2 12 >,
+ < 1324800000 0x40340c45 0x00003737 0x2 13 >,
+ < 1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+ < 1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+ < 1612800000 0x403c0f54 0x00004343 0x2 16 >,
+ < 1689600000 0x40441058 0x00004646 0x2 17 >,
+ < 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
qcom,perfcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
< 403200000 0x500c0115 0x00002020 0x1 2 >,
@@ -631,14 +892,53 @@
< 2649600000 0x40541d8a 0x00006e6e 0x2 30 >,
< 2745600000 0x40511e8f 0x00007272 0x2 31 >;
+ qcom,perfcl-speedbin2-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x2 12 >,
+ < 1286400000 0x40340c43 0x00003636 0x2 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x2 14 >,
+ < 1459200000 0x403c0e4c 0x00003d3d 0x2 15 >,
+ < 1536000000 0x403c0f50 0x00004040 0x2 16 >,
+ < 1612800000 0x403c1054 0x00004343 0x2 17 >,
+ < 1689600000 0x40441158 0x00004646 0x2 18 >,
+ < 1766400000 0x4044125c 0x00004a4a 0x2 19 >,
+ < 1843200000 0x40441360 0x00004d4d 0x2 20 >,
+ < 1920000000 0x404c1464 0x00005050 0x2 21 >,
+ < 1996800000 0x404c1568 0x00005353 0x2 22 >,
+ < 2092800000 0x4054166d 0x00005757 0x2 23 >,
+ < 2169600000 0x40541771 0x00005a5a 0x2 24 >,
+ < 2246400000 0x40541875 0x00005e5e 0x2 25 >,
+ < 2323200000 0x40541979 0x00006161 0x2 26 >,
+ < 2400000000 0x40541a7d 0x00006464 0x2 27 >,
+ < 2476800000 0x40541b81 0x00006767 0x2 28 >,
+ < 2553600000 0x40541c85 0x00006a6a 0x2 29 >,
+ < 2649600000 0x40541d8a 0x00006e6e 0x2 30 >,
+ < 2707200000 0x40511e8d 0x00007171 0x2 30 >,
+ < 2764800000 0x40511f90 0x00007373 0x2 31 >,
+ < 2784000000 0x40512091 0x00007474 0x2 32 >,
+ < 2803200000 0x40512192 0x00007575 0x2 33 >;
+
qcom,l3-memacc-level-vc-bin0 = <8 13>;
qcom,l3-memacc-level-vc-bin1 = <8 13>;
+ qcom,l3-memacc-level-vc-bin2 = <8 13>;
qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
qcom,pwrcl-memacc-level-vc-bin1 = <12 16>;
+ qcom,pwrcl-memacc-level-vc-bin2 = <12 16>;
qcom,perfcl-memacc-level-vc-bin0 = <14 22>;
qcom,perfcl-memacc-level-vc-bin1 = <14 22>;
+ qcom,perfcl-memacc-level-vc-bin2 = <14 22>;
};
&pcie1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 7b3c655..ff092ea 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -547,7 +547,6 @@
wlan_fw_region: wlan_fw_region@8cb00000 {
compatible = "shared-dma-pool";
- no-map;
reg = <0 0x8cb00000 0 0x100000>;
};
@@ -1095,6 +1094,7 @@
reg = <0x5090000 0x9000>;
reg-names = "cc_base";
vdd_cx-supply = <&pm8998_s9_level>;
+ vdd_mx-supply = <&pm8998_s6_level>;
qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>;
#clock-cells = <1>;
#reset-cells = <1>;
@@ -1105,7 +1105,6 @@
reg = <0x5090000 0x9000>;
reg-names = "cc_base";
vdd_gfx-supply = <&pm8005_s1_level>;
- vdd_mx-supply = <&pm8998_s6_level>;
qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>;
#clock-cells = <1>;
#reset-cells = <1>;
@@ -1742,6 +1741,7 @@
qcom,ssctl-instance-id = <0x12>;
qcom,override-acc;
qcom,qdsp6v65-1-0;
+ qcom,mss_pdc_offset = <8>;
status = "ok";
memory-region = <&pil_modem_mem>;
qcom,mem-protect-id = <0xF>;
@@ -3021,7 +3021,6 @@
<0 424 0 /* CE10 */ >,
<0 425 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x100000>;
- qcom,wlan-msa-fixed-region = <&wlan_fw_region>;
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
vdd-1.8-xo-supply = <&pm8998_l7>;
@@ -3053,6 +3052,11 @@
#cooling-cells = <2>;
};
+ modem_skin: modem_skin {
+ qcom,qmi-dev-name = "modem_skin";
+ #cooling-cells = <2>;
+ };
+
modem_vdd: modem_vdd {
qcom,qmi-dev-name = "cpuv_restriction_cold";
#cooling-cells = <2>;
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 01c2662..cd393c2 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -335,6 +335,7 @@
CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP_OLEDB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_REFGEN=y
CONFIG_REGULATOR_RPMH=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
@@ -392,6 +393,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index e706f6e..17231c7 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -29,6 +29,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -234,6 +235,7 @@
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
CONFIG_DMA_CMA=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
@@ -340,6 +342,7 @@
CONFIG_REGULATOR_QPNP_LCDB=y
CONFIG_REGULATOR_QPNP_OLEDB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_REFGEN=y
CONFIG_REGULATOR_RPMH=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
@@ -387,6 +390,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 26994d1..7655c91 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -237,6 +237,7 @@
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
CONFIG_DMA_CMA=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
@@ -652,6 +653,7 @@
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index ab0e5b2..110f750 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -14,14 +14,16 @@
struct dma_iommu_mapping {
/* iommu specific data */
struct iommu_domain *domain;
+ bool init;
+ struct kref kref;
+ const struct dma_map_ops *ops;
+ /* Protects bitmap */
+ spinlock_t lock;
void *bitmap;
size_t bits;
dma_addr_t base;
- spinlock_t lock;
- struct kref kref;
-
struct dma_fast_smmu_mapping *fast;
};
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index afa23b0..1fb0230 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -114,10 +114,10 @@
/*
* This is the base location for PIE (ET_DYN with INTERP) loads. On
- * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
* space open for things that want to use the area for 32-bit pointers.
*/
-#define ELF_ET_DYN_BASE 0x100000000UL
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 394c61d..1d5890f 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -157,9 +157,11 @@
void fpsimd_flush_thread(void)
{
+ preempt_disable();
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
fpsimd_flush_task_state(current);
set_thread_flag(TIF_FOREIGN_FPSTATE);
+ preempt_enable();
}
/*
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 7f90b7e..5229b33 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1906,23 +1906,42 @@
* IO address ranges, which is required to perform memory allocation and
* mapping with IOMMU aware functions.
*
- * The client device need to be attached to the mapping with
- * arm_iommu_attach_device function.
+ * Clients may use iommu_domain_set_attr() to set additional flags prior
+ * to calling arm_iommu_attach_device() to complete initialization.
*/
struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
{
unsigned int bits = size >> PAGE_SHIFT;
- unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
struct dma_iommu_mapping *mapping;
- int err = -ENOMEM;
- if (!bitmap_size)
+ if (!bits)
return ERR_PTR(-EINVAL);
mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
if (!mapping)
- goto err;
+ return ERR_PTR(-ENOMEM);
+
+ mapping->base = base;
+ mapping->bits = bits;
+
+ mapping->domain = iommu_domain_alloc(bus);
+ if (!mapping->domain)
+ goto err_domain_alloc;
+
+ mapping->init = false;
+ return mapping;
+
+err_domain_alloc:
+ kfree(mapping);
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(arm_iommu_create_mapping);
+
+static int
+bitmap_iommu_init_mapping(struct device *dev, struct dma_iommu_mapping *mapping)
+{
+ unsigned int bitmap_size = BITS_TO_LONGS(mapping->bits) * sizeof(long);
mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL | __GFP_NOWARN |
__GFP_NORETRY);
@@ -1930,67 +1949,124 @@
mapping->bitmap = vzalloc(bitmap_size);
if (!mapping->bitmap)
- goto err2;
+ return -ENOMEM;
- mapping->base = base;
- mapping->bits = bits;
spin_lock_init(&mapping->lock);
-
- mapping->domain = iommu_domain_alloc(bus);
- if (!mapping->domain)
- goto err3;
-
- kref_init(&mapping->kref);
- return mapping;
-err3:
- kvfree(mapping->bitmap);
-err2:
- kfree(mapping);
-err:
- return ERR_PTR(err);
+ mapping->ops = &iommu_ops;
+ return 0;
}
-EXPORT_SYMBOL(arm_iommu_create_mapping);
-static void release_iommu_mapping(struct kref *kref)
+static void bitmap_iommu_release_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ kfree(mapping->bitmap);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+}
+
+static void bypass_iommu_release_mapping(struct kref *kref)
{
struct dma_iommu_mapping *mapping =
container_of(kref, struct dma_iommu_mapping, kref);
iommu_domain_free(mapping->domain);
- kvfree(mapping->bitmap);
kfree(mapping);
}
+static int upstream_iommu_init_mapping(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ struct iommu_domain *domain = mapping->domain;
+ struct iommu_group *group = dev->iommu_group;
+ dma_addr_t base = mapping->base;
+ u64 size = mapping->bits << PAGE_SHIFT;
+
+ if (iommu_get_dma_cookie(domain))
+ return -EINVAL;
+
+ /* Need to attach to get geometry */
+ if (iommu_attach_group(domain, group))
+ goto out_put_cookie;
+
+ if (iommu_dma_init_domain(domain, base, size, dev))
+ goto out_detach_group;
+
+ mapping->ops = &iommu_dma_ops;
+ iommu_detach_group(domain, group);
+ return 0;
+
+out_detach_group:
+ iommu_detach_group(domain, group);
+out_put_cookie:
+ iommu_put_dma_cookie(domain);
+ return -EINVAL;
+}
+
+static void upstream_iommu_release_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ iommu_put_dma_cookie(mapping->domain);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+}
+
+/*
+ * arm_iommu_release_mapping
+ * @mapping: allocted via arm_iommu_create_mapping()
+ *
+ * Frees all resources associated with the iommu mapping.
+ * The device associated with this mapping must be in the 'detached' state
+ */
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
- if (mapping)
- kref_put(&mapping->kref, release_iommu_mapping);
+ int s1_bypass = 0, is_fast = 0, is_upstream = 0;
+ void (*release)(struct kref *kref);
+
+ if (!mapping)
+ return;
+
+ if (!mapping->init) {
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+ return;
+ }
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ iommu_domain_get_attr(mapping->domain,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
+ &is_upstream);
+
+ if (s1_bypass)
+ release = bypass_iommu_release_mapping;
+ else if (is_fast)
+ release = fast_smmu_release_mapping;
+ else if (is_upstream)
+ release = upstream_iommu_release_mapping;
+ else
+ release = bitmap_iommu_release_mapping;
+
+ kref_put(&mapping->kref, release);
}
EXPORT_SYMBOL(arm_iommu_release_mapping);
-/**
- * arm_iommu_attach_device
- * @dev: valid struct device pointer
- * @mapping: io address space mapping structure (returned from
- * arm_iommu_create_mapping)
- *
- * Attaches specified io address space mapping to the provided device,
- * this replaces the dma operations (dma_map_ops pointer) with the
- * IOMMU aware version. Only one device in an iommu_group may use this
- * function.
- */
-int arm_iommu_attach_device(struct device *dev,
+static int arm_iommu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
- int err;
- int s1_bypass = 0, is_fast = 0;
+ int err = -EINVAL;
+ int s1_bypass = 0, is_fast = 0, is_upstream = 0;
struct iommu_group *group;
dma_addr_t iova_end;
group = dev->iommu_group;
if (!group) {
dev_err(dev, "No iommu associated with device\n");
- return -ENODEV;
+ return -EINVAL;
}
if (iommu_get_domain_for_dev(dev)) {
@@ -1998,6 +2074,11 @@
return -EINVAL;
}
+ if (mapping->init) {
+ kref_get(&mapping->kref);
+ return 0;
+ }
+
iova_end = mapping->base + (mapping->bits << PAGE_SHIFT) - 1;
if (iova_end > dma_get_mask(dev)) {
dev_err(dev, "dma mask %llx too small for requested iova range %pad to %pad\n",
@@ -2005,21 +2086,59 @@
return -EINVAL;
}
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
- if (is_fast)
- return fast_smmu_attach_device(dev, mapping);
+ iommu_domain_get_attr(mapping->domain,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
+ &is_upstream);
- err = iommu_attach_group(mapping->domain, group);
+ if (s1_bypass) {
+ mapping->ops = &swiotlb_dma_ops;
+ err = 0;
+ } else if (is_fast) {
+ err = fast_smmu_init_mapping(dev, mapping);
+ } else if (is_upstream) {
+ err = upstream_iommu_init_mapping(dev, mapping);
+ } else {
+ err = bitmap_iommu_init_mapping(dev, mapping);
+ }
+ if (!err) {
+ kref_init(&mapping->kref);
+ mapping->init = true;
+ }
+ return err;
+}
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ * arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version.
+ *
+ * Clients are expected to call arm_iommu_attach_device() prior to sharing
+ * the dma_iommu_mapping structure with another device. This ensures
+ * initialization is complete.
+ */
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ int err;
+
+ err = arm_iommu_init_mapping(dev, mapping);
if (err)
return err;
- iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
- &s1_bypass);
+ err = iommu_attach_group(mapping->domain, dev->iommu_group);
+ if (err)
+ return err;
- kref_get(&mapping->kref);
dev->archdata.mapping = mapping;
- if (!s1_bypass)
- set_dma_ops(dev, &iommu_ops);
+ set_dma_ops(dev, mapping->ops);
pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
return 0;
@@ -2036,8 +2155,7 @@
void arm_iommu_detach_device(struct device *dev)
{
struct dma_iommu_mapping *mapping;
- int is_fast, s1_bypass = 0;
- struct iommu_group *group;
+ int s1_bypass = 0;
mapping = to_dma_iommu_mapping(dev);
if (!mapping) {
@@ -2045,26 +2163,22 @@
return;
}
- iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
- if (is_fast) {
- fast_smmu_detach_device(dev, mapping);
+ if (!dev->iommu_group) {
+ dev_err(dev, "No iommu associated with device\n");
return;
}
iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
&s1_bypass);
+ /*
+ * ION defers dma_unmap calls. Ensure they have all completed prior to
+ * setting dma_ops to NULL.
+ */
if (msm_dma_unmap_all_for_dev(dev))
dev_warn(dev, "IOMMU detach with outstanding mappings\n");
- group = dev->iommu_group;
- if (!group) {
- dev_err(dev, "No iommu associated with device\n");
- return;
- }
-
- iommu_detach_group(mapping->domain, group);
- kref_put(&mapping->kref, release_iommu_mapping);
+ iommu_detach_group(mapping->domain, dev->iommu_group);
dev->archdata.mapping = NULL;
if (!s1_bypass)
set_dma_ops(dev, NULL);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 7f9501a..792dac8 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -384,8 +384,11 @@
* signal first. We do not need to release the mmap_sem because it
* would already be released in __lock_page_or_retry in mm/filemap.c.
*/
- if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+ if (!user_mode(regs))
+ goto no_context;
return 0;
+ }
/*
* Major/minor page fault accounting is only done on the initial
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 1910223..cea2bb1 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -147,23 +147,12 @@
* Find irq with highest priority
*/
# open coded PTR_LA t1, cpu_mask_nr_tbl
-#if (_MIPS_SZPTR == 32)
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
# open coded la t1, cpu_mask_nr_tbl
lui t1, %hi(cpu_mask_nr_tbl)
addiu t1, %lo(cpu_mask_nr_tbl)
-
-#endif
-#if (_MIPS_SZPTR == 64)
- # open coded dla t1, cpu_mask_nr_tbl
- .set push
- .set noat
- lui t1, %highest(cpu_mask_nr_tbl)
- lui AT, %hi(cpu_mask_nr_tbl)
- daddiu t1, t1, %higher(cpu_mask_nr_tbl)
- daddiu AT, AT, %lo(cpu_mask_nr_tbl)
- dsll t1, 32
- daddu t1, t1, AT
- .set pop
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
#endif
1: lw t2,(t1)
nop
@@ -214,23 +203,12 @@
* Find irq with highest priority
*/
# open coded PTR_LA t1,asic_mask_nr_tbl
-#if (_MIPS_SZPTR == 32)
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
# open coded la t1, asic_mask_nr_tbl
lui t1, %hi(asic_mask_nr_tbl)
addiu t1, %lo(asic_mask_nr_tbl)
-
-#endif
-#if (_MIPS_SZPTR == 64)
- # open coded dla t1, asic_mask_nr_tbl
- .set push
- .set noat
- lui t1, %highest(asic_mask_nr_tbl)
- lui AT, %hi(asic_mask_nr_tbl)
- daddiu t1, t1, %higher(asic_mask_nr_tbl)
- daddiu AT, AT, %lo(asic_mask_nr_tbl)
- dsll t1, 32
- daddu t1, t1, AT
- .set pop
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
#endif
2: lw t2,(t1)
nop
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index c721ea2..df757c9 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -604,13 +604,12 @@
if (parisc_requires_coherency())
flush_tlb_range(vma, start, end);
- if ((end - start) >= parisc_cache_flush_threshold) {
+ if ((end - start) >= parisc_cache_flush_threshold
+ || vma->vm_mm->context != mfsp(3)) {
flush_cache_all();
return;
}
- BUG_ON(vma->vm_mm->context != mfsp(3));
-
flush_user_dcache_range_asm(start, end);
if (vma->vm_flags & VM_EXEC)
flush_user_icache_range_asm(start, end);
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 0012f03..fe208b7 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -75,9 +75,27 @@
struct task_struct *tsk)
{
/* Mark this context has been used on the new CPU */
- if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next)))
+ if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) {
cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
+ /*
+ * This full barrier orders the store to the cpumask above vs
+ * a subsequent operation which allows this CPU to begin loading
+ * translations for next.
+ *
+ * When using the radix MMU that operation is the load of the
+ * MMU context id, which is then moved to SPRN_PID.
+ *
+ * For the hash MMU it is either the first load from slb_cache
+ * in switch_slb(), and/or the store of paca->mm_ctx_id in
+ * copy_mm_to_paca().
+ *
+ * On the read side the barrier is in pte_xchg(), which orders
+ * the store to the PTE vs the load of mm_cpumask.
+ */
+ smp_mb();
+ }
+
/* 32-bit keeps track of the current PGDIR in the thread struct */
#ifdef CONFIG_PPC32
tsk->thread.pgdir = next->pgd;
diff --git a/arch/powerpc/include/asm/pgtable-be-types.h b/arch/powerpc/include/asm/pgtable-be-types.h
index 49c0a5a..68e087e 100644
--- a/arch/powerpc/include/asm/pgtable-be-types.h
+++ b/arch/powerpc/include/asm/pgtable-be-types.h
@@ -87,6 +87,7 @@
unsigned long *p = (unsigned long *)ptep;
__be64 prev;
+ /* See comment in switch_mm_irqs_off() */
prev = (__force __be64)__cmpxchg_u64(p, (__force unsigned long)pte_raw(old),
(__force unsigned long)pte_raw(new));
diff --git a/arch/powerpc/include/asm/pgtable-types.h b/arch/powerpc/include/asm/pgtable-types.h
index e7f4f3e..41e9d0a 100644
--- a/arch/powerpc/include/asm/pgtable-types.h
+++ b/arch/powerpc/include/asm/pgtable-types.h
@@ -62,6 +62,7 @@
{
unsigned long *p = (unsigned long *)ptep;
+ /* See comment in switch_mm_irqs_off() */
return pte_val(old) == __cmpxchg_u64(p, pte_val(old), pte_val(new));
}
#endif
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 3c05c31..028a22b 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -146,6 +146,19 @@
/* Clear bit 0 which we wouldn't clear otherwise */
local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
+ if (happened & PACA_IRQ_HARD_DIS) {
+ /*
+ * We may have missed a decrementer interrupt if hard disabled.
+ * Check the decrementer register in case we had a rollover
+ * while hard disabled.
+ */
+ if (!(happened & PACA_IRQ_DEC)) {
+ if (decrementer_check_overflow()) {
+ local_paca->irq_happened |= PACA_IRQ_DEC;
+ happened |= PACA_IRQ_DEC;
+ }
+ }
+ }
/*
* Force the delivery of pending soft-disabled interrupts on PS3.
@@ -171,7 +184,7 @@
* in case we also had a rollover while hard disabled
*/
local_paca->irq_happened &= ~PACA_IRQ_DEC;
- if ((happened & PACA_IRQ_DEC) || decrementer_check_overflow())
+ if (happened & PACA_IRQ_DEC)
return 0x900;
/* Finally check if an external interrupt happened */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index b249c2f..1c141d5 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -359,7 +359,8 @@
cpumsr = msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
- if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) {
+ if (current->thread.regs &&
+ (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP))) {
check_if_tm_restore_required(current);
/*
* If a thread has already been reclaimed then the
@@ -383,7 +384,7 @@
{
if (tsk->thread.regs) {
preempt_disable();
- if (tsk->thread.regs->msr & MSR_VSX) {
+ if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
BUG_ON(tsk != current);
giveup_vsx(tsk);
}
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5c8f12f..dcbb914 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -127,12 +127,19 @@
* If task is not current, it will have been flushed already to
* it's thread_struct during __switch_to().
*
- * A reclaim flushes ALL the state.
+ * A reclaim flushes ALL the state or if not in TM save TM SPRs
+ * in the appropriate thread structures from live.
*/
- if (tsk == current && MSR_TM_SUSPENDED(mfmsr()))
- tm_reclaim_current(TM_CAUSE_SIGNAL);
+ if (tsk != current)
+ return;
+ if (MSR_TM_SUSPENDED(mfmsr())) {
+ tm_reclaim_current(TM_CAUSE_SIGNAL);
+ } else {
+ tm_enable();
+ tm_save_sprs(&(tsk->thread));
+ }
}
#else
static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kvm/sthyi.c
index 05c98bb..2f04ad1 100644
--- a/arch/s390/kvm/sthyi.c
+++ b/arch/s390/kvm/sthyi.c
@@ -394,7 +394,7 @@
"srl %[cc],28\n"
: [cc] "=d" (cc)
: [code] "d" (code), [addr] "a" (addr)
- : "memory", "cc");
+ : "3", "memory", "cc");
return cc;
}
@@ -422,7 +422,7 @@
VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
trace_kvm_s390_handle_sthyi(vcpu, code, addr);
- if (reg1 == reg2 || reg1 & 1 || reg2 & 1 || addr & ~PAGE_MASK)
+ if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
if (code & 0xffff) {
@@ -430,6 +430,9 @@
goto out;
}
+ if (addr & ~PAGE_MASK)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
/*
* If the page has not yet been faulted in, we want to do that
* now and not after all the expensive calculations.
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index bee281f..e8dee62 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -1252,7 +1252,8 @@
insn_count = bpf_jit_insn(jit, fp, i);
if (insn_count < 0)
return -1;
- jit->addrs[i + 1] = jit->prg; /* Next instruction address */
+ /* Next instruction address */
+ jit->addrs[i + insn_count] = jit->prg;
}
bpf_jit_epilogue(jit);
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index 349dd23..0cdeb2b 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -25,9 +25,11 @@
void __tsb_context_switch(unsigned long pgd_pa,
struct tsb_config *tsb_base,
struct tsb_config *tsb_huge,
- unsigned long tsb_descr_pa);
+ unsigned long tsb_descr_pa,
+ unsigned long secondary_ctx);
-static inline void tsb_context_switch(struct mm_struct *mm)
+static inline void tsb_context_switch_ctx(struct mm_struct *mm,
+ unsigned long ctx)
{
__tsb_context_switch(__pa(mm->pgd),
&mm->context.tsb_block[0],
@@ -38,9 +40,12 @@
#else
NULL
#endif
- , __pa(&mm->context.tsb_descr[0]));
+ , __pa(&mm->context.tsb_descr[0]),
+ ctx);
}
+#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0)
+
void tsb_grow(struct mm_struct *mm,
unsigned long tsb_index,
unsigned long mm_rss);
@@ -110,8 +115,7 @@
* cpu0 to update it's TSB because at that point the cpu_vm_mask
* only had cpu1 set in it.
*/
- load_secondary_context(mm);
- tsb_context_switch(mm);
+ tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
/* Any time a processor runs a context on an address space
* for the first time, we must flush that context out of the
diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h
index ec9c04d..ff05992 100644
--- a/arch/sparc/include/asm/trap_block.h
+++ b/arch/sparc/include/asm/trap_block.h
@@ -54,6 +54,7 @@
void init_cur_cpu_trap(struct thread_info *);
void setup_tba(void);
extern int ncpus_probed;
+extern u64 cpu_mondo_counter[NR_CPUS];
unsigned long real_hard_smp_processor_id(void);
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index 06981cc..d04111a 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -1240,8 +1240,6 @@
* ATU group, but ATU hcalls won't be available.
*/
hv_atu = false;
- pr_err(PFX "Could not register hvapi ATU err=%d\n",
- err);
} else {
pr_info(PFX "Registered hvapi ATU major[%lu] minor[%lu]\n",
vatu_major, vatu_minor);
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index d5807d2..2deb89e 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -621,22 +621,48 @@
}
}
-/* Multi-cpu list version. */
+#define CPU_MONDO_COUNTER(cpuid) (cpu_mondo_counter[cpuid])
+#define MONDO_USEC_WAIT_MIN 2
+#define MONDO_USEC_WAIT_MAX 100
+#define MONDO_RETRY_LIMIT 500000
+
+/* Multi-cpu list version.
+ *
+ * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'.
+ * Sometimes not all cpus receive the mondo, requiring us to re-send
+ * the mondo until all cpus have received, or cpus are truly stuck
+ * unable to receive mondo, and we timeout.
+ * Occasionally a target cpu strand is borrowed briefly by hypervisor to
+ * perform guest service, such as PCIe error handling. Consider the
+ * service time, 1 second overall wait is reasonable for 1 cpu.
+ * Here two in-between mondo check wait time are defined: 2 usec for
+ * single cpu quick turn around and up to 100usec for large cpu count.
+ * Deliver mondo to large number of cpus could take longer, we adjusts
+ * the retry count as long as target cpus are making forward progress.
+ */
static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
{
- int retries, this_cpu, prev_sent, i, saw_cpu_error;
+ int this_cpu, tot_cpus, prev_sent, i, rem;
+ int usec_wait, retries, tot_retries;
+ u16 first_cpu = 0xffff;
+ unsigned long xc_rcvd = 0;
unsigned long status;
+ int ecpuerror_id = 0;
+ int enocpu_id = 0;
u16 *cpu_list;
+ u16 cpu;
this_cpu = smp_processor_id();
-
cpu_list = __va(tb->cpu_list_pa);
-
- saw_cpu_error = 0;
- retries = 0;
+ usec_wait = cnt * MONDO_USEC_WAIT_MIN;
+ if (usec_wait > MONDO_USEC_WAIT_MAX)
+ usec_wait = MONDO_USEC_WAIT_MAX;
+ retries = tot_retries = 0;
+ tot_cpus = cnt;
prev_sent = 0;
+
do {
- int forward_progress, n_sent;
+ int n_sent, mondo_delivered, target_cpu_busy;
status = sun4v_cpu_mondo_send(cnt,
tb->cpu_list_pa,
@@ -644,94 +670,113 @@
/* HV_EOK means all cpus received the xcall, we're done. */
if (likely(status == HV_EOK))
- break;
+ goto xcall_done;
+
+ /* If not these non-fatal errors, panic */
+ if (unlikely((status != HV_EWOULDBLOCK) &&
+ (status != HV_ECPUERROR) &&
+ (status != HV_ENOCPU)))
+ goto fatal_errors;
/* First, see if we made any forward progress.
*
+ * Go through the cpu_list, count the target cpus that have
+ * received our mondo (n_sent), and those that did not (rem).
+ * Re-pack cpu_list with the cpus remain to be retried in the
+ * front - this simplifies tracking the truly stalled cpus.
+ *
* The hypervisor indicates successful sends by setting
* cpu list entries to the value 0xffff.
+ *
+ * EWOULDBLOCK means some target cpus did not receive the
+ * mondo and retry usually helps.
+ *
+ * ECPUERROR means at least one target cpu is in error state,
+ * it's usually safe to skip the faulty cpu and retry.
+ *
+ * ENOCPU means one of the target cpu doesn't belong to the
+ * domain, perhaps offlined which is unexpected, but not
+ * fatal and it's okay to skip the offlined cpu.
*/
+ rem = 0;
n_sent = 0;
for (i = 0; i < cnt; i++) {
- if (likely(cpu_list[i] == 0xffff))
+ cpu = cpu_list[i];
+ if (likely(cpu == 0xffff)) {
n_sent++;
+ } else if ((status == HV_ECPUERROR) &&
+ (sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) {
+ ecpuerror_id = cpu + 1;
+ } else if (status == HV_ENOCPU && !cpu_online(cpu)) {
+ enocpu_id = cpu + 1;
+ } else {
+ cpu_list[rem++] = cpu;
+ }
}
- forward_progress = 0;
- if (n_sent > prev_sent)
- forward_progress = 1;
+ /* No cpu remained, we're done. */
+ if (rem == 0)
+ break;
+ /* Otherwise, update the cpu count for retry. */
+ cnt = rem;
+
+ /* Record the overall number of mondos received by the
+ * first of the remaining cpus.
+ */
+ if (first_cpu != cpu_list[0]) {
+ first_cpu = cpu_list[0];
+ xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+ }
+
+ /* Was any mondo delivered successfully? */
+ mondo_delivered = (n_sent > prev_sent);
prev_sent = n_sent;
- /* If we get a HV_ECPUERROR, then one or more of the cpus
- * in the list are in error state. Use the cpu_state()
- * hypervisor call to find out which cpus are in error state.
+ /* or, was any target cpu busy processing other mondos? */
+ target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu));
+ xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+
+ /* Retry count is for no progress. If we're making progress,
+ * reset the retry count.
*/
- if (unlikely(status == HV_ECPUERROR)) {
- for (i = 0; i < cnt; i++) {
- long err;
- u16 cpu;
-
- cpu = cpu_list[i];
- if (cpu == 0xffff)
- continue;
-
- err = sun4v_cpu_state(cpu);
- if (err == HV_CPU_STATE_ERROR) {
- saw_cpu_error = (cpu + 1);
- cpu_list[i] = 0xffff;
- }
- }
- } else if (unlikely(status != HV_EWOULDBLOCK))
- goto fatal_mondo_error;
-
- /* Don't bother rewriting the CPU list, just leave the
- * 0xffff and non-0xffff entries in there and the
- * hypervisor will do the right thing.
- *
- * Only advance timeout state if we didn't make any
- * forward progress.
- */
- if (unlikely(!forward_progress)) {
- if (unlikely(++retries > 10000))
- goto fatal_mondo_timeout;
-
- /* Delay a little bit to let other cpus catch up
- * on their cpu mondo queue work.
- */
- udelay(2 * cnt);
+ if (likely(mondo_delivered || target_cpu_busy)) {
+ tot_retries += retries;
+ retries = 0;
+ } else if (unlikely(retries > MONDO_RETRY_LIMIT)) {
+ goto fatal_mondo_timeout;
}
+
+ /* Delay a little bit to let other cpus catch up on
+ * their cpu mondo queue work.
+ */
+ if (!mondo_delivered)
+ udelay(usec_wait);
+
+ retries++;
} while (1);
- if (unlikely(saw_cpu_error))
- goto fatal_mondo_cpu_error;
-
+xcall_done:
+ if (unlikely(ecpuerror_id > 0)) {
+ pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n",
+ this_cpu, ecpuerror_id - 1);
+ } else if (unlikely(enocpu_id > 0)) {
+ pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n",
+ this_cpu, enocpu_id - 1);
+ }
return;
-fatal_mondo_cpu_error:
- printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus "
- "(including %d) were in error state\n",
- this_cpu, saw_cpu_error - 1);
- return;
+fatal_errors:
+ /* fatal errors include bad alignment, etc */
+ pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n",
+ this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
+ panic("Unexpected SUN4V mondo error %lu\n", status);
fatal_mondo_timeout:
- printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward "
- " progress after %d retries.\n",
- this_cpu, retries);
- goto dump_cpu_list_and_out;
-
-fatal_mondo_error:
- printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n",
- this_cpu, status);
- printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) "
- "mondo_block_pa(%lx)\n",
- this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
-
-dump_cpu_list_and_out:
- printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu);
- for (i = 0; i < cnt; i++)
- printk("%u ", cpu_list[i]);
- printk("]\n");
+ /* some cpus being non-responsive to the cpu mondo */
+ pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n",
+ this_cpu, first_cpu, (tot_retries + retries), tot_cpus);
+ panic("SUN4V mondo timeout panic\n");
}
static void (*xcall_deliver_impl)(struct trap_per_cpu *, int);
diff --git a/arch/sparc/kernel/sun4v_ivec.S b/arch/sparc/kernel/sun4v_ivec.S
index 559bc5e..3463199 100644
--- a/arch/sparc/kernel/sun4v_ivec.S
+++ b/arch/sparc/kernel/sun4v_ivec.S
@@ -26,6 +26,21 @@
ldxa [%g0] ASI_SCRATCHPAD, %g4
sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4
+ /* Get smp_processor_id() into %g3 */
+ sethi %hi(trap_block), %g5
+ or %g5, %lo(trap_block), %g5
+ sub %g4, %g5, %g3
+ srlx %g3, TRAP_BLOCK_SZ_SHIFT, %g3
+
+ /* Increment cpu_mondo_counter[smp_processor_id()] */
+ sethi %hi(cpu_mondo_counter), %g5
+ or %g5, %lo(cpu_mondo_counter), %g5
+ sllx %g3, 3, %g3
+ add %g5, %g3, %g5
+ ldx [%g5], %g3
+ add %g3, 1, %g3
+ stx %g3, [%g5]
+
/* Get CPU mondo queue base phys address into %g7. */
ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index d44fb80..32dafb92 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2732,6 +2732,7 @@
}
}
+u64 cpu_mondo_counter[NR_CPUS] = {0};
struct trap_per_cpu trap_block[NR_CPUS];
EXPORT_SYMBOL(trap_block);
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index 395ec18..7d961f6 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -375,6 +375,7 @@
* %o1: TSB base config pointer
* %o2: TSB huge config pointer, or NULL if none
* %o3: Hypervisor TSB descriptor physical address
+ * %o4: Secondary context to load, if non-zero
*
* We have to run this whole thing with interrupts
* disabled so that the current cpu doesn't change
@@ -387,6 +388,17 @@
rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
+ brz,pn %o4, 1f
+ mov SECONDARY_CONTEXT, %o5
+
+661: stxa %o4, [%o5] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %o4, [%o5] ASI_MMU
+ .previous
+ flush %g6
+
+1:
TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S
index 54f9870..5a8cb37 100644
--- a/arch/sparc/lib/U3memcpy.S
+++ b/arch/sparc/lib/U3memcpy.S
@@ -145,13 +145,13 @@
ENTRY(U3_retl_o2_and_7_plus_GS)
and %o2, 7, %o2
retl
- add %o2, GLOBAL_SPARE, %o2
+ add %o2, GLOBAL_SPARE, %o0
ENDPROC(U3_retl_o2_and_7_plus_GS)
ENTRY(U3_retl_o2_and_7_plus_GS_plus_8)
add GLOBAL_SPARE, 8, GLOBAL_SPARE
and %o2, 7, %o2
retl
- add %o2, GLOBAL_SPARE, %o2
+ add %o2, GLOBAL_SPARE, %o0
ENDPROC(U3_retl_o2_and_7_plus_GS_plus_8)
#endif
diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c
index 17bd2e1..df707a8 100644
--- a/arch/sparc/power/hibernate.c
+++ b/arch/sparc/power/hibernate.c
@@ -35,6 +35,5 @@
{
struct mm_struct *mm = current->active_mm;
- load_secondary_context(mm);
- tsb_context_switch(mm);
+ tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
}
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index cc3bd58..9e240fc 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include "ctype.h"
+#include "string.h"
int memcmp(const void *s1, const void *s2, size_t len)
{
diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h
index 725e820..113588d 100644
--- a/arch/x86/boot/string.h
+++ b/arch/x86/boot/string.h
@@ -18,4 +18,13 @@
#define memset(d,c,l) __builtin_memset(d,c,l)
#define memcmp __builtin_memcmp
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern size_t strlen(const char *s);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strnlen(const char *s, size_t maxlen);
+extern unsigned int atou(const char *s);
+extern unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base);
+
#endif /* BOOT_STRING_H */
diff --git a/arch/x86/crypto/sha1_avx2_x86_64_asm.S b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
index 1cd792d..1eab79c 100644
--- a/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+++ b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
@@ -117,11 +117,10 @@
.set T1, REG_T1
.endm
-#define K_BASE %r8
#define HASH_PTR %r9
+#define BLOCKS_CTR %r8
#define BUFFER_PTR %r10
#define BUFFER_PTR2 %r13
-#define BUFFER_END %r11
#define PRECALC_BUF %r14
#define WK_BUF %r15
@@ -205,14 +204,14 @@
* blended AVX2 and ALU instruction scheduling
* 1 vector iteration per 8 rounds
*/
- vmovdqu ((i * 2) + PRECALC_OFFSET)(BUFFER_PTR), W_TMP
+ vmovdqu (i * 2)(BUFFER_PTR), W_TMP
.elseif ((i & 7) == 1)
- vinsertf128 $1, (((i-1) * 2)+PRECALC_OFFSET)(BUFFER_PTR2),\
+ vinsertf128 $1, ((i-1) * 2)(BUFFER_PTR2),\
WY_TMP, WY_TMP
.elseif ((i & 7) == 2)
vpshufb YMM_SHUFB_BSWAP, WY_TMP, WY
.elseif ((i & 7) == 4)
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
.elseif ((i & 7) == 7)
vmovdqu WY_TMP, PRECALC_WK(i&~7)
@@ -255,7 +254,7 @@
vpxor WY, WY_TMP, WY_TMP
.elseif ((i & 7) == 7)
vpxor WY_TMP2, WY_TMP, WY
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
vmovdqu WY_TMP, PRECALC_WK(i&~7)
PRECALC_ROTATE_WY
@@ -291,7 +290,7 @@
vpsrld $30, WY, WY
vpor WY, WY_TMP, WY
.elseif ((i & 7) == 7)
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
vmovdqu WY_TMP, PRECALC_WK(i&~7)
PRECALC_ROTATE_WY
@@ -446,6 +445,16 @@
.endm
+/* Add constant only if (%2 > %3) condition met (uses RTA as temp)
+ * %1 + %2 >= %3 ? %4 : 0
+ */
+.macro ADD_IF_GE a, b, c, d
+ mov \a, RTA
+ add $\d, RTA
+ cmp $\c, \b
+ cmovge RTA, \a
+.endm
+
/*
* macro implements 80 rounds of SHA-1, for multiple blocks with s/w pipelining
*/
@@ -463,13 +472,16 @@
lea (2*4*80+32)(%rsp), WK_BUF
# Precalc WK for first 2 blocks
- PRECALC_OFFSET = 0
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 2, 64
.set i, 0
.rept 160
PRECALC i
.set i, i + 1
.endr
- PRECALC_OFFSET = 128
+
+ /* Go to next block if needed */
+ ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 3, 128
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
xchg WK_BUF, PRECALC_BUF
.align 32
@@ -479,8 +491,8 @@
* we use K_BASE value as a signal of a last block,
* it is set below by: cmovae BUFFER_PTR, K_BASE
*/
- cmp K_BASE, BUFFER_PTR
- jne _begin
+ test BLOCKS_CTR, BLOCKS_CTR
+ jnz _begin
.align 32
jmp _end
.align 32
@@ -512,10 +524,10 @@
.set j, j+2
.endr
- add $(2*64), BUFFER_PTR /* move to next odd-64-byte block */
- cmp BUFFER_END, BUFFER_PTR /* is current block the last one? */
- cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
-
+ /* Update Counter */
+ sub $1, BLOCKS_CTR
+ /* Move to the next block only if needed*/
+ ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 4, 128
/*
* rounds
* 60,62,64,66,68
@@ -532,8 +544,8 @@
UPDATE_HASH 12(HASH_PTR), D
UPDATE_HASH 16(HASH_PTR), E
- cmp K_BASE, BUFFER_PTR /* is current block the last one? */
- je _loop
+ test BLOCKS_CTR, BLOCKS_CTR
+ jz _loop
mov TB, B
@@ -575,10 +587,10 @@
.set j, j+2
.endr
- add $(2*64), BUFFER_PTR2 /* move to next even-64-byte block */
-
- cmp BUFFER_END, BUFFER_PTR2 /* is current block the last one */
- cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
+ /* update counter */
+ sub $1, BLOCKS_CTR
+ /* Move to the next block only if needed*/
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
jmp _loop3
_loop3:
@@ -641,19 +653,12 @@
avx2_zeroupper
- lea K_XMM_AR(%rip), K_BASE
-
+ /* Setup initial values */
mov CTX, HASH_PTR
mov BUF, BUFFER_PTR
- lea 64(BUF), BUFFER_PTR2
- shl $6, CNT /* mul by 64 */
- add BUF, CNT
- add $64, CNT
- mov CNT, BUFFER_END
-
- cmp BUFFER_END, BUFFER_PTR2
- cmovae K_BASE, BUFFER_PTR2
+ mov BUF, BUFFER_PTR2
+ mov CNT, BLOCKS_CTR
xmm_mov BSWAP_SHUFB_CTL(%rip), YMM_SHUFB_BSWAP
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index f960a04..fc61739 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -201,7 +201,7 @@
static bool avx2_usable(void)
{
- if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
+ if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
&& boot_cpu_has(X86_FEATURE_BMI1)
&& boot_cpu_has(X86_FEATURE_BMI2))
return true;
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index ef766a3..e7b0e7f 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -1215,6 +1215,8 @@
* other IST entries.
*/
+ ASM_CLAC
+
/* Use %rdx as our temp variable throughout */
pushq %rdx
diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c
index 970c1de..4c1b7ea 100644
--- a/arch/x86/events/intel/rapl.c
+++ b/arch/x86/events/intel/rapl.c
@@ -161,7 +161,13 @@
static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
{
- return rapl_pmus->pmus[topology_logical_package_id(cpu)];
+ unsigned int pkgid = topology_logical_package_id(cpu);
+
+ /*
+ * The unsigned check also catches the '-1' return value for non
+ * existent mappings in the topology map.
+ */
+ return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL;
}
static inline u64 rapl_read_counter(struct perf_event *event)
@@ -402,6 +408,8 @@
/* must be done before validate_group */
pmu = cpu_to_rapl_pmu(event->cpu);
+ if (!pmu)
+ return -EINVAL;
event->cpu = pmu->cpu;
event->pmu_private = pmu;
event->hw.event_base = msr;
@@ -585,6 +593,19 @@
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
int target;
+ if (!pmu) {
+ pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+ if (!pmu)
+ return -ENOMEM;
+
+ raw_spin_lock_init(&pmu->lock);
+ INIT_LIST_HEAD(&pmu->active_list);
+ pmu->pmu = &rapl_pmus->pmu;
+ pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
+ rapl_hrtimer_init(pmu);
+
+ rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
+ }
/*
* Check if there is an online cpu in the package which collects rapl
* events already.
@@ -598,27 +619,6 @@
return 0;
}
-static int rapl_cpu_prepare(unsigned int cpu)
-{
- struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
-
- if (pmu)
- return 0;
-
- pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
- if (!pmu)
- return -ENOMEM;
-
- raw_spin_lock_init(&pmu->lock);
- INIT_LIST_HEAD(&pmu->active_list);
- pmu->pmu = &rapl_pmus->pmu;
- pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
- pmu->cpu = -1;
- rapl_hrtimer_init(pmu);
- rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
- return 0;
-}
-
static int rapl_check_hw_unit(bool apply_quirk)
{
u64 msr_rapl_power_unit_bits;
@@ -804,28 +804,21 @@
* Install callbacks. Core will call them for each online cpu.
*/
- ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "PERF_X86_RAPL_PREP",
- rapl_cpu_prepare, NULL);
- if (ret)
- goto out;
-
ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
"AP_PERF_X86_RAPL_ONLINE",
rapl_cpu_online, rapl_cpu_offline);
if (ret)
- goto out1;
+ goto out;
ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
if (ret)
- goto out2;
+ goto out1;
rapl_advertise();
return 0;
-out2:
- cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out1:
- cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP);
+ cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out:
pr_warn("Initialization failed (%d), disabled\n", ret);
cleanup_rapl_pmus();
@@ -836,7 +829,6 @@
static void __exit intel_rapl_exit(void)
{
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
- cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP);
perf_pmu_unregister(&rapl_pmus->pmu);
cleanup_rapl_pmus();
}
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index c152db2..b31761e 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -247,11 +247,11 @@
/*
* This is the base location for PIE (ET_DYN with INTERP) loads. On
- * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
* space open for things that want to use the area for 32-bit pointers.
*/
#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
- 0x100000000UL)
+ (TASK_SIZE / 3 * 2))
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This could be done in user space,
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index d34bd37..6c50201 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -304,13 +304,13 @@
static inline void outs##bwl(int port, const void *addr, unsigned long count) \
{ \
asm volatile("rep; outs" #bwl \
- : "+S"(addr), "+c"(count) : "d"(port)); \
+ : "+S"(addr), "+c"(count) : "d"(port) : "memory"); \
} \
\
static inline void ins##bwl(int port, void *addr, unsigned long count) \
{ \
asm volatile("rep; ins" #bwl \
- : "+D"(addr), "+c"(count) : "d"(port)); \
+ : "+D"(addr), "+c"(count) : "d"(port) : "memory"); \
}
BUILDIO(b, b, char)
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 8e0a9fe..f9dd224 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -116,9 +116,7 @@
mm->context.execute_only_pkey = -1;
}
#endif
- init_new_context_ldt(tsk, mm);
-
- return 0;
+ return init_new_context_ldt(tsk, mm);
}
static inline void destroy_context(struct mm_struct *mm)
{
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 9cf697c..55ffd9d 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -152,6 +152,8 @@
if (hlist_unhashed(&n.link))
break;
+ rcu_irq_exit();
+
if (!n.halted) {
local_irq_enable();
schedule();
@@ -160,11 +162,11 @@
/*
* We cannot reschedule. So halt.
*/
- rcu_irq_exit();
native_safe_halt();
local_irq_disable();
- rcu_irq_enter();
}
+
+ rcu_irq_enter();
}
if (!n.halted)
finish_swait(&n.wq, &wait);
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 649d8f2..91af75e 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -456,7 +456,7 @@
entry->ecx &= kvm_cpuid_7_0_ecx_x86_features;
cpuid_mask(&entry->ecx, CPUID_7_ECX);
/* PKU is not yet implemented for shadow paging. */
- if (!tdp_enabled)
+ if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
entry->ecx &= ~F(PKU);
} else {
entry->ebx = 0;
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 4d2872f..a71d273 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -94,13 +94,11 @@
}
EXPORT_SYMBOL(__sync_fetch_and_or_4);
-#ifdef CONFIG_NET
/*
* Networking support
*/
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
-#endif /* CONFIG_NET */
/*
* Architecture-specific symbols
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
index 1a804a2..3c75c4e 100644
--- a/arch/xtensa/mm/cache.c
+++ b/arch/xtensa/mm/cache.c
@@ -103,6 +103,7 @@
clear_page_alias(kvaddr, paddr);
preempt_enable();
}
+EXPORT_SYMBOL(clear_user_highpage);
void copy_user_highpage(struct page *dst, struct page *src,
unsigned long vaddr, struct vm_area_struct *vma)
@@ -119,10 +120,7 @@
copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
preempt_enable();
}
-
-#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+EXPORT_SYMBOL(copy_user_highpage);
/*
* Any time the kernel writes to a user page cache page, or it is about to
@@ -176,7 +174,7 @@
/* There shouldn't be an entry in the cache for this page anymore. */
}
-
+EXPORT_SYMBOL(flush_dcache_page);
/*
* For now, flush the whole cache. FIXME??
@@ -188,6 +186,7 @@
__flush_invalidate_dcache_all();
__invalidate_icache_all();
}
+EXPORT_SYMBOL(local_flush_cache_range);
/*
* Remove any entry in the cache for this page.
@@ -207,8 +206,9 @@
__flush_invalidate_dcache_page_alias(virt, phys);
__invalidate_icache_page_alias(virt, phys);
}
+EXPORT_SYMBOL(local_flush_cache_page);
-#endif
+#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
void
update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
@@ -225,7 +225,7 @@
flush_tlb_page(vma, addr);
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
unsigned long phys = page_to_phys(page);
@@ -256,7 +256,7 @@
* flush_dcache_page() on the page.
*/
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
diff --git a/block/blk-mq-pci.c b/block/blk-mq-pci.c
index 966c216..ee9d3d9 100644
--- a/block/blk-mq-pci.c
+++ b/block/blk-mq-pci.c
@@ -36,12 +36,18 @@
for (queue = 0; queue < set->nr_hw_queues; queue++) {
mask = pci_irq_get_affinity(pdev, queue);
if (!mask)
- return -EINVAL;
+ goto fallback;
for_each_cpu(cpu, mask)
set->mq_map[cpu] = queue;
}
return 0;
+
+fallback:
+ WARN_ON_ONCE(set->nr_hw_queues > 1);
+ for_each_possible_cpu(cpu)
+ set->mq_map[cpu] = 0;
+ return 0;
}
EXPORT_SYMBOL_GPL(blk_mq_pci_map_queues);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 28556fc..45af0fe 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -86,8 +86,13 @@
}
sgl = sreq->tsg;
n = sg_nents(sgl);
- for_each_sg(sgl, sg, n, i)
- put_page(sg_page(sg));
+ for_each_sg(sgl, sg, n, i) {
+ struct page *page = sg_page(sg);
+
+ /* some SGs may not have a page mapped */
+ if (page && page_ref_count(page))
+ put_page(page);
+ }
kfree(sreq->tsg);
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index e53bef6..0375c60 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -1072,6 +1072,7 @@
if (list_empty(&ghes_sci))
unregister_acpi_hed_notifier(&ghes_notifier_sci);
mutex_unlock(&ghes_list_mutex);
+ synchronize_rcu();
break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_remove(ghes);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 79152db..5187469 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1728,7 +1728,7 @@
* functioning ECDT EC first in order to handle the events.
* https://bugzilla.kernel.org/show_bug.cgi?id=115021
*/
-int __init acpi_ec_ecdt_start(void)
+static int __init acpi_ec_ecdt_start(void)
{
acpi_handle handle;
@@ -1959,20 +1959,17 @@
int __init acpi_ec_init(void)
{
int result;
+ int ecdt_fail, dsdt_fail;
/* register workqueue for _Qxx evaluations */
result = acpi_ec_query_init();
if (result)
- goto err_exit;
- /* Now register the driver for the EC */
- result = acpi_bus_register_driver(&acpi_ec_driver);
- if (result)
- goto err_exit;
+ return result;
-err_exit:
- if (result)
- acpi_ec_query_exit();
- return result;
+ /* Drivers must be started after acpi_ec_query_init() */
+ ecdt_fail = acpi_ec_ecdt_start();
+ dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver);
+ return ecdt_fail && dsdt_fail ? -ENODEV : 0;
}
/* EC driver currently not unloadable */
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 219b90b..08b3ca0 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -185,7 +185,6 @@
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_ec_dsdt_probe(void);
-int acpi_ec_ecdt_start(void);
void acpi_ec_block_transactions(void);
void acpi_ec_unblock_transactions(void);
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 6d7ce6e..5e18ccf 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -45,6 +45,12 @@
struct resource *res = data;
struct resource_win win;
+ /*
+ * We might assign this to 'res' later, make sure all pointers are
+ * cleared before the resource is added to the global list
+ */
+ memset(&win, 0, sizeof(win));
+
res->flags = 0;
if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM))
return AE_OK;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index dd3786a..cf725d5 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2051,7 +2051,6 @@
acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();
- acpi_ec_ecdt_start();
acpi_scan_initialized = true;
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index 4d4cdc1..01de42c 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -44,6 +44,16 @@
Note that enabling this will break newer Android user-space.
+config ANDROID_BINDER_IPC_SELFTEST
+ bool "Android Binder IPC Driver Selftest"
+ depends on ANDROID_BINDER_IPC
+ ---help---
+ This feature allows binder selftest to run.
+
+ Binder selftest checks the allocation and free of binder buffers
+ exhaustively with combinations of various buffer sizes and
+ alignments.
+
endif # if ANDROID
endmenu
diff --git a/drivers/android/Makefile b/drivers/android/Makefile
index 4b7c726..a01254c 100644
--- a/drivers/android/Makefile
+++ b/drivers/android/Makefile
@@ -1,3 +1,4 @@
ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
+obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 9f1a1bb..1ac8008 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2480,7 +2480,6 @@
(u64)node->ptr);
binder_node_unlock(node);
} else {
- int ret;
struct binder_ref_data dest_rdata;
binder_node_unlock(node);
@@ -3522,11 +3521,13 @@
BUG_ON(buf_node->proc != proc);
w = binder_dequeue_work_head_ilocked(
&buf_node->async_todo);
- if (!w)
+ if (!w) {
buf_node->has_async_transaction = 0;
- else
+ } else {
binder_enqueue_work_ilocked(
- w, &thread->todo);
+ w, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ }
binder_node_inner_unlock(buf_node);
}
trace_binder_transaction_buffer_release(buffer);
@@ -3670,22 +3671,12 @@
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
- if (thread->looper &
- (BINDER_LOOPER_STATE_REGISTERED |
- BINDER_LOOPER_STATE_ENTERED))
- binder_enqueue_work(
- proc,
- &ref->death->work,
- &thread->todo);
- else {
- binder_inner_proc_lock(proc);
- binder_enqueue_work_ilocked(
- &ref->death->work,
- &proc->todo);
- binder_wakeup_proc_ilocked(
- proc);
- binder_inner_proc_unlock(proc);
- }
+
+ binder_inner_proc_lock(proc);
+ binder_enqueue_work_ilocked(
+ &ref->death->work, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ binder_inner_proc_unlock(proc);
}
} else {
if (ref->death == NULL) {
@@ -3802,12 +3793,6 @@
}
}
-static int binder_has_thread_work(struct binder_thread *thread)
-{
- return !binder_worklist_empty(thread->proc, &thread->todo) ||
- thread->looper_need_return;
-}
-
static int binder_put_node_cmd(struct binder_proc *proc,
struct binder_thread *thread,
void __user **ptrp,
@@ -4438,12 +4423,9 @@
binder_inner_proc_unlock(thread->proc);
- if (binder_has_work(thread, wait_for_proc_work))
- return POLLIN;
-
poll_wait(filp, &thread->wait, wait);
- if (binder_has_thread_work(thread))
+ if (binder_has_work(thread, wait_for_proc_work))
return POLLIN;
return 0;
@@ -4597,6 +4579,8 @@
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
+ binder_selftest_alloc(&proc->alloc);
+
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
@@ -5442,6 +5426,8 @@
count = binder_alloc_get_allocated_count(&proc->alloc);
seq_printf(m, " buffers: %d\n", count);
+ binder_alloc_print_pages(m, &proc->alloc);
+
count = 0;
binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry) {
@@ -5638,6 +5624,8 @@
struct binder_device *device;
struct hlist_node *tmp;
+ binder_alloc_shrinker_init();
+
atomic_set(&binder_transaction_log.cur, ~0U);
atomic_set(&binder_transaction_log_failed.cur, ~0U);
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index b90222a..e026894 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -27,9 +27,12 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/list_lru.h>
#include "binder_alloc.h"
#include "binder_trace.h"
+struct list_lru binder_alloc_lru;
+
static DEFINE_MUTEX(binder_alloc_mmap_lock);
enum {
@@ -48,14 +51,23 @@
pr_info(x); \
} while (0)
+static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer)
+{
+ return list_entry(buffer->entry.next, struct binder_buffer, entry);
+}
+
+static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer)
+{
+ return list_entry(buffer->entry.prev, struct binder_buffer, entry);
+}
+
static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
if (list_is_last(&buffer->entry, &alloc->buffers))
- return alloc->buffer +
- alloc->buffer_size - (void *)buffer->data;
- return (size_t)list_entry(buffer->entry.next,
- struct binder_buffer, entry) - (size_t)buffer->data;
+ return (u8 *)alloc->buffer +
+ alloc->buffer_size - (u8 *)buffer->data;
+ return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data;
}
static void binder_insert_free_buffer(struct binder_alloc *alloc,
@@ -105,9 +117,9 @@
buffer = rb_entry(parent, struct binder_buffer, rb_node);
BUG_ON(buffer->free);
- if (new_buffer < buffer)
+ if (new_buffer->data < buffer->data)
p = &parent->rb_left;
- else if (new_buffer > buffer)
+ else if (new_buffer->data > buffer->data)
p = &parent->rb_right;
else
BUG();
@@ -122,18 +134,17 @@
{
struct rb_node *n = alloc->allocated_buffers.rb_node;
struct binder_buffer *buffer;
- struct binder_buffer *kern_ptr;
+ void *kern_ptr;
- kern_ptr = (struct binder_buffer *)(user_ptr - alloc->user_buffer_offset
- - offsetof(struct binder_buffer, data));
+ kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset);
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(buffer->free);
- if (kern_ptr < buffer)
+ if (kern_ptr < buffer->data)
n = n->rb_left;
- else if (kern_ptr > buffer)
+ else if (kern_ptr > buffer->data)
n = n->rb_right;
else {
/*
@@ -180,8 +191,9 @@
{
void *page_addr;
unsigned long user_page_addr;
- struct page **page;
- struct mm_struct *mm;
+ struct binder_lru_page *page;
+ struct mm_struct *mm = NULL;
+ bool need_mm = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: %s pages %pK-%pK\n", alloc->pid,
@@ -192,9 +204,18 @@
trace_binder_update_page_range(alloc, allocate, start, end);
- if (vma)
- mm = NULL;
- else
+ if (allocate == 0)
+ goto free_range;
+
+ for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
+ if (!page->page_ptr) {
+ need_mm = true;
+ break;
+ }
+ }
+
+ if (!vma && need_mm)
mm = get_task_mm(alloc->tsk);
if (mm) {
@@ -207,10 +228,7 @@
}
}
- if (allocate == 0)
- goto free_range;
-
- if (vma == NULL) {
+ if (!vma && need_mm) {
pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
alloc->pid);
goto err_no_vma;
@@ -218,18 +236,40 @@
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
int ret;
+ bool on_lru;
+ size_t index;
- page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
+ index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ page = &alloc->pages[index];
- BUG_ON(*page);
- *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
- if (*page == NULL) {
+ if (page->page_ptr) {
+ trace_binder_alloc_lru_start(alloc, index);
+
+ on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
+ WARN_ON(!on_lru);
+
+ trace_binder_alloc_lru_end(alloc, index);
+ continue;
+ }
+
+ if (WARN_ON(!vma))
+ goto err_page_ptr_cleared;
+
+ trace_binder_alloc_page_start(alloc, index);
+ page->page_ptr = alloc_page(GFP_KERNEL |
+ __GFP_HIGHMEM |
+ __GFP_ZERO);
+ if (!page->page_ptr) {
pr_err("%d: binder_alloc_buf failed for page at %pK\n",
alloc->pid, page_addr);
goto err_alloc_page_failed;
}
+ page->alloc = alloc;
+ INIT_LIST_HEAD(&page->lru);
+
ret = map_kernel_range_noflush((unsigned long)page_addr,
- PAGE_SIZE, PAGE_KERNEL, page);
+ PAGE_SIZE, PAGE_KERNEL,
+ &page->page_ptr);
flush_cache_vmap((unsigned long)page_addr,
(unsigned long)page_addr + PAGE_SIZE);
if (ret != 1) {
@@ -239,12 +279,14 @@
}
user_page_addr =
(uintptr_t)page_addr + alloc->user_buffer_offset;
- ret = vm_insert_page(vma, user_page_addr, page[0]);
+ ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
if (ret) {
pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
alloc->pid, user_page_addr);
goto err_vm_insert_page_failed;
}
+
+ trace_binder_alloc_page_end(alloc, index);
/* vm_insert_page does not seem to increment the refcount */
}
if (mm) {
@@ -256,16 +298,27 @@
free_range:
for (page_addr = end - PAGE_SIZE; page_addr >= start;
page_addr -= PAGE_SIZE) {
- page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
- if (vma)
- zap_page_range(vma, (uintptr_t)page_addr +
- alloc->user_buffer_offset, PAGE_SIZE, NULL);
+ bool ret;
+ size_t index;
+
+ index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ page = &alloc->pages[index];
+
+ trace_binder_free_lru_start(alloc, index);
+
+ ret = list_lru_add(&binder_alloc_lru, &page->lru);
+ WARN_ON(!ret);
+
+ trace_binder_free_lru_end(alloc, index);
+ continue;
+
err_vm_insert_page_failed:
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
err_map_kernel_failed:
- __free_page(*page);
- *page = NULL;
+ __free_page(page->page_ptr);
+ page->page_ptr = NULL;
err_alloc_page_failed:
+err_page_ptr_cleared:
;
}
err_no_vma:
@@ -321,6 +374,9 @@
return ERR_PTR(-ENOSPC);
}
+ /* Pad 0-size buffers so they get assigned unique addresses */
+ size = max(size, sizeof(void *));
+
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
@@ -380,14 +436,9 @@
has_page_addr =
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK);
- if (n == NULL) {
- if (size + sizeof(struct binder_buffer) + 4 >= buffer_size)
- buffer_size = size; /* no room for other buffers */
- else
- buffer_size = size + sizeof(struct binder_buffer);
- }
+ WARN_ON(n && buffer_size != size);
end_page_addr =
- (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
if (end_page_addr > has_page_addr)
end_page_addr = has_page_addr;
ret = binder_update_page_range(alloc, 1,
@@ -395,17 +446,25 @@
if (ret)
return ERR_PTR(ret);
- rb_erase(best_fit, &alloc->free_buffers);
- buffer->free = 0;
- buffer->free_in_progress = 0;
- binder_insert_allocated_buffer_locked(alloc, buffer);
if (buffer_size != size) {
- struct binder_buffer *new_buffer = (void *)buffer->data + size;
+ struct binder_buffer *new_buffer;
+ new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!new_buffer) {
+ pr_err("%s: %d failed to alloc new buffer struct\n",
+ __func__, alloc->pid);
+ goto err_alloc_buf_struct_failed;
+ }
+ new_buffer->data = (u8 *)buffer->data + size;
list_add(&new_buffer->entry, &buffer->entry);
new_buffer->free = 1;
binder_insert_free_buffer(alloc, new_buffer);
}
+
+ rb_erase(best_fit, &alloc->free_buffers);
+ buffer->free = 0;
+ buffer->free_in_progress = 0;
+ binder_insert_allocated_buffer_locked(alloc, buffer);
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd got %pK\n",
alloc->pid, size, buffer);
@@ -420,6 +479,12 @@
alloc->pid, size, alloc->free_async_space);
}
return buffer;
+
+err_alloc_buf_struct_failed:
+ binder_update_page_range(alloc, 0,
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data),
+ end_page_addr, NULL);
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -454,57 +519,59 @@
static void *buffer_start_page(struct binder_buffer *buffer)
{
- return (void *)((uintptr_t)buffer & PAGE_MASK);
+ return (void *)((uintptr_t)buffer->data & PAGE_MASK);
}
-static void *buffer_end_page(struct binder_buffer *buffer)
+static void *prev_buffer_end_page(struct binder_buffer *buffer)
{
- return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK);
+ return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK);
}
static void binder_delete_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
struct binder_buffer *prev, *next = NULL;
- int free_page_end = 1;
- int free_page_start = 1;
-
+ bool to_free = true;
BUG_ON(alloc->buffers.next == &buffer->entry);
- prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
+ prev = binder_buffer_prev(buffer);
BUG_ON(!prev->free);
- if (buffer_end_page(prev) == buffer_start_page(buffer)) {
- free_page_start = 0;
- if (buffer_end_page(prev) == buffer_end_page(buffer))
- free_page_end = 0;
+ if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) {
+ to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid, buffer, prev);
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid, buffer->data, prev->data);
}
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
- next = list_entry(buffer->entry.next,
- struct binder_buffer, entry);
- if (buffer_start_page(next) == buffer_end_page(buffer)) {
- free_page_end = 0;
- if (buffer_start_page(next) ==
- buffer_start_page(buffer))
- free_page_start = 0;
+ next = binder_buffer_next(buffer);
+ if (buffer_start_page(next) == buffer_start_page(buffer)) {
+ to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid, buffer, prev);
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid,
+ buffer->data,
+ next->data);
}
}
- list_del(&buffer->entry);
- if (free_page_start || free_page_end) {
+
+ if (PAGE_ALIGNED(buffer->data)) {
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
- alloc->pid, buffer, free_page_start ? "" : " end",
- free_page_end ? "" : " start", prev, next);
- binder_update_page_range(alloc, 0, free_page_start ?
- buffer_start_page(buffer) : buffer_end_page(buffer),
- (free_page_end ? buffer_end_page(buffer) :
- buffer_start_page(buffer)) + PAGE_SIZE, NULL);
+ "%d: merge free, buffer start %pK is page aligned\n",
+ alloc->pid, buffer->data);
+ to_free = false;
}
+
+ if (to_free) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: merge free, buffer %pK do not share page with %pK or %pK\n",
+ alloc->pid, buffer->data,
+ prev->data, next->data);
+ binder_update_page_range(alloc, 0, buffer_start_page(buffer),
+ buffer_start_page(buffer) + PAGE_SIZE,
+ NULL);
+ }
+ list_del(&buffer->entry);
+ kfree(buffer);
}
static void binder_free_buf_locked(struct binder_alloc *alloc,
@@ -525,8 +592,8 @@
BUG_ON(buffer->free);
BUG_ON(size > buffer_size);
BUG_ON(buffer->transaction != NULL);
- BUG_ON((void *)buffer < alloc->buffer);
- BUG_ON((void *)buffer > alloc->buffer + alloc->buffer_size);
+ BUG_ON(buffer->data < alloc->buffer);
+ BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size);
if (buffer->async_transaction) {
alloc->free_async_space += size + sizeof(struct binder_buffer);
@@ -544,8 +611,7 @@
rb_erase(&buffer->rb_node, &alloc->allocated_buffers);
buffer->free = 1;
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
- struct binder_buffer *next = list_entry(buffer->entry.next,
- struct binder_buffer, entry);
+ struct binder_buffer *next = binder_buffer_next(buffer);
if (next->free) {
rb_erase(&next->rb_node, &alloc->free_buffers);
@@ -553,8 +619,7 @@
}
}
if (alloc->buffers.next != &buffer->entry) {
- struct binder_buffer *prev = list_entry(buffer->entry.prev,
- struct binder_buffer, entry);
+ struct binder_buffer *prev = binder_buffer_prev(buffer);
if (prev->free) {
binder_delete_free_buffer(alloc, buffer);
@@ -640,14 +705,14 @@
}
alloc->buffer_size = vma->vm_end - vma->vm_start;
- if (binder_update_page_range(alloc, 1, alloc->buffer,
- alloc->buffer + PAGE_SIZE, vma)) {
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
ret = -ENOMEM;
- failure_string = "alloc small buf";
- goto err_alloc_small_buf_failed;
+ failure_string = "alloc buffer struct";
+ goto err_alloc_buf_struct_failed;
}
- buffer = alloc->buffer;
- INIT_LIST_HEAD(&alloc->buffers);
+
+ buffer->data = alloc->buffer;
list_add(&buffer->entry, &alloc->buffers);
buffer->free = 1;
binder_insert_free_buffer(alloc, buffer);
@@ -658,7 +723,7 @@
return 0;
-err_alloc_small_buf_failed:
+err_alloc_buf_struct_failed:
kfree(alloc->pages);
alloc->pages = NULL;
err_alloc_pages_failed:
@@ -678,14 +743,13 @@
{
struct rb_node *n;
int buffers, page_count;
+ struct binder_buffer *buffer;
BUG_ON(alloc->vma);
buffers = 0;
mutex_lock(&alloc->mutex);
while ((n = rb_first(&alloc->allocated_buffers))) {
- struct binder_buffer *buffer;
-
buffer = rb_entry(n, struct binder_buffer, rb_node);
/* Transaction should already have been freed */
@@ -695,22 +759,36 @@
buffers++;
}
+ while (!list_empty(&alloc->buffers)) {
+ buffer = list_first_entry(&alloc->buffers,
+ struct binder_buffer, entry);
+ WARN_ON(!buffer->free);
+
+ list_del(&buffer->entry);
+ WARN_ON_ONCE(!list_empty(&alloc->buffers));
+ kfree(buffer);
+ }
+
page_count = 0;
if (alloc->pages) {
int i;
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
void *page_addr;
+ bool on_lru;
- if (!alloc->pages[i])
+ if (!alloc->pages[i].page_ptr)
continue;
+ on_lru = list_lru_del(&binder_alloc_lru,
+ &alloc->pages[i].lru);
page_addr = alloc->buffer + i * PAGE_SIZE;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%s: %d: page %d at %pK not freed\n",
- __func__, alloc->pid, i, page_addr);
+ "%s: %d: page %d at %pK %s\n",
+ __func__, alloc->pid, i, page_addr,
+ on_lru ? "on lru" : "active");
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
- __free_page(alloc->pages[i]);
+ __free_page(alloc->pages[i].page_ptr);
page_count++;
}
kfree(alloc->pages);
@@ -754,6 +832,34 @@
}
/**
+ * binder_alloc_print_pages() - print page usage
+ * @m: seq_file for output via seq_printf()
+ * @alloc: binder_alloc for this proc
+ */
+void binder_alloc_print_pages(struct seq_file *m,
+ struct binder_alloc *alloc)
+{
+ struct binder_lru_page *page;
+ int i;
+ int active = 0;
+ int lru = 0;
+ int free = 0;
+
+ mutex_lock(&alloc->mutex);
+ for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+ page = &alloc->pages[i];
+ if (!page->page_ptr)
+ free++;
+ else if (list_empty(&page->lru))
+ active++;
+ else
+ lru++;
+ }
+ mutex_unlock(&alloc->mutex);
+ seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
+}
+
+/**
* binder_alloc_get_allocated_count() - return count of buffers
* @alloc: binder_alloc for this proc
*
@@ -787,6 +893,108 @@
}
/**
+ * binder_alloc_free_page() - shrinker callback to free pages
+ * @item: item to free
+ * @lock: lock protecting the item
+ * @cb_arg: callback argument
+ *
+ * Called from list_lru_walk() in binder_shrink_scan() to free
+ * up pages when the system is under memory pressure.
+ */
+enum lru_status binder_alloc_free_page(struct list_head *item,
+ struct list_lru_one *lru,
+ spinlock_t *lock,
+ void *cb_arg)
+{
+ struct mm_struct *mm = NULL;
+ struct binder_lru_page *page = container_of(item,
+ struct binder_lru_page,
+ lru);
+ struct binder_alloc *alloc;
+ uintptr_t page_addr;
+ size_t index;
+ struct vm_area_struct *vma;
+
+ alloc = page->alloc;
+ if (!mutex_trylock(&alloc->mutex))
+ goto err_get_alloc_mutex_failed;
+
+ if (!page->page_ptr)
+ goto err_page_already_freed;
+
+ index = page - alloc->pages;
+ page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
+ vma = alloc->vma;
+ if (vma) {
+ mm = get_task_mm(alloc->tsk);
+ if (!mm)
+ goto err_get_task_mm_failed;
+ if (!down_write_trylock(&mm->mmap_sem))
+ goto err_down_write_mmap_sem_failed;
+ }
+
+ list_lru_isolate(lru, item);
+ spin_unlock(lock);
+
+ if (vma) {
+ trace_binder_unmap_user_start(alloc, index);
+
+ zap_page_range(vma,
+ page_addr +
+ alloc->user_buffer_offset,
+ PAGE_SIZE, NULL);
+
+ trace_binder_unmap_user_end(alloc, index);
+
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ }
+
+ trace_binder_unmap_kernel_start(alloc, index);
+
+ unmap_kernel_range(page_addr, PAGE_SIZE);
+ __free_page(page->page_ptr);
+ page->page_ptr = NULL;
+
+ trace_binder_unmap_kernel_end(alloc, index);
+
+ spin_lock(lock);
+ mutex_unlock(&alloc->mutex);
+ return LRU_REMOVED_RETRY;
+
+err_down_write_mmap_sem_failed:
+ mmput_async(mm);
+err_get_task_mm_failed:
+err_page_already_freed:
+ mutex_unlock(&alloc->mutex);
+err_get_alloc_mutex_failed:
+ return LRU_SKIP;
+}
+
+static unsigned long
+binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+ unsigned long ret = list_lru_count(&binder_alloc_lru);
+ return ret;
+}
+
+static unsigned long
+binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+{
+ unsigned long ret;
+
+ ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ NULL, sc->nr_to_scan);
+ return ret;
+}
+
+struct shrinker binder_shrinker = {
+ .count_objects = binder_shrink_count,
+ .scan_objects = binder_shrink_scan,
+ .seeks = DEFAULT_SEEKS,
+};
+
+/**
* binder_alloc_init() - called by binder_open() for per-proc initialization
* @alloc: binder_alloc for this proc
*
@@ -798,5 +1006,11 @@
alloc->tsk = current->group_leader;
alloc->pid = current->group_leader->pid;
mutex_init(&alloc->mutex);
+ INIT_LIST_HEAD(&alloc->buffers);
}
+void binder_alloc_shrinker_init(void)
+{
+ list_lru_init(&binder_alloc_lru);
+ register_shrinker(&binder_shrinker);
+}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 088e4ff..a3a3602 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -21,7 +21,9 @@
#include <linux/rtmutex.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/list_lru.h>
+extern struct list_lru binder_alloc_lru;
struct binder_transaction;
/**
@@ -57,7 +59,19 @@
size_t data_size;
size_t offsets_size;
size_t extra_buffers_size;
- uint8_t data[0];
+ void *data;
+};
+
+/**
+ * struct binder_lru_page - page object used for binder shrinker
+ * @page_ptr: pointer to physical page in mmap'd space
+ * @lru: entry in binder_alloc_lru
+ * @alloc: binder_alloc for a proc
+ */
+struct binder_lru_page {
+ struct list_head lru;
+ struct page *page_ptr;
+ struct binder_alloc *alloc;
};
/**
@@ -75,8 +89,7 @@
* @allocated_buffers: rb tree of allocated buffers sorted by address
* @free_async_space: VA space available for async buffers. This is
* initialized at mmap time to 1/2 the full VA space
- * @pages: array of physical page addresses for each
- * page of mmap'd space
+ * @pages: array of binder_lru_page
* @buffer_size: size of address space specified via mmap
* @pid: pid for associated binder_proc (invariant after init)
*
@@ -96,18 +109,27 @@
struct rb_root free_buffers;
struct rb_root allocated_buffers;
size_t free_async_space;
- struct page **pages;
+ struct binder_lru_page *pages;
size_t buffer_size;
uint32_t buffer_free;
int pid;
};
+#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
+void binder_selftest_alloc(struct binder_alloc *alloc);
+#else
+static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
+#endif
+enum lru_status binder_alloc_free_page(struct list_head *item,
+ struct list_lru_one *lru,
+ spinlock_t *lock, void *cb_arg);
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async);
extern void binder_alloc_init(struct binder_alloc *alloc);
+void binder_alloc_shrinker_init(void);
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
extern struct binder_buffer *
binder_alloc_prepare_to_free(struct binder_alloc *alloc,
@@ -120,6 +142,8 @@
extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
extern void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc);
+void binder_alloc_print_pages(struct seq_file *m,
+ struct binder_alloc *alloc);
/**
* binder_alloc_get_free_async_space() - get free space available for async
diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c
new file mode 100644
index 0000000..8bd7bce
--- /dev/null
+++ b/drivers/android/binder_alloc_selftest.c
@@ -0,0 +1,310 @@
+/* binder_alloc_selftest.c
+ *
+ * Android IPC Subsystem
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mm_types.h>
+#include <linux/err.h>
+#include "binder_alloc.h"
+
+#define BUFFER_NUM 5
+#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
+
+static bool binder_selftest_run = true;
+static int binder_selftest_failures;
+static DEFINE_MUTEX(binder_selftest_lock);
+
+/**
+ * enum buf_end_align_type - Page alignment of a buffer
+ * end with regard to the end of the previous buffer.
+ *
+ * In the pictures below, buf2 refers to the buffer we
+ * are aligning. buf1 refers to previous buffer by addr.
+ * Symbol [ means the start of a buffer, ] means the end
+ * of a buffer, and | means page boundaries.
+ */
+enum buf_end_align_type {
+ /**
+ * @SAME_PAGE_UNALIGNED: The end of this buffer is on
+ * the same page as the end of the previous buffer and
+ * is not page aligned. Examples:
+ * buf1 ][ buf2 ][ ...
+ * buf1 ]|[ buf2 ][ ...
+ */
+ SAME_PAGE_UNALIGNED = 0,
+ /**
+ * @SAME_PAGE_ALIGNED: When the end of the previous buffer
+ * is not page aligned, the end of this buffer is on the
+ * same page as the end of the previous buffer and is page
+ * aligned. When the previous buffer is page aligned, the
+ * end of this buffer is aligned to the next page boundary.
+ * Examples:
+ * buf1 ][ buf2 ]| ...
+ * buf1 ]|[ buf2 ]| ...
+ */
+ SAME_PAGE_ALIGNED,
+ /**
+ * @NEXT_PAGE_UNALIGNED: The end of this buffer is on
+ * the page next to the end of the previous buffer and
+ * is not page aligned. Examples:
+ * buf1 ][ buf2 | buf2 ][ ...
+ * buf1 ]|[ buf2 | buf2 ][ ...
+ */
+ NEXT_PAGE_UNALIGNED,
+ /**
+ * @NEXT_PAGE_ALIGNED: The end of this buffer is on
+ * the page next to the end of the previous buffer and
+ * is page aligned. Examples:
+ * buf1 ][ buf2 | buf2 ]| ...
+ * buf1 ]|[ buf2 | buf2 ]| ...
+ */
+ NEXT_PAGE_ALIGNED,
+ /**
+ * @NEXT_NEXT_UNALIGNED: The end of this buffer is on
+ * the page that follows the page after the end of the
+ * previous buffer and is not page aligned. Examples:
+ * buf1 ][ buf2 | buf2 | buf2 ][ ...
+ * buf1 ]|[ buf2 | buf2 | buf2 ][ ...
+ */
+ NEXT_NEXT_UNALIGNED,
+ LOOP_END,
+};
+
+static void pr_err_size_seq(size_t *sizes, int *seq)
+{
+ int i;
+
+ pr_err("alloc sizes: ");
+ for (i = 0; i < BUFFER_NUM; i++)
+ pr_cont("[%zu]", sizes[i]);
+ pr_cont("\n");
+ pr_err("free seq: ");
+ for (i = 0; i < BUFFER_NUM; i++)
+ pr_cont("[%d]", seq[i]);
+ pr_cont("\n");
+}
+
+static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ size_t size)
+{
+ void *page_addr, *end;
+ int page_index;
+
+ end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
+ page_addr = buffer->data;
+ for (; page_addr < end; page_addr += PAGE_SIZE) {
+ page_index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ if (!alloc->pages[page_index].page_ptr ||
+ !list_empty(&alloc->pages[page_index].lru)) {
+ pr_err("expect alloc but is %s at page index %d\n",
+ alloc->pages[page_index].page_ptr ?
+ "lru" : "free", page_index);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffers[],
+ size_t *sizes, int *seq)
+{
+ int i;
+
+ for (i = 0; i < BUFFER_NUM; i++) {
+ buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
+ if (IS_ERR(buffers[i]) ||
+ !check_buffer_pages_allocated(alloc, buffers[i],
+ sizes[i])) {
+ pr_err_size_seq(sizes, seq);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_free_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffers[],
+ size_t *sizes, int *seq, size_t end)
+{
+ int i;
+
+ for (i = 0; i < BUFFER_NUM; i++)
+ binder_alloc_free_buf(alloc, buffers[seq[i]]);
+
+ for (i = 0; i < end / PAGE_SIZE; i++) {
+ /**
+ * Error message on a free page can be false positive
+ * if binder shrinker ran during binder_alloc_free_buf
+ * calls above.
+ */
+ if (list_empty(&alloc->pages[i].lru)) {
+ pr_err_size_seq(sizes, seq);
+ pr_err("expect lru but is %s at page index %d\n",
+ alloc->pages[i].page_ptr ? "alloc" : "free", i);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_free_page(struct binder_alloc *alloc)
+{
+ int i;
+ unsigned long count;
+
+ while ((count = list_lru_count(&binder_alloc_lru))) {
+ list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ NULL, count);
+ }
+
+ for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
+ if (alloc->pages[i].page_ptr) {
+ pr_err("expect free but is %s at page index %d\n",
+ list_empty(&alloc->pages[i].lru) ?
+ "alloc" : "lru", i);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_alloc_free(struct binder_alloc *alloc,
+ size_t *sizes, int *seq, size_t end)
+{
+ struct binder_buffer *buffers[BUFFER_NUM];
+
+ binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
+ binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
+
+ /* Allocate from lru. */
+ binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
+ if (list_lru_count(&binder_alloc_lru))
+ pr_err("lru list should be empty but is not\n");
+
+ binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
+ binder_selftest_free_page(alloc);
+}
+
+static bool is_dup(int *seq, int index, int val)
+{
+ int i;
+
+ for (i = 0; i < index; i++) {
+ if (seq[i] == val)
+ return true;
+ }
+ return false;
+}
+
+/* Generate BUFFER_NUM factorial free orders. */
+static void binder_selftest_free_seq(struct binder_alloc *alloc,
+ size_t *sizes, int *seq,
+ int index, size_t end)
+{
+ int i;
+
+ if (index == BUFFER_NUM) {
+ binder_selftest_alloc_free(alloc, sizes, seq, end);
+ return;
+ }
+ for (i = 0; i < BUFFER_NUM; i++) {
+ if (is_dup(seq, index, i))
+ continue;
+ seq[index] = i;
+ binder_selftest_free_seq(alloc, sizes, seq, index + 1, end);
+ }
+}
+
+static void binder_selftest_alloc_size(struct binder_alloc *alloc,
+ size_t *end_offset)
+{
+ int i;
+ int seq[BUFFER_NUM] = {0};
+ size_t front_sizes[BUFFER_NUM];
+ size_t back_sizes[BUFFER_NUM];
+ size_t last_offset, offset = 0;
+
+ for (i = 0; i < BUFFER_NUM; i++) {
+ last_offset = offset;
+ offset = end_offset[i];
+ front_sizes[i] = offset - last_offset;
+ back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
+ }
+ /*
+ * Buffers share the first or last few pages.
+ * Only BUFFER_NUM - 1 buffer sizes are adjustable since
+ * we need one giant buffer before getting to the last page.
+ */
+ back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
+ binder_selftest_free_seq(alloc, front_sizes, seq, 0,
+ end_offset[BUFFER_NUM - 1]);
+ binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size);
+}
+
+static void binder_selftest_alloc_offset(struct binder_alloc *alloc,
+ size_t *end_offset, int index)
+{
+ int align;
+ size_t end, prev;
+
+ if (index == BUFFER_NUM) {
+ binder_selftest_alloc_size(alloc, end_offset);
+ return;
+ }
+ prev = index == 0 ? 0 : end_offset[index - 1];
+ end = prev;
+
+ BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
+
+ for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
+ if (align % 2)
+ end = ALIGN(end, PAGE_SIZE);
+ else
+ end += BUFFER_MIN_SIZE;
+ end_offset[index] = end;
+ binder_selftest_alloc_offset(alloc, end_offset, index + 1);
+ }
+}
+
+/**
+ * binder_selftest_alloc() - Test alloc and free of buffer pages.
+ * @alloc: Pointer to alloc struct.
+ *
+ * Allocate BUFFER_NUM buffers to cover all page alignment cases,
+ * then free them in all orders possible. Check that pages are
+ * correctly allocated, put onto lru when buffers are freed, and
+ * are freed when binder_alloc_free_page is called.
+ */
+void binder_selftest_alloc(struct binder_alloc *alloc)
+{
+ size_t end_offset[BUFFER_NUM];
+
+ if (!binder_selftest_run)
+ return;
+ mutex_lock(&binder_selftest_lock);
+ if (!binder_selftest_run || !alloc->vma)
+ goto done;
+ pr_info("STARTED\n");
+ binder_selftest_alloc_offset(alloc, end_offset, 0);
+ binder_selftest_run = false;
+ if (binder_selftest_failures > 0)
+ pr_info("%d tests FAILED\n", binder_selftest_failures);
+ else
+ pr_info("PASSED\n");
+
+done:
+ mutex_unlock(&binder_selftest_lock);
+}
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
index 7967db1..76e3b9c 100644
--- a/drivers/android/binder_trace.h
+++ b/drivers/android/binder_trace.h
@@ -291,6 +291,61 @@
__entry->offset, __entry->size)
);
+DECLARE_EVENT_CLASS(binder_lru_page_class,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index),
+ TP_STRUCT__entry(
+ __field(int, proc)
+ __field(size_t, page_index)
+ ),
+ TP_fast_assign(
+ __entry->proc = alloc->pid;
+ __entry->page_index = page_index;
+ ),
+ TP_printk("proc=%d page_index=%zu",
+ __entry->proc, __entry->page_index)
+);
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
TRACE_EVENT(binder_command,
TP_PROTO(uint32_t cmd),
TP_ARGS(cmd),
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 8e575fb..e3e10e8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2971,10 +2971,12 @@
static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{
if (!sata_pmp_attached(ap)) {
- if (likely(devno < ata_link_max_devices(&ap->link)))
+ if (likely(devno >= 0 &&
+ devno < ata_link_max_devices(&ap->link)))
return &ap->link.device[devno];
} else {
- if (likely(devno < ap->nr_pmp_links))
+ if (likely(devno >= 0 &&
+ devno < ap->nr_pmp_links))
return &ap->pmp_link[devno].device[0];
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 35ab4d5..ac43d6f 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1116,13 +1116,7 @@
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
- if ((dev->pm_domain) || (dev->type && dev->type->pm)
- || (dev->class && (dev->class->pm || dev->class->resume))
- || (dev->bus && (dev->bus->pm || dev->bus->resume)) ||
- (dev->driver && dev->driver->pm)) {
- device_pm_add(dev);
- }
-
+ device_pm_add(dev);
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index c1e56c3..4f99101 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -162,12 +162,6 @@
pr_debug("PM: Moving %s:%s before %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert before devb. */
list_move_tail(&deva->power.entry, &devb->power.entry);
}
@@ -182,12 +176,6 @@
pr_debug("PM: Moving %s:%s after %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert after devb. */
list_move(&deva->power.entry, &devb->power.entry);
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 43a36d6..06f6668 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -182,11 +182,12 @@
return 0;
}
-static inline struct fwnode_handle *dev_fwnode(struct device *dev)
+struct fwnode_handle *dev_fwnode(struct device *dev)
{
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
&dev->of_node->fwnode : dev->fwnode;
}
+EXPORT_SYMBOL_GPL(dev_fwnode);
/**
* device_property_present - check if a property of a device is present
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index fc814a3..45fc564 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -32,3 +32,12 @@
config REGMAP_SWR
tristate
+
+config REGMAP_ALLOW_WRITE_DEBUGFS
+ depends on REGMAP && DEBUG_FS
+ bool "Allow REGMAP debugfs write"
+ default n
+ help
+ Say 'y' here to allow the regmap debugfs write. Regmap debugfs write
+ could be risky when accessing some essential hardwares, so it is not
+ recommended to enable this option on any production device.
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index b4c5224..1559070 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -269,8 +269,7 @@
count, ppos);
}
-#define REGMAP_ALLOW_WRITE_DEBUGFS
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous especially when we have clients such as
* PMICs, therefore don't provide any real compile time configuration option
@@ -340,7 +339,7 @@
new_count, ppos);
}
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
static ssize_t regmap_data_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -633,7 +632,7 @@
if (map->max_register || regmap_readable(map, 0)) {
umode_t registers_mode;
-#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
registers_mode = 0600;
#else
registers_mode = 0400;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c9441f9..98b767d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -929,6 +929,7 @@
return -ENOMEM;
for (i = 0; i < nbds_max; i++) {
+ struct request_queue *q;
struct gendisk *disk = alloc_disk(1 << part_shift);
if (!disk)
goto out;
@@ -954,12 +955,13 @@
* every gendisk to have its very own request_queue struct.
* These structs are big so we dynamically allocate them.
*/
- disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set);
- if (!disk->queue) {
+ q = blk_mq_init_queue(&nbd_dev[i].tag_set);
+ if (IS_ERR(q)) {
blk_mq_free_tag_set(&nbd_dev[i].tag_set);
put_disk(disk);
goto out;
}
+ disk->queue = q;
/*
* Tell the block layer that we are not a rotational device
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 3c3b8f6..10332c2 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -630,11 +630,12 @@
if (err)
goto out_put_disk;
- q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
+ q = blk_mq_init_queue(&vblk->tag_set);
if (IS_ERR(q)) {
err = -ENOMEM;
goto out_free_tags;
}
+ vblk->disk->queue = q;
q->queuedata = vblk;
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 9908597..f11d62d 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2112,9 +2112,9 @@
/*
* Get the bios in the request so we can re-queue them.
*/
- if (req_op(shadow[i].request) == REQ_OP_FLUSH ||
- req_op(shadow[i].request) == REQ_OP_DISCARD ||
- req_op(shadow[i].request) == REQ_OP_SECURE_ERASE ||
+ if (req_op(shadow[j].request) == REQ_OP_FLUSH ||
+ req_op(shadow[j].request) == REQ_OP_DISCARD ||
+ req_op(shadow[j].request) == REQ_OP_SECURE_ERASE ||
shadow[j].request->cmd_flags & REQ_FUA) {
/*
* Flush operations don't contain bios, so
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index d7e24fc..354c6a0 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -729,8 +729,9 @@
struct diagfwd_info *fwd_info_cmd = NULL;
char *process_name = NULL;
int err = 0;
+ char *root_str = NULL;
uint8_t local_diag_id = 0;
- uint8_t new_request = 0;
+ uint8_t new_request = 0, i = 0;
if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
return;
@@ -753,20 +754,31 @@
ctrl_pkt.diag_id = diag_id;
new_request = 1;
}
+ root_str = strnstr(process_name, DIAG_ID_ROOT_STRING,
+ strlen(process_name));
if (new_request) {
fwd_info_data->num_pd++;
fwd_info_cmd->num_pd++;
+ if (root_str) {
+ fwd_info_cmd->diagid_root = ctrl_pkt.diag_id;
+ fwd_info_data->diagid_root = ctrl_pkt.diag_id;
+ } else {
+ i = fwd_info_cmd->num_pd - 2;
+ if (i >= 0)
+ fwd_info_cmd->diagid_user[i] =
+ ctrl_pkt.diag_id;
+
+ i = fwd_info_data->num_pd - 2;
+ if (i >= 0)
+ fwd_info_data->diagid_user[i] =
+ ctrl_pkt.diag_id;
+ }
}
- if (strnstr(process_name, DIAG_ID_ROOT_STRING, strlen(process_name))) {
- fwd_info_cmd->diagid_root = diag_id;
- fwd_info_data->diagid_root = diag_id;
+ if (root_str)
driver->diag_id_sent[peripheral] = 0;
- } else {
- fwd_info_cmd->diagid_user[fwd_info_cmd->num_pd - 2] = diag_id;
- fwd_info_data->diagid_user[fwd_info_data->num_pd - 2] = diag_id;
- }
+
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
@@ -794,6 +806,10 @@
* to peripherals.
*/
driver->diag_id_sent[peripheral] = 1;
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
+ driver->diag_id_sent[peripheral], peripheral,
+ ctrl_pkt.diag_id, process_name);
diag_send_updates_peripheral(peripheral);
diagfwd_buffers_init(fwd_info_data);
}
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 13904fd..9f7f699 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1058,7 +1058,7 @@
return -ENODEV;
if (type == TYPE_CMD) {
- if (driver->feature[peripheral].untag_header)
+ if (driver->feature[peripheral].diag_id_support)
if (!fwd_info->diagid_root ||
(!driver->diag_id_sent[peripheral])) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index e7d3ee4..afb2c01 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -459,6 +459,37 @@
}
}
+static int clk_fabia_pll_latch_input(struct clk_alpha_pll *pll,
+ struct regmap *regmap)
+{
+ u32 regval;
+ int ret = 0;
+
+ /* Latch the PLL input */
+ ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+ FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
+ if (ret)
+ return ret;
+
+ /* Wait for 2 reference cycles before checking the ACK bit. */
+ udelay(1);
+ regmap_read(regmap, pll->offset + PLL_MODE, ®val);
+ if (!(regval & FABIA_PLL_ACK_LATCH)) {
+ WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
+ return -EINVAL;
+ }
+
+ /* Return the latch input to 0 */
+ ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+ FABIA_PLL_UPDATE, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for PLL output to stabilize */
+ udelay(100);
+ return ret;
+}
+
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct pll_config *config)
{
@@ -471,6 +502,7 @@
if (config->frac)
regmap_write(regmap, pll->offset + FABIA_FRAC_VAL,
config->frac);
+
if (config->config_ctl_val)
regmap_write(regmap, pll->offset + PLL_CONFIG_CTL,
config->config_ctl_val);
@@ -482,6 +514,14 @@
mask, val);
}
+ /*
+ * If the PLL has already been initialized, it would now be in a STANDBY
+ * state. Any new updates to the PLL frequency will require setting the
+ * PLL_UPDATE bit.
+ */
+ if (pll->inited)
+ clk_fabia_pll_latch_input(pll, regmap);
+
regmap_update_bits(regmap, pll->offset + PLL_MODE,
FABIA_PLL_HW_UPDATE_LOGIC_BYPASS,
FABIA_PLL_HW_UPDATE_LOGIC_BYPASS);
@@ -627,29 +667,8 @@
regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
regmap_write(pll->clkr.regmap, off + FABIA_FRAC_VAL, a);
- /* Latch the PLL input */
- ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
- FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
- if (ret)
- return ret;
-
- /* Wait for 2 reference cycles before checking the ACK bit. */
- udelay(1);
- regmap_read(pll->clkr.regmap, off + PLL_MODE, ®val);
- if (!(regval & FABIA_PLL_ACK_LATCH)) {
- WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
- return -EINVAL;
- }
-
- /* Return the latch input to 0 */
- ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
- FABIA_PLL_UPDATE, 0);
- if (ret)
- return ret;
-
- /* Wait for PLL output to stabilize */
- udelay(100);
- return 0;
+ ret = clk_fabia_pll_latch_input(pll, pll->clkr.regmap);
+ return ret;
}
static void clk_fabia_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
index ff229fb..e2bfe42 100644
--- a/drivers/clk/qcom/clk-aop-qmp.c
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -139,6 +139,12 @@
struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
mutex_lock(&clk_aop_lock);
+ /*
+ * Return early if the clock has been enabled already. This
+ * is to avoid issues with sending duplicate enable requests.
+ */
+ if (clk->enabled)
+ goto err;
if (clk->level)
rate = clk->level;
@@ -179,6 +185,9 @@
mutex_lock(&clk_aop_lock);
+ if (!clk->enabled)
+ goto err;
+
rate = clk->disable_state;
snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}",
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index d57bf5f..7a2969a 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -385,6 +385,20 @@
{ }
};
+static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm670[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(286670000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
.cmd_rcgr = 0x2088,
.mnd_width = 0,
@@ -1036,9 +1050,9 @@
disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
358000000;
disp_cc_mdss_dp_pixel1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
- 337500000;
+ 337500;
disp_cc_mdss_dp_pixel_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
- 337500000;
+ 337500;
disp_cc_mdss_mdp_clk_src.freq_tbl =
ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2;
disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
@@ -1068,6 +1082,9 @@
static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap)
{
disp_cc_sdm845_fixup_sdm845v2(regmap);
+
+ disp_cc_mdss_mdp_clk_src.freq_tbl =
+ ftbl_disp_cc_mdss_mdp_clk_src_sdm670;
}
static int disp_cc_sdm845_fixup(struct platform_device *pdev,
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index eb6c658..1cd6c9c 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -665,7 +665,6 @@
static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
{
- dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
dsi_pll_disable_pll_bias(rsc);
}
@@ -684,11 +683,20 @@
pr_debug("stop PLL (%d)\n", rsc->index);
+ /*
+ * To avoid any stray glitches while
+ * abruptly powering down the PLL
+ * make sure to gate the clock using
+ * the clock enable bit before powering
+ * down the PLL
+ */
+ dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0);
dsi_pll_disable_sub(rsc);
- if (rsc->slave)
+ if (rsc->slave) {
+ dsi_pll_disable_global_clk(rsc->slave);
dsi_pll_disable_sub(rsc->slave);
-
+ }
/* flush, ensure all register writes are done*/
wmb();
rsc->pll_on = false;
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 8c8b495..cdc092a 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -586,7 +586,7 @@
GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
GATE_BUS_TOP, 24, 0, 0),
GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
- GATE_BUS_TOP, 27, 0, 0),
+ GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
};
static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
@@ -956,20 +956,20 @@
GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0),
GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys",
- GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0),
GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2",
GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d",
GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d",
- GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0),
GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg",
GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0",
GATE_BUS_TOP, 5, 0, 0),
GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl",
- GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0),
GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl",
GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp",
@@ -983,20 +983,20 @@
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333",
- GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0),
GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
GATE_BUS_TOP, 16, 0, 0),
GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl",
GATE_BUS_TOP, 17, 0, 0),
GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1",
- GATE_BUS_TOP, 18, 0, 0),
+ GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0),
GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24",
GATE_BUS_TOP, 28, 0, 0),
GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m",
GATE_BUS_TOP, 29, 0, 0),
GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
- SRC_MASK_TOP2, 24, 0, 0),
+ SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0),
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
SRC_MASK_TOP7, 20, 0, 0),
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index 0ab4c21..fb11acd 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -779,6 +779,7 @@
if (ret)
goto failed_parse_params;
+ INIT_LIST_HEAD(&c->list);
INIT_LIST_HEAD(&c->child);
INIT_LIST_HEAD(&c->cpu);
c->parent = parent;
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 7868765..b54af97 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -1074,7 +1074,7 @@
req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
&crypt->icv_rev_aes);
if (unlikely(!req_ctx->hmac_virt))
- goto free_buf_src;
+ goto free_buf_dst;
if (!encrypt) {
scatterwalk_map_and_copy(req_ctx->hmac_virt,
req->src, cryptlen, authsize, 0);
@@ -1089,10 +1089,10 @@
BUG_ON(qmgr_stat_overflow(SEND_QID));
return -EINPROGRESS;
-free_buf_src:
- free_buf_chain(dev, req_ctx->src, crypt->src_buf);
free_buf_dst:
free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
+free_buf_src:
+ free_buf_chain(dev, req_ctx->src, crypt->src_buf);
crypt->ctl_flags = CTL_FLAG_UNUSED;
return -ENOMEM;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f2bb512..063d176 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -703,24 +703,23 @@
{
struct lineevent_state *le = p;
struct gpioevent_data ge;
- int ret;
+ int ret, level;
ge.timestamp = ktime_get_real_ns();
+ level = gpiod_get_value_cansleep(le->desc);
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
- int level = gpiod_get_value_cansleep(le->desc);
-
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) {
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) {
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else {
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index dc9511c..327bdf1 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -1301,6 +1301,7 @@
amdgpu_program_register_sequence(adev,
pitcairn_mgcg_cgcg_init,
(const u32)ARRAY_SIZE(pitcairn_mgcg_cgcg_init));
+ break;
case CHIP_VERDE:
amdgpu_program_register_sequence(adev,
verde_golden_registers,
@@ -1325,6 +1326,7 @@
amdgpu_program_register_sequence(adev,
oland_mgcg_cgcg_init,
(const u32)ARRAY_SIZE(oland_mgcg_cgcg_init));
+ break;
case CHIP_HAINAN:
amdgpu_program_register_sequence(adev,
hainan_golden_registers,
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 99011621..4e16dff 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1459,6 +1459,9 @@
if (config->funcs->atomic_check)
ret = config->funcs->atomic_check(state->dev, state);
+ if (ret)
+ return ret;
+
if (!state->allow_modeset) {
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
@@ -1469,7 +1472,7 @@
}
}
- return ret;
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_check_only);
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index ac5437e..6394109 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -358,20 +358,13 @@
*/
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
{
- u8 value;
+ u8 value = DP_SET_POWER_D0;
int err;
/* DP_SET_POWER register is only available on DPCD v1.1 and later */
if (link->revision < 0x11)
return 0;
- err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
- if (err < 0)
- return err;
-
- value &= ~DP_SET_POWER_MASK;
- value |= DP_SET_POWER_D0;
-
err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 465bacd..48e99ab 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -255,13 +255,13 @@
struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev;
+ if (dev->driver->gem_close_object)
+ dev->driver->gem_close_object(obj, file_priv);
+
if (drm_core_check_feature(dev, DRIVER_PRIME))
drm_gem_remove_prime_handles(obj, file_priv);
drm_vma_node_revoke(&obj->vma_node, file_priv);
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, file_priv);
-
drm_gem_object_handle_unreference_unlocked(obj);
return 0;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index afdd55d..1ac9a95 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -264,8 +264,8 @@
if (ret)
return ret;
- if (r->reloc_offset >= bo->obj->base.size - sizeof(*ptr)) {
- DRM_ERROR("relocation %u outside object", i);
+ if (r->reloc_offset > bo->obj->base.size - sizeof(*ptr)) {
+ DRM_ERROR("relocation %u outside object\n", i);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c
index 95a7277..89a7774 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -394,6 +394,7 @@
}
/* Program the max register to clamp values > 1.0. */
+ i = lut_size - 1;
I915_WRITE(PREC_PAL_GC_MAX(pipe, 0),
drm_color_lut_extract(lut[i].red, 16));
I915_WRITE(PREC_PAL_GC_MAX(pipe, 1),
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 3a33ce4..9327ddc 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -20,6 +20,9 @@
#include "dp_catalog.h"
#include "dp_reg.h"
+#define DP_GET_MSB(x) (x >> 8)
+#define DP_GET_LSB(x) (x & 0xff)
+
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
@@ -278,6 +281,174 @@
return dp_read(base + DP_HDCP_STATUS);
}
+static void dp_catalog_ctrl_setup_infoframe_sdp(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 header, data;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ header = dp_read(base + MMSS_DP_VSCEXT_0);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_0, header);
+
+ header = dp_read(base + MMSS_DP_VSCEXT_1);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_1, header);
+
+ header = dp_read(base + MMSS_DP_VSCEXT_1);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_1, header);
+
+ header = ctrl->hdr_data.version;
+ header |= ctrl->hdr_data.length << 8;
+ header |= ctrl->hdr_data.eotf << 16;
+ header |= (ctrl->hdr_data.descriptor_id << 24);
+ dp_write(base + MMSS_DP_VSCEXT_2, header);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[0]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_3, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[1]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_4, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[2]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_5, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.white_point_x) |
+ (DP_GET_MSB(ctrl->hdr_data.white_point_x) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.white_point_y) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.white_point_y) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_6, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.max_luminance) |
+ (DP_GET_MSB(ctrl->hdr_data.max_luminance) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.min_luminance) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.min_luminance) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_7, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.max_content_light_level) |
+ (DP_GET_MSB(ctrl->hdr_data.max_content_light_level) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.max_average_light_level) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.max_average_light_level) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_8, data);
+
+ dp_write(base + MMSS_DP_VSCEXT_9, 0x00);
+}
+
+static void dp_catalog_ctrl_setup_vsc_sdp(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 value;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ value = dp_read(base + MMSS_DP_GENERIC0_0);
+ value |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_GENERIC0_0, value);
+
+ value = dp_read(base + MMSS_DP_GENERIC0_1);
+ value |= ctrl->hdr_data.vsc_hdr_byte2;
+ dp_write(base + MMSS_DP_GENERIC0_1, value);
+
+ value = dp_read(base + MMSS_DP_GENERIC0_1);
+ value |= ctrl->hdr_data.vsc_hdr_byte3;
+ dp_write(base + MMSS_DP_GENERIC0_1, value);
+
+ dp_write(base + MMSS_DP_GENERIC0_2, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_3, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_4, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_5, 0x00);
+
+ dp_write(base + MMSS_DP_GENERIC0_6, ctrl->hdr_data.pkt_payload);
+ dp_write(base + MMSS_DP_GENERIC0_7, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_8, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_9, 0x00);
+}
+
+static void dp_catalog_ctrl_config_hdr(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 cfg, cfg2;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ cfg = dp_read(base + MMSS_DP_SDP_CFG);
+ /* VSCEXT_SDP_EN */
+ cfg |= BIT(16);
+
+ /* GEN0_SDP_EN */
+ cfg |= BIT(17);
+
+ dp_write(base + MMSS_DP_SDP_CFG, cfg);
+
+ cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+ /* Generic0 SDP Payload is 19 bytes which is > 16, so Bit16 is 1 */
+ cfg2 |= BIT(16);
+ dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+
+ dp_catalog_ctrl_setup_vsc_sdp(ctrl);
+ dp_catalog_ctrl_setup_infoframe_sdp(ctrl);
+
+ cfg = dp_read(base + DP_MISC1_MISC0);
+ /* Indicates presence of VSC */
+ cfg |= BIT(6) << 8;
+
+ dp_write(base + DP_MISC1_MISC0, cfg);
+
+ cfg = dp_read(base + DP_CONFIGURATION_CTRL);
+ /* Send VSC */
+ cfg |= BIT(7);
+
+ switch (ctrl->hdr_data.bpc) {
+ default:
+ case 10:
+ cfg |= BIT(9);
+ break;
+ case 8:
+ cfg |= BIT(8);
+ break;
+ }
+
+ dp_write(base + DP_CONFIGURATION_CTRL, cfg);
+
+ cfg = dp_read(base + DP_COMPRESSION_MODE_CTRL);
+
+ /* Trigger SDP values in registers */
+ cfg |= BIT(8);
+ dp_write(base + DP_COMPRESSION_MODE_CTRL, cfg);
+}
+
static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
{
struct dp_catalog_private *catalog;
@@ -382,7 +553,7 @@
static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl,
u32 cc, u32 tb)
{
- u32 misc_val = cc;
+ u32 misc_val;
struct dp_catalog_private *catalog;
void __iomem *base;
@@ -394,6 +565,8 @@
dp_catalog_get_priv(ctrl);
base = catalog->io->ctrl_io.base;
+ misc_val = dp_read(base + DP_MISC1_MISC0);
+ misc_val |= cc;
misc_val |= (tb << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */
@@ -1063,6 +1236,7 @@
.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg,
.update_vx_px = dp_catalog_ctrl_update_vx_px,
.get_interrupt = dp_catalog_ctrl_get_interrupt,
+ .config_hdr = dp_catalog_ctrl_config_hdr,
.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
.read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
.send_phy_pattern = dp_catalog_ctrl_send_phy_pattern,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 4523b4f..39c5c6d 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -34,6 +34,32 @@
#define DP_INTR_FRAME_END BIT(6)
#define DP_INTR_CRC_UPDATED BIT(9)
+#define HDR_PRIMARIES_COUNT 3
+
+struct dp_catalog_hdr_data {
+ u32 vsc_hdr_byte0;
+ u32 vsc_hdr_byte1;
+ u32 vsc_hdr_byte2;
+ u32 vsc_hdr_byte3;
+ u32 pkt_payload;
+
+ u32 bpc;
+
+ u32 version;
+ u32 length;
+ u32 eotf;
+ u32 descriptor_id;
+
+ u32 display_primaries_x[HDR_PRIMARIES_COUNT];
+ u32 display_primaries_y[HDR_PRIMARIES_COUNT];
+ u32 white_point_x;
+ u32 white_point_y;
+ u32 max_luminance;
+ u32 min_luminance;
+ u32 max_content_light_level;
+ u32 max_average_light_level;
+};
+
struct dp_catalog_aux {
u32 data;
u32 isr;
@@ -55,6 +81,7 @@
u32 valid_boundary;
u32 valid_boundary2;
u32 isr;
+ struct dp_catalog_hdr_data hdr_data;
void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state);
void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u32 config);
@@ -75,6 +102,7 @@
void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level,
u8 p_level);
void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
+ void (*config_hdr)(struct dp_catalog_ctrl *ctrl);
void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 9ce23b1..dcdcc6f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1086,7 +1086,6 @@
catalog = ctrl->catalog;
catalog->usb_reset(ctrl->catalog, flip);
- catalog->reset(ctrl->catalog);
catalog->phy_reset(ctrl->catalog);
catalog->enable_irq(ctrl->catalog, true);
@@ -1112,12 +1111,6 @@
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
ctrl->catalog->enable_irq(ctrl->catalog, false);
- ctrl->catalog->reset(ctrl->catalog);
-
- /* Make sure DP is disabled before clk disable */
- wmb();
-
- dp_ctrl_disable_mainlink_clocks(ctrl);
pr_debug("Host deinitialized successfully\n");
}
@@ -1390,8 +1383,14 @@
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
- pr_debug("DP off done\n");
+ ctrl->catalog->reset(ctrl->catalog);
+ /* Make sure DP is disabled before clk disable */
+ wmb();
+
+ dp_ctrl_disable_mainlink_clocks(ctrl);
+
+ pr_debug("DP off done\n");
}
static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 27cf147..5aaad24 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -79,6 +79,8 @@
#define MMSS_DP_PSR_CRC_RG (0x00000554)
#define MMSS_DP_PSR_CRC_B (0x00000558)
+#define DP_COMPRESSION_MODE_CTRL (0x00000580)
+
#define MMSS_DP_AUDIO_CFG (0x00000600)
#define MMSS_DP_AUDIO_STATUS (0x00000604)
#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
@@ -141,6 +143,17 @@
#define MMSS_DP_GENERIC1_8 (0x00000748)
#define MMSS_DP_GENERIC1_9 (0x0000074C)
+#define MMSS_DP_VSCEXT_0 (0x000006D0)
+#define MMSS_DP_VSCEXT_1 (0x000006D4)
+#define MMSS_DP_VSCEXT_2 (0x000006D8)
+#define MMSS_DP_VSCEXT_3 (0x000006DC)
+#define MMSS_DP_VSCEXT_4 (0x000006E0)
+#define MMSS_DP_VSCEXT_5 (0x000006E4)
+#define MMSS_DP_VSCEXT_6 (0x000006E8)
+#define MMSS_DP_VSCEXT_7 (0x000006EC)
+#define MMSS_DP_VSCEXT_8 (0x000006F0)
+#define MMSS_DP_VSCEXT_9 (0x000006F4)
+
#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index dcde566..4756bf6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1193,7 +1193,9 @@
msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, aspace);
+ mutex_lock(&dsi_ctrl->drm_dev->struct_mutex);
msm_gem_free_object(dsi_ctrl->tx_cmd_buf);
+ mutex_unlock(&dsi_ctrl->drm_dev->struct_mutex);
dsi_ctrl->tx_cmd_buf = NULL;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index aa81d55..5c22e65 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -84,6 +84,10 @@
return -EINVAL;
panel = dsi_display->panel;
+
+ if (!dsi_panel_initialized(panel))
+ return -EINVAL;
+
panel->bl_config.bl_level = bl_lvl;
/* scale backlight */
@@ -1708,7 +1712,9 @@
put_iova:
msm_gem_put_iova(display->tx_cmd_buf, aspace);
free_gem:
+ mutex_lock(&display->drm_dev->struct_mutex);
msm_gem_free_object(display->tx_cmd_buf);
+ mutex_unlock(&display->drm_dev->struct_mutex);
error:
return rc;
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index b829460..f8c3df5 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -311,8 +311,7 @@
}
}
-static void
-put_iova(struct drm_gem_object *obj)
+static void put_iova(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -324,12 +323,14 @@
if (iommu_present(&platform_bus_type)) {
msm_gem_unmap_vma(domain->aspace, domain,
msm_obj->sgt, get_dmabuf_ptr(obj));
-
- msm_gem_remove_obj_from_aspace_active_list(
- domain->aspace,
- obj);
}
+ /*
+ * put_iova removes the domain connected to the obj which makes
+ * the aspace inaccessible. Store the aspace, as it is used to
+ * update the active_list during gem_free_obj and gem_purege.
+ */
+ msm_obj->aspace = domain->aspace;
obj_remove_domain(domain);
}
}
@@ -409,7 +410,8 @@
if (!ret && domain) {
*iova = domain->iova;
- msm_gem_add_obj_to_aspace_active_list(aspace, obj);
+ if (aspace && aspace->domain_attached)
+ msm_gem_add_obj_to_aspace_active_list(aspace, obj);
} else {
obj_remove_domain(domain);
}
@@ -485,24 +487,21 @@
/**
* Unmap active buffers,
* typically clients should do this when the callback is called,
- * but this needs to be done for the framebuffers which are not
- * attached to any planes. (background apps)
+ * but this needs to be done for the buffers which are not
+ * attached to any planes.
*/
list_for_each_entry(msm_obj, &aspace->active_list, iova_list) {
obj = &msm_obj->base;
- if (obj->import_attach) {
+ if (obj->import_attach)
put_iova(obj);
- put_pages(obj);
- }
}
} else {
/* map active buffers */
- list_for_each_entry(msm_obj, &aspace->active_list,
- iova_list) {
+ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) {
obj = &msm_obj->base;
ret = msm_gem_get_iova_locked(obj, aspace, &iova);
if (ret) {
- mutex_unlock(&obj->dev->struct_mutex);
+ mutex_unlock(&aspace->dev->struct_mutex);
return;
}
}
@@ -613,6 +612,7 @@
WARN_ON(obj->import_attach);
put_iova(obj);
+ msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, obj);
msm_gem_vunmap(obj);
@@ -841,6 +841,7 @@
list_del(&msm_obj->mm_list);
put_iova(obj);
+ msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, obj);
if (obj->import_attach) {
if (msm_obj->vaddr)
@@ -913,6 +914,8 @@
return -EINVAL;
}
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
if (!iommu_present(&platform_bus_type))
use_vram = true;
else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
@@ -946,6 +949,7 @@
INIT_LIST_HEAD(&msm_obj->submit_entry);
INIT_LIST_HEAD(&msm_obj->domains);
INIT_LIST_HEAD(&msm_obj->iova_list);
+ msm_obj->aspace = NULL;
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
@@ -987,7 +991,7 @@
struct dma_buf *dmabuf, struct sg_table *sgt)
{
struct msm_gem_object *msm_obj;
- struct drm_gem_object *obj;
+ struct drm_gem_object *obj = NULL;
uint32_t size;
int ret, npages;
@@ -999,7 +1003,12 @@
size = PAGE_ALIGN(dmabuf->size);
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ERR_PTR(ret);
+
ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj);
+ mutex_unlock(&dev->struct_mutex);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index c50c453..8521bea 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -122,6 +122,8 @@
*/
struct drm_mm_node *vram_node;
struct list_head iova_list;
+
+ struct msm_gem_address_space *aspace;
};
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 30cf3df..efbbd24 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1263,7 +1263,7 @@
struct sde_hw_stage_cfg *stage_cfg;
struct sde_rect plane_crtc_roi;
- u32 flush_mask, flush_sbuf, flush_tmp;
+ u32 flush_mask, flush_sbuf;
uint32_t stage_idx, lm_idx;
int zpos_cnt[SDE_STAGE_MAX + 1] = { 0 };
int i;
@@ -1279,10 +1279,9 @@
lm = mixer->hw_lm;
stage_cfg = &sde_crtc->stage_cfg;
cstate = to_sde_crtc_state(crtc->state);
- flush_sbuf = 0x0;
- cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
cstate->sbuf_prefill_line = 0;
+ sde_crtc->sbuf_flush_mask = 0x0;
drm_atomic_crtc_for_each_plane(plane, crtc) {
state = plane->state;
@@ -1297,17 +1296,14 @@
pstate = to_sde_plane_state(state);
fb = state->fb;
- if (sde_plane_is_sbuf_mode(plane, &prefill))
- cstate->sbuf_cfg.rot_op_mode =
- SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
+ prefill = sde_plane_rot_calc_prefill(plane);
if (prefill > cstate->sbuf_prefill_line)
cstate->sbuf_prefill_line = prefill;
- sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_tmp);
+ sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_sbuf);
- /* persist rotator flush bit(s) for one more commit */
- flush_mask |= cstate->sbuf_flush_mask | flush_tmp;
- flush_sbuf |= flush_tmp;
+ /* save sbuf flush value for later */
+ sde_crtc->sbuf_flush_mask |= flush_sbuf;
SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
crtc->base.id,
@@ -1331,8 +1327,7 @@
state->src_w >> 16, state->src_h >> 16,
state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h,
- flush_tmp ? cstate->sbuf_cfg.rot_op_mode :
- SDE_CTL_ROT_OP_MODE_OFFLINE);
+ flush_sbuf != 0);
stage_idx = zpos_cnt[pstate->stage]++;
stage_cfg->stage[pstate->stage][stage_idx] =
@@ -1359,8 +1354,6 @@
}
}
- cstate->sbuf_flush_mask = flush_sbuf;
-
if (lm && lm->ops.setup_dim_layer) {
cstate = to_sde_crtc_state(crtc->state);
for (i = 0; i < cstate->num_dim_layers; i++)
@@ -2731,17 +2724,73 @@
return rc;
}
-void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
+static void _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
+ struct sde_crtc_state *cstate)
{
struct drm_plane *plane;
+ struct sde_crtc *sde_crtc;
+ struct sde_hw_ctl *ctl, *master_ctl;
+ u32 flush_mask;
+ int i;
+
+ if (!crtc || !cstate)
+ return;
+
+ sde_crtc = to_sde_crtc(crtc);
+
+ /*
+ * Update sbuf configuration and flush bits if a flush
+ * mask has been defined for either the current or
+ * previous commit.
+ *
+ * Updates are also required for the first commit after
+ * sbuf_flush_mask becomes 0x0, to properly transition
+ * the hardware out of sbuf mode.
+ */
+ if (!sde_crtc->sbuf_flush_mask_old && !sde_crtc->sbuf_flush_mask)
+ return;
+
+ flush_mask = sde_crtc->sbuf_flush_mask_old | sde_crtc->sbuf_flush_mask;
+ sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask;
+
+ SDE_ATRACE_BEGIN("crtc_kickoff_rot");
+
+ if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ sde_plane_kickoff(plane);
+ }
+ }
+
+ master_ctl = NULL;
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ ctl = sde_crtc->mixers[i].hw_ctl;
+ if (!ctl || !ctl->ops.setup_sbuf_cfg ||
+ !ctl->ops.update_pending_flush)
+ continue;
+
+ if (!master_ctl || master_ctl->idx > ctl->idx)
+ master_ctl = ctl;
+
+ ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ }
+
+ if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
+ master_ctl && master_ctl->ops.trigger_rot_start)
+ master_ctl->ops.trigger_rot_start(master_ctl);
+
+ SDE_ATRACE_END("crtc_kickoff_rot");
+}
+
+void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
+{
struct drm_encoder *encoder;
struct drm_device *dev;
struct sde_crtc *sde_crtc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
struct sde_crtc_state *cstate;
- struct sde_hw_ctl *ctl;
- int ret, i;
+ int ret;
if (!crtc) {
SDE_ERROR("invalid argument\n");
@@ -2768,6 +2817,11 @@
return;
SDE_ATRACE_BEGIN("crtc_commit");
+
+ /* default to ASYNC mode for inline rotation */
+ cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask ?
+ SDE_CTL_ROT_OP_MODE_INLINE_ASYNC : SDE_CTL_ROT_OP_MODE_OFFLINE;
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct sde_encoder_kickoff_params params = { 0 };
@@ -2782,8 +2836,27 @@
params.affected_displays = _sde_crtc_get_displays_affected(crtc,
crtc->state);
sde_encoder_prepare_for_kickoff(encoder, ¶ms);
+
+ /*
+ * For inline ASYNC modes, the flush bits are not written
+ * to hardware atomically, so avoid using it if a video
+ * mode encoder is active on this CRTC.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode ==
+ SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
+ sde_encoder_get_intf_mode(encoder) ==
+ INTF_MODE_VIDEO)
+ cstate->sbuf_cfg.rot_op_mode =
+ SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
}
+ /*
+ * For ASYNC inline modes, kick off the rotator now so that the H/W
+ * can start as soon as it's ready.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
+ _sde_crtc_commit_kickoff_rot(crtc, cstate);
+
/* wait for frame_event_done completion */
SDE_ATRACE_BEGIN("wait_for_frame_done_event");
ret = _sde_crtc_wait_for_frame_done(crtc);
@@ -2798,24 +2871,24 @@
if (atomic_inc_return(&sde_crtc->frame_pending) == 1) {
/* acquire bandwidth and other resources */
SDE_DEBUG("crtc%d first commit\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE1);
+ SDE_EVT32(DRMID(crtc), cstate->sbuf_cfg.rot_op_mode,
+ SDE_EVTLOG_FUNC_CASE1);
} else {
SDE_DEBUG("crtc%d commit\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE2);
+ SDE_EVT32(DRMID(crtc), cstate->sbuf_cfg.rot_op_mode,
+ SDE_EVTLOG_FUNC_CASE2);
}
sde_crtc->play_count++;
- if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
- drm_atomic_crtc_for_each_plane(plane, crtc) {
- sde_plane_kickoff(plane);
- }
- }
-
- for (i = 0; i < sde_crtc->num_mixers; i++) {
- ctl = sde_crtc->mixers[i].hw_ctl;
- if (ctl && ctl->ops.setup_sbuf_cfg)
- ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
- }
+ /*
+ * For SYNC inline modes, delay the kick off until after the
+ * wait for frame done in case the wait times out.
+ *
+ * Also perform a final kickoff when transitioning back to
+ * offline mode.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
+ _sde_crtc_commit_kickoff_rot(crtc, cstate);
sde_vbif_clear_errors(sde_kms);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index ea606b3..0783f11 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -204,6 +204,8 @@
* @misr_enable : boolean entry indicates misr enable/disable status.
* @misr_frame_count : misr frame count provided by client
* @misr_data : store misr data before turning off the clocks.
+ * @sbuf_flush_mask: flush mask for inline rotator
+ * @sbuf_flush_mask_old: inline rotator flush mask for previous commit
* @power_event : registered power event handle
* @cur_perf : current performance committed to clock/bandwidth driver
* @rp_lock : serialization lock for resource pool
@@ -264,6 +266,9 @@
u32 misr_frame_count;
u32 misr_data[CRTC_DUAL_MIXERS];
+ u32 sbuf_flush_mask;
+ u32 sbuf_flush_mask_old;
+
struct sde_power_event *power_event;
struct sde_core_perf_params cur_perf;
@@ -357,7 +362,6 @@
* @new_perf: new performance state being requested
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
- * @sbuf_flush_mask: flush mask for inline rotator
*/
struct sde_crtc_state {
struct drm_crtc_state base;
@@ -385,7 +389,6 @@
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
u32 sbuf_prefill_line;
- u32 sbuf_flush_mask;
struct sde_crtc_respool rp;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index b80ed1f..3158fe2 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -279,8 +279,9 @@
return;
SDE_DEBUG_VIDENC(vid_enc,
- "rot_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
- rot_fetch_lines, rot_fetch_start_vsync_counter);
+ "rot_fetch_lines %u vfp_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
+ rot_fetch_lines, vfp_fetch_lines,
+ rot_fetch_start_vsync_counter);
phys_enc->hw_ctl->ops.get_bitmask_intf(
phys_enc->hw_ctl, &flush_mask, vid_enc->hw_intf->idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index d3c2654..f35e999 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -2891,7 +2891,8 @@
vig_list_size += ARRAY_SIZE(rgb_10bit_formats)
+ ARRAY_SIZE(tp10_ubwc_formats)
+ ARRAY_SIZE(p010_formats);
- if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400))
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) ||
+ (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)))
vig_list_size += ARRAY_SIZE(p010_ubwc_formats);
wb2_list_size += ARRAY_SIZE(rgb_10bit_formats)
@@ -2932,7 +2933,8 @@
ARRAY_SIZE(rgb_10bit_formats));
index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
index, p010_formats, ARRAY_SIZE(p010_formats));
- if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400))
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) ||
+ (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)))
index += sde_copy_formats(sde_cfg->vig_formats,
vig_list_size, index, p010_ubwc_formats,
ARRAY_SIZE(p010_ubwc_formats));
@@ -2971,7 +2973,7 @@
sde_cfg->perf.min_prefill_lines = 25;
sde_cfg->vbif_qos_nlvl = 4;
sde_cfg->ts_prefill_rev = 1;
- } else if (IS_SDM845_TARGET(hw_rev)) {
+ } else if (IS_SDM845_TARGET(hw_rev) || IS_SDM670_TARGET(hw_rev)) {
/* update sdm845 target here */
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 24;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index d85c8720..7c43988 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -46,10 +46,12 @@
#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */
#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* sdm845 v1.0 */
#define SDE_HW_VER_401 SDE_HW_VER(4, 0, 1) /* sdm845 v2.0 */
+#define SDE_HW_VER_410 SDE_HW_VER(4, 1, 0) /* sdm670 v1.0 */
#define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170)
#define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300)
#define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
+#define IS_SDM670_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_410)
#define SDE_HW_BLK_NAME_LEN 16
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
index 4191367..c8e732a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
@@ -12,6 +12,7 @@
#include <drm/msm_drm_pp.h>
#include "sde_hw_color_processing_v1_7.h"
+#include "sde_hw_ctl.h"
#define PA_HUE_VIG_OFF 0x110
#define PA_SAT_VIG_OFF 0x114
@@ -26,6 +27,9 @@
#define PA_LUTV_DSPP_OFF 0x1400
#define PA_LUT_SWAP_OFF 0x234
+#define PA_LUTV_DSPP_CTRL_OFF 0x4c
+#define PA_LUTV_DSPP_SWAP_OFF 0x18
+
#define PA_HUE_MASK 0xFFF
#define PA_SAT_MASK 0xFFFF
#define PA_VAL_MASK 0xFF
@@ -458,6 +462,62 @@
SDE_REG_WRITE(&ctx->hw, base, op_mode);
}
+void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_pa_vlut *payload = NULL;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_hw_ctl *ctl = NULL;
+ u32 vlut_base, pa_hist_base;
+ u32 ctrl_off, swap_off;
+ u32 tmp = 0;
+ int i = 0, j = 0;
+ u32 flush_mask = 0;
+
+ if (!ctx) {
+ DRM_ERROR("invalid input parameter NULL ctx\n");
+ return;
+ }
+
+ if (!hw_cfg || (hw_cfg->payload && hw_cfg->len !=
+ sizeof(struct drm_msm_pa_vlut))) {
+ DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n",
+ hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
+ ((hw_cfg) ? hw_cfg->len : 0),
+ sizeof(struct drm_msm_pa_vlut));
+ return;
+ }
+
+ ctl = hw_cfg->ctl;
+ vlut_base = ctx->cap->sblk->vlut.base;
+ pa_hist_base = ctx->cap->sblk->hist.base;
+ ctrl_off = pa_hist_base + PA_LUTV_DSPP_CTRL_OFF;
+ swap_off = pa_hist_base + PA_LUTV_DSPP_SWAP_OFF;
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("Disable vlut feature\n");
+ SDE_REG_WRITE(&ctx->hw, ctrl_off, 0);
+ goto exit;
+ }
+
+ payload = hw_cfg->payload;
+ DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
+ for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) {
+ tmp = (payload->val[i] & REG_MASK(10)) |
+ ((payload->val[i + 1] & REG_MASK(10)) << 16);
+ SDE_REG_WRITE(&ctx->hw, (vlut_base + j), tmp);
+ }
+ SDE_REG_WRITE(&ctx->hw, ctrl_off, 1);
+ SDE_REG_WRITE(&ctx->hw, swap_off, 1);
+
+exit:
+ /* update flush bit */
+ if (ctl && ctl->ops.get_bitmask_dspp_pavlut) {
+ ctl->ops.get_bitmask_dspp_pavlut(ctl, &flush_mask, ctx->idx);
+ if (ctl->ops.update_pending_flush)
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ }
+}
+
void sde_setup_dspp_gc_v1_7(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_pgc_lut *payload = NULL;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
index 25e446b7..4cd2e5a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
@@ -76,6 +76,13 @@
void sde_setup_dspp_pa_vlut_v1_7(struct sde_hw_dspp *ctx, void *cfg);
/**
+ * sde_setup_dspp_pa_vlut_v1_8 - setup DSPP PA vLUT feature in v1.8 hardware
+ * @ctx: Pointer to DSPP context
+ * @cfg: Pointer to vLUT data
+ */
+void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg);
+
+/**
* sde_setup_dspp_gc_v1_7 - setup DSPP gc feature in v1.7 hardware
* @ctx: Pointer to DSPP context
* @cfg: Pointer to gc data
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 621a172..95b7a6d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -89,6 +89,11 @@
static inline void sde_hw_ctl_trigger_rot_start(struct sde_hw_ctl *ctx)
{
+ /* ROT flush bit is latched during ROT start, so set it first */
+ if (CTL_FLUSH_MASK_ROT & ctx->pending_flush_mask) {
+ ctx->pending_flush_mask &= ~CTL_FLUSH_MASK_ROT;
+ SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, CTL_FLUSH_MASK_ROT);
+ }
SDE_REG_WRITE(&ctx->hw, CTL_ROT_START, BIT(0));
}
@@ -235,6 +240,22 @@
return 0;
}
+static inline int sde_hw_ctl_get_bitmask_dspp_pavlut(struct sde_hw_ctl *ctx,
+ u32 *flushbits, enum sde_dspp dspp)
+{
+ switch (dspp) {
+ case DSPP_0:
+ *flushbits |= BIT(3);
+ break;
+ case DSPP_1:
+ *flushbits |= BIT(4);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static inline int sde_hw_ctl_get_bitmask_intf(struct sde_hw_ctl *ctx,
u32 *flushbits, enum sde_intf intf)
{
@@ -568,6 +589,7 @@
ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp;
ops->get_bitmask_mixer = sde_hw_ctl_get_bitmask_mixer;
ops->get_bitmask_dspp = sde_hw_ctl_get_bitmask_dspp;
+ ops->get_bitmask_dspp_pavlut = sde_hw_ctl_get_bitmask_dspp_pavlut;
ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf;
ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm;
ops->get_bitmask_wb = sde_hw_ctl_get_bitmask_wb;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 5d3ced3..97bc1c1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -173,6 +173,10 @@
u32 *flushbits,
enum sde_dspp blk);
+ int (*get_bitmask_dspp_pavlut)(struct sde_hw_ctl *ctx,
+ u32 *flushbits,
+ enum sde_dspp blk);
+
int (*get_bitmask_intf)(struct sde_hw_ctl *ctx,
u32 *flushbits,
enum sde_intf blk);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 5b3f51e..d30c0ae 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -82,9 +82,12 @@
} else if (c->cap->sblk->vlut.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x8))) {
ret = reg_dmav1_init_dspp_op_v4(i, c->idx);
- if (ret)
+ if (!ret)
c->ops.setup_vlut =
reg_dmav1_setup_dspp_vlutv18;
+ else
+ c->ops.setup_vlut =
+ sde_setup_dspp_pa_vlut_v1_8;
}
break;
case SDE_DSPP_GAMUT:
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 3d282ee..4e677c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -262,7 +262,7 @@
unsigned long features)
{
ops->setup_mixer_out = sde_hw_lm_setup_out;
- if (IS_SDM845_TARGET(m->hwversion))
+ if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion))
ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845;
else
ops->setup_blend_config = sde_hw_lm_setup_blend_config;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 4487d78..93637a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -582,7 +582,7 @@
return 0;
}
-static void sde_reg_dma_aspace_cb(void *cb_data, bool attach)
+static void sde_reg_dma_aspace_cb_locked(void *cb_data, bool is_detach)
{
struct sde_reg_dma_buffer *dma_buf = NULL;
struct msm_gem_address_space *aspace = NULL;
@@ -597,14 +597,23 @@
dma_buf = (struct sde_reg_dma_buffer *)cb_data;
aspace = dma_buf->aspace;
- if (attach) {
- rc = msm_gem_get_iova(dma_buf->buf, aspace, &dma_buf->iova);
+ if (is_detach) {
+ /* invalidate the stored iova */
+ dma_buf->iova = 0;
+
+ /* return the virtual address mapping */
+ msm_gem_put_vaddr_locked(dma_buf->buf);
+ msm_gem_vunmap(dma_buf->buf);
+
+ } else {
+ rc = msm_gem_get_iova_locked(dma_buf->buf, aspace,
+ &dma_buf->iova);
if (rc) {
DRM_ERROR("failed to get the iova rc %d\n", rc);
return;
}
- dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf);
+ dma_buf->vaddr = msm_gem_get_vaddr_locked(dma_buf->buf);
if (IS_ERR_OR_NULL(dma_buf->vaddr)) {
DRM_ERROR("failed to get va rc %d\n", rc);
return;
@@ -615,13 +624,6 @@
dma_buf->iova = dma_buf->iova + offset;
dma_buf->vaddr = (void *)(((u8 *)dma_buf->vaddr) + offset);
dma_buf->next_op_allowed = DECODE_SEL_OP;
- } else {
- /* invalidate the stored iova */
- dma_buf->iova = 0;
-
- /* return the virtual address mapping */
- msm_gem_put_vaddr(dma_buf->buf);
- msm_gem_vunmap(dma_buf->buf);
}
}
@@ -661,7 +663,7 @@
/* register to aspace */
rc = msm_gem_address_space_register_cb(aspace,
- sde_reg_dma_aspace_cb,
+ sde_reg_dma_aspace_cb_locked,
(void *)dma_buf);
if (rc) {
DRM_ERROR("failed to register callback %d", rc);
@@ -694,8 +696,8 @@
put_iova:
msm_gem_put_iova(dma_buf->buf, aspace);
free_aspace_cb:
- msm_gem_address_space_unregister_cb(aspace, sde_reg_dma_aspace_cb,
- dma_buf);
+ msm_gem_address_space_unregister_cb(aspace,
+ sde_reg_dma_aspace_cb_locked, dma_buf);
free_gem:
msm_gem_free_object(dma_buf->buf);
fail:
@@ -713,7 +715,7 @@
if (dma_buf->buf) {
msm_gem_put_iova(dma_buf->buf, 0);
msm_gem_address_space_unregister_cb(dma_buf->aspace,
- sde_reg_dma_aspace_cb, dma_buf);
+ sde_reg_dma_aspace_cb_locked, dma_buf);
mutex_lock(®_dma->drm_dev->struct_mutex);
msm_gem_free_object(dma_buf->buf);
mutex_unlock(®_dma->drm_dev->struct_mutex);
@@ -774,6 +776,11 @@
return -EINVAL;
}
+ if (!last_cmd_buf->iova) {
+ DRM_DEBUG("iova not set, possible secure session\n");
+ return 0;
+ }
+
cfg.dma_buf = last_cmd_buf;
reset_reg_dma_buffer_v1(last_cmd_buf);
if (validate_last_cmd(&cfg)) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 55cb260..b59dd16 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -44,7 +44,7 @@
static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX];
static u32 feature_map[SDE_DSPP_MAX] = {
- [SDE_DSPP_VLUT] = VLUT,
+ [SDE_DSPP_VLUT] = REG_DMA_FEATURES_MAX,
[SDE_DSPP_GAMUT] = GAMUT,
[SDE_DSPP_IGC] = IGC,
[SDE_DSPP_PCC] = PCC,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 1a00517..c5af3a9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -656,7 +656,7 @@
SDE_ERROR("failed to get dst format\n");
return -EINVAL;
}
- } else if (hw_cmd == SDE_HW_ROT_CMD_COMMIT) {
+ } else {
rc = sde_hw_rot_to_v4l2_pixfmt(data->dst_pixel_format,
data->dst_modifier, &rot_cmd.dst_pixfmt);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index e7e39d3..e5f6471 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -119,57 +119,6 @@
#define COMP1_2_INIT_PHASE_Y 0x2C
#define VIG_0_QSEED2_SHARP 0x30
-/* SDE_SSPP_SCALER_QSEED3 */
-#define QSEED3_HW_VERSION 0x00
-#define QSEED3_OP_MODE 0x04
-#define QSEED3_RGB2Y_COEFF 0x08
-#define QSEED3_PHASE_INIT 0x0C
-#define QSEED3_PHASE_STEP_Y_H 0x10
-#define QSEED3_PHASE_STEP_Y_V 0x14
-#define QSEED3_PHASE_STEP_UV_H 0x18
-#define QSEED3_PHASE_STEP_UV_V 0x1C
-#define QSEED3_PRELOAD 0x20
-#define QSEED3_DE_SHARPEN 0x24
-#define QSEED3_DE_SHARPEN_CTL 0x28
-#define QSEED3_DE_SHAPE_CTL 0x2C
-#define QSEED3_DE_THRESHOLD 0x30
-#define QSEED3_DE_ADJUST_DATA_0 0x34
-#define QSEED3_DE_ADJUST_DATA_1 0x38
-#define QSEED3_DE_ADJUST_DATA_2 0x3C
-#define QSEED3_SRC_SIZE_Y_RGB_A 0x40
-#define QSEED3_SRC_SIZE_UV 0x44
-#define QSEED3_DST_SIZE 0x48
-#define QSEED3_COEF_LUT_CTRL 0x4C
-#define QSEED3_COEF_LUT_SWAP_BIT 0
-#define QSEED3_COEF_LUT_DIR_BIT 1
-#define QSEED3_COEF_LUT_Y_CIR_BIT 2
-#define QSEED3_COEF_LUT_UV_CIR_BIT 3
-#define QSEED3_COEF_LUT_Y_SEP_BIT 4
-#define QSEED3_COEF_LUT_UV_SEP_BIT 5
-#define QSEED3_BUFFER_CTRL 0x50
-#define QSEED3_CLK_CTRL0 0x54
-#define QSEED3_CLK_CTRL1 0x58
-#define QSEED3_CLK_STATUS 0x5C
-#define QSEED3_MISR_CTRL 0x70
-#define QSEED3_MISR_SIGNATURE_0 0x74
-#define QSEED3_MISR_SIGNATURE_1 0x78
-#define QSEED3_PHASE_INIT_Y_H 0x90
-#define QSEED3_PHASE_INIT_Y_V 0x94
-#define QSEED3_PHASE_INIT_UV_H 0x98
-#define QSEED3_PHASE_INIT_UV_V 0x9C
-#define QSEED3_COEF_LUT 0x100
-#define QSEED3_FILTERS 5
-#define QSEED3_LUT_REGIONS 4
-#define QSEED3_CIRCULAR_LUTS 9
-#define QSEED3_SEPARABLE_LUTS 10
-#define QSEED3_LUT_SIZE 60
-#define QSEED3_ENABLE 2
-#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32))
-#define QSEED3_CIR_LUT_SIZE \
- (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32))
-#define QSEED3_SEP_LUT_SIZE \
- (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32))
-
/*
* Definitions for ViG op modes
*/
@@ -556,144 +505,12 @@
pe->phase_step_y[SDE_SSPP_COMP_1_2]);
}
-static void _sde_hw_sspp_setup_scaler3_lut(struct sde_hw_pipe *ctx,
- struct sde_hw_scaler3_cfg *scaler3_cfg)
-{
- u32 idx;
- int i, j, filter;
- int config_lut = 0x0;
- unsigned long lut_flags;
- u32 lut_addr, lut_offset, lut_len;
- u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL};
- static const uint32_t offset[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = {
- {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} },
- {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} },
- {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} },
- {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} },
- {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} },
- };
-
- if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx) ||
- !scaler3_cfg)
- return;
-
- lut_flags = (unsigned long) scaler3_cfg->lut_flag;
- if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) &&
- (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) {
- lut[0] = scaler3_cfg->dir_lut;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) &&
- (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
- (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
- lut[1] = scaler3_cfg->cir_lut +
- scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) &&
- (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
- (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
- lut[2] = scaler3_cfg->cir_lut +
- scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) &&
- (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
- (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
- lut[3] = scaler3_cfg->sep_lut +
- scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) &&
- (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
- (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
- lut[4] = scaler3_cfg->sep_lut +
- scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
-
- if (config_lut) {
- for (filter = 0; filter < QSEED3_FILTERS; filter++) {
- if (!lut[filter])
- continue;
- lut_offset = 0;
- for (i = 0; i < QSEED3_LUT_REGIONS; i++) {
- lut_addr = QSEED3_COEF_LUT + idx
- + offset[filter][i][1];
- lut_len = offset[filter][i][0] << 2;
- for (j = 0; j < lut_len; j++) {
- SDE_REG_WRITE(&ctx->hw,
- lut_addr,
- (lut[filter])[lut_offset++]);
- lut_addr += 4;
- }
- }
- }
- }
-
- if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags))
- SDE_REG_WRITE(&ctx->hw, QSEED3_COEF_LUT_CTRL + idx, BIT(0));
-
-}
-
-static void _sde_hw_sspp_setup_scaler3_de(struct sde_hw_pipe *ctx,
- struct sde_hw_scaler3_de_cfg *de_cfg)
-{
- u32 idx;
- u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr;
- u32 adjust_a, adjust_b, adjust_c;
- struct sde_hw_blk_reg_map *hw;
-
- if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx) || !de_cfg)
- return;
-
- if (!de_cfg->enable)
- return;
-
- hw = &ctx->hw;
- sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) |
- ((de_cfg->sharpen_level2 & 0x1FF) << 16);
-
- sharp_ctl = ((de_cfg->limit & 0xF) << 9) |
- ((de_cfg->prec_shift & 0x7) << 13) |
- ((de_cfg->clip & 0x7) << 16);
-
- shape_ctl = (de_cfg->thr_quiet & 0xFF) |
- ((de_cfg->thr_dieout & 0x3FF) << 16);
-
- de_thr = (de_cfg->thr_low & 0x3FF) |
- ((de_cfg->thr_high & 0x3FF) << 16);
-
- adjust_a = (de_cfg->adjust_a[0] & 0x3FF) |
- ((de_cfg->adjust_a[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_a[2] & 0x3FF) << 20);
-
- adjust_b = (de_cfg->adjust_b[0] & 0x3FF) |
- ((de_cfg->adjust_b[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_b[2] & 0x3FF) << 20);
-
- adjust_c = (de_cfg->adjust_c[0] & 0x3FF) |
- ((de_cfg->adjust_c[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_c[2] & 0x3FF) << 20);
-
- SDE_REG_WRITE(hw, QSEED3_DE_SHARPEN + idx, sharp_lvl);
- SDE_REG_WRITE(hw, QSEED3_DE_SHARPEN_CTL + idx, sharp_ctl);
- SDE_REG_WRITE(hw, QSEED3_DE_SHAPE_CTL + idx, shape_ctl);
- SDE_REG_WRITE(hw, QSEED3_DE_THRESHOLD + idx, de_thr);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_0 + idx, adjust_a);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_1 + idx, adjust_b);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_2 + idx, adjust_c);
-
-}
-
static void _sde_hw_sspp_setup_scaler3(struct sde_hw_pipe *ctx,
struct sde_hw_pipe_cfg *sspp,
struct sde_hw_pixel_ext *pe,
void *scaler_cfg)
{
u32 idx;
- u32 op_mode = 0;
- u32 phase_init, preload, src_y_rgb, src_uv, dst;
struct sde_hw_scaler3_cfg *scaler3_cfg = scaler_cfg;
(void)pe;
@@ -701,93 +518,9 @@
|| !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk)
return;
- if (!scaler3_cfg->enable)
- goto end;
-
- op_mode |= BIT(0);
- op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16;
-
- if (SDE_FORMAT_IS_YUV(sspp->layout.format)) {
- op_mode |= BIT(12);
- op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24;
- }
-
- op_mode |= (scaler3_cfg->blend_cfg & 1) << 31;
- op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0;
-
- preload =
- ((scaler3_cfg->preload_x[0] & 0x7F) << 0) |
- ((scaler3_cfg->preload_y[0] & 0x7F) << 8) |
- ((scaler3_cfg->preload_x[1] & 0x7F) << 16) |
- ((scaler3_cfg->preload_y[1] & 0x7F) << 24);
-
- src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) |
- ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16);
-
- src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) |
- ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16);
-
- dst = (scaler3_cfg->dst_width & 0x1FFFF) |
- ((scaler3_cfg->dst_height & 0x1FFFF) << 16);
-
- if (scaler3_cfg->de.enable) {
- _sde_hw_sspp_setup_scaler3_de(ctx, &scaler3_cfg->de);
- op_mode |= BIT(8);
- }
-
- if (scaler3_cfg->lut_flag)
- _sde_hw_sspp_setup_scaler3_lut(ctx, scaler3_cfg);
-
- if (ctx->cap->sblk->scaler_blk.version == 0x1002) {
- phase_init =
- ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) |
- ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) |
- ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) |
- ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT + idx, phase_init);
- } else {
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_Y_H + idx,
- scaler3_cfg->init_phase_x[0] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_Y_V + idx,
- scaler3_cfg->init_phase_y[0] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_UV_H + idx,
- scaler3_cfg->init_phase_x[1] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_UV_V + idx,
- scaler3_cfg->init_phase_y[1] & 0x1FFFFF);
- }
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_Y_H + idx,
- scaler3_cfg->phase_step_x[0] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_Y_V + idx,
- scaler3_cfg->phase_step_y[0] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_UV_H + idx,
- scaler3_cfg->phase_step_x[1] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_UV_V + idx,
- scaler3_cfg->phase_step_y[1] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PRELOAD + idx, preload);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_SRC_SIZE_Y_RGB_A + idx, src_y_rgb);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_SRC_SIZE_UV + idx, src_uv);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_DST_SIZE + idx, dst);
-
-end:
- if (!SDE_FORMAT_IS_DX(sspp->layout.format))
- op_mode |= BIT(14);
-
- if (sspp->layout.format->alpha_enable) {
- op_mode |= BIT(10);
- if (ctx->cap->sblk->scaler_blk.version == 0x1002)
- op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30;
- else
- op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29;
- }
- SDE_REG_WRITE(&ctx->hw, QSEED3_OP_MODE + idx, op_mode);
+ sde_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx,
+ ctx->cap->sblk->scaler_blk.version,
+ sspp->layout.format);
}
static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx)
@@ -797,7 +530,7 @@
if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx))
return 0;
- return SDE_REG_READ(&ctx->hw, QSEED3_HW_VERSION + idx);
+ return sde_hw_get_scaler3_ver(&ctx->hw, idx);
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 8700627..6e03ab1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -156,114 +156,6 @@
};
/**
- * struct sde_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration
- * @enable: detail enhancer enable/disable
- * @sharpen_level1: sharpening strength for noise
- * @sharpen_level2: sharpening strength for signal
- * @ clip: clip shift
- * @ limit: limit value
- * @ thr_quiet: quiet threshold
- * @ thr_dieout: dieout threshold
- * @ thr_high: low threshold
- * @ thr_high: high threshold
- * @ prec_shift: precision shift
- * @ adjust_a: A-coefficients for mapping curve
- * @ adjust_b: B-coefficients for mapping curve
- * @ adjust_c: C-coefficients for mapping curve
- */
-struct sde_hw_scaler3_de_cfg {
- u32 enable;
- int16_t sharpen_level1;
- int16_t sharpen_level2;
- uint16_t clip;
- uint16_t limit;
- uint16_t thr_quiet;
- uint16_t thr_dieout;
- uint16_t thr_low;
- uint16_t thr_high;
- uint16_t prec_shift;
- int16_t adjust_a[SDE_MAX_DE_CURVES];
- int16_t adjust_b[SDE_MAX_DE_CURVES];
- int16_t adjust_c[SDE_MAX_DE_CURVES];
-};
-
-/**
- * struct sde_hw_scaler3_cfg : QSEEDv3 configuration
- * @enable: scaler enable
- * @dir_en: direction detection block enable
- * @ init_phase_x: horizontal initial phase
- * @ phase_step_x: horizontal phase step
- * @ init_phase_y: vertical initial phase
- * @ phase_step_y: vertical phase step
- * @ preload_x: horizontal preload value
- * @ preload_y: vertical preload value
- * @ src_width: source width
- * @ src_height: source height
- * @ dst_width: destination width
- * @ dst_height: destination height
- * @ y_rgb_filter_cfg: y/rgb plane filter configuration
- * @ uv_filter_cfg: uv plane filter configuration
- * @ alpha_filter_cfg: alpha filter configuration
- * @ blend_cfg: blend coefficients configuration
- * @ lut_flag: scaler LUT update flags
- * 0x1 swap LUT bank
- * 0x2 update 2D filter LUT
- * 0x4 update y circular filter LUT
- * 0x8 update uv circular filter LUT
- * 0x10 update y separable filter LUT
- * 0x20 update uv separable filter LUT
- * @ dir_lut_idx: 2D filter LUT index
- * @ y_rgb_cir_lut_idx: y circular filter LUT index
- * @ uv_cir_lut_idx: uv circular filter LUT index
- * @ y_rgb_sep_lut_idx: y circular filter LUT index
- * @ uv_sep_lut_idx: uv separable filter LUT index
- * @ dir_lut: pointer to 2D LUT
- * @ cir_lut: pointer to circular filter LUT
- * @ sep_lut: pointer to separable filter LUT
- * @ de: detail enhancer configuration
- */
-struct sde_hw_scaler3_cfg {
- u32 enable;
- u32 dir_en;
- int32_t init_phase_x[SDE_MAX_PLANES];
- int32_t phase_step_x[SDE_MAX_PLANES];
- int32_t init_phase_y[SDE_MAX_PLANES];
- int32_t phase_step_y[SDE_MAX_PLANES];
-
- u32 preload_x[SDE_MAX_PLANES];
- u32 preload_y[SDE_MAX_PLANES];
- u32 src_width[SDE_MAX_PLANES];
- u32 src_height[SDE_MAX_PLANES];
-
- u32 dst_width;
- u32 dst_height;
-
- u32 y_rgb_filter_cfg;
- u32 uv_filter_cfg;
- u32 alpha_filter_cfg;
- u32 blend_cfg;
-
- u32 lut_flag;
- u32 dir_lut_idx;
-
- u32 y_rgb_cir_lut_idx;
- u32 uv_cir_lut_idx;
- u32 y_rgb_sep_lut_idx;
- u32 uv_sep_lut_idx;
- u32 *dir_lut;
- size_t dir_len;
- u32 *cir_lut;
- size_t cir_len;
- u32 *sep_lut;
- size_t sep_len;
-
- /*
- * Detail enhancer settings
- */
- struct sde_hw_scaler3_de_cfg de;
-};
-
-/**
* struct sde_hw_pipe_cfg : Pipe description
* @layout: format layout information for programming buffer to hardware
* @src_rect: src ROI, caller takes into account the different operations
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.c b/drivers/gpu/drm/msm/sde/sde_hw_util.c
index 7df5736..08fe5e1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.c
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include <uapi/drm/sde_drm.h>
#include "msm_drv.h"
#include "sde_kms.h"
#include "sde_hw_mdss.h"
@@ -18,6 +20,57 @@
/* using a file static variables for debugfs access */
static u32 sde_hw_util_log_mask = SDE_DBG_MASK_NONE;
+/* SDE_SCALER_QSEED3 */
+#define QSEED3_HW_VERSION 0x00
+#define QSEED3_OP_MODE 0x04
+#define QSEED3_RGB2Y_COEFF 0x08
+#define QSEED3_PHASE_INIT 0x0C
+#define QSEED3_PHASE_STEP_Y_H 0x10
+#define QSEED3_PHASE_STEP_Y_V 0x14
+#define QSEED3_PHASE_STEP_UV_H 0x18
+#define QSEED3_PHASE_STEP_UV_V 0x1C
+#define QSEED3_PRELOAD 0x20
+#define QSEED3_DE_SHARPEN 0x24
+#define QSEED3_DE_SHARPEN_CTL 0x28
+#define QSEED3_DE_SHAPE_CTL 0x2C
+#define QSEED3_DE_THRESHOLD 0x30
+#define QSEED3_DE_ADJUST_DATA_0 0x34
+#define QSEED3_DE_ADJUST_DATA_1 0x38
+#define QSEED3_DE_ADJUST_DATA_2 0x3C
+#define QSEED3_SRC_SIZE_Y_RGB_A 0x40
+#define QSEED3_SRC_SIZE_UV 0x44
+#define QSEED3_DST_SIZE 0x48
+#define QSEED3_COEF_LUT_CTRL 0x4C
+#define QSEED3_COEF_LUT_SWAP_BIT 0
+#define QSEED3_COEF_LUT_DIR_BIT 1
+#define QSEED3_COEF_LUT_Y_CIR_BIT 2
+#define QSEED3_COEF_LUT_UV_CIR_BIT 3
+#define QSEED3_COEF_LUT_Y_SEP_BIT 4
+#define QSEED3_COEF_LUT_UV_SEP_BIT 5
+#define QSEED3_BUFFER_CTRL 0x50
+#define QSEED3_CLK_CTRL0 0x54
+#define QSEED3_CLK_CTRL1 0x58
+#define QSEED3_CLK_STATUS 0x5C
+#define QSEED3_MISR_CTRL 0x70
+#define QSEED3_MISR_SIGNATURE_0 0x74
+#define QSEED3_MISR_SIGNATURE_1 0x78
+#define QSEED3_PHASE_INIT_Y_H 0x90
+#define QSEED3_PHASE_INIT_Y_V 0x94
+#define QSEED3_PHASE_INIT_UV_H 0x98
+#define QSEED3_PHASE_INIT_UV_V 0x9C
+#define QSEED3_COEF_LUT 0x100
+#define QSEED3_FILTERS 5
+#define QSEED3_LUT_REGIONS 4
+#define QSEED3_CIRCULAR_LUTS 9
+#define QSEED3_SEPARABLE_LUTS 10
+#define QSEED3_LUT_SIZE 60
+#define QSEED3_ENABLE 2
+#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32))
+#define QSEED3_CIR_LUT_SIZE \
+ (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32))
+#define QSEED3_SEP_LUT_SIZE \
+ (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32))
+
void sde_reg_write(struct sde_hw_blk_reg_map *c,
u32 reg_off,
u32 val,
@@ -40,6 +93,283 @@
return &sde_hw_util_log_mask;
}
+void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg,
+ const struct sde_drm_scaler_v2 *scale_v2)
+{
+ int i;
+
+ cfg->enable = scale_v2->enable;
+ cfg->dir_en = scale_v2->dir_en;
+
+ for (i = 0; i < SDE_MAX_PLANES; i++) {
+ cfg->init_phase_x[i] = scale_v2->init_phase_x[i];
+ cfg->phase_step_x[i] = scale_v2->phase_step_x[i];
+ cfg->init_phase_y[i] = scale_v2->init_phase_y[i];
+ cfg->phase_step_y[i] = scale_v2->phase_step_y[i];
+
+ cfg->preload_x[i] = scale_v2->preload_x[i];
+ cfg->preload_y[i] = scale_v2->preload_y[i];
+ cfg->src_width[i] = scale_v2->src_width[i];
+ cfg->src_height[i] = scale_v2->src_height[i];
+ }
+
+ cfg->dst_width = scale_v2->dst_width;
+ cfg->dst_height = scale_v2->dst_height;
+
+ cfg->y_rgb_filter_cfg = scale_v2->y_rgb_filter_cfg;
+ cfg->uv_filter_cfg = scale_v2->uv_filter_cfg;
+ cfg->alpha_filter_cfg = scale_v2->alpha_filter_cfg;
+ cfg->blend_cfg = scale_v2->blend_cfg;
+
+ cfg->lut_flag = scale_v2->lut_flag;
+ cfg->dir_lut_idx = scale_v2->dir_lut_idx;
+ cfg->y_rgb_cir_lut_idx = scale_v2->y_rgb_cir_lut_idx;
+ cfg->uv_cir_lut_idx = scale_v2->uv_cir_lut_idx;
+ cfg->y_rgb_sep_lut_idx = scale_v2->y_rgb_sep_lut_idx;
+ cfg->uv_sep_lut_idx = scale_v2->uv_sep_lut_idx;
+
+ cfg->de.enable = scale_v2->de.enable;
+ cfg->de.sharpen_level1 = scale_v2->de.sharpen_level1;
+ cfg->de.sharpen_level2 = scale_v2->de.sharpen_level2;
+ cfg->de.clip = scale_v2->de.clip;
+ cfg->de.limit = scale_v2->de.limit;
+ cfg->de.thr_quiet = scale_v2->de.thr_quiet;
+ cfg->de.thr_dieout = scale_v2->de.thr_dieout;
+ cfg->de.thr_low = scale_v2->de.thr_low;
+ cfg->de.thr_high = scale_v2->de.thr_high;
+ cfg->de.prec_shift = scale_v2->de.prec_shift;
+
+ for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
+ cfg->de.adjust_a[i] = scale_v2->de.adjust_a[i];
+ cfg->de.adjust_b[i] = scale_v2->de.adjust_b[i];
+ cfg->de.adjust_c[i] = scale_v2->de.adjust_c[i];
+ }
+}
+
+static void _sde_hw_setup_scaler3_lut(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset)
+{
+ int i, j, filter;
+ int config_lut = 0x0;
+ unsigned long lut_flags;
+ u32 lut_addr, lut_offset, lut_len;
+ u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL};
+ static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = {
+ {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} },
+ {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} },
+ {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} },
+ {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} },
+ {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} },
+ };
+
+ lut_flags = (unsigned long) scaler3_cfg->lut_flag;
+ if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) &&
+ (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) {
+ lut[0] = scaler3_cfg->dir_lut;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) &&
+ (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
+ (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
+ lut[1] = scaler3_cfg->cir_lut +
+ scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) &&
+ (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
+ (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
+ lut[2] = scaler3_cfg->cir_lut +
+ scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) &&
+ (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
+ (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
+ lut[3] = scaler3_cfg->sep_lut +
+ scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) &&
+ (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
+ (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
+ lut[4] = scaler3_cfg->sep_lut +
+ scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+
+ if (config_lut) {
+ for (filter = 0; filter < QSEED3_FILTERS; filter++) {
+ if (!lut[filter])
+ continue;
+ lut_offset = 0;
+ for (i = 0; i < QSEED3_LUT_REGIONS; i++) {
+ lut_addr = QSEED3_COEF_LUT + offset
+ + off_tbl[filter][i][1];
+ lut_len = off_tbl[filter][i][0] << 2;
+ for (j = 0; j < lut_len; j++) {
+ SDE_REG_WRITE(c,
+ lut_addr,
+ (lut[filter])[lut_offset++]);
+ lut_addr += 4;
+ }
+ }
+ }
+ }
+
+ if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags))
+ SDE_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0));
+
+}
+
+static void _sde_hw_setup_scaler3_de(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_de_cfg *de_cfg, u32 offset)
+{
+ u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr;
+ u32 adjust_a, adjust_b, adjust_c;
+
+ if (!de_cfg->enable)
+ return;
+
+ sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) |
+ ((de_cfg->sharpen_level2 & 0x1FF) << 16);
+
+ sharp_ctl = ((de_cfg->limit & 0xF) << 9) |
+ ((de_cfg->prec_shift & 0x7) << 13) |
+ ((de_cfg->clip & 0x7) << 16);
+
+ shape_ctl = (de_cfg->thr_quiet & 0xFF) |
+ ((de_cfg->thr_dieout & 0x3FF) << 16);
+
+ de_thr = (de_cfg->thr_low & 0x3FF) |
+ ((de_cfg->thr_high & 0x3FF) << 16);
+
+ adjust_a = (de_cfg->adjust_a[0] & 0x3FF) |
+ ((de_cfg->adjust_a[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_a[2] & 0x3FF) << 20);
+
+ adjust_b = (de_cfg->adjust_b[0] & 0x3FF) |
+ ((de_cfg->adjust_b[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_b[2] & 0x3FF) << 20);
+
+ adjust_c = (de_cfg->adjust_c[0] & 0x3FF) |
+ ((de_cfg->adjust_c[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_c[2] & 0x3FF) << 20);
+
+ SDE_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl);
+ SDE_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl);
+ SDE_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl);
+ SDE_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c);
+
+}
+
+void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg,
+ u32 scaler_offset, u32 scaler_version,
+ const struct sde_format *format)
+{
+ u32 op_mode = 0;
+ u32 phase_init, preload, src_y_rgb, src_uv, dst;
+
+ if (!scaler3_cfg->enable)
+ goto end;
+
+ op_mode |= BIT(0);
+ op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16;
+
+ if (format && SDE_FORMAT_IS_YUV(format)) {
+ op_mode |= BIT(12);
+ op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24;
+ }
+
+ op_mode |= (scaler3_cfg->blend_cfg & 1) << 31;
+ op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0;
+
+ preload =
+ ((scaler3_cfg->preload_x[0] & 0x7F) << 0) |
+ ((scaler3_cfg->preload_y[0] & 0x7F) << 8) |
+ ((scaler3_cfg->preload_x[1] & 0x7F) << 16) |
+ ((scaler3_cfg->preload_y[1] & 0x7F) << 24);
+
+ src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) |
+ ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16);
+
+ src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) |
+ ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16);
+
+ dst = (scaler3_cfg->dst_width & 0x1FFFF) |
+ ((scaler3_cfg->dst_height & 0x1FFFF) << 16);
+
+ if (scaler3_cfg->de.enable) {
+ _sde_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset);
+ op_mode |= BIT(8);
+ }
+
+ if (scaler3_cfg->lut_flag)
+ _sde_hw_setup_scaler3_lut(c, scaler3_cfg,
+ scaler_offset);
+
+ if (scaler_version == 0x1002) {
+ phase_init =
+ ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) |
+ ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) |
+ ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) |
+ ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init);
+ } else {
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset,
+ scaler3_cfg->init_phase_x[0] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset,
+ scaler3_cfg->init_phase_y[0] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset,
+ scaler3_cfg->init_phase_x[1] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset,
+ scaler3_cfg->init_phase_y[1] & 0x1FFFFF);
+ }
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset,
+ scaler3_cfg->phase_step_x[0] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset,
+ scaler3_cfg->phase_step_y[0] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset,
+ scaler3_cfg->phase_step_x[1] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset,
+ scaler3_cfg->phase_step_y[1] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload);
+
+ SDE_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb);
+
+ SDE_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv);
+
+ SDE_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst);
+
+end:
+ if (format && !SDE_FORMAT_IS_DX(format))
+ op_mode |= BIT(14);
+
+ if (format && format->alpha_enable) {
+ op_mode |= BIT(10);
+ if (scaler_version == 0x1002)
+ op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30;
+ else
+ op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29;
+ }
+
+ SDE_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode);
+}
+
+u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c,
+ u32 scaler_offset)
+{
+ return SDE_REG_READ(c, QSEED3_HW_VERSION + scaler_offset);
+}
+
void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c,
u32 csc_reg_off,
struct sde_csc_cfg *data, bool csc10)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h
index aa3d5b9..720e113 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h
@@ -39,6 +39,125 @@
u32 log_mask;
};
+/**
+ * struct sde_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration
+ * @enable: detail enhancer enable/disable
+ * @sharpen_level1: sharpening strength for noise
+ * @sharpen_level2: sharpening strength for signal
+ * @ clip: clip shift
+ * @ limit: limit value
+ * @ thr_quiet: quiet threshold
+ * @ thr_dieout: dieout threshold
+ * @ thr_high: low threshold
+ * @ thr_high: high threshold
+ * @ prec_shift: precision shift
+ * @ adjust_a: A-coefficients for mapping curve
+ * @ adjust_b: B-coefficients for mapping curve
+ * @ adjust_c: C-coefficients for mapping curve
+ */
+struct sde_hw_scaler3_de_cfg {
+ u32 enable;
+ int16_t sharpen_level1;
+ int16_t sharpen_level2;
+ uint16_t clip;
+ uint16_t limit;
+ uint16_t thr_quiet;
+ uint16_t thr_dieout;
+ uint16_t thr_low;
+ uint16_t thr_high;
+ uint16_t prec_shift;
+ int16_t adjust_a[SDE_MAX_DE_CURVES];
+ int16_t adjust_b[SDE_MAX_DE_CURVES];
+ int16_t adjust_c[SDE_MAX_DE_CURVES];
+};
+
+
+/**
+ * struct sde_hw_scaler3_cfg : QSEEDv3 configuration
+ * @enable: scaler enable
+ * @dir_en: direction detection block enable
+ * @ init_phase_x: horizontal initial phase
+ * @ phase_step_x: horizontal phase step
+ * @ init_phase_y: vertical initial phase
+ * @ phase_step_y: vertical phase step
+ * @ preload_x: horizontal preload value
+ * @ preload_y: vertical preload value
+ * @ src_width: source width
+ * @ src_height: source height
+ * @ dst_width: destination width
+ * @ dst_height: destination height
+ * @ y_rgb_filter_cfg: y/rgb plane filter configuration
+ * @ uv_filter_cfg: uv plane filter configuration
+ * @ alpha_filter_cfg: alpha filter configuration
+ * @ blend_cfg: blend coefficients configuration
+ * @ lut_flag: scaler LUT update flags
+ * 0x1 swap LUT bank
+ * 0x2 update 2D filter LUT
+ * 0x4 update y circular filter LUT
+ * 0x8 update uv circular filter LUT
+ * 0x10 update y separable filter LUT
+ * 0x20 update uv separable filter LUT
+ * @ dir_lut_idx: 2D filter LUT index
+ * @ y_rgb_cir_lut_idx: y circular filter LUT index
+ * @ uv_cir_lut_idx: uv circular filter LUT index
+ * @ y_rgb_sep_lut_idx: y circular filter LUT index
+ * @ uv_sep_lut_idx: uv separable filter LUT index
+ * @ dir_lut: pointer to 2D LUT
+ * @ cir_lut: pointer to circular filter LUT
+ * @ sep_lut: pointer to separable filter LUT
+ * @ de: detail enhancer configuration
+ */
+struct sde_hw_scaler3_cfg {
+ u32 enable;
+ u32 dir_en;
+ int32_t init_phase_x[SDE_MAX_PLANES];
+ int32_t phase_step_x[SDE_MAX_PLANES];
+ int32_t init_phase_y[SDE_MAX_PLANES];
+ int32_t phase_step_y[SDE_MAX_PLANES];
+
+ u32 preload_x[SDE_MAX_PLANES];
+ u32 preload_y[SDE_MAX_PLANES];
+ u32 src_width[SDE_MAX_PLANES];
+ u32 src_height[SDE_MAX_PLANES];
+
+ u32 dst_width;
+ u32 dst_height;
+
+ u32 y_rgb_filter_cfg;
+ u32 uv_filter_cfg;
+ u32 alpha_filter_cfg;
+ u32 blend_cfg;
+
+ u32 lut_flag;
+ u32 dir_lut_idx;
+
+ u32 y_rgb_cir_lut_idx;
+ u32 uv_cir_lut_idx;
+ u32 y_rgb_sep_lut_idx;
+ u32 uv_sep_lut_idx;
+ u32 *dir_lut;
+ size_t dir_len;
+ u32 *cir_lut;
+ size_t cir_len;
+ u32 *sep_lut;
+ size_t sep_len;
+
+ /*
+ * Detail enhancer settings
+ */
+ struct sde_hw_scaler3_de_cfg de;
+};
+
+struct sde_hw_scaler3_lut_cfg {
+ bool is_configured;
+ u32 *dir_lut;
+ size_t dir_len;
+ u32 *cir_lut;
+ size_t cir_len;
+ u32 *sep_lut;
+ size_t sep_len;
+};
+
u32 *sde_hw_util_get_log_mask_ptr(void);
void sde_reg_write(struct sde_hw_blk_reg_map *c,
@@ -58,6 +177,17 @@
void *sde_hw_util_get_dir(void);
+void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg,
+ const struct sde_drm_scaler_v2 *scale_v2);
+
+void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg,
+ u32 scaler_offset, u32 scaler_version,
+ const struct sde_format *format);
+
+u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c,
+ u32 scaler_offset);
+
void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c,
u32 csc_reg_off,
struct sde_csc_cfg *data, bool csc10);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 10f796f..edd1611 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1518,7 +1518,7 @@
* @plane: Pointer to drm plane
* return: prefill time in line
*/
-static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
+u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
{
struct drm_plane_state *state;
struct sde_plane_state *pstate;
@@ -1547,33 +1547,19 @@
&blocksize, &blocksize);
prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
-
- SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
+ prefill_line = mult_frac(prefill_line, rstate->out_src_h >> 16,
+ state->crtc_h);
+ SDE_DEBUG(
+ "plane%d.%d blk:%u head:%u vdst/vsrc:%u/%u prefill:%u\n",
+ plane->base.id, rstate->sequence_id,
+ blocksize, sde_kms->catalog->sbuf_headroom,
+ state->crtc_h, rstate->out_src_h >> 16,
+ prefill_line);
return prefill_line;
}
/**
- * sde_plane_is_sbuf_mode - check if sspp of given plane is in streaming
- * buffer mode
- * @plane: Pointer to drm plane
- * @prefill: Pointer to prefill line count
- * return: true if sspp is in stream buffer mode
- */
-bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill)
-{
- struct sde_plane_state *pstate = plane && plane->state ?
- to_sde_plane_state(plane->state) : NULL;
- struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
- bool sbuf_mode = rstate ? rstate->out_sbuf : false;
-
- if (prefill)
- *prefill = sde_plane_rot_calc_prefill(plane);
-
- return sbuf_mode;
-}
-
-/**
* sde_plane_rot_calc_cfg - calculate rotator/sspp configuration by
* enumerating over all planes attached to the same rotator
* @plane: Pointer to drm plane
@@ -2752,7 +2738,7 @@
return;
*flush_rot = 0x0;
- if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
+ if (rstate && rstate->out_sbuf && rstate->rot_hw &&
ctl->ops.get_bitmask_rot)
ctl->ops.get_bitmask_rot(ctl, flush_rot, rstate->rot_hw->idx);
}
@@ -4078,51 +4064,11 @@
&pstate->property_state, PLANE_PROP_SCALER_V2);
/* populate from user space */
+ sde_set_scaler_v2(cfg, &scale_v2);
+
pe = &pstate->pixel_ext;
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
- cfg->enable = scale_v2.enable;
- cfg->dir_en = scale_v2.dir_en;
- for (i = 0; i < SDE_MAX_PLANES; i++) {
- cfg->init_phase_x[i] = scale_v2.init_phase_x[i];
- cfg->phase_step_x[i] = scale_v2.phase_step_x[i];
- cfg->init_phase_y[i] = scale_v2.init_phase_y[i];
- cfg->phase_step_y[i] = scale_v2.phase_step_y[i];
- cfg->preload_x[i] = scale_v2.preload_x[i];
- cfg->preload_y[i] = scale_v2.preload_y[i];
- cfg->src_width[i] = scale_v2.src_width[i];
- cfg->src_height[i] = scale_v2.src_height[i];
- }
- cfg->dst_width = scale_v2.dst_width;
- cfg->dst_height = scale_v2.dst_height;
-
- cfg->y_rgb_filter_cfg = scale_v2.y_rgb_filter_cfg;
- cfg->uv_filter_cfg = scale_v2.uv_filter_cfg;
- cfg->alpha_filter_cfg = scale_v2.alpha_filter_cfg;
- cfg->blend_cfg = scale_v2.blend_cfg;
-
- cfg->lut_flag = scale_v2.lut_flag;
- cfg->dir_lut_idx = scale_v2.dir_lut_idx;
- cfg->y_rgb_cir_lut_idx = scale_v2.y_rgb_cir_lut_idx;
- cfg->uv_cir_lut_idx = scale_v2.uv_cir_lut_idx;
- cfg->y_rgb_sep_lut_idx = scale_v2.y_rgb_sep_lut_idx;
- cfg->uv_sep_lut_idx = scale_v2.uv_sep_lut_idx;
-
- cfg->de.enable = scale_v2.de.enable;
- cfg->de.sharpen_level1 = scale_v2.de.sharpen_level1;
- cfg->de.sharpen_level2 = scale_v2.de.sharpen_level2;
- cfg->de.clip = scale_v2.de.clip;
- cfg->de.limit = scale_v2.de.limit;
- cfg->de.thr_quiet = scale_v2.de.thr_quiet;
- cfg->de.thr_dieout = scale_v2.de.thr_dieout;
- cfg->de.thr_low = scale_v2.de.thr_low;
- cfg->de.thr_high = scale_v2.de.thr_high;
- cfg->de.prec_shift = scale_v2.de.prec_shift;
- for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
- cfg->de.adjust_a[i] = scale_v2.de.adjust_a[i];
- cfg->de.adjust_b[i] = scale_v2.de.adjust_b[i];
- cfg->de.adjust_c[i] = scale_v2.de.adjust_c[i];
- }
for (i = 0; i < SDE_MAX_PLANES; i++) {
pe->left_ftch[i] = scale_v2.pe.left_ftch[i];
pe->right_ftch[i] = scale_v2.pe.right_ftch[i];
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 913647f..c956345 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -207,12 +207,11 @@
u32 *flush_sspp, u32 *flush_rot);
/**
- * sde_plane_is_sbuf_mode - return status of stream buffer mode
- * @plane: Pointer to DRM plane object
- * @prefill: Pointer to updated prefill in stream buffer mode (optional)
- * Returns: true if plane is in stream buffer mode
+ * sde_plane_rot_calc_prefill - calculate rotator start prefill
+ * @plane: Pointer to drm plane
+ * return: prefill time in line
*/
-bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill);
+u32 sde_plane_rot_calc_prefill(struct drm_plane *plane);
/**
* sde_plane_restore - restore hw state if previously power collapsed
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 768dfbd..7143a8b 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -3075,7 +3075,7 @@
dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
dbg->dbgbus_vbif_rt.cmn.entries_size =
ARRAY_SIZE(vbif_dbg_bus_msm8998);
- } else if (IS_SDM845_TARGET(hwversion)) {
+ } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) {
dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845;
dbg->dbgbus_sde.cmn.entries_size =
ARRAY_SIZE(dbg_bus_sde_sdm845);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7316fc7..a2ec6d8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -149,8 +149,8 @@
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
/* Signal polarities */
- value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
- | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
+ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
+ | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
| DSMR_DIPM_DISP | DSMR_CSPM;
rcar_du_crtc_write(rcrtc, DSMR, value);
@@ -172,7 +172,7 @@
mode->crtc_vsync_start - 1);
rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1);
- rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
+ rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start - 1);
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index cfc302c..c58602b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -453,13 +453,13 @@
}
ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
- of_node_put(encoder);
- of_node_put(connector);
-
if (ret && ret != -EPROBE_DEFER)
dev_warn(rcdu->dev,
- "failed to initialize encoder %s (%d), skipping\n",
- encoder->full_name, ret);
+ "failed to initialize encoder %s on output %u (%d), skipping\n",
+ of_node_full_name(encoder), output, ret);
+
+ of_node_put(encoder);
+ of_node_put(connector);
return ret;
}
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index a37de5d..ddd6badd 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -612,7 +612,7 @@
} else {
pr_err("Failed to fill pool (%p)\n", pool);
/* If we have any pages left put them to the pool. */
- list_for_each_entry(p, &pool->list, lru) {
+ list_for_each_entry(p, &new_pages, lru) {
++cpages;
}
list_splice(&new_pages, &pool->list);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index 2242a80..dc2976c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -337,7 +337,7 @@
info->fbops = &virtio_gpufb_ops;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->screen_base = obj->vmap;
+ info->screen_buffer = obj->vmap;
info->screen_size = obj->gem_base.size;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &vfbdev->helper,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d16e42d..506f6ad 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2464,7 +2464,7 @@
dev_err(device->dev, " hwfault=%8.8X\n", hwfault);
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, adreno_gmu_gpu_fault(adreno_dev));
}
/**
@@ -3091,6 +3091,7 @@
.irq_handler = adreno_irq_handler,
.drain = adreno_drain,
/* Optional functions */
+ .snapshot_gmu = adreno_snapshot_gmu,
.drawctxt_create = adreno_drawctxt_create,
.drawctxt_detach = adreno_drawctxt_detach,
.drawctxt_destroy = adreno_drawctxt_destroy,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 36bd656..8349a9f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -621,6 +621,8 @@
ADRENO_REG_RBBM_RBBM_CTL,
ADRENO_REG_UCHE_INVALIDATE0,
ADRENO_REG_UCHE_INVALIDATE1,
+ ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
@@ -832,6 +834,7 @@
/* GPU specific function hooks */
void (*irq_trace)(struct adreno_device *, unsigned int status);
void (*snapshot)(struct adreno_device *, struct kgsl_snapshot *);
+ void (*snapshot_gmu)(struct adreno_device *, struct kgsl_snapshot *);
void (*platform_setup)(struct adreno_device *);
void (*init)(struct adreno_device *);
void (*remove)(struct adreno_device *);
@@ -1006,6 +1009,9 @@
struct kgsl_snapshot *snapshot,
struct kgsl_context *context);
+void adreno_snapshot_gmu(struct kgsl_device *device,
+ struct kgsl_snapshot *snapshot);
+
int adreno_reset(struct kgsl_device *device, int fault);
void adreno_fault_skipcmd_detached(struct adreno_device *adreno_dev,
@@ -1329,6 +1335,10 @@
smp_wmb();
}
+static inline bool adreno_gmu_gpu_fault(struct adreno_device *adreno_dev)
+{
+ return adreno_gpu_fault(adreno_dev) & ADRENO_GMU_FAULT;
+}
/**
* adreno_clear_gpu_fault() - Clear the GPU fault register
@@ -1693,21 +1703,60 @@
spin_unlock_irqrestore(&rb->preempt_lock, flags);
}
+static inline bool is_power_counter_overflow(struct adreno_device *adreno_dev,
+ unsigned int reg, unsigned int prev_val, unsigned int *perfctr_pwr_hi)
+{
+ unsigned int val;
+ bool ret = false;
+
+ /*
+ * If prev_val is zero, it is first read after perf counter reset.
+ * So set perfctr_pwr_hi register to zero.
+ */
+ if (prev_val == 0) {
+ *perfctr_pwr_hi = 0;
+ return ret;
+ }
+ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val);
+ if (val != *perfctr_pwr_hi) {
+ *perfctr_pwr_hi = val;
+ ret = true;
+ }
+ return ret;
+}
+
static inline unsigned int counter_delta(struct kgsl_device *device,
unsigned int reg, unsigned int *counter)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int val;
unsigned int ret = 0;
+ bool overflow = true;
+ static unsigned int perfctr_pwr_hi;
/* Read the value */
kgsl_regread(device, reg, &val);
+ if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg
+ (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO))
+ overflow = is_power_counter_overflow(adreno_dev, reg,
+ *counter, &perfctr_pwr_hi);
+
/* Return 0 for the first read */
if (*counter != 0) {
- if (val < *counter)
- ret = (0xFFFFFFFF - *counter) + val;
- else
+ if (val >= *counter) {
ret = val - *counter;
+ } else if (overflow == true) {
+ ret = (0xFFFFFFFF - *counter) + val;
+ } else {
+ /*
+ * Since KGSL got abnormal value from the counter,
+ * We will drop the value from being accumulated.
+ */
+ pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n",
+ val, *counter, reg);
+ return 0;
+ }
}
*counter = val;
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5d7fb21..b2cdf56 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -685,7 +685,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
dev_err(device->dev, "CP initialization failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
return ret;
@@ -1533,6 +1533,10 @@
A3XX_UCHE_CACHE_INVALIDATE0_REG),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1,
A3XX_UCHE_CACHE_INVALIDATE1_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A3XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A3XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A3XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
@@ -1823,7 +1827,7 @@
if (ret) {
KGSL_DRV_ERR(device, "microcode bootstrap failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
/* Clear the chicken bit for speed up on A430 and its derivatives */
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index c807b67..80ceabd 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -808,6 +808,10 @@
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SW_RESET_CMD, A4XX_RBBM_SW_RESET_CMD),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A4XX_UCHE_INVALIDATE0),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A4XX_UCHE_INVALIDATE1),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A4XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A4XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A4XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
@@ -1535,7 +1539,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
dev_err(device->dev, "CP initialization failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
return ret;
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 6cddd08..2d078ba 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2998,6 +2998,10 @@
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_BLOCK_SW_RESET_CMD2,
A5XX_RBBM_BLOCK_SW_RESET_CMD2),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A5XX_UCHE_INVALIDATE0),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A5XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A5XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A5XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index b9df4ec..88c15eb 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -2915,6 +2915,7 @@
.reg_offsets = &a6xx_reg_offsets,
.start = a6xx_start,
.snapshot = a6xx_snapshot,
+ .snapshot_gmu = a6xx_snapshot_gmu,
.irq = &a6xx_irq,
.snapshot_data = &a6xx_snapshot_data,
.irq_trace = trace_kgsl_a5xx_irq_status,
diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h
index ee2fd71..dd8af80 100644
--- a/drivers/gpu/msm/adreno_a6xx.h
+++ b/drivers/gpu/msm/adreno_a6xx.h
@@ -110,6 +110,8 @@
void a6xx_snapshot(struct adreno_device *adreno_dev,
struct kgsl_snapshot *snapshot);
+void a6xx_snapshot_gmu(struct adreno_device *adreno_dev,
+ struct kgsl_snapshot *snapshot);
void a6xx_crashdump_init(struct adreno_device *adreno_dev);
#endif
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
index 1d5f4a5..ca011e4 100644
--- a/drivers/gpu/msm/adreno_a6xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -635,6 +635,9 @@
return;
gpumem_free_entry(context->user_ctxt_record);
+
+ /* Put the extra ref from gpumem_alloc_entry() */
+ kgsl_mem_entry_put(context->user_ctxt_record);
}
int a6xx_preemption_context_init(struct kgsl_context *context)
@@ -645,6 +648,10 @@
if (!adreno_is_preemption_setup_enabled(adreno_dev))
return 0;
+ /*
+ * gpumem_alloc_entry takes an extra refcount. Put it only when
+ * destroying the context to keep the context record valid
+ */
context->user_ctxt_record = gpumem_alloc_entry(context->dev_priv,
A6XX_CP_CTXRECORD_USER_RESTORE_SIZE, 0);
if (IS_ERR(context->user_ctxt_record)) {
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 6269682..32c8085 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -1471,10 +1471,18 @@
}
}
-static void a6xx_snapshot_gmu(struct kgsl_device *device,
+/*
+ * a6xx_snapshot_gmu() - A6XX GMU snapshot function
+ * @adreno_dev: Device being snapshotted
+ * @snapshot: Pointer to the snapshot instance
+ *
+ * This is where all of the A6XX GMU specific bits and pieces are grabbed
+ * into the snapshot memory
+ */
+void a6xx_snapshot_gmu(struct adreno_device *adreno_dev,
struct kgsl_snapshot *snapshot)
{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
if (!kgsl_gmu_isenabled(device))
@@ -1573,16 +1581,11 @@
struct adreno_snapshot_data *snap_data = gpudev->snapshot_data;
bool sptprac_on;
- /* GMU TCM data dumped through AHB */
- a6xx_snapshot_gmu(device, snapshot);
-
sptprac_on = gpudev->sptprac_is_on(adreno_dev);
/* Return if the GX is off */
- if (!gpudev->gx_is_on(adreno_dev)) {
- pr_err("GX is off. Only dumping GMU data in snapshot\n");
+ if (!gpudev->gx_is_on(adreno_dev))
return;
- }
/* Dump the registers which get affected by crash dumper trigger */
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 25aeaef..6bdc486 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2046,7 +2046,7 @@
kfree(replay);
}
-static void do_header_and_snapshot(struct kgsl_device *device,
+static void do_header_and_snapshot(struct kgsl_device *device, int fault,
struct adreno_ringbuffer *rb, struct kgsl_drawobj_cmd *cmdobj)
{
struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj);
@@ -2054,7 +2054,7 @@
/* Always dump the snapshot on a non-drawobj failure */
if (cmdobj == NULL) {
adreno_fault_header(device, rb, NULL);
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, fault & ADRENO_GMU_FAULT);
return;
}
@@ -2066,7 +2066,8 @@
adreno_fault_header(device, rb, cmdobj);
if (!(drawobj->context->flags & KGSL_CONTEXT_NO_SNAPSHOT))
- kgsl_device_snapshot(device, drawobj->context);
+ kgsl_device_snapshot(device, drawobj->context,
+ fault & ADRENO_GMU_FAULT);
}
static int dispatcher_do_fault(struct adreno_device *adreno_dev)
@@ -2192,7 +2193,7 @@
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &base);
- do_header_and_snapshot(device, hung_rb, cmdobj);
+ do_header_and_snapshot(device, fault, hung_rb, cmdobj);
/* Turn off the KEEPALIVE vote from the ISR for hard fault */
if (gpudev->gpu_keepalive && fault & ADRENO_HARD_FAULT)
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 0882447..2615d44 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -533,7 +533,8 @@
drawctxt->internal_timestamp,
drawctxt->type, ret);
device->force_panic = 1;
- kgsl_device_snapshot(device, context);
+ kgsl_device_snapshot(device, context,
+ adreno_gmu_gpu_fault(adreno_dev));
}
kgsl_sharedmem_writel(device, &device->memstore,
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index f608927..b5999e6 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -837,8 +837,7 @@
snapshot_frozen_objsize = 0;
- if (!IS_ERR(context))
- setup_fault_process(device, snapshot,
+ setup_fault_process(device, snapshot,
context ? context->proc_priv : NULL);
/* Add GPU specific sections - registers mainly, but other stuff too */
@@ -946,6 +945,24 @@
}
+/* adreno_snapshot_gmu - Snapshot the Adreno GMU state
+ * @device - KGSL device to snapshot
+ * @snapshot - Pointer to the snapshot instance
+ * This is a hook function called by kgsl_snapshot to snapshot the
+ * Adreno specific information for the GMU snapshot. In turn, this function
+ * calls the GMU specific snapshot function to get core specific information.
+ */
+void adreno_snapshot_gmu(struct kgsl_device *device,
+ struct kgsl_snapshot *snapshot)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+ /* Add GMU specific sections */
+ if (gpudev->snapshot_gmu)
+ gpudev->snapshot_gmu(adreno_dev, snapshot);
+}
+
/*
* adreno_snapshot_cp_roq - Dump CP merciu data in snapshot
* @device: Device being snapshotted
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7dff251..0a7d165 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2280,7 +2280,7 @@
struct kgsl_mem_entry *entry,
struct kgsl_gpuobj_import *param)
{
- struct kgsl_gpuobj_import_useraddr useraddr;
+ struct kgsl_gpuobj_import_useraddr useraddr = {0};
int ret;
param->flags &= KGSL_MEMFLAGS_GPUREADONLY
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2cc1869..0ab775a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -151,6 +151,8 @@
unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid);
void (*snapshot)(struct kgsl_device *device,
struct kgsl_snapshot *snapshot, struct kgsl_context *context);
+ void (*snapshot_gmu)(struct kgsl_device *device,
+ struct kgsl_snapshot *snapshot);
irqreturn_t (*irq_handler)(struct kgsl_device *device);
int (*drain)(struct kgsl_device *device);
/*
@@ -493,7 +495,9 @@
* @work: worker to dump the frozen memory
* @dump_gate: completion gate signaled by worker when it is finished.
* @process: the process that caused the hang, if known.
- * @sysfs_read: An atomic for concurrent snapshot reads via syfs.
+ * @sysfs_read: Count of current reads via sysfs
+ * @first_read: True until the snapshot read is started
+ * @gmu_fault: Snapshot collected when GMU fault happened
*/
struct kgsl_snapshot {
uint64_t ib1base;
@@ -514,7 +518,9 @@
struct work_struct work;
struct completion dump_gate;
struct kgsl_process_private *process;
- atomic_t sysfs_read;
+ unsigned int sysfs_read;
+ bool first_read;
+ bool gmu_fault;
};
/**
@@ -700,9 +706,8 @@
int kgsl_device_snapshot_init(struct kgsl_device *device);
void kgsl_device_snapshot(struct kgsl_device *device,
- struct kgsl_context *context);
+ struct kgsl_context *context, bool gmu_fault);
void kgsl_device_snapshot_close(struct kgsl_device *device);
-void kgsl_snapshot_save_frozen_objs(struct work_struct *work);
void kgsl_events_init(void);
void kgsl_events_exit(void);
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index f21a179..7ea2255 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1366,7 +1366,7 @@
/* Wait for the NMI to be handled */
wmb();
udelay(100);
- kgsl_device_snapshot(device, ERR_PTR(-EINVAL));
+ kgsl_device_snapshot(device, NULL, true);
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index e704db7..f710d8f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -24,6 +24,8 @@
#include "kgsl_snapshot.h"
#include "adreno_cp_parser.h"
+static void kgsl_snapshot_save_frozen_objs(struct work_struct *work);
+
/* Placeholder for list of ib objects that contain all objects in that IB */
struct kgsl_snapshot_cp_obj {
@@ -182,8 +184,7 @@
context = kgsl_context_get(device, header->current_context);
/* Get the current PT base */
- if (!IS_ERR(priv))
- header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
+ header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
/* And the PID for the task leader */
if (context) {
@@ -207,6 +208,44 @@
return size;
}
+/* Snapshot the Linux specific information */
+static size_t snapshot_os_no_ctxt(struct kgsl_device *device,
+ u8 *buf, size_t remain, void *priv)
+{
+ struct kgsl_snapshot_linux_v2 *header =
+ (struct kgsl_snapshot_linux_v2 *)buf;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ size_t size = sizeof(*header);
+
+ /* Make sure there is enough room for the data */
+ if (remain < size) {
+ SNAPSHOT_ERR_NOMEM(device, "OS");
+ return 0;
+ }
+
+ memset(header, 0, sizeof(*header));
+
+ header->osid = KGSL_SNAPSHOT_OS_LINUX_V3;
+
+ /* Get the kernel build information */
+ strlcpy(header->release, init_utsname()->release,
+ sizeof(header->release));
+ strlcpy(header->version, init_utsname()->version,
+ sizeof(header->version));
+
+ /* Get the Unix time for the timestamp */
+ header->seconds = get_seconds();
+
+ /* Remember the power information */
+ header->power_flags = pwr->power_flags;
+ header->power_level = pwr->active_pwrlevel;
+ header->power_interval_timeout = pwr->interval_timeout;
+ header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
+
+ /* Return the size of the data segment */
+ return size;
+}
+
static void kgsl_snapshot_put_object(struct kgsl_snapshot_object *obj)
{
list_del(&obj->node);
@@ -573,16 +612,34 @@
snapshot->size += header->size;
}
+static void kgsl_free_snapshot(struct kgsl_snapshot *snapshot)
+{
+ struct kgsl_snapshot_object *obj, *tmp;
+
+ wait_for_completion(&snapshot->dump_gate);
+
+ list_for_each_entry_safe(obj, tmp,
+ &snapshot->obj_list, node)
+ kgsl_snapshot_put_object(obj);
+
+ if (snapshot->mempool)
+ vfree(snapshot->mempool);
+
+ kfree(snapshot);
+ KGSL_CORE_ERR("snapshot: objects released\n");
+}
+
/**
* kgsl_snapshot() - construct a device snapshot
* @device: device to snapshot
* @context: the context that is hung, might be NULL if unknown.
+ * @gmu_fault: whether this snapshot is triggered by a GMU fault.
*
* Given a device, construct a binary snapshot dump of the current device state
* and store it in the device snapshot memory.
*/
void kgsl_device_snapshot(struct kgsl_device *device,
- struct kgsl_context *context)
+ struct kgsl_context *context, bool gmu_fault)
{
struct kgsl_snapshot_header *header = device->snapshot_memory.ptr;
struct kgsl_snapshot *snapshot;
@@ -603,11 +660,20 @@
device->snapshot_faultcount++;
/*
- * The first hang is always the one we are interested in. Don't capture
- * a new snapshot instance if the old one hasn't been grabbed yet
+ * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
*/
- if (device->snapshot != NULL)
- return;
+ if (device->snapshot != NULL) {
+ if (!gmu_fault || device->snapshot->gmu_fault)
+ return;
+
+ /*
+ * If another thread is currently reading it, that thread
+ * will free it, otherwise free it now.
+ */
+ if (!device->snapshot->sysfs_read)
+ kgsl_free_snapshot(device->snapshot);
+ device->snapshot = NULL;
+ }
/* Allocate memory for the snapshot instance */
snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
@@ -622,7 +688,9 @@
snapshot->start = device->snapshot_memory.ptr;
snapshot->ptr = device->snapshot_memory.ptr;
snapshot->remain = device->snapshot_memory.size;
- atomic_set(&snapshot->sysfs_read, 0);
+ snapshot->gmu_fault = gmu_fault;
+ snapshot->first_read = true;
+ snapshot->sysfs_read = 0;
header = (struct kgsl_snapshot_header *) snapshot->ptr;
@@ -634,14 +702,24 @@
snapshot->size += sizeof(*header);
/* Build the Linux specific header */
- /* Context err is implied a GMU fault, so limit dump */
- kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
- snapshot, snapshot_os,
- IS_ERR(context) ? context : NULL);
+ /* We either want to only dump GMU, or we want to dump GPU and GMU */
+ if (gmu_fault) {
+ /* Dump only the GMU */
+ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
+ snapshot, snapshot_os_no_ctxt, NULL);
- /* Get the device specific sections */
- if (device->ftbl->snapshot)
- device->ftbl->snapshot(device, snapshot, context);
+ if (device->ftbl->snapshot_gmu)
+ device->ftbl->snapshot_gmu(device, snapshot);
+ } else {
+ /* Dump GPU and GMU */
+ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
+ snapshot, snapshot_os, NULL);
+
+ if (device->ftbl->snapshot)
+ device->ftbl->snapshot(device, snapshot, context);
+ if (device->ftbl->snapshot_gmu)
+ device->ftbl->snapshot_gmu(device, snapshot);
+ }
/*
* The timestamp is the seconds since boot so it is easier to match to
@@ -711,6 +789,30 @@
#define kobj_to_device(a) \
container_of(a, struct kgsl_device, snapshot_kobj)
+static int snapshot_release(struct kgsl_device *device,
+ struct kgsl_snapshot *snapshot)
+{
+ bool snapshot_free = false;
+ int ret = 0;
+
+ mutex_lock(&device->mutex);
+ snapshot->sysfs_read--;
+
+ /*
+ * If someone's replaced the snapshot, return an error and free
+ * the snapshot if this is the last thread to read it.
+ */
+ if (device->snapshot != snapshot) {
+ ret = -EIO;
+ if (!snapshot->sysfs_read)
+ snapshot_free = true;
+ }
+ mutex_unlock(&device->mutex);
+ if (snapshot_free)
+ kgsl_free_snapshot(snapshot);
+ return ret;
+}
+
/* Dump the sysfs binary data to the user */
static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off,
@@ -718,20 +820,35 @@
{
struct kgsl_device *device = kobj_to_device(kobj);
struct kgsl_snapshot *snapshot;
- struct kgsl_snapshot_object *obj, *tmp;
struct kgsl_snapshot_section_header head;
struct snapshot_obj_itr itr;
- int ret;
+ int ret = 0;
if (device == NULL)
return 0;
mutex_lock(&device->mutex);
snapshot = device->snapshot;
- if (snapshot != NULL)
- atomic_inc(&snapshot->sysfs_read);
+ if (snapshot != NULL) {
+ /*
+ * If we're reading at a non-zero offset from a new snapshot,
+ * that means we want to read from the previous snapshot (which
+ * was overwritten), so return an error
+ */
+ if (snapshot->first_read) {
+ if (off)
+ ret = -EIO;
+ else
+ snapshot->first_read = false;
+ }
+ if (!ret)
+ snapshot->sysfs_read++;
+ }
mutex_unlock(&device->mutex);
+ if (ret)
+ return ret;
+
/* Return nothing if we haven't taken a snapshot yet */
if (snapshot == NULL)
return 0;
@@ -742,7 +859,7 @@
*/
ret = wait_for_completion_interruptible(&snapshot->dump_gate);
if (ret) {
- atomic_dec(&snapshot->sysfs_read);
+ snapshot_release(device, snapshot);
return ret;
}
@@ -779,29 +896,21 @@
bool snapshot_free = false;
mutex_lock(&device->mutex);
- if (atomic_dec_and_test(&snapshot->sysfs_read)) {
- device->snapshot = NULL;
+ if (--snapshot->sysfs_read == 0) {
+ if (device->snapshot == snapshot)
+ device->snapshot = NULL;
snapshot_free = true;
}
mutex_unlock(&device->mutex);
- if (snapshot_free) {
- list_for_each_entry_safe(obj, tmp,
- &snapshot->obj_list, node)
- kgsl_snapshot_put_object(obj);
-
- if (snapshot->mempool)
- vfree(snapshot->mempool);
-
- kfree(snapshot);
- KGSL_CORE_ERR("snapshot: objects released\n");
- }
+ if (snapshot_free)
+ kgsl_free_snapshot(snapshot);
return 0;
}
done:
- atomic_dec(&snapshot->sysfs_read);
- return itr.write;
+ ret = snapshot_release(device, snapshot);
+ return (ret < 0) ? ret : itr.write;
}
/* Show the total number of hangs since device boot */
@@ -872,9 +981,11 @@
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
- unsigned long timestamp =
- device->snapshot ? device->snapshot->timestamp : 0;
+ unsigned long timestamp;
+ mutex_lock(&device->mutex);
+ timestamp = device->snapshot ? device->snapshot->timestamp : 0;
+ mutex_unlock(&device->mutex);
return snprintf(buf, PAGE_SIZE, "%lu\n", timestamp);
}
@@ -1131,7 +1242,7 @@
* is taken
* @work: The work item that scheduled this work
*/
-void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
+static void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
{
struct kgsl_snapshot *snapshot = container_of(work,
struct kgsl_snapshot, work);
@@ -1143,6 +1254,9 @@
if (IS_ERR_OR_NULL(device))
return;
+ if (snapshot->gmu_fault)
+ goto gmu_only;
+
kgsl_snapshot_process_ib_obj_list(snapshot);
list_for_each_entry(obj, &snapshot->obj_list, node) {
@@ -1189,6 +1303,7 @@
"snapshot: Active IB2:%016llx not dumped\n",
snapshot->ib2base);
+gmu_only:
complete_all(&snapshot->dump_gate);
BUG_ON(device->force_panic);
}
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index ae494d7..8d242f8 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -156,6 +156,17 @@
occurrence. These events can be controlled by using module
parameters.
+config CORESIGHT_TGU
+ bool "CoreSight Trigger Generation Unit driver"
+ help
+ This driver provides support for Trigger Generation Unit that is
+ used to detect patterns or sequences on a given set of signals.
+ TGU is used to monitor a particular bus within a given region to
+ detect illegal transaction sequences or slave responses. It is also
+ used to monitor a data stream to detect protocol violations and to
+ provide a trigger point for centering data around a specific event
+ within the trace data buffer.
+
config CORESIGHT_CSR
bool "CoreSight Slave Register driver"
help
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 0b5e434..44e55ff 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -21,6 +21,7 @@
obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
+obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c
new file mode 100644
index 0000000..e919f47
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tgu.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/amba/bus.h>
+#include <linux/topology.h>
+#include <linux/of.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
+#define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off)
+
+#define TGU_LOCK(drvdata) \
+do { \
+ mb(); /* ensure configuration take effect before we lock it */ \
+ tgu_writel(drvdata, 0x0, CORESIGHT_LAR); \
+} while (0)
+#define TGU_UNLOCK(drvdata) \
+do { \
+ tgu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ mb(); /* ensure unlock take effect before we configure */ \
+} while (0)
+
+#define TGU_CONTROL 0x0000
+#define TIMER0_STATUS 0x0004
+#define COUNTER0_STATUS 0x000C
+#define TGU_STATUS 0x0014
+#define TIMER0_COMPARE_STEP(n) (0x0040 + 0x1D8 * n)
+#define COUNTER0_COMPARE_STEP(n) (0x0048 + 0x1D8 * n)
+#define GROUP_REG_STEP(grp, reg, step) (0x0074 + 0x60 * grp + 0x4 * reg + \
+ 0x1D8 * step)
+#define CONDITION_DECODE_STEP(m, n) (0x0050 + 0x4 * m + 0x1D8 * n)
+#define CONDITION_SELECT_STEP(m, n) (0x0060 + 0x4 * m + 0x1D8 * n)
+#define GROUP0 0x0074
+#define GROUP1 0x00D4
+#define GROUP2 0x0134
+#define GROUP3 0x0194
+#define TGU_LAR 0x0FB0
+
+#define MAX_GROUP_SETS 256
+#define MAX_GROUPS 4
+#define MAX_CONDITION_SETS 64
+#define MAX_TIMER_COUNTER_SETS 8
+
+#define to_tgu_drvdata(c) container_of(c, struct tgu_drvdata, tgu)
+
+struct Trigger_group_data {
+ unsigned long grpaddr;
+ unsigned long value;
+};
+
+struct Trigger_condition_data {
+ unsigned long condaddr;
+ unsigned long value;
+};
+
+struct Trigger_select_data {
+ unsigned long selectaddr;
+ unsigned long value;
+};
+
+struct Trigger_timer_data {
+ unsigned long timeraddr;
+ unsigned long value;
+};
+
+struct Trigger_counter_data {
+ unsigned long counteraddr;
+ unsigned long value;
+};
+struct tgu_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ struct clk *clk;
+ spinlock_t spinlock;
+ int max_steps;
+ int max_conditions;
+ int max_regs;
+ int max_timer_counter;
+ struct Trigger_group_data *grp_data;
+ struct Trigger_condition_data *condition_data;
+ struct Trigger_select_data *select_data;
+ struct Trigger_timer_data *timer_data;
+ struct Trigger_counter_data *counter_data;
+ int grp_refcnt;
+ int cond_refcnt;
+ int select_refcnt;
+ int timer_refcnt;
+ int counter_refcnt;
+ bool enable;
+};
+
+static ssize_t enable_tgu(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long value;
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int ret, i, j;
+
+ if (kstrtoul(buf, 16, &value))
+ return -EINVAL;
+
+ /* Enable clock */
+ ret = pm_runtime_get_sync(drvdata->dev);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ /* Unlock the TGU LAR */
+ TGU_UNLOCK(drvdata);
+
+ if (value) {
+
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+
+ /* program the TGU Group data for the desired use case*/
+
+ for (i = 0; i <= drvdata->grp_refcnt; i++)
+ tgu_writel(drvdata, drvdata->grp_data[i].value,
+ drvdata->grp_data[i].grpaddr);
+
+ /* program the unused Condition Decode registers NOT bits to 1*/
+ for (i = 0; i <= drvdata->max_conditions; i++) {
+ for (j = 0; j <= drvdata->max_steps; j++)
+ tgu_writel(drvdata, 0x1000000,
+ CONDITION_DECODE_STEP(i, j));
+ }
+ /* program the TGU Condition Decode for the desired use case*/
+ for (i = 0; i <= drvdata->cond_refcnt; i++)
+ tgu_writel(drvdata, drvdata->condition_data[i].value,
+ drvdata->condition_data[i].condaddr);
+
+ /* program the TGU Condition Select for the desired use case*/
+ for (i = 0; i <= drvdata->select_refcnt; i++)
+ tgu_writel(drvdata, drvdata->select_data[i].value,
+ drvdata->select_data[i].selectaddr);
+
+ /* Timer and Counter Check */
+ for (i = 0; i <= drvdata->timer_refcnt; i++)
+ tgu_writel(drvdata, drvdata->timer_data[i].value,
+ drvdata->timer_data[i].timeraddr);
+
+ for (i = 0; i <= drvdata->counter_refcnt; i++)
+ tgu_writel(drvdata, drvdata->counter_data[i].value,
+ drvdata->counter_data[i].counteraddr);
+
+ /* Enable TGU to program the triggers */
+ tgu_writel(drvdata, 1, TGU_CONTROL);
+
+ drvdata->enable = true;
+ dev_dbg(dev, "Coresight-TGU enabled\n");
+
+ } else {
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+
+ pm_runtime_put(drvdata->dev);
+ dev_dbg(dev, "Coresight-TGU disabled\n");
+ }
+
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR(enable_tgu, 0200, NULL, enable_tgu);
+
+static ssize_t reset_tgu(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long value;
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int ret;
+
+ if (kstrtoul(buf, 16, &value))
+ return -EINVAL;
+
+ if (!drvdata->enable) {
+ /* Enable clock */
+ ret = pm_runtime_get_sync(drvdata->dev);
+ if (ret)
+ return ret;
+ }
+
+ spin_lock(&drvdata->spinlock);
+ /* Unlock the TGU LAR */
+ TGU_UNLOCK(drvdata);
+
+ if (value) {
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+
+ /* Reset the Reference counters*/
+ drvdata->grp_refcnt = 0;
+ drvdata->cond_refcnt = 0;
+ drvdata->select_refcnt = 0;
+ drvdata->timer_refcnt = 0;
+ drvdata->counter_refcnt = 0;
+
+ dev_dbg(dev, "Coresight-TGU disabled\n");
+ } else
+ dev_dbg(dev, "Invalid input to reset the TGU\n");
+
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+ pm_runtime_put(drvdata->dev);
+ return size;
+}
+static DEVICE_ATTR(reset_tgu, 0200, NULL, reset_tgu);
+
+static ssize_t set_group(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int grp, reg, step;
+ unsigned long value;
+
+ if (drvdata->grp_refcnt >= MAX_GROUP_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %d %lx", &grp, ®, &step, &value) != 4)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if ((grp <= MAX_GROUPS) && (reg <= drvdata->max_regs)) {
+ drvdata->grp_data[drvdata->grp_refcnt].grpaddr =
+ GROUP_REG_STEP(grp, reg, step);
+ drvdata->grp_data[drvdata->grp_refcnt].value = value;
+ drvdata->grp_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid group data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_group, 0200, NULL, set_group);
+
+static ssize_t tgu_set_condition(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int cond, step;
+
+ if (drvdata->cond_refcnt >= MAX_CONDITION_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %lx", &cond, &step, &value) != 3)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if ((cond <= drvdata->max_conditions) && (step <=
+ drvdata->max_steps)) {
+ drvdata->condition_data[drvdata->cond_refcnt].condaddr =
+ CONDITION_DECODE_STEP(cond, step);
+ drvdata->condition_data[drvdata->cond_refcnt].value = value;
+ drvdata->cond_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid condition decode data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_condition, 0200, NULL, tgu_set_condition);
+
+static ssize_t tgu_set_select(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int select, step;
+
+ if (drvdata->select_refcnt >= MAX_CONDITION_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %lx", &select, &step, &value) != 3)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+
+ if ((select <= drvdata->max_conditions) && (step <=
+ drvdata->max_steps)) {
+ drvdata->select_data[drvdata->select_refcnt].selectaddr =
+ CONDITION_SELECT_STEP(select, step);
+ drvdata->select_data[drvdata->select_refcnt].value = value;
+ drvdata->select_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid select decode data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_select, 0200, NULL, tgu_set_select);
+
+static ssize_t tgu_set_timers(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int step;
+
+ if (drvdata->select_refcnt >= MAX_TIMER_COUNTER_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %lx", &step, &value) != 2)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (step <= drvdata->max_timer_counter) {
+ drvdata->timer_data[drvdata->timer_refcnt].timeraddr =
+ TIMER0_COMPARE_STEP(step);
+ drvdata->timer_data[drvdata->timer_refcnt].value = value;
+ drvdata->timer_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid TGU timer data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_timer, 0200, NULL, tgu_set_timers);
+
+static ssize_t tgu_set_counters(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int step;
+
+ if (drvdata->counter_refcnt >= MAX_TIMER_COUNTER_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %lx", &step, &value) != 2)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (step <= drvdata->max_timer_counter) {
+ drvdata->counter_data[drvdata->counter_refcnt].counteraddr =
+ COUNTER0_COMPARE_STEP(step);
+ drvdata->counter_data[drvdata->counter_refcnt].value = value;
+ drvdata->counter_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid TGU counter data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_counter, 0200, NULL, tgu_set_counters);
+
+static struct attribute *tgu_attrs[] = {
+ &dev_attr_enable_tgu.attr,
+ &dev_attr_reset_tgu.attr,
+ &dev_attr_set_group.attr,
+ &dev_attr_set_condition.attr,
+ &dev_attr_set_select.attr,
+ &dev_attr_set_timer.attr,
+ &dev_attr_set_counter.attr,
+ NULL,
+};
+
+static struct attribute_group tgu_attr_grp = {
+ .attrs = tgu_attrs,
+};
+
+static const struct attribute_group *tgu_attr_grps[] = {
+ &tgu_attr_grp,
+ NULL,
+};
+
+static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ int ret = 0;
+ struct device *dev = &adev->dev;
+ struct coresight_platform_data *pdata;
+ struct tgu_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &adev->dev;
+
+ dev_set_drvdata(dev, drvdata);
+
+ drvdata->base = devm_ioremap_resource(dev, &adev->res);
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ spin_lock_init(&drvdata->spinlock);
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-steps",
+ &drvdata->max_steps);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-conditions",
+ &drvdata->max_conditions);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-regs",
+ &drvdata->max_regs);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-timer-counters",
+ &drvdata->max_timer_counter);
+ if (ret)
+ return -EINVAL;
+
+ /* Alloc memory for Grps, Conditions and Steps */
+ drvdata->grp_data = devm_kzalloc(dev, MAX_GROUP_SETS *
+ sizeof(*drvdata->grp_data),
+ GFP_KERNEL);
+ if (!drvdata->grp_data)
+ return -ENOMEM;
+
+ drvdata->condition_data = devm_kzalloc(dev, MAX_CONDITION_SETS *
+ sizeof(*drvdata->condition_data),
+ GFP_KERNEL);
+
+ if (!drvdata->condition_data)
+ return -ENOMEM;
+
+ drvdata->select_data = devm_kzalloc(dev, MAX_CONDITION_SETS *
+ sizeof(*drvdata->select_data),
+ GFP_KERNEL);
+ if (!drvdata->select_data)
+ return -ENOMEM;
+
+ drvdata->timer_data = devm_kzalloc(dev, MAX_TIMER_COUNTER_SETS *
+ sizeof(*drvdata->timer_data),
+ GFP_KERNEL);
+ if (!drvdata->timer_data)
+ return -ENOMEM;
+
+ drvdata->counter_data = devm_kzalloc(dev, MAX_TIMER_COUNTER_SETS *
+ sizeof(*drvdata->counter_data),
+ GFP_KERNEL);
+ if (!drvdata->counter_data)
+ return -ENOMEM;
+
+ drvdata->enable = false;
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = adev->dev.platform_data;
+ desc->dev = &adev->dev;
+ desc->groups = tgu_attr_grps;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev)) {
+ ret = PTR_ERR(drvdata->csdev);
+ goto err;
+ }
+
+ pm_runtime_put(&adev->dev);
+ dev_dbg(dev, "TGU initialized\n");
+ return 0;
+err:
+ pm_runtime_put(&adev->dev);
+ return ret;
+}
+
+static struct amba_id tgu_ids[] = {
+ {
+ .id = 0x0003b999,
+ .mask = 0x0003ffff,
+ .data = "TGU",
+ },
+ { 0, 0},
+};
+
+static struct amba_driver tgu_driver = {
+ .drv = {
+ .name = "coresight-tgu",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
+ },
+ .probe = tgu_probe,
+ .id_table = tgu_ids,
+};
+
+builtin_amba_driver(tgu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight TGU driver");
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0b42a12..b42d95f 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -319,7 +319,7 @@
#endif
#ifdef CONFIG_PM
-static int dw_i2c_plat_suspend(struct device *dev)
+static int dw_i2c_plat_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -343,11 +343,21 @@
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int dw_i2c_plat_suspend(struct device *dev)
+{
+ pm_runtime_resume(dev);
+ return dw_i2c_plat_runtime_suspend(dev);
+}
+#endif
+
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = dw_i2c_plat_prepare,
.complete = dw_i2c_plat_complete,
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
- SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
+ SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
+ dw_i2c_plat_resume,
+ NULL)
};
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index f573448..8477292 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -341,8 +341,10 @@
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_I2C_BLOCK_DATA:
- memcpy(&data->block[1], dma_buffer, desc->rxbytes);
- data->block[0] = desc->rxbytes;
+ if (desc->rxbytes != dma_buffer[0] + 1)
+ return -EMSGSIZE;
+
+ memcpy(data->block, dma_buffer, desc->rxbytes);
break;
}
return 0;
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index 3de0e25..4daed7f 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -2164,7 +2164,6 @@
++cur_buf->msg_idx;
++cur_msg;
- }
} else {
cur_buf->is_init = true;
}
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index f70dbf2..7264381 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -191,13 +191,6 @@
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
- u32 m_cmd = readl_relaxed(gi2c->base + SE_GENI_M_CMD0);
- u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
- u32 geni_s = readl_relaxed(gi2c->base + SE_GENI_STATUS);
- u32 geni_ios = readl_relaxed(gi2c->base + SE_GENI_IOS);
- u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN);
- u32 rx_st, tx_st;
-
if (gi2c->cur)
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
"len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len,
@@ -211,23 +204,9 @@
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
gi2c_log[err].msg);
}
- if (gi2c->se_mode == GSI_ONLY)
- goto err_out;
-
- if (dma) {
- rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
- tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
- } else {
- rx_st = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
- tx_st = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
- }
- GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
- dma, tx_st, rx_st, m_stat);
-err_out:
- GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
- m_cmd, geni_s, geni_ios);
+ GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__,
+ gi2c->se_mode);
+ geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl);
err_ret:
gi2c->err = gi2c_log[err].err;
}
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 59b380d..c388882 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -193,7 +193,6 @@
struct regmap *regmap;
int irq;
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
- atomic_t active_intr;
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
struct mutex mutex;
u8 fifo_mode, watermark;
@@ -493,11 +492,6 @@
goto out_fix_power_state;
}
- if (state)
- atomic_inc(&data->active_intr);
- else
- atomic_dec(&data->active_intr);
-
return 0;
out_fix_power_state:
@@ -1709,8 +1703,7 @@
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
- if (atomic_read(&data->active_intr))
- bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
+ bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
bmc150_accel_fifo_set_mode(data);
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 228a003..d1bde6d 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -77,7 +77,7 @@
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
-#define VF610_ADC_REFSEL_VALT 0x100
+#define VF610_ADC_REFSEL_VALT 0x800
#define VF610_ADC_REFSEL_VBG 0x1000
#define VF610_ADC_ADTRG_HARD 0x2000
#define VF610_ADC_AVGS_8 0x4000
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 6082934..b60e5d8 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -36,8 +36,6 @@
s32 poll_value = 0;
if (state) {
- if (!atomic_read(&st->user_requested_state))
- return 0;
if (sensor_hub_device_open(st->hsdev))
return -EIO;
@@ -86,6 +84,9 @@
&report_val);
}
+ pr_debug("HID_SENSOR %s set power_state %d report_state %d\n",
+ st->pdev->name, state_val, report_val);
+
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
sizeof(state_val), &state_val);
@@ -107,6 +108,7 @@
ret = pm_runtime_get_sync(&st->pdev->dev);
else {
pm_runtime_mark_last_busy(&st->pdev->dev);
+ pm_runtime_use_autosuspend(&st->pdev->dev);
ret = pm_runtime_put_autosuspend(&st->pdev->dev);
}
if (ret < 0) {
@@ -201,8 +203,6 @@
/* Default to 3 seconds, but can be changed from sysfs */
pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
3000);
- pm_runtime_use_autosuspend(&attrb->pdev->dev);
-
return ret;
error_unreg_trigger:
iio_trigger_unregister(trig);
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 8cf84d3..1289842 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -696,7 +696,7 @@
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(12500),
- .accel_max_scale = 5,
+ .accel_max_scale = 10,
},
[ADIS16485] = {
.channels = adis16485_channels,
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 04598ae..f0d3f74 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -626,7 +626,7 @@
struct tsl2563_chip *chip = iio_priv(dev_info);
iio_push_event(dev_info,
- IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_EITHER),
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index f1510cc..9398143 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1804,20 +1804,21 @@
skb_trim(skb, dlen);
mutex_lock(&ep->com.mutex);
- /* update RX credits */
- update_rx_credits(ep, dlen);
-
switch (ep->com.state) {
case MPA_REQ_SENT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_reply(ep, skb);
break;
case MPA_REQ_WAIT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_request(ep, skb);
break;
case FPDU_MODE: {
struct c4iw_qp_attributes attrs;
+
+ update_rx_credits(ep, dlen);
BUG_ON(!ep->com.qp);
if (status)
pr_err("%s Unexpected streaming data." \
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
index c5ab3dd..fdcc146 100644
--- a/drivers/input/misc/keychord.c
+++ b/drivers/input/misc/keychord.c
@@ -60,6 +60,10 @@
unsigned char head;
unsigned char tail;
__u16 buff[BUFFER_SIZE];
+ /* Bit to serialize writes to this device */
+#define KEYCHORD_BUSY 0x01
+ unsigned long flags;
+ wait_queue_head_t write_waitq;
};
static int check_keychord(struct keychord_device *kdev,
@@ -172,7 +176,6 @@
goto err_input_open_device;
pr_info("keychord: using input dev %s for fevent\n", dev->name);
-
return 0;
err_input_open_device:
@@ -225,6 +228,41 @@
}
/*
+ * serializes writes on a device. can use mutex_lock_interruptible()
+ * for this particular use case as well - a matter of preference.
+ */
+static int
+keychord_write_lock(struct keychord_device *kdev)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kdev->lock, flags);
+ while (kdev->flags & KEYCHORD_BUSY) {
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ ret = wait_event_interruptible(kdev->write_waitq,
+ ((kdev->flags & KEYCHORD_BUSY) == 0));
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&kdev->lock, flags);
+ }
+ kdev->flags |= KEYCHORD_BUSY;
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ return 0;
+}
+
+static void
+keychord_write_unlock(struct keychord_device *kdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kdev->lock, flags);
+ kdev->flags &= ~KEYCHORD_BUSY;
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ wake_up_interruptible(&kdev->write_waitq);
+}
+
+/*
* keychord_write is used to configure the driver
*/
static ssize_t keychord_write(struct file *file, const char __user *buffer,
@@ -250,6 +288,22 @@
return -EFAULT;
}
+ /*
+ * Serialize writes to this device to prevent various races.
+ * 1) writers racing here could do duplicate input_unregister_handler()
+ * calls, resulting in attempting to unlink a node from a list that
+ * does not exist.
+ * 2) writers racing here could do duplicate input_register_handler() calls
+ * below, resulting in a duplicate insertion of a node into the list.
+ * 3) a double kfree of keychords can occur (in the event that
+ * input_register_handler() fails below.
+ */
+ ret = keychord_write_lock(kdev);
+ if (ret) {
+ kfree(keychords);
+ return ret;
+ }
+
/* unregister handler before changing configuration */
if (kdev->registered) {
input_unregister_handler(&kdev->input_handler);
@@ -318,15 +372,19 @@
if (ret) {
kfree(keychords);
kdev->keychords = 0;
+ keychord_write_unlock(kdev);
return ret;
}
kdev->registered = 1;
+ keychord_write_unlock(kdev);
+
return count;
err_unlock_return:
spin_unlock_irqrestore(&kdev->lock, flags);
kfree(keychords);
+ keychord_write_unlock(kdev);
return -EINVAL;
}
@@ -352,6 +410,7 @@
spin_lock_init(&kdev->lock);
init_waitqueue_head(&kdev->waitq);
+ init_waitqueue_head(&kdev->write_waitq);
kdev->input_handler.event = keychord_event;
kdev->input_handler.connect = keychord_connect;
@@ -373,6 +432,7 @@
if (kdev->registered)
input_unregister_handler(&kdev->input_handler);
+ kfree(kdev->keychords);
kfree(kdev);
return 0;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 518e8a7..f26807c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1212,14 +1212,24 @@
case SS4_PACKET_ID_TWO:
if (priv->flags & ALPS_BUTTONPAD) {
- f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
+ }
f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0);
- f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1);
} else {
- f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+ }
f->mt[0].y = SS4_STD_MF_Y_V2(p, 0);
- f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
f->mt[1].y = SS4_STD_MF_Y_V2(p, 1);
}
f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
@@ -1236,16 +1246,27 @@
case SS4_PACKET_ID_MULTI:
if (priv->flags & ALPS_BUTTONPAD) {
- f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+ } else {
+ f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
+ f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
+ }
+
f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
- f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
no_data_x = SS4_MFPACKET_NO_AX_BL;
no_data_y = SS4_MFPACKET_NO_AY_BL;
} else {
- f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+ }
f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
- f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
no_data_x = SS4_MFPACKET_NO_AX;
no_data_y = SS4_MFPACKET_NO_AY;
@@ -2535,8 +2556,8 @@
memset(otp, 0, sizeof(otp));
- if (alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]) ||
- alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]))
+ if (alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]) ||
+ alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]))
return -1;
alps_update_device_area_ss4_v2(otp, priv);
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index dbfd260..7931237 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -91,6 +91,10 @@
((_b[1 + _i * 3] << 5) & 0x1F00) \
)
+#define SS4_PLUS_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 4) & 0x0070) | \
+ ((_b[1 + (_i) * 3] << 4) & 0x0F80) \
+ )
+
#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \
((_b[2 + (_i) * 3] << 5) & 0x01E0) | \
((_b[2 + (_i) * 3] << 4) & 0x0E00) \
@@ -100,6 +104,10 @@
((_b[0 + (_i) * 3] >> 3) & 0x0010) \
)
+#define SS4_PLUS_BTL_MF_X_V2(_b, _i) (SS4_PLUS_STD_MF_X_V2(_b, _i) | \
+ ((_b[0 + (_i) * 3] >> 4) & 0x0008) \
+ )
+
#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
((_b[0 + (_i) * 3] >> 3) & 0x0008) \
)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index da5458d..681dce1 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1234,7 +1234,12 @@
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
{ "ELAN0600", 0 },
+ { "ELAN0602", 0 },
{ "ELAN0605", 0 },
+ { "ELAN0608", 0 },
+ { "ELAN0605", 0 },
+ { "ELAN0609", 0 },
+ { "ELAN060B", 0 },
{ "ELAN1000", 0 },
{ }
};
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 354d47e..ce6ff9b 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -265,7 +265,8 @@
if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
return -1;
- if (param[0] != TP_MAGIC_IDENT)
+ /* add new TP ID. */
+ if (!(param[0] & TP_MAGIC_IDENT))
return -1;
if (firmware_id)
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 5617ed3..8805575 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -21,8 +21,9 @@
#define TP_COMMAND 0xE2 /* Commands start with this */
#define TP_READ_ID 0xE1 /* Sent for device identification */
-#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */
+#define TP_MAGIC_IDENT 0x03 /* Sent after a TP_READ_ID followed */
/* by the firmware ID */
+ /* Firmware ID includes 0x1, 0x2, 0x3 */
/*
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 41800b6..c380b7e 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4294,6 +4294,7 @@
/* Setting */
irte->hi.fields.ga_root_ptr = (pi_data->base >> 12);
irte->hi.fields.vector = vcpu_pi_info->vector;
+ irte->lo.fields_vapic.ga_log_intr = 1;
irte->lo.fields_vapic.guest_mode = 1;
irte->lo.fields_vapic.ga_tag = pi_data->ga_tag;
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a2c5579..d49fd55 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -427,6 +427,7 @@
#define ARM_SMMU_OPT_DYNAMIC (1 << 3)
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
+#define ARM_SMMU_OPT_DISABLE_ATOS (1 << 6)
u32 options;
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
@@ -547,6 +548,7 @@
{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
+ { ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" },
{ 0, NULL},
};
@@ -2490,6 +2492,10 @@
phys_addr_t ret = 0;
unsigned long flags;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+ if (smmu->options & ARM_SMMU_OPT_DISABLE_ATOS)
+ return 0;
if (smmu_domain->smmu->arch_ops &&
smmu_domain->smmu->arch_ops->iova_to_phys_hard) {
@@ -2760,6 +2766,11 @@
& (1 << DOMAIN_ATTR_FAST));
ret = 0;
break;
+ case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
+ *((int *)data) = !!(smmu_domain->attributes
+ & (1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR));
+ ret = 0;
+ break;
case DOMAIN_ATTR_USE_UPSTREAM_HINT:
*((int *)data) = !!(smmu_domain->attributes &
(1 << DOMAIN_ATTR_USE_UPSTREAM_HINT));
@@ -2912,6 +2923,12 @@
}
smmu_domain->secure_vmid = *((int *)data);
break;
+ case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
+ if (*((int *)data))
+ smmu_domain->attributes |=
+ 1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR;
+ ret = 0;
+ break;
case DOMAIN_ATTR_FAST:
if (*((int *)data))
smmu_domain->attributes |= 1 << DOMAIN_ATTR_FAST;
@@ -3265,11 +3282,6 @@
u32 sctlr, sctlr_orig, fsr;
void __iomem *cb_base;
- if (smmu->model == QCOM_SMMUV2) {
- dev_err(smmu->dev, "ATOS support is disabled\n");
- return 0;
- }
-
ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
if (ret)
return ret;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index d92a352..da4d283 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -202,39 +202,58 @@
}
}
-static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size,
- dma_addr_t dma_limit)
+static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
+ size_t size, dma_addr_t dma_limit, struct device *dev)
{
struct iova_domain *iovad = cookie_iovad(domain);
unsigned long shift = iova_shift(iovad);
- unsigned long length = iova_align(iovad, size) >> shift;
+ unsigned long iova_len = size >> shift;
+ unsigned long iova = 0;
+ dma_addr_t limit;
+
+ /*
+ * Freeing non-power-of-two-sized allocations back into the IOVA caches
+ * will come back to bite us badly, so we have to waste a bit of space
+ * rounding up anything cacheable to make sure that can't happen. The
+ * order of the unadjusted size will still match upon freeing.
+ */
+ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+ iova_len = roundup_pow_of_two(iova_len);
if (domain->geometry.force_aperture)
dma_limit = min(dma_limit, domain->geometry.aperture_end);
+
/*
- * Enforce size-alignment to be safe - there could perhaps be an
- * attribute to control this per-device, or at least per-domain...
+ * Ensure iova is within range specified in iommu_dma_init_domain().
+ * This also prevents unnecessary work iterating through the entire
+ * rb_tree.
*/
- return alloc_iova(iovad, length, dma_limit >> shift, true);
+ limit = min_t(dma_addr_t, dma_limit >> shift, iovad->dma_32bit_pfn);
+ iova = alloc_iova_fast(iovad, iova_len, limit);
+
+ return (dma_addr_t)iova << shift;
}
-/* The IOVA allocator knows what we mapped, so just unmap whatever that was */
-static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr)
+static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
+ dma_addr_t iova, size_t size)
+{
+ struct iova_domain *iovad = &cookie->iovad;
+ unsigned long shift = iova_shift(iovad);
+
+ free_iova_fast(iovad, iova >> shift, size >> shift);
+}
+
+static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
+ size_t size)
{
struct iova_domain *iovad = cookie_iovad(domain);
- unsigned long shift = iova_shift(iovad);
- unsigned long pfn = dma_addr >> shift;
- struct iova *iova = find_iova(iovad, pfn);
- size_t size;
+ size_t iova_off = iova_offset(iovad, dma_addr);
- if (WARN_ON(!iova))
- return;
+ dma_addr -= iova_off;
+ size = iova_align(iovad, size + iova_off);
- size = iova_size(iova) << shift;
- size -= iommu_unmap(domain, pfn << shift, size);
- /* ...and if we can't, then something is horribly, horribly wrong */
- WARN_ON(size > 0);
- __free_iova(iovad, iova);
+ WARN_ON(iommu_unmap(domain, dma_addr, size) != size);
+ iommu_dma_free_iova(domain->iova_cookie, dma_addr, size);
}
static void __iommu_dma_free_pages(struct page **pages, int count)
@@ -316,7 +335,7 @@
void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
dma_addr_t *handle)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size);
__iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
*handle = DMA_ERROR_CODE;
}
@@ -344,11 +363,11 @@
void (*flush_page)(struct device *, const void *, phys_addr_t))
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
- struct iova *iova;
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
struct page **pages;
struct sg_table sgt;
- dma_addr_t dma_addr;
+ dma_addr_t iova;
unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
*handle = DMA_ERROR_CODE;
@@ -368,11 +387,11 @@
if (!pages)
return NULL;
- iova = __alloc_iova(domain, size, dev->coherent_dma_mask);
+ size = iova_align(iovad, size);
+ iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev);
if (!iova)
goto out_free_pages;
- size = iova_align(iovad, size);
if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL))
goto out_free_iova;
@@ -388,19 +407,18 @@
sg_miter_stop(&miter);
}
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map_sg(domain, dma_addr, sgt.sgl, sgt.orig_nents, prot)
+ if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot)
< size)
goto out_free_sg;
- *handle = dma_addr;
+ *handle = iova;
sg_free_table(&sgt);
return pages;
out_free_sg:
sg_free_table(&sgt);
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, size);
out_free_pages:
__iommu_dma_free_pages(pages, count);
return NULL;
@@ -434,22 +452,22 @@
static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
size_t size, int prot)
{
- dma_addr_t dma_addr;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
size_t iova_off = iova_offset(iovad, phys);
- size_t len = iova_align(iovad, size + iova_off);
- struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev));
+ dma_addr_t iova;
+ size = iova_align(iovad, size + iova_off);
+ iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
if (!iova)
return DMA_ERROR_CODE;
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) {
- __free_iova(iovad, iova);
+ if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+ iommu_dma_free_iova(cookie, iova, size);
return DMA_ERROR_CODE;
}
- return dma_addr + iova_off;
+ return iova + iova_off;
}
dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
@@ -461,7 +479,7 @@
void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
}
/*
@@ -550,10 +568,10 @@
int nents, int prot)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
- struct iova *iova;
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
struct scatterlist *s, *prev = NULL;
- dma_addr_t dma_addr;
+ dma_addr_t iova;
size_t iova_len = 0;
unsigned long mask = dma_get_seg_boundary(dev);
int i;
@@ -597,7 +615,7 @@
prev = s;
}
- iova = __alloc_iova(domain, iova_len, dma_get_mask(dev));
+ iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev);
if (!iova)
goto out_restore_sg;
@@ -605,14 +623,13 @@
* We'll leave any physical concatenation to the IOMMU driver's
* implementation - it knows better than we do.
*/
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len)
+ if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len)
goto out_free_iova;
- return __finalise_sg(dev, sg, nents, dma_addr);
+ return __finalise_sg(dev, sg, nents, iova);
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, iova_len);
out_restore_sg:
__invalidate_sg(sg, nents);
return 0;
@@ -621,11 +638,21 @@
void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, unsigned long attrs)
{
+ dma_addr_t start, end;
+ struct scatterlist *tmp;
+ int i;
/*
* The scatterlist segments are mapped into a single
* contiguous IOVA allocation, so this is incredibly easy.
*/
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg));
+ start = sg_dma_address(sg);
+ for_each_sg(sg_next(sg), tmp, nents - 1, i) {
+ if (sg_dma_len(tmp) == 0)
+ break;
+ sg = tmp;
+ }
+ end = sg_dma_address(sg) + sg_dma_len(sg);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start);
}
dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
@@ -638,7 +665,7 @@
void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
}
int iommu_dma_supported(struct device *dev, u64 mask)
@@ -662,7 +689,7 @@
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iommu_dma_msi_page *msi_page;
struct iova_domain *iovad = &cookie->iovad;
- struct iova *iova;
+ dma_addr_t iova;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
msi_addr &= ~(phys_addr_t)iova_mask(iovad);
@@ -674,12 +701,13 @@
if (!msi_page)
return NULL;
- iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev));
+ iova = iommu_dma_alloc_iova(domain, iovad->granule, dma_get_mask(dev),
+ dev);
if (!iova)
goto out_free_page;
msi_page->phys = msi_addr;
- msi_page->iova = iova_dma_addr(iovad, iova);
+ msi_page->iova = iova;
if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot))
goto out_free_iova;
@@ -688,7 +716,7 @@
return msi_page;
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, iovad->granule);
out_free_page:
kfree(msi_page);
return NULL;
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index b5e817b..04a5c09 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -855,29 +855,28 @@
spin_unlock_irqrestore(&mapping->lock, flags);
}
-
/**
- * fast_smmu_attach_device
+ * fast_smmu_init_mapping
* @dev: valid struct device pointer
* @mapping: io address space mapping structure (returned from
- * fast_smmu_create_mapping)
+ * arm_iommu_create_mapping)
*
- * Attaches specified io address space mapping to the provided device,
- * this replaces the dma operations (dma_map_ops pointer) with the
- * IOMMU aware version. More than one client might be attached to
- * the same io address space mapping.
+ * Called the first time a device is attached to this mapping.
+ * Not for dma client use.
*/
-int fast_smmu_attach_device(struct device *dev,
+int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
- int atomic_domain = 1;
+ int err, atomic_domain = 1;
struct iommu_domain *domain = mapping->domain;
struct iommu_group *group;
struct iommu_pgtbl_info info;
u64 size = (u64)mapping->bits << PAGE_SHIFT;
- if (mapping->base + size > (SZ_1G * 4ULL))
+ if (mapping->base + size > (SZ_1G * 4ULL)) {
+ dev_err(dev, "Iova end address too large\n");
return -EINVAL;
+ }
if (iommu_domain_set_attr(domain, DOMAIN_ATTR_ATOMIC,
&atomic_domain))
@@ -894,54 +893,67 @@
group = dev->iommu_group;
if (!group) {
dev_err(dev, "No iommu associated with device\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto release_mapping;
}
if (iommu_get_domain_for_dev(dev)) {
dev_err(dev, "Device already attached to other iommu_domain\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto release_mapping;
}
- if (iommu_attach_group(mapping->domain, group))
- return -EINVAL;
+ /*
+ * Need to attach prior to calling DOMAIN_ATTR_PGTBL_INFO and then
+ * detach to be in the expected state. Its a bit messy.
+ */
+ if (iommu_attach_group(mapping->domain, group)) {
+ err = -EINVAL;
+ goto release_mapping;
+ }
if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PGTBL_INFO,
&info)) {
dev_err(dev, "Couldn't get page table info\n");
- fast_smmu_detach_device(dev, mapping);
- return -EINVAL;
+ err = -EINVAL;
+ goto detach_group;
}
mapping->fast->pgtbl_pmds = info.pmds;
if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
- &mapping->fast->is_smmu_pt_coherent))
- return -EINVAL;
+ &mapping->fast->is_smmu_pt_coherent)) {
+ err = -EINVAL;
+ goto detach_group;
+ }
mapping->fast->notifier.notifier_call = fast_smmu_notify;
av8l_register_notify(&mapping->fast->notifier);
- dev->archdata.mapping = mapping;
- set_dma_ops(dev, &fast_smmu_dma_ops);
-
+ iommu_detach_group(mapping->domain, group);
+ mapping->ops = &fast_smmu_dma_ops;
return 0;
+
+detach_group:
+ iommu_detach_group(mapping->domain, group);
+release_mapping:
+ kfree(mapping->fast->bitmap);
+ kfree(mapping->fast);
+ return err;
}
-EXPORT_SYMBOL(fast_smmu_attach_device);
/**
- * fast_smmu_detach_device
- * @dev: valid struct device pointer
+ * fast_smmu_release_mapping
+ * @kref: dma_iommu_mapping->kref
*
- * Detaches the provided device from a previously attached map.
- * This voids the dma operations (dma_map_ops pointer)
+ * Cleans up the given iommu mapping.
*/
-void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
+void fast_smmu_release_mapping(struct kref *kref)
{
- iommu_detach_group(mapping->domain, dev->iommu_group);
- dev->archdata.mapping = NULL;
- set_dma_ops(dev, NULL);
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
kvfree(mapping->fast->bitmap);
kfree(mapping->fast);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
}
-EXPORT_SYMBOL(fast_smmu_detach_device);
diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c
index 28b26c8..0565070 100644
--- a/drivers/irqchip/irq-atmel-aic-common.c
+++ b/drivers/irqchip/irq-atmel-aic-common.c
@@ -142,9 +142,9 @@
struct device_node *np;
void __iomem *regs;
- np = of_find_compatible_node(root, NULL, "atmel,at91rm9200-rtc");
+ np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-rtc");
if (!np)
- np = of_find_compatible_node(root, NULL,
+ np = of_find_compatible_node(NULL, NULL,
"atmel,at91sam9x5-rtc");
if (!np)
@@ -196,7 +196,6 @@
return;
match = of_match_node(matches, root);
- of_node_put(root);
if (match) {
void (*fixup)(struct device_node *) = match->data;
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index c0178a1..d74374f 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -1115,8 +1115,11 @@
gic_len = resource_size(&res);
}
- if (mips_cm_present())
+ if (mips_cm_present()) {
write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
+ /* Ensure GIC region is enabled before trying to access it */
+ __sync();
+ }
gic_present = true;
__gic_init(gic_base, gic_len, cpu_vec, 0, node);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 817dfa3..ab0e4f9 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1213,7 +1213,7 @@
static int qpnp_flash_set(struct qpnp_led_data *led)
{
- int rc, error;
+ int rc = 0, error;
int val = led->cdev.brightness;
if (led->flash_cfg->torch_enable)
@@ -1251,7 +1251,8 @@
}
}
- qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+ rc = qpnp_led_masked_write(led,
+ FLASH_MAX_CURR(led->base),
FLASH_CURRENT_MASK,
TORCH_MAX_LEVEL);
if (rc) {
@@ -1261,7 +1262,7 @@
goto error_reg_write;
}
- qpnp_led_masked_write(led,
+ rc = qpnp_led_masked_write(led,
FLASH_LED_TMR_CTRL(led->base),
FLASH_TMR_MASK,
FLASH_TMR_WATCHDOG);
@@ -1293,7 +1294,7 @@
goto error_reg_write;
}
- qpnp_led_masked_write(led,
+ rc = qpnp_led_masked_write(led,
FLASH_WATCHDOG_TMR(led->base),
FLASH_WATCHDOG_MASK,
led->flash_cfg->duration);
@@ -1341,7 +1342,7 @@
goto error_flash_set;
}
- qpnp_led_masked_write(led,
+ rc = qpnp_led_masked_write(led,
FLASH_LED_TMR_CTRL(led->base),
FLASH_TMR_MASK,
FLASH_TMR_SAFETY);
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index c9f3862..410c39c 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/leds.h>
#include <linux/reboot.h>
-#include <linux/suspend.h>
#include "../leds.h"
static int panic_heartbeats;
@@ -155,30 +154,6 @@
.deactivate = heartbeat_trig_deactivate,
};
-static int heartbeat_pm_notifier(struct notifier_block *nb,
- unsigned long pm_event, void *unused)
-{
- int rc;
-
- switch (pm_event) {
- case PM_SUSPEND_PREPARE:
- case PM_HIBERNATION_PREPARE:
- case PM_RESTORE_PREPARE:
- led_trigger_unregister(&heartbeat_led_trigger);
- break;
- case PM_POST_SUSPEND:
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
- rc = led_trigger_register(&heartbeat_led_trigger);
- if (rc)
- pr_err("could not re-register heartbeat trigger\n");
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
static int heartbeat_reboot_notifier(struct notifier_block *nb,
unsigned long code, void *unused)
{
@@ -193,10 +168,6 @@
return NOTIFY_DONE;
}
-static struct notifier_block heartbeat_pm_nb = {
- .notifier_call = heartbeat_pm_notifier,
-};
-
static struct notifier_block heartbeat_reboot_nb = {
.notifier_call = heartbeat_reboot_notifier,
};
@@ -213,14 +184,12 @@
atomic_notifier_chain_register(&panic_notifier_list,
&heartbeat_panic_nb);
register_reboot_notifier(&heartbeat_reboot_nb);
- register_pm_notifier(&heartbeat_pm_nb);
}
return rc;
}
static void __exit heartbeat_trig_exit(void)
{
- unregister_pm_notifier(&heartbeat_pm_nb);
unregister_reboot_notifier(&heartbeat_reboot_nb);
atomic_notifier_chain_unregister(&panic_notifier_list,
&heartbeat_panic_nb);
diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c
index f0bb0bc..3b07c47 100644
--- a/drivers/mailbox/msm_qmp.c
+++ b/drivers/mailbox/msm_qmp.c
@@ -27,7 +27,7 @@
#define QMP_VERSION 0x1
#define QMP_FEATURES 0x0
#define QMP_TOUT_MS 5000
-#define QMP_TX_TOUT_MS 2000
+#define QMP_TX_TOUT_MS 1000
#define QMP_MBOX_LINK_DOWN 0xFFFF0000
#define QMP_MBOX_LINK_UP 0x0000FFFF
@@ -229,7 +229,7 @@
}
/**
- * qmp_notify_timeout() - Notify client of tx timeout with -EIO
+ * qmp_notify_timeout() - Notify client of tx timeout with -ETIME
* @work: Structure for work that was scheduled.
*/
static void qmp_notify_timeout(struct work_struct *work)
@@ -237,7 +237,7 @@
struct delayed_work *dwork = to_delayed_work(work);
struct qmp_mbox *mbox = container_of(dwork, struct qmp_mbox, dwork);
struct mbox_chan *chan = &mbox->ctrl.chans[mbox->idx_in_flight];
- int err = -EIO;
+ int err = -ETIME;
unsigned long flags;
spin_lock_irqsave(&mbox->tx_lock, flags);
@@ -246,6 +246,7 @@
return;
}
pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight);
+ iowrite32(0, mbox->mdev->msgram + mbox->mcore_mbox_offset);
mbox->tx_sent = false;
spin_unlock_irqrestore(&mbox->tx_lock, flags);
mbox_chan_txdone(chan, err);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index bca4c0e..e289aae 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -848,8 +848,12 @@
tio = tio_from_request(rq);
/* Establish tio->ti before queuing work (map_tio_request) */
tio->ti = ti;
- kthread_queue_work(&md->kworker, &tio->work);
+ spin_unlock(q->queue_lock);
+ if (map_request(tio) == DM_MAPIO_REQUEUE)
+ dm_requeue_original_request(tio, false);
+
BUG_ON(!irqs_disabled());
+ spin_lock(q->queue_lock);
}
}
diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c
index a18fe5d..b4857cd 100644
--- a/drivers/media/pci/saa7164/saa7164-bus.c
+++ b/drivers/media/pci/saa7164/saa7164-bus.c
@@ -393,11 +393,11 @@
msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
+ memcpy(msg, &msg_tmp, sizeof(*msg));
/* No need to update the read positions, because this was a peek */
/* If the caller specifically want to peek, return */
if (peekonly) {
- memcpy(msg, &msg_tmp, sizeof(*msg));
goto peekout;
}
@@ -442,21 +442,15 @@
space_rem = bus->m_dwSizeGetRing - curr_grp;
if (space_rem < sizeof(*msg)) {
- /* msg wraps around the ring */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem);
- memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing,
- sizeof(*msg) - space_rem);
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
space_rem, buf_size);
} else if (space_rem == sizeof(*msg)) {
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
} else {
/* Additional data wraps around the ring */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf) {
memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
sizeof(*msg), space_rem - sizeof(*msg));
@@ -469,15 +463,10 @@
} else {
/* No wrapping */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
buf_size);
}
- /* Convert from little endian to CPU */
- msg->size = le16_to_cpu((__force __le16)msg->size);
- msg->command = le32_to_cpu((__force __le32)msg->command);
- msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
/* Update the read positions, adjusting the ring */
saa7164_writel(bus->m_dwGetReadPos, new_grp);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 6efb2f1..bdb7a0a 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1725,27 +1725,9 @@
switch (cmd) {
case VPFE_CMD_S_CCDC_RAW_PARAMS:
+ ret = -EINVAL;
v4l2_warn(&vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
- if (ccdc_dev->hw_ops.set_params) {
- ret = ccdc_dev->hw_ops.set_params(param);
- if (ret) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Error setting parameters in CCDC\n");
- goto unlock_out;
- }
- ret = vpfe_get_ccdc_image_format(vpfe_dev,
- &vpfe_dev->fmt);
- if (ret < 0) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Invalid image format at CCDC\n");
- goto unlock_out;
- }
- } else {
- ret = -EINVAL;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
- }
+ "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
break;
default:
ret = -ENOTTY;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 47e8d5f..400f53b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -39,6 +39,7 @@
#define SDE_MDP_HW_REV_300 SDE_MDP_REV(3, 0, 0) /* 8998 v1.0 */
#define SDE_MDP_HW_REV_301 SDE_MDP_REV(3, 0, 1) /* 8998 v1.1 */
#define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_MDP_HW_REV_410 SDE_MDP_REV(4, 1, 0) /* sdm670 v1.0 */
#define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4
#define SDE_MDP_VBIF_8_LEVEL_REMAPPER 8
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index a7717f2..03d4840 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -3080,7 +3080,9 @@
} else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
SDE_MDP_HW_REV_300) ||
IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
- SDE_MDP_HW_REV_400)) {
+ SDE_MDP_HW_REV_400) ||
+ IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
+ SDE_MDP_HW_REV_410)) {
mgr->ops_hw_init = sde_rotator_r3_init;
} else {
ret = -ENODEV;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 4ad960d8..a838128 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1478,7 +1478,7 @@
}
SDEROT_DBG(
- "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu wb:%d vid:%d cmd:%d\n",
+ "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu prefill:%llu wb:%d vid:%d cmd:%d\n",
ctx->session_id, cmd->sequence_id,
cmd->src_rect_x, cmd->src_rect_y,
cmd->src_rect_w, cmd->src_rect_h,
@@ -1490,7 +1490,7 @@
cmd->dst_pixfmt >> 0, cmd->dst_pixfmt >> 8,
cmd->dst_pixfmt >> 16, cmd->dst_pixfmt >> 24,
cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps,
- cmd->clkrate, cmd->data_bw,
+ cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
cmd->dst_writeback, cmd->video_mode, cmd_type);
SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id,
cmd->src_rect_x, cmd->src_rect_y,
@@ -1498,11 +1498,11 @@
cmd->src_pixfmt,
cmd->dst_rect_w, cmd->dst_rect_h,
cmd->dst_pixfmt,
+ cmd->fps, cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
(cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) |
(cmd->secure << 3) | (cmd->dst_writeback << 4) |
- (cmd->video_mode << 5),
- cmd->fps, cmd->clkrate, cmd->data_bw,
- cmd_type);
+ (cmd->video_mode << 5) |
+ (cmd_type << 24));
sde_rot_mgr_lock(rot_dev->mgr);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 1a9e84d..3d39fa2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1437,8 +1437,7 @@
wrptr = sde_hw_rotator_get_regdma_segment(ctx);
/* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
- if (!ctx->sbuf_mode &&
- (ctx->is_traffic_shaping || cfg->prefill_bw)) {
+ if (ctx->is_traffic_shaping || cfg->prefill_bw) {
u32 bw;
/*
@@ -2700,7 +2699,9 @@
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
/* features exposed via mdss h/w version */
- if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
+ if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400) ||
+ IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
+ SDE_MDP_HW_REV_410)) {
SDEROT_DBG("Supporting sys cache inline rotation\n");
set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index a11be2c..cf0413e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1420,6 +1420,9 @@
case HAL_FLIP_VERTICAL:
hfi->flip = HFI_FLIP_VERTICAL;
break;
+ case HAL_FLIP_BOTH:
+ hfi->flip = HFI_FLIP_HORIZONTAL | HFI_FLIP_VERTICAL;
+ break;
default:
dprintk(VIDC_ERR, "Invalid flip setting: %#x\n",
prop->flip);
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 9b23376..7688f89 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -603,22 +603,25 @@
__func__, mem->handle, mem->device_addr, mem->size,
mem->kvaddr, mem->buffer_type);
- if (mem->device_addr)
+ if (mem->device_addr) {
msm_ion_put_device_address(client, mem->handle, mem->flags,
&mem->mapping_info, mem->buffer_type);
+ mem->device_addr = 0x0;
+ }
- if (mem->kvaddr)
+ if (mem->kvaddr) {
ion_unmap_kernel(client->clnt, mem->handle);
+ mem->kvaddr = NULL;
+ }
if (mem->handle) {
trace_msm_smem_buffer_ion_op_start("FREE",
(u32)mem->buffer_type, -1, mem->size, -1,
mem->flags, -1);
ion_free(client->clnt, mem->handle);
+ mem->handle = NULL;
trace_msm_smem_buffer_ion_op_end("FREE", (u32)mem->buffer_type,
-1, mem->size, -1, mem->flags, -1);
- } else {
- dprintk(VIDC_ERR, "%s: invalid ion_handle\n", __func__);
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 56f9675..fa40091 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -448,14 +448,14 @@
static DEVICE_ATTR(thermal_level, 0644, show_thermal_level,
store_thermal_level);
-static ssize_t show_platform_version(struct device *dev,
+static ssize_t show_sku_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d",
- vidc_driver->platform_version);
+ vidc_driver->sku_version);
}
-static ssize_t store_platform_version(struct device *dev,
+static ssize_t store_sku_version(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -463,13 +463,13 @@
return count;
}
-static DEVICE_ATTR(platform_version, 0444, show_platform_version,
- store_platform_version);
+static DEVICE_ATTR(sku_version, 0444, show_sku_version,
+ store_sku_version);
static struct attribute *msm_vidc_core_attrs[] = {
&dev_attr_pwr_collapse_delay.attr,
&dev_attr_thermal_level.attr,
- &dev_attr_platform_version.attr,
+ &dev_attr_sku_version.attr,
NULL
};
@@ -487,8 +487,6 @@
static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
{
int rc = 0;
- void __iomem *base;
- struct resource *res;
struct msm_vidc_core *core;
struct device *dev;
int nr = BASE_DEVICE_NUMBER;
@@ -605,32 +603,7 @@
core->debugfs_root = msm_vidc_debugfs_init_core(
core, vidc_driver->debugfs_root);
- vidc_driver->platform_version = 0;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
- if (!res) {
- dprintk(VIDC_DBG, "failed to get efuse resource\n");
- } else {
- base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!base) {
- dprintk(VIDC_ERR,
- "failed efuse ioremap: res->start %#x, size %d\n",
- (u32)res->start, (u32)resource_size(res));
- } else {
- u32 efuse = 0;
- struct platform_version_table *pf_ver_tbl =
- core->resources.pf_ver_tbl;
-
- efuse = readl_relaxed(base);
- vidc_driver->platform_version =
- (efuse & pf_ver_tbl->version_mask) >>
- pf_ver_tbl->version_shift;
- dprintk(VIDC_DBG,
- "efuse 0x%x, platform version 0x%x\n",
- efuse, vidc_driver->platform_version);
-
- devm_iounmap(&pdev->dev, base);
- }
- }
+ vidc_driver->sku_version = core->resources.sku_version;
dprintk(VIDC_DBG, "populating sub devices\n");
/*
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index cb03576..286a67e 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -413,7 +413,16 @@
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
- .step = OPERATING_FRAME_RATE_STEP,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ .name = "Set Decoder Frame rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
@@ -528,7 +537,7 @@
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
- .get_frame_size = get_frame_size_compressed,
+ .get_frame_size = get_frame_size_compressed_full_yuv,
.type = OUTPUT_PORT,
.defer_outputs = false,
},
@@ -1127,11 +1136,27 @@
}
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
- dprintk(VIDC_DBG,
- "inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->clk_data.operating_rate >> 16,
- ctrl->val >> 16);
- inst->clk_data.operating_rate = ctrl->val;
+ if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+ ctrl->val != INT_MAX) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else if (ctrl->val == INT_MAX) {
+ dprintk(VIDC_DBG,
+ "inst(%pK) Request for turbo mode\n", inst);
+ inst->clk_data.turbo_mode = true;
+ } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+ dprintk(VIDC_ERR, "Failed to set operating rate\n");
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->clk_data.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->clk_data.operating_rate = ctrl->val;
+ inst->clk_data.turbo_mode = false;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
if (ctrl->val ==
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 0d8cb76..22c0df1 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -61,6 +61,14 @@
NULL
};
+static const char *const mpeg_video_flip[] = {
+ "No Flip",
+ "Horizontal Flip",
+ "Vertical Flip",
+ "Both",
+ NULL
+};
+
static const char *const h264_video_entropy_cabac_model[] = {
"Model 0",
"Model 1",
@@ -909,7 +917,16 @@
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
- .step = OPERATING_FRAME_RATE_STEP,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ .name = "Set Encoder Frame rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE,
@@ -1036,6 +1053,21 @@
.default_value = 0,
.step = 1,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ .name = "Flip",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH)
+ ),
+ .qmenu = mpeg_video_flip,
+ },
};
@@ -1112,6 +1144,13 @@
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
+ {
+ .name = "YCbCr Semiplanar 4:2:0 10bit",
+ .description = "Y/CbCr 4:2:0 10bit",
+ .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010,
+ .get_frame_size = get_frame_size_p010,
+ .type = OUTPUT_PORT,
+ },
};
static int msm_venc_set_csc(struct msm_vidc_inst *inst,
@@ -1420,11 +1459,27 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
{
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FLIP);
property_id = HAL_PARAM_VPE_ROTATION;
vpe_rotation.rotate = msm_comm_v4l2_to_hal(
V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
ctrl->val);
- vpe_rotation.flip = HAL_FLIP_NONE;
+ vpe_rotation.flip = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ temp_ctrl->val);
+ pdata = &vpe_rotation;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP:
+ {
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+ property_id = HAL_PARAM_VPE_ROTATION;
+ vpe_rotation.rotate = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+ temp_ctrl->val);
+ vpe_rotation.flip = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ ctrl->val);
pdata = &vpe_rotation;
break;
}
@@ -1464,13 +1519,14 @@
pdata = &multi_slice_control;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
- bool codec_avc =
+ bool codecs_supported =
+ inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC ||
inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 ||
inst->fmts[CAPTURE_PORT].fourcc ==
V4L2_PIX_FMT_H264_NO_SC;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
- if (codec_avc && temp_ctrl->val ==
+ if (codecs_supported && temp_ctrl->val ==
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
enable.enable = true;
@@ -1817,12 +1873,27 @@
}
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
- dprintk(VIDC_DBG,
- "inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->clk_data.operating_rate >> 16,
+ if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+ ctrl->val != INT_MAX) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else if (ctrl->val == INT_MAX) {
+ dprintk(VIDC_DBG, "inst(%pK) Request for turbo mode\n",
+ inst);
+ inst->clk_data.turbo_mode = true;
+ } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+ dprintk(VIDC_ERR, "Failed to set operating rate\n");
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->clk_data.operating_rate >> 16,
ctrl->val >> 16);
- inst->clk_data.operating_rate = ctrl->val;
-
+ inst->clk_data.operating_rate = ctrl->val;
+ inst->clk_data.turbo_mode = false;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 5149086..ae2a2c6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -179,6 +179,10 @@
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_bytes);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+ msm_vidc_ctrl_get_range(ctrl, &inst->capability.frame_rate);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
@@ -276,6 +280,7 @@
break;
case V4L2_PIX_FMT_NV12_TP10_UBWC:
color_format = COLOR_FMT_NV12_BPP10_UBWC;
+ break;
case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010:
color_format = COLOR_FMT_P010;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index d557959..c6d31f7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -553,7 +553,8 @@
static int msm_vidc_set_clocks(struct msm_vidc_core *core)
{
struct hfi_device *hdev;
- unsigned long freq = 0, rate = 0;
+ unsigned long freq_core_1 = 0, freq_core_2 = 0, rate = 0;
+ unsigned long freq_core_max = 0;
struct msm_vidc_inst *temp = NULL;
int rc = 0, i = 0;
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
@@ -568,14 +569,33 @@
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
- freq += temp->clk_data.curr_freq;
+
+ if (temp->clk_data.core_id == VIDC_CORE_ID_1)
+ freq_core_1 += temp->clk_data.min_freq;
+ else if (temp->clk_data.core_id == VIDC_CORE_ID_2)
+ freq_core_2 += temp->clk_data.min_freq;
+ else if (temp->clk_data.core_id == VIDC_CORE_ID_3) {
+ freq_core_1 += temp->clk_data.min_freq / 2;
+ freq_core_2 += temp->clk_data.min_freq / 2;
+ }
+
+ freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2);
+
+ if (temp->clk_data.turbo_mode) {
+ dprintk(VIDC_PROF,
+ "Found an instance with Turbo request\n");
+ freq_core_max = msm_vidc_max_freq(core);
+ break;
+ }
}
+
for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
rate = allowed_clks_tbl[i].clock_rate;
- if (rate >= freq)
+ if (rate >= freq_core_max)
break;
}
- core->min_freq = freq;
+
+ core->min_freq = freq_core_max;
core->curr_freq = rate;
mutex_unlock(&core->lock);
@@ -587,19 +607,22 @@
return rc;
}
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+ u32 operating_rate)
{
- struct v4l2_ctrl *ctrl = NULL;
struct msm_vidc_inst *temp;
struct msm_vidc_core *core;
unsigned long max_freq, freq_left, ops_left, load, cycles, freq = 0;
unsigned long mbs_per_second;
+ int rc = 0;
+ u32 curr_operating_rate = 0;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
return -EINVAL;
}
core = inst->core;
+ curr_operating_rate = inst->clk_data.operating_rate >> 16;
mutex_lock(&core->lock);
max_freq = msm_vidc_max_freq(core);
@@ -614,51 +637,35 @@
freq_left = max_freq - freq;
- list_for_each_entry(temp, &core->instances, list) {
-
- if (!temp ||
- temp->state < MSM_VIDC_START_DONE ||
- temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
- continue;
-
- mbs_per_second = msm_comm_get_inst_load_per_core(temp,
+ mbs_per_second = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
- cycles = temp->clk_data.entry->vpp_cycles;
- if (temp->session_type == MSM_VIDC_ENCODER)
- cycles = temp->flags & VIDC_LOW_POWER ?
- temp->clk_data.entry->low_power_cycles :
- cycles;
+ cycles = inst->clk_data.entry->vpp_cycles;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ cycles = inst->flags & VIDC_LOW_POWER ?
+ inst->clk_data.entry->low_power_cycles :
+ cycles;
- load = cycles * mbs_per_second;
+ load = cycles * mbs_per_second;
- ops_left = load ? (freq_left / load) : 0;
- /* Convert remaining operating rate to Q16 format */
- ops_left = ops_left << 16;
+ ops_left = load ? (freq_left / load) : 0;
- ctrl = v4l2_ctrl_find(&temp->ctrl_handler,
- V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE);
- if (ctrl) {
- dprintk(VIDC_DBG,
- "%s: Before Range = %lld --> %lld\n",
- ctrl->name, ctrl->minimum, ctrl->maximum);
- dprintk(VIDC_DBG,
- "%s: Before Def value = %lld Cur val = %d\n",
- ctrl->name, ctrl->default_value, ctrl->val);
- v4l2_ctrl_modify_range(ctrl, ctrl->minimum,
- ctrl->val + ops_left, ctrl->step,
- ctrl->default_value);
- dprintk(VIDC_DBG,
- "%s: Updated Range = %lld --> %lld\n",
- ctrl->name, ctrl->minimum, ctrl->maximum);
- dprintk(VIDC_DBG,
- "%s: Updated Def value = %lld Cur val = %d\n",
- ctrl->name, ctrl->default_value, ctrl->val);
- }
+ operating_rate = operating_rate >> 16;
+
+ if ((curr_operating_rate + ops_left) >= operating_rate) {
+ dprintk(VIDC_DBG,
+ "Requestd operating rate is valid %u\n",
+ operating_rate);
+ rc = 0;
+ } else {
+ dprintk(VIDC_DBG,
+ "Current load is high for requested settings. Cannot set operating rate to %u\n",
+ operating_rate);
+ rc = -EINVAL;
}
mutex_unlock(&core->lock);
- return 0;
+ return rc;
}
int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
@@ -980,8 +987,8 @@
return 0;
}
mbs_per_frame = msm_vidc_get_mbs_per_frame(inst);
- if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
- inst->prop.fps >= inst->core->resources.max_hq_fps) {
+ if (mbs_per_frame > inst->core->resources.max_hq_mbs_per_frame ||
+ inst->prop.fps > inst->core->resources.max_hq_fps) {
enable = true;
}
@@ -1025,17 +1032,21 @@
}
static u32 get_core_load(struct msm_vidc_core *core,
- u32 core_id, bool lp_mode)
+ u32 core_id, bool lp_mode, bool real_time)
{
struct msm_vidc_inst *inst = NULL;
u32 current_inst_mbs_per_sec = 0, load = 0;
+ bool real_time_mode = false;
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
u32 cycles, lp_cycles;
+ real_time_mode = inst->flags & VIDC_REALTIME ? true : false;
if (!(inst->clk_data.core_id & core_id))
continue;
+ if (real_time_mode != real_time)
+ continue;
if (inst->session_type == MSM_VIDC_DECODER) {
cycles = lp_cycles = inst->clk_data.entry->vpp_cycles;
} else if (inst->session_type == MSM_VIDC_ENCODER) {
@@ -1080,10 +1091,10 @@
max_freq = msm_vidc_max_freq(inst->core);
inst->clk_data.core_id = 0;
- core0_load = get_core_load(core, VIDC_CORE_ID_1, false);
- core1_load = get_core_load(core, VIDC_CORE_ID_2, false);
- core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true);
- core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true);
+ core0_load = get_core_load(core, VIDC_CORE_ID_1, false, true);
+ core1_load = get_core_load(core, VIDC_CORE_ID_2, false, true);
+ core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true, true);
+ core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true, true);
min_load = min(core0_load, core1_load);
min_core_id = core0_load < core1_load ?
@@ -1102,9 +1113,9 @@
current_inst_lp_load = msm_comm_get_inst_load(inst,
LOAD_CALC_NO_QUIRKS) * lp_cycles;
- dprintk(VIDC_DBG, "Core 0 Load = %d Core 1 Load = %d\n",
+ dprintk(VIDC_DBG, "Core 0 RT Load = %d Core 1 RT Load = %d\n",
core0_load, core1_load);
- dprintk(VIDC_DBG, "Core 0 LP Load = %d Core 1 LP Load = %d\n",
+ dprintk(VIDC_DBG, "Core 0 RT LP Load = %d Core 1 RT LP Load = %d\n",
core0_lp_load, core1_lp_load);
dprintk(VIDC_DBG, "Max Load = %lu\n", max_freq);
dprintk(VIDC_DBG, "Current Load = %d Current LP Load = %d\n",
@@ -1184,7 +1195,38 @@
rc = msm_comm_scale_clocks_and_bus(inst);
+ msm_print_core_status(core, VIDC_CORE_ID_1);
+ msm_print_core_status(core, VIDC_CORE_ID_2);
+
return rc;
}
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id)
+{
+ struct msm_vidc_inst *inst = NULL;
+ dprintk(VIDC_PROF, "Instances running on core %u", core_id);
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+
+ if ((inst->clk_data.core_id != core_id) &&
+ (inst->clk_data.core_id != VIDC_CORE_ID_3))
+ continue;
+
+ dprintk(VIDC_PROF,
+ "inst %pK (%4ux%4u) to (%4ux%4u) %3u %s %s %s %s %lu\n",
+ inst,
+ inst->prop.width[OUTPUT_PORT],
+ inst->prop.height[OUTPUT_PORT],
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ inst->prop.fps,
+ inst->session_type == MSM_VIDC_ENCODER ? "ENC" : "DEC",
+ inst->clk_data.work_mode == VIDC_WORK_MODE_1 ?
+ "WORK_MODE_1" : "WORK_MODE_2",
+ inst->flags & VIDC_LOW_POWER ? "LP" : "HQ",
+ inst->flags & VIDC_REALTIME ? "RealTime" : "NonRTime",
+ inst->clk_data.min_freq);
+ }
+ mutex_unlock(&core->lock);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 707f034..142d63f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -22,7 +22,8 @@
#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
void msm_clock_data_reset(struct msm_vidc_inst *inst);
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+ u32 operating_rate);
int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type);
int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
@@ -31,6 +32,7 @@
void msm_comm_free_freq_table(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst);
int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
u32 device_addr);
void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 6e29c53..2beb90c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -560,6 +560,19 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP:
+ switch (value) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE:
+ return HAL_FLIP_NONE;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI:
+ return HAL_FLIP_HORIZONTAL;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT:
+ return HAL_FLIP_VERTICAL;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH:
+ return HAL_FLIP_BOTH;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
switch (value) {
case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
@@ -1437,6 +1450,9 @@
V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
&inst->capability.bframe);
}
+ msm_vidc_comm_update_ctrl(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ &inst->capability.frame_rate);
}
static void handle_session_init_done(enum hal_command_response cmd, void *data)
@@ -2180,7 +2196,8 @@
"%s: Send sys error for inst %pK\n", __func__, inst);
change_inst_state(inst, MSM_VIDC_CORE_INVALID);
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- msm_comm_print_inst_info(inst);
+ if (!core->trigger_ssr)
+ msm_comm_print_inst_info(inst);
}
dprintk(VIDC_DBG, "Calling core_release\n");
rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
@@ -2272,6 +2289,8 @@
mutex_lock(&inst->bufq[port].lock);
found = false;
list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->state != VB2_BUF_STATE_ACTIVE)
+ continue;
if (msm_comm_compare_vb2_planes(inst, mbuf, vb)) {
found = true;
break;
@@ -4758,6 +4777,7 @@
mutex_lock(&inst->eosbufs.lock);
list_for_each_entry_safe(buf, next, &inst->eosbufs.list, list) {
list_del(&buf->list);
+ msm_comm_smem_free(inst, &buf->smem);
kfree(buf);
}
INIT_LIST_HEAD(&inst->eosbufs.list);
@@ -5305,8 +5325,7 @@
LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
if (inst->state == MSM_VIDC_OPEN_DONE) {
- max_load_adj = inst->core->resources.max_load +
- inst->capability.mbs_per_frame.max;
+ max_load_adj = inst->core->resources.max_load;
num_mbs_per_sec = msm_comm_get_load(inst->core,
MSM_VIDC_DECODER, quirks);
num_mbs_per_sec += msm_comm_get_load(inst->core,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index c1828b3..dbebe5d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -113,7 +113,6 @@
#define MSM_VIDC_ERROR(value) \
do { \
- dprintk(VIDC_DBG, "Fatal Level = %d\n", value);\
BUG_ON(value); \
} while (0)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index a0f7d2e..37645fe 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -195,12 +195,33 @@
int low_power_cycles;
};
+enum efuse_purpose {
+ SKU_VERSION = 0,
+};
+
+enum sku_version {
+ SKU_VERSION_0 = 0,
+ SKU_VERSION_1,
+ SKU_VERSION_2,
+};
+
+struct msm_vidc_efuse_data {
+ u32 start_address;
+ u32 size;
+ u32 mask;
+ u32 shift;
+ enum efuse_purpose purpose;
+};
+
struct msm_vidc_platform_data {
struct msm_vidc_common_data *common_data;
unsigned int common_data_length;
struct msm_vidc_codec_data *codec_data;
unsigned int codec_data_length;
struct msm_vidc_csc_coeff csc_data;
+ struct msm_vidc_efuse_data *efuse_data;
+ unsigned int efuse_data_length;
+ unsigned int sku_version;
};
struct msm_vidc_format {
@@ -218,7 +239,7 @@
int num_cores;
struct dentry *debugfs_root;
int thermal_level;
- u32 platform_version;
+ u32 sku_version;
};
struct msm_video_device {
@@ -286,6 +307,7 @@
u32 opb_fourcc;
enum hal_work_mode work_mode;
bool low_latency_mode;
+ bool turbo_mode;
};
struct profile_data {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 0fe09e2..a82b598 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -24,6 +24,7 @@
#include <linux/version.h>
#include <linux/io.h>
#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
#define CODEC_ENTRY(n, p, vsp, vpp, lp) \
@@ -35,6 +36,15 @@
.low_power_cycles = lp \
}
+#define EFUSE_ENTRY(sa, s, m, sh, p) \
+{ \
+ .start_address = sa, \
+ .size = s, \
+ .mask = m, \
+ .shift = sh, \
+ .purpose = p \
+}
+
static struct msm_vidc_codec_data default_codec_data[] = {
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 125, 675, 320),
@@ -44,7 +54,18 @@
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
- CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540),
+ CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200),
+};
+
+static struct msm_vidc_codec_data sdm670_codec_data[] = {
+ CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
@@ -98,7 +119,7 @@
},
{
.key = "qcom,max-hw-load",
- .value = 2563200,
+ .value = 3110400, /* 4096x2160@90 */
},
{
.key = "qcom,max-hq-mbs-per-frame",
@@ -130,6 +151,95 @@
},
};
+static struct msm_vidc_common_data sdm670_common_data_v0[] = {
+ {
+ .key = "qcom,never-unload-fw",
+ .value = 1,
+ },
+ {
+ .key = "qcom,sw-power-collapse",
+ .value = 1,
+ },
+ {
+ .key = "qcom,max-secure-instances",
+ .value = 5,
+ },
+ {
+ .key = "qcom,max-hw-load",
+ .value = 1944000,
+ },
+ {
+ .key = "qcom,max-hq-mbs-per-frame",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-hq-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,max-b-frame-size",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-b-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,power-collapse-delay",
+ .value = 500,
+ },
+ {
+ .key = "qcom,hw-resp-timeout",
+ .value = 250,
+ },
+};
+
+static struct msm_vidc_common_data sdm670_common_data_v1[] = {
+ {
+ .key = "qcom,never-unload-fw",
+ .value = 1,
+ },
+ {
+ .key = "qcom,sw-power-collapse",
+ .value = 1,
+ },
+ {
+ .key = "qcom,max-secure-instances",
+ .value = 5,
+ },
+ {
+ .key = "qcom,max-hw-load",
+ .value = 1216800,
+ },
+ {
+ .key = "qcom,max-hq-mbs-per-frame",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-hq-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,max-b-frame-size",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-b-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,power-collapse-delay",
+ .value = 500,
+ },
+ {
+ .key = "qcom,hw-resp-timeout",
+ .value = 250,
+ },
+};
+
+static struct msm_vidc_efuse_data sdm670_efuse_data[] = {
+ EFUSE_ENTRY(0x007801A0, 4, 0x00008000, 0x0f, SKU_VERSION),
+};
static struct msm_vidc_platform_data default_data = {
.codec_data = default_codec_data,
@@ -139,6 +249,9 @@
.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = NULL,
+ .efuse_data_length = 0,
+ .sku_version = 0,
};
static struct msm_vidc_platform_data sdm845_data = {
@@ -149,6 +262,22 @@
.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = NULL,
+ .efuse_data_length = 0,
+ .sku_version = 0,
+};
+
+static struct msm_vidc_platform_data sdm670_data = {
+ .codec_data = sdm670_codec_data,
+ .codec_data_length = ARRAY_SIZE(sdm670_codec_data),
+ .common_data = sdm670_common_data_v0,
+ .common_data_length = ARRAY_SIZE(sdm670_common_data_v0),
+ .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+ .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+ .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = sdm670_efuse_data,
+ .efuse_data_length = ARRAY_SIZE(sdm670_efuse_data),
+ .sku_version = 0,
};
static const struct of_device_id msm_vidc_dt_match[] = {
@@ -156,15 +285,62 @@
.compatible = "qcom,sdm845-vidc",
.data = &sdm845_data,
},
- {},
+ {
+ .compatible = "qcom,sdm670-vidc",
+ .data = &sdm670_data,
+ },
};
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+static int msm_vidc_read_efuse(
+ struct msm_vidc_platform_data *data, struct device *dev)
+{
+ void __iomem *base;
+ uint32_t i;
+ struct msm_vidc_efuse_data *efuse_data = data->efuse_data;
+ uint32_t efuse_data_count = data->efuse_data_length;
+
+ for (i = 0; i < efuse_data_count; i++) {
+
+ switch ((efuse_data[i]).purpose) {
+
+ case SKU_VERSION:
+ base = devm_ioremap(dev, (efuse_data[i]).start_address,
+ (efuse_data[i]).size);
+ if (!base) {
+ dprintk(VIDC_ERR,
+ "failed efuse ioremap: res->start %#x, size %d\n",
+ (efuse_data[i]).start_address,
+ (efuse_data[i]).size);
+ return -EINVAL;
+ } else {
+ u32 efuse = 0;
+
+ efuse = readl_relaxed(base);
+ data->sku_version =
+ (efuse & (efuse_data[i]).mask) >>
+ (efuse_data[i]).shift;
+ dprintk(VIDC_DBG,
+ "efuse 0x%x, platform version 0x%x\n",
+ efuse, data->sku_version);
+
+ devm_iounmap(dev, base);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
void *vidc_get_drv_data(struct device *dev)
{
struct msm_vidc_platform_data *driver_data = NULL;
const struct of_device_id *match;
+ int rc = 0;
if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) {
driver_data = &default_data;
@@ -176,6 +352,21 @@
if (match)
driver_data = (struct msm_vidc_platform_data *)match->data;
+ if (!of_find_property(dev->of_node, "sku-index", NULL) ||
+ !driver_data) {
+ goto exit;
+ } else if (!strcmp(match->compatible, "qcom,sdm670-vidc")) {
+ rc = msm_vidc_read_efuse(driver_data, dev);
+ if (rc)
+ goto exit;
+
+ if (driver_data->sku_version == SKU_VERSION_1) {
+ driver_data->common_data = sdm670_common_data_v1;
+ driver_data->common_data_length =
+ ARRAY_SIZE(sdm670_common_data_v1);
+ }
+ }
+
exit:
return driver_data;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index f343939..a0214a2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -73,12 +73,6 @@
res->clock_freq_tbl.clk_prof_entries = NULL;
}
-static inline void msm_vidc_free_platform_version_table(
- struct msm_vidc_platform_resources *res)
-{
- res->pf_ver_tbl = NULL;
-}
-
static inline void msm_vidc_free_reg_table(
struct msm_vidc_platform_resources *res)
{
@@ -133,7 +127,6 @@
{
msm_vidc_free_clock_table(res);
msm_vidc_free_regulator_table(res);
- msm_vidc_free_platform_version_table(res);
msm_vidc_free_allowed_clocks_table(res);
msm_vidc_free_reg_table(res);
msm_vidc_free_qdss_addr_table(res);
@@ -344,33 +337,6 @@
}
EXPORT_SYMBOL(msm_vidc_load_u32_table);
-static int msm_vidc_load_platform_version_table(
- struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- struct platform_device *pdev = res->pdev;
-
- if (!of_find_property(pdev->dev.of_node,
- "qcom,platform-version", NULL)) {
- dprintk(VIDC_DBG, "qcom,platform-version not found\n");
- return 0;
- }
-
- rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
- "qcom,platform-version",
- sizeof(*res->pf_ver_tbl),
- (u32 **)&res->pf_ver_tbl,
- NULL);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s: failed to read platform version table\n",
- __func__);
- return rc;
- }
-
- return 0;
-}
-
/* A comparator to compare loads (needed later on) */
static int cmp(const void *a, const void *b)
{
@@ -712,6 +678,29 @@
return rc;
}
+static int msm_decide_dt_node(
+ struct msm_vidc_platform_resources *res) {
+ struct platform_device *pdev = res->pdev;
+ int rc = 0;
+ u32 sku_index = 0;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "sku-index",
+ &sku_index);
+ if (rc) {
+ dprintk(VIDC_DBG, "'sku_index' not found in node\n");
+ return 0;
+ }
+
+ if (sku_index != res->sku_version) {
+ dprintk(VIDC_DBG,
+ "Failed to parser dt: sku_index %d res->sku_version - %d\n",
+ sku_index, res->sku_version);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int find_key_value(struct msm_vidc_platform_data *platform_data,
const char *key)
{
@@ -743,6 +732,8 @@
res->codec_data_count = platform_data->codec_data_length;
res->codec_data = platform_data->codec_data;
+ res->sku_version = platform_data->sku_version;
+
res->fw_name = "venus";
dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
@@ -805,6 +796,11 @@
return -ENOENT;
}
+ rc = msm_decide_dt_node(res);
+ if (rc)
+ return rc;
+
+
INIT_LIST_HEAD(&res->context_banks);
res->firmware_base = (phys_addr_t)firmware_base;
@@ -816,10 +812,6 @@
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res->irq = kres ? kres->start : -1;
- rc = msm_vidc_load_platform_version_table(res);
- if (rc)
- dprintk(VIDC_ERR, "Failed to load pf version table: %d\n", rc);
-
rc = msm_vidc_load_subcache_info(res);
if (rc)
dprintk(VIDC_WARN, "Failed to load subcache info: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8309fce..99b4e30 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -21,11 +21,6 @@
#define MAX_BUFFER_TYPES 32
-struct platform_version_table {
- u32 version_mask;
- u32 version_shift;
-};
-
struct dcvs_table {
u32 load;
u32 load_low;
@@ -153,7 +148,7 @@
phys_addr_t register_base;
uint32_t register_size;
uint32_t irq;
- struct platform_version_table *pf_ver_tbl;
+ uint32_t sku_version;
struct allowed_clock_rates_table *allowed_clks_tbl;
u32 allowed_clks_tbl_size;
struct clock_freq_table clock_freq_tbl;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index dde6029..0fbc96e 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -4282,10 +4282,65 @@
return rc;
}
+static void __noc_error_info(struct venus_hfi_device *device, u32 core_num)
+{
+ u32 vcodec_core_video_noc_base_offs, val;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: null device\n", __func__);
+ return;
+ }
+ if (!core_num) {
+ vcodec_core_video_noc_base_offs =
+ VCODEC_CORE0_VIDEO_NOC_BASE_OFFS;
+ } else if (core_num == 1) {
+ vcodec_core_video_noc_base_offs =
+ VCODEC_CORE1_VIDEO_NOC_BASE_OFFS;
+ } else {
+ dprintk(VIDC_ERR, "%s: invalid core_num %u\n",
+ __func__, core_num);
+ return;
+ }
+
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_SWID_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_SWID_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_SWID_HIGH_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_SWID_HIGH: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_MAINCTL_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_MAINCTL_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG0_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_HIGH_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG0_HIGH: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG1_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_HIGH_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG1_HIGH: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG2_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_HIGH_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG2_HIGH: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_LOW_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG3_LOW: %#x\n", core_num, val);
+ val = __read_register(device, vcodec_core_video_noc_base_offs +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_HIGH_OFFS);
+ dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG3_HIGH: %#x\n", core_num, val);
+}
+
static int venus_hfi_noc_error_info(void *dev)
{
struct venus_hfi_device *device;
- u32 val = 0;
+ const u32 core0 = 0, core1 = 1;
if (!dev) {
dprintk(VIDC_ERR, "%s: null device\n", __func__);
@@ -4296,44 +4351,13 @@
mutex_lock(&device->lock);
dprintk(VIDC_ERR, "%s: non error information\n", __func__);
- val = __read_register(device, 0x0C500);
- dprintk(VIDC_ERR, "NOC_ERR_SWID_LOW(0x00AA0C500): %#x\n", val);
+ if (__read_register(device, VCODEC_CORE0_VIDEO_NOC_BASE_OFFS +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS))
+ __noc_error_info(device, core0);
- val = __read_register(device, 0x0C504);
- dprintk(VIDC_ERR, "NOC_ERR_SWID_HIGH(0x00AA0C504): %#x\n", val);
-
- val = __read_register(device, 0x0C508);
- dprintk(VIDC_ERR, "NOC_ERR_MAINCTL_LOW(0x00AA0C508): %#x\n", val);
-
- val = __read_register(device, 0x0C510);
- dprintk(VIDC_ERR, "NOC_ERR_ERRVLD_LOW(0x00AA0C510): %#x\n", val);
-
- val = __read_register(device, 0x0C518);
- dprintk(VIDC_ERR, "NOC_ERR_ERRCLR_LOW(0x00AA0C518): %#x\n", val);
-
- val = __read_register(device, 0x0C520);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_LOW(0x00AA0C520): %#x\n", val);
-
- val = __read_register(device, 0x0C524);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_HIGH(0x00AA0C524): %#x\n", val);
-
- val = __read_register(device, 0x0C528);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_LOW(0x00AA0C528): %#x\n", val);
-
- val = __read_register(device, 0x0C52C);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_HIGH(0x00AA0C52C): %#x\n", val);
-
- val = __read_register(device, 0x0C530);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_LOW(0x00AA0C530): %#x\n", val);
-
- val = __read_register(device, 0x0C534);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_HIGH(0x00AA0C534): %#x\n", val);
-
- val = __read_register(device, 0x0C538);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_LOW(0x00AA0C538): %#x\n", val);
-
- val = __read_register(device, 0x0C53C);
- dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_HIGH(0x00AA0C53C): %#x\n", val);
+ if (__read_register(device, VCODEC_CORE1_VIDEO_NOC_BASE_OFFS +
+ VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS))
+ __noc_error_info(device, core1);
mutex_unlock(&device->lock);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 738828d..53df90f5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -660,6 +660,7 @@
HAL_FLIP_NONE,
HAL_FLIP_HORIZONTAL,
HAL_FLIP_VERTICAL,
+ HAL_FLIP_BOTH,
HAL_UNUSED_FLIP = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index fc32d73..3433483 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -190,4 +190,25 @@
#define VIDC_UC_REGION_ADDR 0x000D2064
#define VIDC_UC_REGION_SIZE 0x000D2068
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: vcodec noc error log registers
+ * --------------------------------------------------------------------------
+ */
+#define VCODEC_CORE0_VIDEO_NOC_BASE_OFFS 0x00004000
+#define VCODEC_CORE1_VIDEO_NOC_BASE_OFFS 0x0000C000
+#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_LOW_OFFS 0x0500
+#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_HIGH_OFFS 0x0504
+#define VCODEC_COREX_VIDEO_NOC_ERR_MAINCTL_LOW_OFFS 0x0508
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS 0x0510
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRCLR_LOW_OFFS 0x0518
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_LOW_OFFS 0x0520
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_HIGH_OFFS 0x0524
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_LOW_OFFS 0x0528
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_HIGH_OFFS 0x052C
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_LOW_OFFS 0x0530
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_HIGH_OFFS 0x0534
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_LOW_OFFS 0x0538
+#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_HIGH_OFFS 0x053C
+
#endif
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index c3277308..b49f80c 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -254,7 +254,7 @@
return 0;
case LIRC_GET_REC_RESOLUTION:
- val = dev->rx_resolution;
+ val = dev->rx_resolution / 1000;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cada3c1..e3f4c39 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -791,6 +791,13 @@
Per UID based io statistics exported to /proc/uid_io
Per UID based procstat control in /proc/uid_procstat
+config UID_SYS_STATS_DEBUG
+ bool "Per-TASK statistics"
+ depends on UID_SYS_STATS
+ default n
+ help
+ Per TASK based io statistics exported to /proc/uid_io
+
config MEMORY_STATE_TIME
tristate "Memory freq/bandwidth time statistics"
depends on PROFILING
diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c
index 3c11de0..690b28b 100644
--- a/drivers/misc/qpnp-misc.c
+++ b/drivers/misc/qpnp-misc.c
@@ -135,7 +135,7 @@
struct qpnp_misc_dev *mdev = NULL;
struct qpnp_misc_dev *mdev_found = NULL;
int rc;
- u8 temp;
+ u8 temp = 0;
if (IS_ERR_OR_NULL(node)) {
pr_err("Invalid device node pointer\n");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 7077b30..7567f86 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -3126,6 +3126,7 @@
struct qseecom_send_cmd_req *req)
{
int ret = 0;
+ int ret2 = 0;
u32 reqd_len_sb_in = 0;
struct qseecom_client_send_data_ireq send_data_req = {0};
struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
@@ -3224,32 +3225,38 @@
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
- return ret;
+ goto exit;
}
if (qseecom.qsee_reentrancy_support) {
ret = __qseecom_process_reentrancy(&resp, ptr_app, data);
+ if (ret)
+ goto exit;
} else {
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
pr_err("process_incomplete_cmd failed err: %d\n",
ret);
- return ret;
+ goto exit;
}
} else {
if (resp.result != QSEOS_RESULT_SUCCESS) {
pr_err("Response result %d not supported\n",
resp.result);
ret = -EINVAL;
+ goto exit;
}
}
}
- ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+exit:
+ ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_INV_CACHES);
- if (ret)
- pr_err("cache operation failed %d\n", ret);
+ if (ret2) {
+ pr_err("cache operation failed %d\n", ret2);
+ return ret2;
+ }
return ret;
}
@@ -6575,6 +6582,7 @@
bool found_app = false;
unsigned long flags;
int ret = 0;
+ int ret2 = 0;
uint32_t reqd_len_sb_in = 0;
void *cmd_buf = NULL;
size_t cmd_len;
@@ -6684,43 +6692,47 @@
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
- return ret;
+ goto exit;
}
if (qseecom.qsee_reentrancy_support) {
ret = __qseecom_process_reentrancy(&resp, ptr_app, data);
+ if (ret)
+ goto exit;
} else {
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
pr_err("process_incomplete_cmd failed err: %d\n",
ret);
- return ret;
+ goto exit;
}
} else {
if (resp.result != QSEOS_RESULT_SUCCESS) {
pr_err("Response result %d not supported\n",
resp.result);
ret = -EINVAL;
+ goto exit;
}
}
}
- ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+exit:
+ ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_INV_CACHES);
- if (ret) {
+ if (ret2) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ return ret2;
}
if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
(cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
- ret = __qseecom_update_qteec_req_buf(
+ ret2 = __qseecom_update_qteec_req_buf(
(struct qseecom_qteec_modfd_req *)req, data, true);
- if (ret)
- return ret;
+ if (ret2)
+ return ret2;
}
- return 0;
+ return ret;
}
static int qseecom_qteec_open_session(struct qseecom_dev_handle *data,
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 8bf4c57..7d69dd5 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/profile.h>
#include <linux/rtmutex.h>
@@ -53,6 +54,15 @@
#define UID_STATE_DEAD_TASKS 4
#define UID_STATE_SIZE 5
+#define MAX_TASK_COMM_LEN 256
+
+struct task_entry {
+ char comm[MAX_TASK_COMM_LEN];
+ pid_t pid;
+ struct io_stats io[UID_STATE_SIZE];
+ struct hlist_node hash;
+};
+
struct uid_entry {
uid_t uid;
cputime_t utime;
@@ -62,8 +72,231 @@
int state;
struct io_stats io[UID_STATE_SIZE];
struct hlist_node hash;
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+ DECLARE_HASHTABLE(task_entries, UID_HASH_BITS);
+#endif
};
+static u64 compute_write_bytes(struct task_struct *task)
+{
+ if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
+ return 0;
+
+ return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
+}
+
+static void compute_io_bucket_stats(struct io_stats *io_bucket,
+ struct io_stats *io_curr,
+ struct io_stats *io_last,
+ struct io_stats *io_dead)
+{
+ /* tasks could switch to another uid group, but its io_last in the
+ * previous uid group could still be positive.
+ * therefore before each update, do an overflow check first
+ */
+ int64_t delta;
+
+ delta = io_curr->read_bytes + io_dead->read_bytes -
+ io_last->read_bytes;
+ io_bucket->read_bytes += delta > 0 ? delta : 0;
+ delta = io_curr->write_bytes + io_dead->write_bytes -
+ io_last->write_bytes;
+ io_bucket->write_bytes += delta > 0 ? delta : 0;
+ delta = io_curr->rchar + io_dead->rchar - io_last->rchar;
+ io_bucket->rchar += delta > 0 ? delta : 0;
+ delta = io_curr->wchar + io_dead->wchar - io_last->wchar;
+ io_bucket->wchar += delta > 0 ? delta : 0;
+ delta = io_curr->fsync + io_dead->fsync - io_last->fsync;
+ io_bucket->fsync += delta > 0 ? delta : 0;
+
+ io_last->read_bytes = io_curr->read_bytes;
+ io_last->write_bytes = io_curr->write_bytes;
+ io_last->rchar = io_curr->rchar;
+ io_last->wchar = io_curr->wchar;
+ io_last->fsync = io_curr->fsync;
+
+ memset(io_dead, 0, sizeof(struct io_stats));
+}
+
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+static void get_full_task_comm(struct task_entry *task_entry,
+ struct task_struct *task)
+{
+ int i = 0, offset = 0, len = 0;
+ /* save one byte for terminating null character */
+ int unused_len = MAX_TASK_COMM_LEN - TASK_COMM_LEN - 1;
+ char buf[unused_len];
+ struct mm_struct *mm = task->mm;
+
+ /* fill the first TASK_COMM_LEN bytes with thread name */
+ get_task_comm(task_entry->comm, task);
+ i = strlen(task_entry->comm);
+ while (i < TASK_COMM_LEN)
+ task_entry->comm[i++] = ' ';
+
+ /* next the executable file name */
+ if (mm) {
+ down_read(&mm->mmap_sem);
+ if (mm->exe_file) {
+ char *pathname = d_path(&mm->exe_file->f_path, buf,
+ unused_len);
+
+ if (!IS_ERR(pathname)) {
+ len = strlcpy(task_entry->comm + i, pathname,
+ unused_len);
+ i += len;
+ task_entry->comm[i++] = ' ';
+ unused_len--;
+ }
+ }
+ up_read(&mm->mmap_sem);
+ }
+ unused_len -= len;
+
+ /* fill the rest with command line argument
+ * replace each null or new line character
+ * between args in argv with whitespace */
+ len = get_cmdline(task, buf, unused_len);
+ while (offset < len) {
+ if (buf[offset] != '\0' && buf[offset] != '\n')
+ task_entry->comm[i++] = buf[offset];
+ else
+ task_entry->comm[i++] = ' ';
+ offset++;
+ }
+
+ /* get rid of trailing whitespaces in case when arg is memset to
+ * zero before being reset in userspace
+ */
+ while (task_entry->comm[i-1] == ' ')
+ i--;
+ task_entry->comm[i] = '\0';
+}
+
+static struct task_entry *find_task_entry(struct uid_entry *uid_entry,
+ struct task_struct *task)
+{
+ struct task_entry *task_entry;
+
+ hash_for_each_possible(uid_entry->task_entries, task_entry, hash,
+ task->pid) {
+ if (task->pid == task_entry->pid) {
+ /* if thread name changed, update the entire command */
+ int len = strnchr(task_entry->comm, ' ', TASK_COMM_LEN)
+ - task_entry->comm;
+
+ if (strncmp(task_entry->comm, task->comm, len))
+ get_full_task_comm(task_entry, task);
+ return task_entry;
+ }
+ }
+ return NULL;
+}
+
+static struct task_entry *find_or_register_task(struct uid_entry *uid_entry,
+ struct task_struct *task)
+{
+ struct task_entry *task_entry;
+ pid_t pid = task->pid;
+
+ task_entry = find_task_entry(uid_entry, task);
+ if (task_entry)
+ return task_entry;
+
+ task_entry = kzalloc(sizeof(struct task_entry), GFP_ATOMIC);
+ if (!task_entry)
+ return NULL;
+
+ get_full_task_comm(task_entry, task);
+
+ task_entry->pid = pid;
+ hash_add(uid_entry->task_entries, &task_entry->hash, (unsigned int)pid);
+
+ return task_entry;
+}
+
+static void remove_uid_tasks(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+ struct hlist_node *tmp_task;
+
+ hash_for_each_safe(uid_entry->task_entries, bkt_task,
+ tmp_task, task_entry, hash) {
+ hash_del(&task_entry->hash);
+ kfree(task_entry);
+ }
+}
+
+static void set_io_uid_tasks_zero(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ memset(&task_entry->io[UID_STATE_TOTAL_CURR], 0,
+ sizeof(struct io_stats));
+ }
+}
+
+static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
+ struct task_struct *task, int slot)
+{
+ struct task_entry *task_entry = find_or_register_task(uid_entry, task);
+ struct io_stats *task_io_slot = &task_entry->io[slot];
+
+ task_io_slot->read_bytes += task->ioac.read_bytes;
+ task_io_slot->write_bytes += compute_write_bytes(task);
+ task_io_slot->rchar += task->ioac.rchar;
+ task_io_slot->wchar += task->ioac.wchar;
+ task_io_slot->fsync += task->ioac.syscfs;
+}
+
+static void compute_io_uid_tasks(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ compute_io_bucket_stats(&task_entry->io[uid_entry->state],
+ &task_entry->io[UID_STATE_TOTAL_CURR],
+ &task_entry->io[UID_STATE_TOTAL_LAST],
+ &task_entry->io[UID_STATE_DEAD_TASKS]);
+ }
+}
+
+static void show_io_uid_tasks(struct seq_file *m, struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ /* Separated by comma because space exists in task comm */
+ seq_printf(m, "task,%s,%lu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
+ task_entry->comm,
+ (unsigned long)task_entry->pid,
+ task_entry->io[UID_STATE_FOREGROUND].rchar,
+ task_entry->io[UID_STATE_FOREGROUND].wchar,
+ task_entry->io[UID_STATE_FOREGROUND].read_bytes,
+ task_entry->io[UID_STATE_FOREGROUND].write_bytes,
+ task_entry->io[UID_STATE_BACKGROUND].rchar,
+ task_entry->io[UID_STATE_BACKGROUND].wchar,
+ task_entry->io[UID_STATE_BACKGROUND].read_bytes,
+ task_entry->io[UID_STATE_BACKGROUND].write_bytes,
+ task_entry->io[UID_STATE_FOREGROUND].fsync,
+ task_entry->io[UID_STATE_BACKGROUND].fsync);
+ }
+}
+#else
+static void remove_uid_tasks(struct uid_entry *uid_entry) {};
+static void set_io_uid_tasks_zero(struct uid_entry *uid_entry) {};
+static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
+ struct task_struct *task, int slot) {};
+static void compute_io_uid_tasks(struct uid_entry *uid_entry) {};
+static void show_io_uid_tasks(struct seq_file *m,
+ struct uid_entry *uid_entry) {}
+#endif
+
static struct uid_entry *find_uid_entry(uid_t uid)
{
struct uid_entry *uid_entry;
@@ -87,7 +320,9 @@
return NULL;
uid_entry->uid = uid;
-
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+ hash_init(uid_entry->task_entries);
+#endif
hash_add(hash_table, &uid_entry->hash, uid);
return uid_entry;
@@ -193,6 +428,7 @@
hash_for_each_possible_safe(hash_table, uid_entry, tmp,
hash, (uid_t)uid_start) {
if (uid_start == uid_entry->uid) {
+ remove_uid_tasks(uid_entry);
hash_del(&uid_entry->hash);
kfree(uid_entry);
}
@@ -209,13 +445,6 @@
.write = uid_remove_write,
};
-static u64 compute_write_bytes(struct task_struct *task)
-{
- if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
- return 0;
-
- return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
-}
static void add_uid_io_stats(struct uid_entry *uid_entry,
struct task_struct *task, int slot)
@@ -227,28 +456,8 @@
io_slot->rchar += task->ioac.rchar;
io_slot->wchar += task->ioac.wchar;
io_slot->fsync += task->ioac.syscfs;
-}
-static void compute_uid_io_bucket_stats(struct io_stats *io_bucket,
- struct io_stats *io_curr,
- struct io_stats *io_last,
- struct io_stats *io_dead)
-{
- io_bucket->read_bytes += io_curr->read_bytes + io_dead->read_bytes -
- io_last->read_bytes;
- io_bucket->write_bytes += io_curr->write_bytes + io_dead->write_bytes -
- io_last->write_bytes;
- io_bucket->rchar += io_curr->rchar + io_dead->rchar - io_last->rchar;
- io_bucket->wchar += io_curr->wchar + io_dead->wchar - io_last->wchar;
- io_bucket->fsync += io_curr->fsync + io_dead->fsync - io_last->fsync;
-
- io_last->read_bytes = io_curr->read_bytes;
- io_last->write_bytes = io_curr->write_bytes;
- io_last->rchar = io_curr->rchar;
- io_last->wchar = io_curr->wchar;
- io_last->fsync = io_curr->fsync;
-
- memset(io_dead, 0, sizeof(struct io_stats));
+ add_uid_tasks_io_stats(uid_entry, task, slot);
}
static void update_io_stats_all_locked(void)
@@ -259,9 +468,11 @@
unsigned long bkt;
uid_t uid;
- hash_for_each(hash_table, bkt, uid_entry, hash)
+ hash_for_each(hash_table, bkt, uid_entry, hash) {
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
sizeof(struct io_stats));
+ set_io_uid_tasks_zero(uid_entry);
+ }
rcu_read_lock();
do_each_thread(temp, task) {
@@ -275,10 +486,11 @@
rcu_read_unlock();
hash_for_each(hash_table, bkt, uid_entry, hash) {
- compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
+ compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
&uid_entry->io[UID_STATE_TOTAL_CURR],
&uid_entry->io[UID_STATE_TOTAL_LAST],
&uid_entry->io[UID_STATE_DEAD_TASKS]);
+ compute_io_uid_tasks(uid_entry);
}
}
@@ -289,6 +501,7 @@
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
sizeof(struct io_stats));
+ set_io_uid_tasks_zero(uid_entry);
rcu_read_lock();
do_each_thread(temp, task) {
@@ -298,12 +511,14 @@
} while_each_thread(temp, task);
rcu_read_unlock();
- compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
+ compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
&uid_entry->io[UID_STATE_TOTAL_CURR],
&uid_entry->io[UID_STATE_TOTAL_LAST],
&uid_entry->io[UID_STATE_DEAD_TASKS]);
+ compute_io_uid_tasks(uid_entry);
}
+
static int uid_io_show(struct seq_file *m, void *v)
{
struct uid_entry *uid_entry;
@@ -315,21 +530,22 @@
hash_for_each(hash_table, bkt, uid_entry, hash) {
seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
- uid_entry->uid,
- uid_entry->io[UID_STATE_FOREGROUND].rchar,
- uid_entry->io[UID_STATE_FOREGROUND].wchar,
- uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
- uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
- uid_entry->io[UID_STATE_BACKGROUND].rchar,
- uid_entry->io[UID_STATE_BACKGROUND].wchar,
- uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
- uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
- uid_entry->io[UID_STATE_FOREGROUND].fsync,
- uid_entry->io[UID_STATE_BACKGROUND].fsync);
+ uid_entry->uid,
+ uid_entry->io[UID_STATE_FOREGROUND].rchar,
+ uid_entry->io[UID_STATE_FOREGROUND].wchar,
+ uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
+ uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
+ uid_entry->io[UID_STATE_BACKGROUND].rchar,
+ uid_entry->io[UID_STATE_BACKGROUND].wchar,
+ uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
+ uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
+ uid_entry->io[UID_STATE_FOREGROUND].fsync,
+ uid_entry->io[UID_STATE_BACKGROUND].fsync);
+
+ show_io_uid_tasks(m, uid_entry);
}
rt_mutex_unlock(&uid_lock);
-
return 0;
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 978dd9a..727b301 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3407,6 +3407,13 @@
pm_wakeup_event(mmc_dev(host), 5000);
host->detect_change = 1;
+ /*
+ * Change in cd_gpio state, so make sure detection part is
+ * not overided because of manual resume.
+ */
+ if (cd_irq && mmc_bus_manual_resume(host))
+ host->ignore_bus_resume_flags = true;
+
mmc_schedule_delayed_work(&host->detect, delay);
}
@@ -4387,6 +4394,8 @@
host->bus_ops->detect(host);
host->detect_change = 0;
+ if (host->ignore_bus_resume_flags)
+ host->ignore_bus_resume_flags = false;
/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
@@ -4643,7 +4652,8 @@
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
- if (mmc_bus_manual_resume(host)) {
+ if (mmc_bus_manual_resume(host) &&
+ !host->ignore_bus_resume_flags) {
spin_unlock_irqrestore(&host->lock, flags);
break;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 127ab0f..64c8743 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -482,19 +482,17 @@
*/
int mmc_of_parse(struct mmc_host *host)
{
- struct device_node *np;
+ struct device *dev = host->parent;
u32 bus_width;
int ret;
bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false;
- if (!host->parent || !host->parent->of_node)
+ if (!dev || !dev_fwnode(dev))
return 0;
- np = host->parent->of_node;
-
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
- if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
+ if (device_property_read_u32(dev, "bus-width", &bus_width) < 0) {
dev_dbg(host->parent,
"\"bus-width\" property is missing, assuming 1 bit.\n");
bus_width = 1;
@@ -516,7 +514,7 @@
}
/* f_max is obtained from the optional "max-frequency" property */
- of_property_read_u32(np, "max-frequency", &host->f_max);
+ device_property_read_u32(dev, "max-frequency", &host->f_max);
/*
* Configure CD and WP pins. They are both by default active low to
@@ -531,12 +529,12 @@
*/
/* Parse Card Detection */
- if (of_property_read_bool(np, "non-removable")) {
+ if (device_property_read_bool(dev, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else {
- cd_cap_invert = of_property_read_bool(np, "cd-inverted");
+ cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
- if (of_property_read_bool(np, "broken-cd"))
+ if (device_property_read_bool(dev, "broken-cd"))
host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
@@ -562,7 +560,7 @@
}
/* Parse Write Protection */
- ro_cap_invert = of_property_read_bool(np, "wp-inverted");
+ ro_cap_invert = device_property_read_bool(dev, "wp-inverted");
ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
if (!ret)
@@ -570,62 +568,62 @@
else if (ret != -ENOENT && ret != -ENOSYS)
return ret;
- if (of_property_read_bool(np, "disable-wp"))
+ if (device_property_read_bool(dev, "disable-wp"))
host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
/* See the comment on CD inversion above */
if (ro_cap_invert ^ ro_gpio_invert)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
- if (of_property_read_bool(np, "cap-sd-highspeed"))
+ if (device_property_read_bool(dev, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED;
- if (of_property_read_bool(np, "cap-mmc-highspeed"))
+ if (device_property_read_bool(dev, "cap-mmc-highspeed"))
host->caps |= MMC_CAP_MMC_HIGHSPEED;
- if (of_property_read_bool(np, "sd-uhs-sdr12"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr12"))
host->caps |= MMC_CAP_UHS_SDR12;
- if (of_property_read_bool(np, "sd-uhs-sdr25"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr25"))
host->caps |= MMC_CAP_UHS_SDR25;
- if (of_property_read_bool(np, "sd-uhs-sdr50"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr50"))
host->caps |= MMC_CAP_UHS_SDR50;
- if (of_property_read_bool(np, "sd-uhs-sdr104"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr104"))
host->caps |= MMC_CAP_UHS_SDR104;
- if (of_property_read_bool(np, "sd-uhs-ddr50"))
+ if (device_property_read_bool(dev, "sd-uhs-ddr50"))
host->caps |= MMC_CAP_UHS_DDR50;
- if (of_property_read_bool(np, "cap-power-off-card"))
+ if (device_property_read_bool(dev, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD;
- if (of_property_read_bool(np, "cap-mmc-hw-reset"))
+ if (device_property_read_bool(dev, "cap-mmc-hw-reset"))
host->caps |= MMC_CAP_HW_RESET;
- if (of_property_read_bool(np, "cap-sdio-irq"))
+ if (device_property_read_bool(dev, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ;
- if (of_property_read_bool(np, "full-pwr-cycle"))
+ if (device_property_read_bool(dev, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
- if (of_property_read_bool(np, "keep-power-in-suspend"))
+ if (device_property_read_bool(dev, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER;
- if (of_property_read_bool(np, "wakeup-source") ||
- of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
+ if (device_property_read_bool(dev, "wakeup-source") ||
+ device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
- if (of_property_read_bool(np, "mmc-ddr-1_8v"))
+ if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR;
- if (of_property_read_bool(np, "mmc-ddr-1_2v"))
+ if (device_property_read_bool(dev, "mmc-ddr-1_2v"))
host->caps |= MMC_CAP_1_2V_DDR;
- if (of_property_read_bool(np, "mmc-hs200-1_8v"))
+ if (device_property_read_bool(dev, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
- if (of_property_read_bool(np, "mmc-hs200-1_2v"))
+ if (device_property_read_bool(dev, "mmc-hs200-1_2v"))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-1_8v"))
+ if (device_property_read_bool(dev, "mmc-hs400-1_8v"))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-1_2v"))
+ if (device_property_read_bool(dev, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+ if (device_property_read_bool(dev, "mmc-hs400-enhanced-strobe"))
host->caps2 |= MMC_CAP2_HS400_ES;
- if (of_property_read_bool(np, "no-sdio"))
+ if (device_property_read_bool(dev, "no-sdio"))
host->caps2 |= MMC_CAP2_NO_SDIO;
- if (of_property_read_bool(np, "no-sd"))
+ if (device_property_read_bool(dev, "no-sd"))
host->caps2 |= MMC_CAP2_NO_SD;
- if (of_property_read_bool(np, "no-mmc"))
+ if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
- host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
+ host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {
dev_err(host->parent,
"device tree specified broken value for DSR: 0x%x, ignoring\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6a421ec..36295f5 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1416,7 +1416,7 @@
static int mmc_select_hs400es(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- int err = 0;
+ int err = -EINVAL;
u8 val;
if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
@@ -2148,7 +2148,7 @@
err = mmc_select_hs400(card);
if (err)
goto free_card;
- } else {
+ } else if (!mmc_card_hs400es(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (err > 0 && mmc_card_hs(card)) {
@@ -2159,11 +2159,11 @@
}
card->clk_scaling_lowest = host->f_min;
- if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS400) ||
- (card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS200))
+ if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
+ (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200))
card->clk_scaling_highest = card->ext_csd.hs200_max_dtr;
- else if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS) ||
- (card->mmc_avail_type | EXT_CSD_CARD_TYPE_DDR_52))
+ else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ||
+ (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
card->clk_scaling_highest = card->ext_csd.hs_max_dtr;
else
card->clk_scaling_highest = card->csd.max_dtr;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 650f658..d591ded 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1275,7 +1275,10 @@
if (!err) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_suspended(&host->card->dev);
- }
+ /* if suspend fails, force mmc_detect_change during resume */
+ } else if (mmc_bus_manual_resume(host))
+ host->ignore_bus_resume_flags = true;
+
MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err);
return err;
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 7c3638c..591d6b2 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -145,6 +145,29 @@
mb();
}
+static int cmdq_clear_task_poll(struct cmdq_host *cq_host, unsigned int tag)
+{
+ int retries = 100;
+
+ cmdq_clear_set_irqs(cq_host, CQIS_TCL, 0);
+ cmdq_writel(cq_host, 1<<tag, CQTCLR);
+ while (retries) {
+ /*
+ * Task Clear register and doorbell,
+ * both should indicate that task is cleared
+ */
+ if ((cmdq_readl(cq_host, CQTCLR) & 1<<tag) ||
+ (cmdq_readl(cq_host, CQTDBR) & 1<<tag)) {
+ udelay(5);
+ retries--;
+ continue;
+ } else
+ break;
+ }
+
+ cmdq_clear_set_irqs(cq_host, 0, CQIS_TCL);
+ return retries ? 0 : -ETIMEDOUT;
+}
#define DRV_NAME "cmdq-host"
@@ -197,6 +220,10 @@
static void cmdq_dumpregs(struct cmdq_host *cq_host)
{
struct mmc_host *mmc = cq_host->mmc;
+ int offset = 0;
+
+ if (cq_host->offset_changed)
+ offset = CQ_V5_VENDOR_CFG;
MMC_TRACE(mmc,
"%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n",
@@ -243,7 +270,7 @@
cmdq_readl(cq_host, CQCRI),
cmdq_readl(cq_host, CQCRA));
pr_err(DRV_NAME": Vendor cfg 0x%08x\n",
- cmdq_readl(cq_host, CQ_VENDOR_CFG));
+ cmdq_readl(cq_host, CQ_VENDOR_CFG + offset));
pr_err(DRV_NAME ": ===========================================\n");
cmdq_dump_task_history(cq_host);
@@ -345,6 +372,7 @@
{
int err = 0;
u32 cqcfg;
+ u32 cqcap = 0;
bool dcmd_enable;
struct cmdq_host *cq_host = mmc_cmdq_private(mmc);
@@ -373,6 +401,24 @@
cqcfg = ((cq_host->caps & CMDQ_TASK_DESC_SZ_128 ? CQ_TASK_DESC_SZ : 0) |
(dcmd_enable ? CQ_DCMD : 0));
+ cqcap = cmdq_readl(cq_host, CQCAP);
+ if (cqcap & CQCAP_CS) {
+ /*
+ * In case host controller supports cryptographic operations
+ * then, it uses 128bit task descriptor. Upper 64 bits of task
+ * descriptor would be used to pass crypto specific informaton.
+ */
+ cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT |
+ CMDQ_TASK_DESC_SZ_128;
+ cqcfg |= CQ_ICE_ENABLE;
+ /*
+ * For SDHC v5.0 onwards, ICE 3.0 specific registers are added
+ * in CQ register space, due to which few CQ registers are
+ * shifted. Set offset_changed boolean to use updated address.
+ */
+ cq_host->offset_changed = true;
+ }
+
cmdq_writel(cq_host, cqcfg, CQCFG);
/* enable CQ_HOST */
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCFG) | CQ_ENABLE,
@@ -688,6 +734,30 @@
upper_32_bits(*task_desc));
}
+static inline
+void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, u64 *task_desc,
+ u64 ice_ctx)
+{
+ u64 *ice_desc = NULL;
+
+ if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) {
+ /*
+ * Get the address of ice context for the given task descriptor.
+ * ice context is present in the upper 64bits of task descriptor
+ * ice_conext_base_address = task_desc + 8-bytes
+ */
+ ice_desc = (__le64 *)((u8 *)task_desc +
+ CQ_TASK_DESC_TASK_PARAMS_SIZE);
+ memset(ice_desc, 0, CQ_TASK_DESC_ICE_PARAMS_SIZE);
+
+ /*
+ * Assign upper 64bits data of task descritor with ice context
+ */
+ if (ice_ctx)
+ *ice_desc = cpu_to_le64(ice_ctx);
+ }
+}
+
static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -711,6 +781,7 @@
u32 tag = mrq->cmdq_req->tag;
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
struct sdhci_host *host = mmc_priv(mmc);
+ u64 ice_ctx = 0;
if (!cq_host->enabled) {
pr_err("%s: CMDQ host not enabled yet !!!\n",
@@ -730,7 +801,7 @@
}
if (cq_host->ops->crypto_cfg) {
- err = cq_host->ops->crypto_cfg(mmc, mrq, tag);
+ err = cq_host->ops->crypto_cfg(mmc, mrq, tag, &ice_ctx);
if (err) {
pr_err("%s: failed to configure crypto: err %d tag %d\n",
mmc_hostname(mmc), err, tag);
@@ -743,6 +814,9 @@
cmdq_prep_task_desc(mrq, &data, 1,
(mrq->cmdq_req->cmdq_req_flags & QBR));
*task_desc = cpu_to_le64(data);
+
+ cmdq_prep_crypto_desc(cq_host, task_desc, ice_ctx);
+
cmdq_log_task_desc_history(cq_host, *task_desc, false);
err = cmdq_prep_tran_desc(mrq, cq_host, tag);
@@ -777,17 +851,31 @@
{
struct mmc_request *mrq;
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
+ int offset = 0;
+ int err = 0;
+ if (cq_host->offset_changed)
+ offset = CQ_V5_VENDOR_CFG;
mrq = get_req_by_tag(cq_host, tag);
if (tag == cq_host->dcmd_slot)
mrq->cmd->resp[0] = cmdq_readl(cq_host, CQCRDCT);
if (mrq->cmdq_req->cmdq_req_flags & DCMD)
- cmdq_writel(cq_host, cmdq_readl(cq_host, CQ_VENDOR_CFG) |
- CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG);
+ cmdq_writel(cq_host,
+ cmdq_readl(cq_host, CQ_VENDOR_CFG + offset) |
+ CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG + offset);
cmdq_runtime_pm_put(cq_host);
- if (cq_host->ops->crypto_cfg_reset)
+
+ if (cq_host->ops->crypto_cfg_end) {
+ err = cq_host->ops->crypto_cfg_end(mmc, mrq);
+ if (err) {
+ pr_err("%s: failed to end ice config: err %d tag %d\n",
+ mmc_hostname(mmc), err, tag);
+ }
+ }
+ if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) &&
+ cq_host->ops->crypto_cfg_reset)
cq_host->ops->crypto_cfg_reset(mmc, tag);
mrq->done(mrq);
}
@@ -801,6 +889,8 @@
struct mmc_request *mrq;
int ret;
u32 dbr_set = 0;
+ u32 dev_pend_set = 0;
+ int stat_err = 0;
status = cmdq_readl(cq_host, CQIS);
@@ -809,7 +899,9 @@
MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n",
__func__, status, err);
- if (err || (status & CQIS_RED)) {
+ stat_err = status & (CQIS_RED | CQIS_GCE | CQIS_ICCE);
+
+ if (err || stat_err) {
err_info = cmdq_readl(cq_host, CQTERRI);
pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n",
mmc_hostname(mmc), err, status, err_info);
@@ -912,7 +1004,7 @@
* CQE detected a response error from device
* In most cases, this would require a reset.
*/
- if (status & CQIS_RED) {
+ if (stat_err & CQIS_RED) {
/*
* will check if the RED error is due to a bkops
* exception once the queue is empty
@@ -931,6 +1023,62 @@
mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA);
}
+ /*
+ * Generic Crypto error detected by CQE.
+ * Its a fatal, would require cmdq reset.
+ */
+ if (stat_err & CQIS_GCE) {
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ pr_err("%s: Crypto generic error while processing task %lu!",
+ mmc_hostname(mmc), tag);
+ MMC_TRACE(mmc, "%s: GCE error detected with tag %lu\n",
+ __func__, tag);
+ }
+ /*
+ * Invalid crypto config error detected by CQE, clear the task.
+ * Task can be cleared only when CQE is halt state.
+ */
+ if (stat_err & CQIS_ICCE) {
+ /*
+ * Invalid Crypto Config Error is detected at the
+ * beginning of the transfer before the actual execution
+ * started. So just clear the task in CQE. No need to
+ * clear in device. Only the task which caused ICCE has
+ * to be cleared. Other tasks can be continue processing
+ * The first task which is about to be prepared would
+ * cause ICCE Error.
+ */
+ dbr_set = cmdq_readl(cq_host, CQTDBR);
+ dev_pend_set = cmdq_readl(cq_host, CQDPT);
+ if (dbr_set ^ dev_pend_set)
+ tag = ffs(dbr_set ^ dev_pend_set) - 1;
+ mrq = get_req_by_tag(cq_host, tag);
+ pr_err("%s: Crypto config error while processing task %lu!",
+ mmc_hostname(mmc), tag);
+ MMC_TRACE(mmc, "%s: ICCE error with tag %lu\n",
+ __func__, tag);
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ else if (mrq->cmd)
+ mrq->cmd->error = -EIO;
+ /*
+ * If CQE is halted and tag is valid then clear the task
+ * then un-halt CQE and set flag to skip error recovery.
+ * If any of the condtions is not met thene it will
+ * enter into default error recovery path.
+ */
+ if (!ret && (dbr_set ^ dev_pend_set)) {
+ ret = cmdq_clear_task_poll(cq_host, tag);
+ if (ret) {
+ pr_err("%s: %s: task[%lu] clear failed ret=%d\n",
+ mmc_hostname(mmc),
+ __func__, tag, ret);
+ } else if (!cmdq_halt_poll(mmc, false)) {
+ mrq->cmdq_req->skip_err_handling = true;
+ }
+ }
+ }
cmdq_finish_data(mmc, tag);
} else {
cmdq_writel(cq_host, status, CQIS);
@@ -1001,6 +1149,7 @@
cq_host->ops->clear_set_irqs(mmc, true);
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
CQCTL);
+ mmc_host_clr_halt(mmc);
return 0;
}
diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h
index 8e9f765..1aabce9 100644
--- a/drivers/mmc/host/cmdq_hci.h
+++ b/drivers/mmc/host/cmdq_hci.h
@@ -18,11 +18,13 @@
#define CQVER 0x00
/* capabilities */
#define CQCAP 0x04
+#define CQCAP_CS (1 << 28)
/* configuration */
#define CQCFG 0x08
#define CQ_DCMD 0x00001000
#define CQ_TASK_DESC_SZ 0x00000100
#define CQ_ENABLE 0x00000001
+#define CQ_ICE_ENABLE 0x00000002
/* control */
#define CQCTL 0x0C
@@ -35,6 +37,8 @@
#define CQIS_TCC (1 << 1)
#define CQIS_RED (1 << 2)
#define CQIS_TCL (1 << 3)
+#define CQIS_GCE (1 << 4)
+#define CQIS_ICCE (1 << 5)
/* interrupt status enable */
#define CQISTE 0x14
@@ -110,7 +114,7 @@
/* command response argument */
#define CQCRA 0x5C
-#define CQ_INT_ALL 0xF
+#define CQ_INT_ALL 0x3F
#define CQIC_DEFAULT_ICCTH 31
#define CQIC_DEFAULT_ICTOVAL 1
@@ -141,9 +145,17 @@
#define DAT_ADDR_LO(x) ((x & 0xFFFFFFFF) << 32)
#define DAT_ADDR_HI(x) ((x & 0xFFFFFFFF) << 0)
+/*
+ * Add new macro for updated CQ vendor specific
+ * register address for SDHC v5.0 onwards.
+ */
+#define CQ_V5_VENDOR_CFG 0x900
#define CQ_VENDOR_CFG 0x100
#define CMDQ_SEND_STATUS_TRIGGER (1 << 31)
+#define CQ_TASK_DESC_TASK_PARAMS_SIZE 8
+#define CQ_TASK_DESC_ICE_PARAMS_SIZE 8
+
struct task_history {
u64 task;
bool is_dcmd;
@@ -161,6 +173,7 @@
u32 dcmd_slot;
u32 caps;
#define CMDQ_TASK_DESC_SZ_128 0x1
+#define CMDQ_CAP_CRYPTO_SUPPORT 0x2
u32 quirks;
#define CMDQ_QUIRK_SHORT_TXFR_DESC_SZ 0x1
@@ -169,6 +182,7 @@
bool enabled;
bool halted;
bool init_done;
+ bool offset_changed;
u8 *desc_base;
@@ -209,7 +223,8 @@
int (*reset)(struct mmc_host *mmc);
void (*post_cqe_halt)(struct mmc_host *mmc);
int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq,
- u32 slot);
+ u32 slot, u64 *ice_ctx);
+ int (*crypto_cfg_end)(struct mmc_host *mmc, struct mmc_request *mrq);
void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot);
};
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index df478ae..f81f417 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2610,8 +2610,8 @@
host->slot[id] = slot;
mmc->ops = &dw_mci_ops;
- if (of_property_read_u32_array(host->dev->of_node,
- "clock-freq-min-max", freq, 2)) {
+ if (device_property_read_u32_array(host->dev, "clock-freq-min-max",
+ freq, 2)) {
mmc->f_min = DW_MCI_FREQ_MIN;
mmc->f_max = DW_MCI_FREQ_MAX;
} else {
@@ -2709,7 +2709,6 @@
{
int addr_config;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
/*
* Check tansfer mode from HCON[17:16]
@@ -2770,8 +2769,9 @@
dev_info(host->dev, "Using internal DMA controller.\n");
} else {
/* TRANS_MODE_EDMAC: check dma bindings again */
- if ((of_property_count_strings(np, "dma-names") < 0) ||
- (!of_find_property(np, "dmas", NULL))) {
+ if ((device_property_read_string_array(dev, "dma-names",
+ NULL, 0) < 0) ||
+ !device_property_present(dev, "dmas")) {
goto no_dma;
}
host->dma_ops = &dw_mci_edmac_ops;
@@ -2931,7 +2931,6 @@
{
struct dw_mci_board *pdata;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int ret;
u32 clock_frequency;
@@ -2948,15 +2947,16 @@
}
/* find out number of slots supported */
- of_property_read_u32(np, "num-slots", &pdata->num_slots);
+ device_property_read_u32(dev, "num-slots", &pdata->num_slots);
- if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+ if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
dev_info(dev,
"fifo-depth property not found, using value of FIFOTH register as default\n");
- of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+ device_property_read_u32(dev, "card-detect-delay",
+ &pdata->detect_delay_ms);
- if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
+ if (!device_property_read_u32(dev, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
if (drv_data && drv_data->parse_dt) {
diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c
index d624b48..f86ce5b 100644
--- a/drivers/mmc/host/sdhci-msm-ice.c
+++ b/drivers/mmc/host/sdhci-msm-ice.c
@@ -276,6 +276,58 @@
mb();
}
+static inline
+void sdhci_msm_ice_hci_update_cmdq_cfg(u64 dun, unsigned int bypass,
+ short key_index, u64 *ice_ctx)
+{
+ /*
+ * The naming convention got changed between ICE2.0 and ICE3.0
+ * registers fields. Below is the equivalent names for
+ * ICE3.0 Vs ICE2.0:
+ * Data Unit Number(DUN) == Logical Base address(LBA)
+ * Crypto Configuration index (CCI) == Key Index
+ * Crypto Enable (CE) == !BYPASS
+ */
+ if (ice_ctx)
+ *ice_ctx = DATA_UNIT_NUM(dun) |
+ CRYPTO_CONFIG_INDEX(key_index) |
+ CRYPTO_ENABLE(!bypass);
+}
+
+static
+void sdhci_msm_ice_hci_update_noncq_cfg(struct sdhci_host *host,
+ u64 dun, unsigned int bypass, short key_index)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned int crypto_params = 0;
+ /*
+ * The naming convention got changed between ICE2.0 and ICE3.0
+ * registers fields. Below is the equivalent names for
+ * ICE3.0 Vs ICE2.0:
+ * Data Unit Number(DUN) == Logical Base address(LBA)
+ * Crypto Configuration index (CCI) == Key Index
+ * Crypto Enable (CE) == !BYPASS
+ */
+ /* Configure ICE bypass mode */
+ crypto_params |=
+ (!bypass & MASK_SDHCI_MSM_ICE_HCI_PARAM_CE)
+ << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE;
+ /* Configure Crypto Configure Index (CCI) */
+ crypto_params |= (key_index &
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI)
+ << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI;
+
+ writel_relaxed((crypto_params & 0xFFFFFFFF),
+ msm_host->cryptoio + ICE_NONCQ_CRYPTO_PARAMS);
+
+ /* Update DUN */
+ writel_relaxed((dun & 0xFFFFFFFF),
+ msm_host->cryptoio + ICE_NONCQ_CRYPTO_DUN);
+ /* Ensure ICE registers are configured before issuing SDHCI request */
+ mb();
+}
+
int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
u32 slot)
{
@@ -308,7 +360,88 @@
slot, bypass, key_index);
}
- sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ if (msm_host->ice_hci_support) {
+ /* For ICE HCI / ICE3.0 */
+ sdhci_msm_ice_hci_update_noncq_cfg(host, lba, bypass,
+ key_index);
+ } else {
+ /* For ICE versions earlier to ICE3.0 */
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ }
+ return 0;
+}
+
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int err = 0;
+ short key_index = 0;
+ sector_t lba = 0;
+ unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
+ struct request *req;
+
+ if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
+ pr_err("%s: ice is in invalid state %d\n",
+ mmc_hostname(host->mmc), msm_host->ice.state);
+ return -EINVAL;
+ }
+
+ WARN_ON(!mrq);
+ if (!mrq)
+ return -EINVAL;
+ req = mrq->req;
+ if (req) {
+ lba = req->__sector;
+ err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index);
+ if (err)
+ return err;
+ pr_debug("%s: %s: slot %d bypass %d key_index %d\n",
+ mmc_hostname(host->mmc),
+ (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
+ slot, bypass, key_index);
+ }
+
+ if (msm_host->ice_hci_support) {
+ /* For ICE HCI / ICE3.0 */
+ sdhci_msm_ice_hci_update_cmdq_cfg(lba, bypass, key_index,
+ ice_ctx);
+ } else {
+ /* For ICE versions earlier to ICE3.0 */
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ }
+ return 0;
+}
+
+int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int err = 0;
+ struct request *req;
+
+ if (!host->is_crypto_en)
+ return 0;
+
+ if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
+ pr_err("%s: ice is in invalid state %d\n",
+ mmc_hostname(host->mmc), msm_host->ice.state);
+ return -EINVAL;
+ }
+
+ req = mrq->req;
+ if (req) {
+ if (msm_host->ice.vops->config_end) {
+ err = msm_host->ice.vops->config_end(req);
+ if (err) {
+ pr_err("%s: ice config end failed %d\n",
+ mmc_hostname(host->mmc), err);
+ return err;
+ }
+ }
+ }
+
return 0;
}
diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h
index 23922cf..6296174 100644
--- a/drivers/mmc/host/sdhci-msm-ice.h
+++ b/drivers/mmc/host/sdhci-msm-ice.h
@@ -42,6 +42,8 @@
#define ICE_HCI_SUPPORT (1 << 28)
#define ICE_CQ_CONFIG 0x08
#define CRYPTO_GENERAL_ENABLE (1 << 1)
+#define ICE_NONCQ_CRYPTO_PARAMS 0x70
+#define ICE_NONCQ_CRYPTO_DUN 0x74
/* ICE3.0 register which got added hc reg space */
#define HC_VENDOR_SPECIFIC_FUNC4 0x260
@@ -52,8 +54,10 @@
/* SDHCI MSM ICE CTRL Info register offset */
enum {
OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0,
- OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1,
- OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x6,
+ OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 1,
+ OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 6,
+ OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0,
+ OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE = 8,
};
/* SDHCI MSM ICE CTRL Info register masks */
@@ -61,6 +65,8 @@
MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0x1,
MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1F,
MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x7,
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CE = 0x1,
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0xff
};
/* SDHCI MSM ICE encryption/decryption bypass state */
@@ -99,6 +105,9 @@
void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot);
int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
u32 slot);
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
+int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq);
int sdhci_msm_ice_reset(struct sdhci_host *host);
int sdhci_msm_ice_resume(struct sdhci_host *host);
int sdhci_msm_ice_suspend(struct sdhci_host *host);
@@ -130,6 +139,16 @@
{
return 0;
}
+static inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ return 0;
+}
+static inline int sdhci_msm_ice_cfg_end(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ return 0;
+}
inline int sdhci_msm_ice_reset(struct sdhci_host *host)
{
return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 71eba6c..60e8ca0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -146,6 +146,7 @@
#define CORE_START_CDC_TRAFFIC (1 << 6)
#define CORE_PWRSAVE_DLL (1 << 3)
+#define CORE_FIFO_ALT_EN (1 << 10)
#define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13)
#define CORE_DDR_CAL_EN (1 << 0)
@@ -3407,6 +3408,8 @@
/* registers offset changed starting from 4.2.0 */
int offset = minor >= SDHCI_MSM_VER_420 ? 0 : 0x48;
+ if (cq_host->offset_changed)
+ offset += CQ_V5_VENDOR_CFG;
pr_err("---- Debug RAM dump ----\n");
pr_err(DRV_NAME ": Debug RAM wrap-around: 0x%08x | Debug RAM overlap: 0x%08x\n",
cmdq_readl(cq_host, CQ_CMD_DBG_RAM_WA + offset),
@@ -4114,6 +4117,9 @@
static struct sdhci_ops sdhci_msm_ops = {
.crypto_engine_cfg = sdhci_msm_ice_cfg,
+ .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg,
+ .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end,
+ .crypto_cfg_reset = sdhci_msm_ice_cfg_reset,
.crypto_engine_reset = sdhci_msm_ice_reset,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.check_power_status = sdhci_msm_check_power_status,
@@ -4213,7 +4219,7 @@
* starts coming.
*/
if ((major == 1) && ((minor == 0x42) || (minor == 0x46) ||
- (minor == 0x49)))
+ (minor == 0x49) || (minor >= 0x6b)))
msm_host->use_14lpp_dll = true;
/* Fake 3.0V support for SDIO devices which requires such voltage */
@@ -4308,6 +4314,7 @@
struct resource *tlmm_memres = NULL;
void __iomem *tlmm_mem;
unsigned long flags;
+ bool force_probe;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -4347,7 +4354,7 @@
*/
dev_err(&pdev->dev, "%s: required ICE device not probed yet err = %d\n",
__func__, ret);
- goto out_host_free;
+ goto pltfm_free;
} else if (ret == -ENODEV) {
/*
@@ -4359,7 +4366,7 @@
} else if (ret) {
dev_err(&pdev->dev, "%s: sdhci_msm_ice_get_dev failed %d\n",
__func__, ret);
- goto out_host_free;
+ goto pltfm_free;
}
/* Extract platform data */
@@ -4371,8 +4378,13 @@
goto pltfm_free;
}
+ /* Read property to determine if the probe is forced */
+ force_probe = of_find_property(pdev->dev.of_node,
+ "qcom,force-sdhc1-probe", NULL);
+
/* skip the probe if eMMC isn't a boot device */
- if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)) {
+ if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)
+ && !force_probe) {
ret = -ENODEV;
goto pltfm_free;
}
@@ -4537,6 +4549,14 @@
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
+ /*
+ * Ensure SDHCI FIFO is enabled by disabling alternative FIFO
+ */
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3) &
+ ~CORE_FIFO_ALT_EN), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
+
if (!msm_host->mci_removed) {
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
@@ -4933,8 +4953,6 @@
if (msm_host->msm_bus_vote.client_handle)
sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
}
- trace_sdhci_msm_runtime_suspend(mmc_hostname(host->mmc), 0,
- ktime_to_us(ktime_sub(ktime_get(), start)));
if (host->is_crypto_en) {
ret = sdhci_msm_ice_suspend(host);
@@ -4942,6 +4960,8 @@
pr_err("%s: failed to suspend crypto engine %d\n",
mmc_hostname(host->mmc), ret);
}
+ trace_sdhci_msm_runtime_suspend(mmc_hostname(host->mmc), 0,
+ ktime_to_us(ktime_sub(ktime_get(), start)));
return 0;
}
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index a8b430f..83b84ff 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -31,6 +31,7 @@
#define SDMMC_MC1R 0x204
#define SDMMC_MC1R_DDR BIT(3)
+#define SDMMC_MC1R_FCD BIT(7)
#define SDMMC_CACR 0x230
#define SDMMC_CACR_CAPWREN BIT(0)
#define SDMMC_CACR_KEY (0x46 << 8)
@@ -43,6 +44,15 @@
struct clk *mainck;
};
+static void sdhci_at91_set_force_card_detect(struct sdhci_host *host)
+{
+ u8 mc1r;
+
+ mc1r = readb(host->ioaddr + SDMMC_MC1R);
+ mc1r |= SDMMC_MC1R_FCD;
+ writeb(mc1r, host->ioaddr + SDMMC_MC1R);
+}
+
static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
@@ -112,10 +122,18 @@
sdhci_set_uhs_signaling(host, timing);
}
+static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
+{
+ sdhci_reset(host, mask);
+
+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ sdhci_at91_set_force_card_detect(host);
+}
+
static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
.set_clock = sdhci_at91_set_clock,
.set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
+ .reset = sdhci_at91_reset,
.set_uhs_signaling = sdhci_at91_set_uhs_signaling,
.set_power = sdhci_at91_set_power,
};
@@ -322,6 +340,21 @@
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
+ /*
+ * If the device attached to the MMC bus is not removable, it is safer
+ * to set the Force Card Detect bit. People often don't connect the
+ * card detect signal and use this pin for another purpose. If the card
+ * detect pin is not muxed to SDHCI controller, a default value is
+ * used. This value can be different from a SoC revision to another
+ * one. Problems come when this default value is not card present. To
+ * avoid this case, if the device is non removable then the card
+ * detection procedure using the SDMCC_CD signal is bypassed.
+ * This bit is reset when a software reset for all command is performed
+ * so we need to implement our own reset function to set back this bit.
+ */
+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ sdhci_at91_set_force_card_detect(host);
+
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 90a0b56..4476e51 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1785,6 +1785,22 @@
return err;
}
+static int sdhci_crypto_cfg_end(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ int err = 0;
+
+ if (host->ops->crypto_engine_cfg_end) {
+ err = host->ops->crypto_engine_cfg_end(host, mrq);
+ if (err) {
+ pr_err("%s: failed to configure crypto\n",
+ mmc_hostname(host->mmc));
+ return err;
+ }
+ }
+ return 0;
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -2876,6 +2892,7 @@
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_crypto_cfg_end(host, mrq);
mmc_request_done(host->mmc, mrq);
return false;
@@ -3775,14 +3792,46 @@
sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
}
static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
- struct mmc_request *mrq, u32 slot)
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ int err = 0;
+
+ if (!host->is_crypto_en)
+ return 0;
+
+ if (host->crypto_reset_reqd && host->ops->crypto_engine_reset) {
+ err = host->ops->crypto_engine_reset(host);
+ if (err) {
+ pr_err("%s: crypto reset failed\n",
+ mmc_hostname(host->mmc));
+ goto out;
+ }
+ host->crypto_reset_reqd = false;
+ }
+
+ if (host->ops->crypto_engine_cmdq_cfg) {
+ err = host->ops->crypto_engine_cmdq_cfg(host, mrq,
+ slot, ice_ctx);
+ if (err) {
+ pr_err("%s: failed to configure crypto\n",
+ mmc_hostname(host->mmc));
+ goto out;
+ }
+ }
+out:
+ return err;
+}
+
+static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc,
+ struct mmc_request *mrq)
{
struct sdhci_host *host = mmc_priv(mmc);
if (!host->is_crypto_en)
return 0;
- return sdhci_crypto_cfg(host, mrq, slot);
+ return sdhci_crypto_cfg_end(host, mrq);
}
static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot)
@@ -3842,7 +3891,13 @@
}
static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
- struct mmc_request *mrq, u32 slot)
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ return 0;
+}
+
+static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc,
+ struct mmc_request *mrq)
{
return 0;
}
@@ -3863,6 +3918,7 @@
.post_cqe_halt = sdhci_cmdq_post_cqe_halt,
.set_transfer_params = sdhci_cmdq_set_transfer_params,
.crypto_cfg = sdhci_cmdq_crypto_cfg,
+ .crypto_cfg_end = sdhci_cmdq_crypto_cfg_end,
.crypto_cfg_reset = sdhci_cmdq_crypto_cfg_reset,
};
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index cafde4b..2b67d0a 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -671,6 +671,10 @@
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*crypto_engine_cfg)(struct sdhci_host *host,
struct mmc_request *mrq, u32 slot);
+ int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
+ int (*crypto_engine_cfg_end)(struct sdhci_host *host,
+ struct mmc_request *mrq);
int (*crypto_engine_reset)(struct sdhci_host *host);
void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot);
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index f222f8a..31a6ee3 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -64,8 +64,14 @@
if (!section) {
oobregion->offset = 0;
- oobregion->length = 4;
+ if (mtd->oobsize == 16)
+ oobregion->length = 4;
+ else
+ oobregion->length = 3;
} else {
+ if (mtd->oobsize == 8)
+ return -ERANGE;
+
oobregion->offset = 6;
oobregion->length = ecc->total - 4;
}
@@ -1081,7 +1087,9 @@
* Ensure the timing mode has been changed on the chip side
* before changing timings on the controller side.
*/
- if (chip->onfi_version) {
+ if (chip->onfi_version &&
+ (le16_to_cpu(chip->onfi_params.opt_cmd) &
+ ONFI_OPT_CMD_SET_GET_FEATURES)) {
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 947adda..3ec573c 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1558,6 +1558,7 @@
.dev_name = "BCM53125",
.vlans = 4096,
.enabled_ports = 0xff,
+ .arl_entries = 4,
.cpu_port = B53_CPU_PORT,
.vta_regs = B53_VTA_REGS,
.duplex_reg = B53_DUPLEX_STAT_GE,
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
index e078d8d..29d29af 100644
--- a/drivers/net/ethernet/aurora/nb8800.c
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -609,7 +609,7 @@
mac_mode |= HALF_DUPLEX;
if (gigabit) {
- if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (phy_interface_is_rgmii(dev->phydev))
mac_mode |= RGMII_MODE;
mac_mode |= GMAC_MODE;
@@ -1277,11 +1277,10 @@
break;
case PHY_INTERFACE_MODE_RGMII:
- pad_mode = PAD_MODE_RGMII;
- break;
-
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
- pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+ pad_mode = PAD_MODE_RGMII;
break;
default:
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index a927a73..edae2dc 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -8720,11 +8720,14 @@
tg3_mem_rx_release(tp);
tg3_mem_tx_release(tp);
+ /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
+ tg3_full_lock(tp, 0);
if (tp->hw_stats) {
dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
tp->hw_stats, tp->stats_mapping);
tp->hw_stats = NULL;
}
+ tg3_full_unlock(tp);
}
/*
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 5d48458..bcbb80f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -724,16 +724,21 @@
* header, the HW adds it. To address that, we are subtracting the pseudo
* header checksum from the checksum value provided by the HW.
*/
-static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
- struct iphdr *iph)
+static int get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
+ struct iphdr *iph)
{
__u16 length_for_csum = 0;
__wsum csum_pseudo_header = 0;
+ __u8 ipproto = iph->protocol;
+
+ if (unlikely(ipproto == IPPROTO_SCTP))
+ return -1;
length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2));
csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr,
- length_for_csum, iph->protocol, 0);
+ length_for_csum, ipproto, 0);
skb->csum = csum_sub(hw_checksum, csum_pseudo_header);
+ return 0;
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -744,17 +749,20 @@
static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
struct ipv6hdr *ipv6h)
{
+ __u8 nexthdr = ipv6h->nexthdr;
__wsum csum_pseudo_hdr = 0;
- if (unlikely(ipv6h->nexthdr == IPPROTO_FRAGMENT ||
- ipv6h->nexthdr == IPPROTO_HOPOPTS))
+ if (unlikely(nexthdr == IPPROTO_FRAGMENT ||
+ nexthdr == IPPROTO_HOPOPTS ||
+ nexthdr == IPPROTO_SCTP))
return -1;
- hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr));
+ hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(nexthdr));
csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len);
- csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr));
+ csum_pseudo_hdr = csum_add(csum_pseudo_hdr,
+ (__force __wsum)htons(nexthdr));
skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr);
skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0));
@@ -777,11 +785,10 @@
}
if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4))
- get_fixed_ipv4_csum(hw_checksum, skb, hdr);
+ return get_fixed_ipv4_csum(hw_checksum, skb, hdr);
#if IS_ENABLED(CONFIG_IPV6)
- else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
- if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr)))
- return -1;
+ if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
+ return get_fixed_ipv6_csum(hw_checksum, skb, hdr);
#endif
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 551786f..ba652d8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -430,7 +430,7 @@
/* Virtual PCI function needs to determine UAR page size from
* firmware. Only master PCI function can set the uar page size
*/
- if (enable_4k_uar)
+ if (enable_4k_uar || !dev->persist->num_vfs)
dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
else
dev->uar_page_shift = PAGE_SHIFT;
@@ -2269,7 +2269,7 @@
dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
- if (enable_4k_uar) {
+ if (enable_4k_uar || !dev->persist->num_vfs) {
init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
PAGE_SHIFT - DEFAULT_UAR_PAGE_SHIFT;
init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index cb45390..f7fabec 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -770,6 +770,10 @@
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
}
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+ struct mlx5_cmd_msg *msg);
+
static void cmd_work_handler(struct work_struct *work)
{
struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -779,16 +783,27 @@
struct mlx5_cmd_layout *lay;
struct semaphore *sem;
unsigned long flags;
+ int alloc_ret;
sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
down(sem);
if (!ent->page_queue) {
- ent->idx = alloc_ent(cmd);
- if (ent->idx < 0) {
+ alloc_ret = alloc_ent(cmd);
+ if (alloc_ret < 0) {
+ if (ent->callback) {
+ ent->callback(-EAGAIN, ent->context);
+ mlx5_free_cmd_msg(dev, ent->out);
+ free_msg(dev, ent->in);
+ free_cmd(ent);
+ } else {
+ ent->ret = -EAGAIN;
+ complete(&ent->done);
+ }
mlx5_core_err(dev, "failed to allocate command entry\n");
up(sem);
return;
}
+ ent->idx = alloc_ret;
} else {
ent->idx = cmd->max_reg_cmds;
spin_lock_irqsave(&cmd->alloc_lock, flags);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
index 13dc388..1612ec0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
@@ -62,12 +62,14 @@
struct delayed_work *dwork = to_delayed_work(work);
struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
overflow_work);
+ struct mlx5e_priv *priv = container_of(tstamp, struct mlx5e_priv, tstamp);
unsigned long flags;
write_lock_irqsave(&tstamp->lock, flags);
timecounter_read(&tstamp->clock);
write_unlock_irqrestore(&tstamp->lock, flags);
- schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
+ queue_delayed_work(priv->wq, &tstamp->overflow_work,
+ msecs_to_jiffies(tstamp->overflow_period * 1000));
}
int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
@@ -263,7 +265,7 @@
INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
if (tstamp->overflow_period)
- schedule_delayed_work(&tstamp->overflow_work, 0);
+ queue_delayed_work(priv->wq, &tstamp->overflow_work, 0);
else
mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
index e034dbc..cf070fc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -276,7 +276,7 @@
static bool outer_header_zero(u32 *match_criteria)
{
- int size = MLX5_ST_SZ_BYTES(fte_match_param);
+ int size = MLX5_FLD_SZ_BYTES(fte_match_param, outer_headers);
char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
outer_headers);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 6ffd5d2..52a3810 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -651,9 +651,14 @@
int vport;
int err;
+ /* disable PF RoCE so missed packets don't go through RoCE steering */
+ mlx5_dev_list_lock();
+ mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
err = esw_create_offloads_fdb_table(esw, nvports);
if (err)
- return err;
+ goto create_fdb_err;
err = esw_create_offloads_table(esw);
if (err)
@@ -673,11 +678,6 @@
goto err_reps;
}
- /* disable PF RoCE so missed packets don't go through RoCE steering */
- mlx5_dev_list_lock();
- mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
return 0;
err_reps:
@@ -694,6 +694,13 @@
create_ft_err:
esw_destroy_offloads_fdb_table(esw);
+
+create_fdb_err:
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
@@ -701,11 +708,6 @@
{
int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
- /* enable back PF RoCE */
- mlx5_dev_list_lock();
- mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
mlx5_eswitch_disable_sriov(esw);
err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
if (err) {
@@ -715,6 +717,11 @@
esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
}
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
index b5d5519..0ca4623 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
@@ -157,22 +157,17 @@
static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
u8 *port1, u8 *port2)
{
- if (tracker->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) {
- if (tracker->netdev_state[0].tx_enabled) {
- *port1 = 1;
- *port2 = 1;
- } else {
- *port1 = 2;
- *port2 = 2;
- }
- } else {
- *port1 = 1;
- *port2 = 2;
- if (!tracker->netdev_state[0].link_up)
- *port1 = 2;
- else if (!tracker->netdev_state[1].link_up)
- *port2 = 1;
+ *port1 = 1;
+ *port2 = 2;
+ if (!tracker->netdev_state[0].tx_enabled ||
+ !tracker->netdev_state[0].link_up) {
+ *port1 = 2;
+ return;
}
+
+ if (!tracker->netdev_state[1].tx_enabled ||
+ !tracker->netdev_state[1].link_up)
+ *port2 = 1;
}
static void mlx5_activate_lag(struct mlx5_lag *ldev,
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index aee3fd2..4ca82bd 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -871,8 +871,7 @@
return NETDEV_TX_OK;
err_unmap:
- --f;
- while (f >= 0) {
+ while (--f >= 0) {
frag = &skb_shinfo(skb)->frags[f];
dma_unmap_page(&nn->pdev->dev,
tx_ring->txbufs[wr_idx].dma_addr,
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 12be259..2140ded 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -574,6 +574,7 @@
.rpadir_value = 2 << 16,
.no_trimd = 1,
.no_ade = 1,
+ .hw_crc = 1,
.tsu = 1,
.select_mii = 1,
.shift_rd0 = 1,
@@ -802,7 +803,7 @@
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
@@ -832,7 +833,7 @@
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index bca6a1e..e1bb802 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -141,9 +141,19 @@
static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
{
struct usb_device *dev = mcs->usbdev;
- int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
- MCS_RD_RTYPE, 0, reg, val, 2,
- msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+ void *dmabuf;
+ int ret;
+
+ dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, reg, dmabuf, 2,
+ msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+
+ memcpy(val, dmabuf, sizeof(__u16));
+ kfree(dmabuf);
return ret;
}
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 4cad955..01cf094 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -29,6 +29,7 @@
#define MII_DP83867_MICR 0x12
#define MII_DP83867_ISR 0x13
#define DP83867_CTRL 0x1f
+#define DP83867_CFG3 0x1e
/* Extended Registers */
#define DP83867_RGMIICTL 0x0032
@@ -90,6 +91,8 @@
micr_status |=
(MII_DP83867_MICR_AN_ERR_INT_EN |
MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+ MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
+ MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
@@ -190,6 +193,13 @@
DP83867_DEVADDR, delay);
}
+ /* Enable Interrupt output INT_OE in CFG3 register */
+ if (phy_interrupt_is_valid(phydev)) {
+ val = phy_read(phydev, DP83867_CFG3);
+ val |= BIT(7);
+ phy_write(phydev, DP83867_CFG3, val);
+ }
+
return 0;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index edd30eb..775a6e1 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -674,6 +674,9 @@
if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
phydev->state = PHY_UP;
mutex_unlock(&phydev->lock);
+
+ /* Now we can run the state machine synchronously */
+ phy_state_machine(&phydev->state_queue.work);
}
/**
@@ -1060,6 +1063,15 @@
if (old_link != phydev->link)
phydev->state = PHY_CHANGELINK;
}
+ /*
+ * Failsafe: check that nobody set phydev->link=0 between two
+ * poll cycles, otherwise we won't leave RUNNING state as long
+ * as link remains down.
+ */
+ if (!phydev->link && phydev->state == PHY_RUNNING) {
+ phydev->state = PHY_CHANGELINK;
+ phydev_err(phydev, "no link in PHY_RUNNING\n");
+ }
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9e7b783..bf02f8e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1714,6 +1714,8 @@
{
struct phy_device *phydev = to_phy_device(dev);
+ cancel_delayed_work_sync(&phydev->state_queue);
+
mutex_lock(&phydev->lock);
phydev->state = PHY_DOWN;
mutex_unlock(&phydev->lock);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 5489c0e..96fa0e6 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -119,6 +119,7 @@
int n_channels; /* how many channels are attached 54 */
spinlock_t rlock; /* lock for receive side 58 */
spinlock_t wlock; /* lock for transmit side 5c */
+ int *xmit_recursion __percpu; /* xmit recursion detect */
int mru; /* max receive unit 60 */
unsigned int flags; /* control bits 64 */
unsigned int xstate; /* transmit state bits 68 */
@@ -1024,6 +1025,7 @@
struct ppp *ppp = netdev_priv(dev);
int indx;
int err;
+ int cpu;
ppp->dev = dev;
ppp->ppp_net = src_net;
@@ -1038,6 +1040,15 @@
INIT_LIST_HEAD(&ppp->channels);
spin_lock_init(&ppp->rlock);
spin_lock_init(&ppp->wlock);
+
+ ppp->xmit_recursion = alloc_percpu(int);
+ if (!ppp->xmit_recursion) {
+ err = -ENOMEM;
+ goto err1;
+ }
+ for_each_possible_cpu(cpu)
+ (*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0;
+
#ifdef CONFIG_PPP_MULTILINK
ppp->minseq = -1;
skb_queue_head_init(&ppp->mrq);
@@ -1049,11 +1060,15 @@
err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
if (err < 0)
- return err;
+ goto err2;
conf->file->private_data = &ppp->file;
return 0;
+err2:
+ free_percpu(ppp->xmit_recursion);
+err1:
+ return err;
}
static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
@@ -1399,18 +1414,16 @@
ppp_xmit_unlock(ppp);
}
-static DEFINE_PER_CPU(int, ppp_xmit_recursion);
-
static void ppp_xmit_process(struct ppp *ppp)
{
local_bh_disable();
- if (unlikely(__this_cpu_read(ppp_xmit_recursion)))
+ if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
goto err;
- __this_cpu_inc(ppp_xmit_recursion);
+ (*this_cpu_ptr(ppp->xmit_recursion))++;
__ppp_xmit_process(ppp);
- __this_cpu_dec(ppp_xmit_recursion);
+ (*this_cpu_ptr(ppp->xmit_recursion))--;
local_bh_enable();
@@ -1901,23 +1914,23 @@
spin_unlock_bh(&pch->downl);
/* see if there is anything from the attached unit to be sent */
if (skb_queue_empty(&pch->file.xq)) {
- read_lock_bh(&pch->upl);
ppp = pch->ppp;
if (ppp)
__ppp_xmit_process(ppp);
- read_unlock_bh(&pch->upl);
}
}
static void ppp_channel_push(struct channel *pch)
{
- local_bh_disable();
-
- __this_cpu_inc(ppp_xmit_recursion);
- __ppp_channel_push(pch);
- __this_cpu_dec(ppp_xmit_recursion);
-
- local_bh_enable();
+ read_lock_bh(&pch->upl);
+ if (pch->ppp) {
+ (*this_cpu_ptr(pch->ppp->xmit_recursion))++;
+ __ppp_channel_push(pch);
+ (*this_cpu_ptr(pch->ppp->xmit_recursion))--;
+ } else {
+ __ppp_channel_push(pch);
+ }
+ read_unlock_bh(&pch->upl);
}
/*
@@ -3056,6 +3069,7 @@
#endif /* CONFIG_PPP_FILTER */
kfree_skb(ppp->xmit_pending);
+ free_percpu(ppp->xmit_recursion);
free_netdev(ppp->dev);
}
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 2f260c6..49a27dc 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -876,6 +876,7 @@
{QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */
{QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */
{QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */
+ {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */
{QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */
{QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */
{QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b7fe0af..63754ee 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -807,9 +807,15 @@
WLAN_STATUS_SUCCESS, GFP_KERNEL);
cfg80211_put_bss(ar->wiphy, bss);
} else if (vif->sme_state == SME_CONNECTED) {
+ struct cfg80211_roam_info roam_info = {
+ .bss = bss,
+ .req_ie = assoc_req_ie,
+ .req_ie_len = assoc_req_len,
+ .resp_ie = assoc_resp_ie,
+ .resp_ie_len = assoc_resp_len,
+ };
/* inform roam event to cfg80211 */
- cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
- assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+ cfg80211_roamed(vif->ndev, &roam_info, GFP_KERNEL);
}
}
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index e01acac..7a33792 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -124,24 +124,19 @@
return 0;
}
-static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
- size_t size)
-{
- wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
-
- return 0;
-}
-
static int
-fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
- size_t size)
+fw_handle_comment(struct wil6210_priv *wil, const void *data,
+ size_t size)
{
const struct wil_fw_record_capabilities *rec = data;
size_t capa_size;
if (size < sizeof(*rec) ||
- le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
+ le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
+ data, size, true);
return 0;
+ }
capa_size = size - offsetof(struct wil_fw_record_capabilities,
capabilities);
@@ -422,7 +417,7 @@
int (*parse_handler)(struct wil6210_priv *wil, const void *data,
size_t size);
} wil_fw_handlers[] = {
- {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
+ {wil_fw_type_comment, fw_handle_comment, fw_handle_comment},
{wil_fw_type_data, fw_handle_data, fw_ignore_section},
{wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
/* wil_fw_type_action */
@@ -517,7 +512,7 @@
rc = request_firmware(&fw, name, wil_to_dev(wil));
if (rc) {
- wil_err_fw(wil, "Failed to load firmware %s\n", name);
+ wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc);
return rc;
}
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index b91298d..c4faa2c 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -765,6 +765,8 @@
u8 retry_short;
int rc;
+ wil_refresh_fw_capabilities(wil);
+
rc = wmi_get_mgmt_retry(wil, &retry_short);
if (!rc) {
wiphy->retry_short = retry_short;
@@ -772,6 +774,25 @@
}
}
+void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
+{
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+
+ wil->keep_radio_on_during_sleep =
+ wil->platform_ops.keep_radio_on_during_sleep &&
+ wil->platform_ops.keep_radio_on_during_sleep(
+ wil->platform_handle) &&
+ test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
+
+ wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
+ wil->keep_radio_on_during_sleep);
+
+ if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ else
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+}
+
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
le32_to_cpus(&r->base);
@@ -1080,14 +1101,14 @@
return rc;
}
+ wil_collect_fw_info(wil);
+
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
wil_ps_update(wil, wil->ps_profile);
if (wil->tt_data_set)
wmi_set_tt_cfg(wil, &wil->tt_data);
- wil_collect_fw_info(wil);
-
if (wil->platform_ops.notify) {
rc = wil->platform_ops.notify(wil->platform_handle,
WIL_PLATFORM_EVT_FW_RDY);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 42a5235..5432b31 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -84,9 +84,7 @@
/* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, wil->wil_fw_name, false);
-
- if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
- wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wil_refresh_fw_capabilities(wil);
}
void wil_disable_irq(struct wil6210_priv *wil)
@@ -289,15 +287,6 @@
wil_set_capabilities(wil);
wil6210_clear_irq(wil);
- wil->keep_radio_on_during_sleep =
- wil->platform_ops.keep_radio_on_during_sleep &&
- wil->platform_ops.keep_radio_on_during_sleep(
- wil->platform_handle) &&
- test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
-
- wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
- wil->keep_radio_on_during_sleep);
-
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index d5b8ea6..1c13b0b 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -870,6 +870,7 @@
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
int __wil_down(struct wil6210_priv *wil);
+void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
void wil_set_ethtoolops(struct net_device *ndev);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b85398c..261a0da 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5419,6 +5419,7 @@
struct ieee80211_supported_band *band;
struct brcmf_bss_info_le *bi;
struct brcmu_chan ch;
+ struct cfg80211_roam_info roam_info = {};
u32 freq;
s32 err = 0;
u8 *buf;
@@ -5457,9 +5458,15 @@
done:
kfree(buf);
- cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+
+ roam_info.channel = notify_channel;
+ roam_info.bssid = profile->bssid;
+ roam_info.req_ie = conn_info->req_ie;
+ roam_info.req_ie_len = conn_info->req_ie_len;
+ roam_info.resp_ie = conn_info->resp_ie;
+ roam_info.resp_ie_len = conn_info->resp_ie_len;
+
+ cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
brcmf_dbg(CONN, "Report roaming result\n");
set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 8744b9b..8e3c6f4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4161,11 +4161,6 @@
goto fail;
}
- /* allocate scatter-gather table. sg support
- * will be disabled upon allocation failure.
- */
- brcmf_sdiod_sgtable_alloc(bus->sdiodev);
-
/* Query the F2 block size, set roundup accordingly */
bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
bus->roundup = min(max_roundup, bus->blocksize);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
index 4b97371..838946d 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
@@ -1190,11 +1190,11 @@
next_reclaimed;
IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
next_reclaimed);
+ iwlagn_check_ratid_empty(priv, sta_id, tid);
}
iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
- iwlagn_check_ratid_empty(priv, sta_id, tid);
freed = 0;
/* process frames */
diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c
index 257a9ea..4ac6764 100644
--- a/drivers/net/wireless/intersil/p54/fwio.c
+++ b/drivers/net/wireless/intersil/p54/fwio.c
@@ -488,7 +488,7 @@
entry += sizeof(__le16);
chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memset(chan->curve_data, 0, sizeof(chan->curve_data));
memcpy(chan->curve_data, entry,
sizeof(struct p54_pa_curve_data_sample) *
min((u8)8, curve_data->points_per_channel));
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..280196a 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2830,15 +2830,22 @@
}
if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- if (!roamed)
+ if (!roamed) {
cfg80211_connect_result(usbdev->net, bssid, req_ie,
req_ie_len, resp_ie,
resp_ie_len, 0, GFP_KERNEL);
- else
- cfg80211_roamed(usbdev->net,
- get_current_channel(usbdev, NULL),
- bssid, req_ie, req_ie_len,
- resp_ie, resp_ie_len, GFP_KERNEL);
+ } else {
+ struct cfg80211_roam_info roam_info = {
+ .channel = get_current_channel(usbdev, NULL),
+ .bssid = bssid,
+ .req_ie = req_ie,
+ .req_ie_len = req_ie_len,
+ .resp_ie = resp_ie,
+ .resp_ie_len = resp_ie_len,
+ };
+
+ cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL);
+ }
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid,
get_current_channel(usbdev, NULL),
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index bbf7604..1c539c8 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1571,6 +1571,7 @@
wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
+ spin_lock_init(&wl->wl_lock);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 3ce1f7d..cb7365b 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -199,6 +199,7 @@
unsigned long remaining_credit;
struct timer_list credit_timeout;
u64 credit_window_start;
+ bool rate_limited;
/* Statistics */
struct xenvif_stats stats;
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index b009d79..5bfaf55 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -105,7 +105,11 @@
if (work_done < budget) {
napi_complete(napi);
- xenvif_napi_schedule_or_enable_events(queue);
+ /* If the queue is rate-limited, it shall be
+ * rescheduled in the timer callback.
+ */
+ if (likely(!queue->rate_limited))
+ xenvif_napi_schedule_or_enable_events(queue);
}
return work_done;
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 47b4810..d9b5b73 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -179,6 +179,7 @@
max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
queue->remaining_credit = min(max_credit, max_burst);
+ queue->rate_limited = false;
}
void xenvif_tx_credit_callback(unsigned long data)
@@ -685,8 +686,10 @@
msecs_to_jiffies(queue->credit_usec / 1000);
/* Timer could already be pending in rare cases. */
- if (timer_pending(&queue->credit_timeout))
+ if (timer_pending(&queue->credit_timeout)) {
+ queue->rate_limited = true;
return true;
+ }
/* Passed the point where we can replenish credit? */
if (time_after_eq64(now, next_credit)) {
@@ -701,6 +704,7 @@
mod_timer(&queue->credit_timeout,
next_credit);
queue->credit_window_start = next_credit;
+ queue->rate_limited = true;
return true;
}
diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c
index 712936f..fbd26ec 100644
--- a/drivers/nfc/fdp/i2c.c
+++ b/drivers/nfc/fdp/i2c.c
@@ -177,6 +177,16 @@
/* Packet that contains a length */
if (tmp[0] == 0 && tmp[1] == 0) {
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
+ /*
+ * Ensure next_read_size does not exceed sizeof(tmp)
+ * for reading that many bytes during next iteration
+ */
+ if (phy->next_read_size > FDP_NCI_I2C_MAX_PAYLOAD) {
+ dev_dbg(&client->dev, "%s: corrupted packet\n",
+ __func__);
+ phy->next_read_size = 5;
+ goto flush;
+ }
} else {
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
diff --git a/drivers/nfc/st21nfca/dep.c b/drivers/nfc/st21nfca/dep.c
index 798a32b..2062852 100644
--- a/drivers/nfc/st21nfca/dep.c
+++ b/drivers/nfc/st21nfca/dep.c
@@ -217,7 +217,8 @@
atr_req = (struct st21nfca_atr_req *)skb->data;
- if (atr_req->length < sizeof(struct st21nfca_atr_req)) {
+ if (atr_req->length < sizeof(struct st21nfca_atr_req) ||
+ atr_req->length > skb->len) {
r = -EPROTO;
goto exit;
}
diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c
index 3a98563..6e84e12 100644
--- a/drivers/nfc/st21nfca/se.c
+++ b/drivers/nfc/st21nfca/se.c
@@ -320,23 +320,33 @@
* AID 81 5 to 16
* PARAMETERS 82 0 to 255
*/
- if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
+ if (skb->len < NFC_MIN_AID_LENGTH + 2 ||
skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
return -EPROTO;
+ /*
+ * Buffer should have enough space for at least
+ * two tag fields + two length fields + aid_len (skb->data[1])
+ */
+ if (skb->len < skb->data[1] + 4)
+ return -EPROTO;
+
transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
skb->len - 2, GFP_KERNEL);
transaction->aid_len = skb->data[1];
memcpy(transaction->aid, &skb->data[2],
transaction->aid_len);
-
- /* Check next byte is PARAMETERS tag (82) */
- if (skb->data[transaction->aid_len + 2] !=
- NFC_EVT_TRANSACTION_PARAMS_TAG)
- return -EPROTO;
-
transaction->params_len = skb->data[transaction->aid_len + 3];
+
+ /* Check next byte is PARAMETERS tag (82) and the length field */
+ if (skb->data[transaction->aid_len + 2] !=
+ NFC_EVT_TRANSACTION_PARAMS_TAG ||
+ skb->len < transaction->aid_len + transaction->params_len + 4) {
+ devm_kfree(dev, transaction);
+ return -EPROTO;
+ }
+
memcpy(transaction->params, skb->data +
transaction->aid_len + 4, transaction->params_len);
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index c234ee43..24222a5 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -176,14 +176,12 @@
u64 rx_err_ver;
u64 rx_memcpy;
u64 rx_async;
- u64 dma_rx_prep_err;
u64 tx_bytes;
u64 tx_pkts;
u64 tx_ring_full;
u64 tx_err_no_buf;
u64 tx_memcpy;
u64 tx_async;
- u64 dma_tx_prep_err;
};
struct ntb_transport_mw {
@@ -256,8 +254,6 @@
#define QP_TO_MW(nt, qp) ((qp) % nt->mw_count)
#define NTB_QP_DEF_NUM_ENTRIES 100
#define NTB_LINK_DOWN_TIMEOUT 10
-#define DMA_RETRIES 20
-#define DMA_OUT_RESOURCE_TO msecs_to_jiffies(50)
static void ntb_transport_rxc_db(unsigned long data);
static const struct ntb_ctx_ops ntb_transport_ops;
@@ -518,12 +514,6 @@
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"free tx - \t%u\n",
ntb_transport_tx_free_entry(qp));
- out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "DMA tx prep err - \t%llu\n",
- qp->dma_tx_prep_err);
- out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "DMA rx prep err - \t%llu\n",
- qp->dma_rx_prep_err);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"\n");
@@ -625,7 +615,7 @@
if (!mw->virt_addr)
return -ENOMEM;
- if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+ if (mw_num < qp_count % mw_count)
num_qps_mw = qp_count / mw_count + 1;
else
num_qps_mw = qp_count / mw_count;
@@ -770,8 +760,6 @@
qp->tx_err_no_buf = 0;
qp->tx_memcpy = 0;
qp->tx_async = 0;
- qp->dma_tx_prep_err = 0;
- qp->dma_rx_prep_err = 0;
}
static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
@@ -933,10 +921,8 @@
ntb_free_mw(nt, i);
/* if there's an actual failure, we should just bail */
- if (rc < 0) {
- ntb_link_disable(ndev);
+ if (rc < 0)
return;
- }
out:
if (ntb_link_is_up(ndev, NULL, NULL) == 1)
@@ -1002,7 +988,7 @@
qp->event_handler = NULL;
ntb_qp_link_down_reset(qp);
- if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+ if (mw_num < qp_count % mw_count)
num_qps_mw = qp_count / mw_count + 1;
else
num_qps_mw = qp_count / mw_count;
@@ -1125,8 +1111,8 @@
qp_count = ilog2(qp_bitmap);
if (max_num_clients && max_num_clients < qp_count)
qp_count = max_num_clients;
- else if (mw_count < qp_count)
- qp_count = mw_count;
+ else if (nt->mw_count < qp_count)
+ qp_count = nt->mw_count;
qp_bitmap &= BIT_ULL(qp_count) - 1;
@@ -1314,7 +1300,6 @@
struct dmaengine_unmap_data *unmap;
dma_cookie_t cookie;
void *buf = entry->buf;
- int retries = 0;
len = entry->len;
device = chan->device;
@@ -1343,22 +1328,11 @@
unmap->from_cnt = 1;
- for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan,
- unmap->addr[1],
- unmap->addr[0], len,
- DMA_PREP_INTERRUPT);
- if (txd)
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(DMA_OUT_RESOURCE_TO);
- }
-
- if (!txd) {
- qp->dma_rx_prep_err++;
+ txd = device->device_prep_dma_memcpy(chan, unmap->addr[1],
+ unmap->addr[0], len,
+ DMA_PREP_INTERRUPT);
+ if (!txd)
goto err_get_unmap;
- }
txd->callback_result = ntb_rx_copy_callback;
txd->callback_param = entry;
@@ -1603,7 +1577,6 @@
struct dmaengine_unmap_data *unmap;
dma_addr_t dest;
dma_cookie_t cookie;
- int retries = 0;
device = chan->device;
dest = qp->tx_mw_phys + qp->tx_max_frame * entry->tx_index;
@@ -1625,21 +1598,10 @@
unmap->to_cnt = 1;
- for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan, dest,
- unmap->addr[0], len,
- DMA_PREP_INTERRUPT);
- if (txd)
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(DMA_OUT_RESOURCE_TO);
- }
-
- if (!txd) {
- qp->dma_tx_prep_err++;
+ txd = device->device_prep_dma_memcpy(chan, dest, unmap->addr[0], len,
+ DMA_PREP_INTERRUPT);
+ if (!txd)
goto err_get_unmap;
- }
txd->callback_result = ntb_tx_copy_callback;
txd->callback_param = entry;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 5c63b92..ed92c12 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -956,7 +956,7 @@
dino_dev->hba.dev = dev;
dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
- dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */
+ dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
spin_lock_init(&dino_dev->dinosaur_pen);
dino_dev->hba.iommu = ccio_get_iommu(dev);
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
index 9931be6..04d6fd2 100644
--- a/drivers/pinctrl/intel/pinctrl-merrifield.c
+++ b/drivers/pinctrl/intel/pinctrl-merrifield.c
@@ -343,9 +343,9 @@
static const unsigned int mrfld_sdio_pins[] = { 50, 51, 52, 53, 54, 55, 56 };
static const unsigned int mrfld_spi5_pins[] = { 90, 91, 92, 93, 94, 95, 96 };
-static const unsigned int mrfld_uart0_pins[] = { 124, 125, 126, 127 };
-static const unsigned int mrfld_uart1_pins[] = { 128, 129, 130, 131 };
-static const unsigned int mrfld_uart2_pins[] = { 132, 133, 134, 135 };
+static const unsigned int mrfld_uart0_pins[] = { 115, 116, 117, 118 };
+static const unsigned int mrfld_uart1_pins[] = { 119, 120, 121, 122 };
+static const unsigned int mrfld_uart2_pins[] = { 123, 124, 125, 126 };
static const unsigned int mrfld_pwm0_pins[] = { 144 };
static const unsigned int mrfld_pwm1_pins[] = { 145 };
static const unsigned int mrfld_pwm2_pins[] = { 132 };
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index c3928aa..7511723 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -85,6 +85,7 @@
MESON_PIN(GPIODV_15, EE_OFF),
MESON_PIN(GPIODV_16, EE_OFF),
MESON_PIN(GPIODV_17, EE_OFF),
+ MESON_PIN(GPIODV_18, EE_OFF),
MESON_PIN(GPIODV_19, EE_OFF),
MESON_PIN(GPIODV_20, EE_OFF),
MESON_PIN(GPIODV_21, EE_OFF),
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index d32fa2b..e8aee6d 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -195,8 +195,6 @@
spin_unlock_irqrestore(&bank->slock, flags);
- exynos_irq_unmask(irqd);
-
return 0;
}
@@ -217,8 +215,6 @@
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
- exynos_irq_mask(irqd);
-
spin_lock_irqsave(&bank->slock, flags);
con = readl(d->virt_base + reg_con);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
index 862a096..be5c71d 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
@@ -811,6 +811,7 @@
SUNXI_FUNCTION(0x2, "lcd1"), /* D16 */
SUNXI_FUNCTION(0x3, "pata"), /* ATAD12 */
SUNXI_FUNCTION(0x4, "keypad"), /* IN6 */
+ SUNXI_FUNCTION(0x5, "sim"), /* DET */
SUNXI_FUNCTION_IRQ(0x6, 16), /* EINT16 */
SUNXI_FUNCTION(0x7, "csi1")), /* D16 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
index 77a0236..b190904 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
@@ -508,57 +508,71 @@
static const int usb1_muxvals[] = {0, 0};
static const unsigned usb2_pins[] = {50, 51};
static const int usb2_muxvals[] = {0, 0};
-static const unsigned port_range_pins[] = {
+static const unsigned port_range0_pins[] = {
159, 160, 161, 162, 163, 164, 165, 166, /* PORT0x */
0, 1, 2, 3, 4, 5, 6, 7, /* PORT1x */
8, 9, 10, 11, 12, 13, 14, 15, /* PORT2x */
- 16, 17, 18, -1, -1, -1, -1, -1, /* PORT3x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT4x */
- -1, -1, -1, 46, 47, 48, 49, 50, /* PORT5x */
- 51, -1, -1, 54, 55, 56, 57, 58, /* PORT6x */
+ 16, 17, 18, /* PORT30-32 */
+};
+static const int port_range0_muxvals[] = {
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
+ 15, 15, 15, /* PORT30-32 */
+};
+static const unsigned port_range1_pins[] = {
+ 46, 47, 48, 49, 50, /* PORT53-57 */
+ 51, /* PORT60 */
+};
+static const int port_range1_muxvals[] = {
+ 15, 15, 15, 15, 15, /* PORT53-57 */
+ 15, /* PORT60 */
+};
+static const unsigned port_range2_pins[] = {
+ 54, 55, 56, 57, 58, /* PORT63-67 */
59, 60, 69, 70, 71, 72, 73, 74, /* PORT7x */
75, 76, 77, 78, 79, 80, 81, 82, /* PORT8x */
83, 84, 85, 86, 87, 88, 89, 90, /* PORT9x */
91, 92, 93, 94, 95, 96, 97, 98, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
- 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
- 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
- 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
- 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
- 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
- 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
- 139, 140, 141, 142, -1, -1, -1, -1, /* PORT22x */
- 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
- 155, 156, 157, 143, 144, 145, 146, 158, /* PORT24x */
};
-static const int port_range_muxvals[] = {
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
- 15, 15, 15, -1, -1, -1, -1, -1, /* PORT3x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT4x */
- -1, -1, -1, 15, 15, 15, 15, 15, /* PORT5x */
- 15, -1, -1, 15, 15, 15, 15, 15, /* PORT6x */
+static const int port_range2_muxvals[] = {
+ 15, 15, 15, 15, 15, /* PORT63-67 */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
+};
+static const unsigned port_range3_pins[] = {
+ 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
+ 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
+ 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
+};
+static const int port_range3_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
+};
+static const unsigned port_range4_pins[] = {
+ 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
+};
+static const int port_range4_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
+};
+static const unsigned port_range5_pins[] = {
+ 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
+ 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
+ 139, 140, 141, 142, /* PORT220-223 */
+};
+static const int port_range5_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */
- 15, 15, 15, 15, -1, -1, -1, -1, /* PORT22x */
+ 15, 15, 15, 15, /* PORT220-223 */
+};
+static const unsigned port_range6_pins[] = {
+ 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
+ 155, 156, 157, 143, 144, 145, 146, 158, /* PORT24x */
+};
+static const int port_range6_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */
};
@@ -607,147 +621,153 @@
UNIPHIER_PINCTRL_GROUP(usb0),
UNIPHIER_PINCTRL_GROUP(usb1),
UNIPHIER_PINCTRL_GROUP(usb2),
- UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range4),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range5),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range6),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range1, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range1, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range1, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range1, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range1, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range1, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range2, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range2, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range2, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range2, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range2, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range2, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range2, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range2, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range2, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range2, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range2, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range2, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range2, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range2, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range2, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range2, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range2, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range2, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range2, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range2, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range2, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range2, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range2, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range2, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range2, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range2, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range2, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range2, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range2, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range2, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range2, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range2, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range2, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range2, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range2, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range2, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range2, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range3, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range3, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range3, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range3, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range3, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range3, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range3, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range3, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range3, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range3, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range3, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range3, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range3, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range3, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range3, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range3, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range3, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range3, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range3, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range3, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range3, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range3, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range3, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range3, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range4, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range4, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range4, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range4, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range4, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range4, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range4, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range4, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range5, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range5, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range5, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range5, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range5, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range5, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range5, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range5, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range5, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range5, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range5, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range5, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range5, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range5, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range5, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range5, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range5, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range5, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range5, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range5, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range6, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range6, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range6, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range6, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range6, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range6, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range6, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range6, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range6, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range6, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range6, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range6, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range6, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range6, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range6, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range6, 15),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
index 9668633..73b828b 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
@@ -597,7 +597,7 @@
static const int usb2_muxvals[] = {0, 0};
static const unsigned usb3_pins[] = {52, 53};
static const int usb3_muxvals[] = {0, 0};
-static const unsigned port_range_pins[] = {
+static const unsigned port_range0_pins[] = {
168, 169, 170, 171, 172, 173, 174, 175, /* PORT0x */
0, 1, 2, 3, 4, 5, 6, 7, /* PORT1x */
8, 9, 10, 11, 12, 13, 14, 15, /* PORT2x */
@@ -609,23 +609,8 @@
75, 76, 77, 78, 79, 80, 81, 82, /* PORT8x */
83, 84, 85, 86, 87, 88, 89, 90, /* PORT9x */
91, 92, 93, 94, 95, 96, 97, 98, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
- 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
- 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
- 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
- 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
- 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
- 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
- 139, 140, 141, 142, 143, 144, 145, 146, /* PORT22x */
- 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
- 155, 156, 157, 158, 159, 160, 161, 162, /* PORT24x */
- 163, 164, 165, 166, 167, /* PORT25x */
};
-static const int port_range_muxvals[] = {
+static const int port_range0_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
@@ -637,21 +622,38 @@
15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
+};
+static const unsigned port_range1_pins[] = {
+ 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
+ 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
+ 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
+};
+static const int port_range1_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
+};
+static const unsigned port_range2_pins[] = {
+ 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
+};
+static const int port_range2_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
+};
+static const unsigned port_range3_pins[] = {
+ 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
+ 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
+ 139, 140, 141, 142, 143, 144, 145, 146, /* PORT22x */
+ 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
+ 155, 156, 157, 158, 159, 160, 161, 162, /* PORT24x */
+ 163, 164, 165, 166, 167, /* PORT250-254 */
+};
+static const int port_range3_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */
- 15, 15, 15, 15, 15, /* PORT25x */
+ 15, 15, 15, 15, 15, /* PORT250-254 */
};
static const unsigned xirq_pins[] = {
149, 150, 151, 152, 153, 154, 155, 156, /* XIRQ0-7 */
@@ -695,174 +697,177 @@
UNIPHIER_PINCTRL_GROUP(usb1),
UNIPHIER_PINCTRL_GROUP(usb2),
UNIPHIER_PINCTRL_GROUP(usb3),
- UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range, 27),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range, 28),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range, 29),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range, 30),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range, 31),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range, 32),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range, 33),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range, 34),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range, 35),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range, 36),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range, 37),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range, 38),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range, 39),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range, 40),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range, 41),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range, 42),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range, 49),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range, 50),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range, 180),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range, 181),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range, 182),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range, 183),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range, 200),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range, 201),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range, 202),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range, 203),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range, 204),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range2, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range2, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range2, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range2, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range2, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range2, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range2, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range2, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range3, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range3, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range3, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range3, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range3, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range3, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range3, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range3, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range3, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range3, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range3, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range3, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range3, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range3, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range3, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range3, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range3, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range3, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range3, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range3, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range3, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range3, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range3, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range3, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range3, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range3, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range3, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range3, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range3, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range3, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range3, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range3, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range3, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range3, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range3, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range3, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range3, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range3, 37),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range3, 38),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range3, 39),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range3, 40),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range3, 41),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range3, 42),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range3, 43),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range3, 44),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index f5f783c..c02881b 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -2598,15 +2598,16 @@
if (curr == GSI_CHAN_MODE_CALLBACK &&
mode == GSI_CHAN_MODE_POLL) {
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
+ atomic_set(&ctx->poll_mode, mode);
ctx->stats.callback_to_poll++;
}
if (curr == GSI_CHAN_MODE_POLL &&
mode == GSI_CHAN_MODE_CALLBACK) {
+ atomic_set(&ctx->poll_mode, mode);
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
ctx->stats.poll_to_callback++;
}
- atomic_set(&ctx->poll_mode, mode);
spin_unlock_irqrestore(&gsi_ctx->slock, flags);
return GSI_STATUS_SUCCESS;
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index 105294a..2975192 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -19,6 +19,8 @@
#include <linux/sched.h>
#include <linux/atomic.h>
#include <linux/ecm_ipa.h>
+#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define DRIVER_NAME "ecm_ipa"
#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
@@ -120,6 +122,7 @@
* @usb_to_ipa_client: producer client
* @ipa_rm_resource_name_prod: IPA resource manager producer resource
* @ipa_rm_resource_name_cons: IPA resource manager consumer resource
+ * @pm_hdl: handle for IPA PM
*/
struct ecm_ipa_dev {
struct net_device *net;
@@ -137,6 +140,7 @@
enum ipa_client_type usb_to_ipa_client;
enum ipa_rm_resource_name ipa_rm_resource_name_prod;
enum ipa_rm_resource_name ipa_rm_resource_name_cons;
+ u32 pm_hdl;
};
static int ecm_ipa_open(struct net_device *net);
@@ -158,6 +162,8 @@
static struct net_device_stats *ecm_ipa_get_stats(struct net_device *net);
static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_destroy_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
+static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
static netdev_tx_t ecm_ipa_start_xmit
@@ -403,27 +409,34 @@
ECM_IPA_DEBUG("usb_to_ipa_client = %d\n",
ecm_ipa_ctx->usb_to_ipa_client);
- ecm_ipa_ctx->ipa_rm_resource_name_cons =
- ipa_get_rm_resource_from_ep(ipa_to_usb_hdl);
- if (ecm_ipa_ctx->ipa_rm_resource_name_cons < 0) {
- ECM_IPA_ERROR("Error getting CONS RM resource from handle %d\n",
+ if (ipa_pm_is_used()) {
+ retval = ecm_ipa_register_pm_client(ecm_ipa_ctx);
+ } else {
+ ecm_ipa_ctx->ipa_rm_resource_name_cons =
+ ipa_get_rm_resource_from_ep(ipa_to_usb_hdl);
+ if (ecm_ipa_ctx->ipa_rm_resource_name_cons < 0) {
+ ECM_IPA_ERROR(
+ "Error getting CONS RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_cons);
+ return -EINVAL;
+ }
+ ECM_IPA_DEBUG("ipa_rm_resource_name_cons = %d\n",
ecm_ipa_ctx->ipa_rm_resource_name_cons);
- return -EINVAL;
- }
- ECM_IPA_DEBUG("ipa_rm_resource_name_cons = %d\n",
- ecm_ipa_ctx->ipa_rm_resource_name_cons);
- ecm_ipa_ctx->ipa_rm_resource_name_prod =
- ipa_get_rm_resource_from_ep(usb_to_ipa_hdl);
- if (ecm_ipa_ctx->ipa_rm_resource_name_prod < 0) {
- ECM_IPA_ERROR("Error getting PROD RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_prod =
+ ipa_get_rm_resource_from_ep(usb_to_ipa_hdl);
+ if (ecm_ipa_ctx->ipa_rm_resource_name_prod < 0) {
+ ECM_IPA_ERROR(
+ "Error getting PROD RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_prod);
+ return -EINVAL;
+ }
+ ECM_IPA_DEBUG("ipa_rm_resource_name_prod = %d\n",
ecm_ipa_ctx->ipa_rm_resource_name_prod);
- return -EINVAL;
- }
- ECM_IPA_DEBUG("ipa_rm_resource_name_prod = %d\n",
- ecm_ipa_ctx->ipa_rm_resource_name_prod);
- retval = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
+ retval = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
+ }
+
if (retval) {
ECM_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -488,7 +501,10 @@
fail:
ecm_ipa_deregister_properties();
fail_create_rm:
- ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
+ if (ipa_pm_is_used())
+ ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
+ else
+ ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
return retval;
}
EXPORT_SYMBOL(ecm_ipa_connect);
@@ -746,7 +762,10 @@
netif_stop_queue(ecm_ipa_ctx->net);
ECM_IPA_DEBUG("queue stopped\n");
- ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
+ if (ipa_pm_is_used())
+ ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
+ else
+ ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
outstanding_dropped_pkts =
atomic_read(&ecm_ipa_ctx->outstanding_pkts);
@@ -1117,15 +1136,65 @@
ECM_IPA_LOG_EXIT();
}
+static void ecm_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ecm_ipa_dev *ecm_ipa_ctx = p;
+
+ ECM_IPA_LOG_ENTRY();
+ if (event != IPA_PM_CLIENT_ACTIVATED) {
+ ECM_IPA_ERROR("unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ if (netif_queue_stopped(ecm_ipa_ctx->net)) {
+ ECM_IPA_DEBUG("Resource Granted - starting queue\n");
+ netif_start_queue(ecm_ipa_ctx->net);
+ }
+ ECM_IPA_LOG_EXIT();
+}
+
+static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = ecm_ipa_ctx->net->name;
+ pm_reg.user_data = ecm_ipa_ctx;
+ pm_reg.callback = ecm_ipa_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &ecm_ipa_ctx->pm_hdl);
+ if (result) {
+ ECM_IPA_ERROR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
+{
+ ipa_pm_deactivate_sync(ecm_ipa_ctx->pm_hdl);
+ ipa_pm_deregister(ecm_ipa_ctx->pm_hdl);
+ ecm_ipa_ctx->pm_hdl = ~0;
+}
+
static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
{
+ if (ipa_pm_is_used())
+ return ipa_pm_activate(ecm_ipa_ctx->pm_hdl);
+
return ipa_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_STD_ECM_PROD);
}
static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+ if (ipa_pm_is_used())
+ ipa_pm_deferred_deactivate(ecm_ipa_ctx->pm_hdl);
+ else
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_STD_ECM_PROD);
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index 9b3b53d..4d3113f 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -19,6 +19,7 @@
#include <linux/ipa_qmi_service_v01.h>
#include <linux/ipa_mhi.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define IPA_MHI_DRV_NAME "ipa_mhi_client"
#define IPA_MHI_DBG(fmt, args...) \
@@ -136,6 +137,8 @@
u32 use_ipadma;
bool assert_bit40;
bool test_mode;
+ u32 pm_hdl;
+ u32 modem_pm_hdl;
};
static struct ipa_mhi_client_ctx *ipa_mhi_client_ctx;
@@ -834,25 +837,38 @@
IPA_MHI_DBG("event_context_array_addr 0x%llx\n",
ipa_mhi_client_ctx->event_context_array_addr);
- /* Add MHI <-> Q6 dependencies to IPA RM */
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS) {
- IPA_MHI_ERR("failed to add dependency %d\n", res);
- goto fail_add_mhi_q6_dep;
- }
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("failed activate client %d\n", res);
+ goto fail_pm_activate;
+ }
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("failed activate modem client %d\n", res);
+ goto fail_pm_activate_modem;
+ }
+ } else {
+ /* Add MHI <-> Q6 dependencies to IPA RM */
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res && res != -EINPROGRESS) {
+ IPA_MHI_ERR("failed to add dependency %d\n", res);
+ goto fail_add_mhi_q6_dep;
+ }
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
- if (res && res != -EINPROGRESS) {
- IPA_MHI_ERR("failed to add dependency %d\n", res);
- goto fail_add_q6_mhi_dep;
- }
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
+ if (res && res != -EINPROGRESS) {
+ IPA_MHI_ERR("failed to add dependency %d\n", res);
+ goto fail_add_q6_mhi_dep;
+ }
- res = ipa_mhi_request_prod();
- if (res) {
- IPA_MHI_ERR("failed request prod %d\n", res);
- goto fail_request_prod;
+ res = ipa_mhi_request_prod();
+ if (res) {
+ IPA_MHI_ERR("failed request prod %d\n", res);
+ goto fail_request_prod;
+ }
}
/* gsi params */
@@ -880,14 +896,23 @@
return 0;
fail_init_engine:
- ipa_mhi_release_prod();
+ if (!ipa_pm_is_used())
+ ipa_mhi_release_prod();
fail_request_prod:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
fail_add_q6_mhi_dep:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
fail_add_mhi_q6_dep:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_pm_activate_modem:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_pm_activate:
ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
return res;
}
@@ -2095,20 +2120,32 @@
*/
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
- IPA_MHI_DBG("release prod\n");
- res = ipa_mhi_release_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
- goto fail_release_prod;
- }
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to deactivate client %d\n", res);
+ goto fail_deactivate_pm;
+ }
+ res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to deactivate client %d\n", res);
+ goto fail_deactivate_modem_pm;
+ }
+ } else {
+ IPA_MHI_DBG("release prod\n");
+ res = ipa_mhi_release_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
+ goto fail_release_prod;
+ }
- IPA_MHI_DBG("wait for cons release\n");
- res = ipa_mhi_wait_for_cons_release();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n", res);
- goto fail_release_cons;
+ IPA_MHI_DBG("wait for cons release\n");
+ res = ipa_mhi_wait_for_cons_release();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed\n");
+ goto fail_release_cons;
+ }
}
-
usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
res = ipa_mhi_suspend_dl(force);
@@ -2132,8 +2169,15 @@
fail_suspend_dl_channel:
fail_release_cons:
+ if (!ipa_pm_is_used())
ipa_mhi_request_prod();
fail_release_prod:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_deactivate_modem_pm:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_deactivate_pm:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
fail_suspend_ul_channel:
ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels);
@@ -2193,10 +2237,23 @@
ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
}
- res = ipa_mhi_request_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
- goto fail_request_prod;
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to activate client %d\n", res);
+ goto fail_pm_activate;
+ }
+ ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to activate client %d\n", res);
+ goto fail_pm_activate_modem;
+ }
+ } else {
+ res = ipa_mhi_request_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
+ goto fail_request_prod;
+ }
}
/* resume all UL channels */
@@ -2234,8 +2291,15 @@
fail_resume_dl_channels2:
ipa_mhi_suspend_channels(ipa_mhi_client_ctx->ul_channels);
fail_resume_ul_channels:
- ipa_mhi_release_prod();
+ if (!ipa_pm_is_used())
+ ipa_mhi_release_prod();
fail_request_prod:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_pm_activate_modem:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_pm_activate:
ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
fail_resume_dl_channels:
ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
@@ -2319,6 +2383,85 @@
debugfs_remove_recursive(dent);
}
+static void ipa_mhi_delete_rm_resources(void)
+{
+ int res;
+
+ if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED &&
+ ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {
+
+ IPA_MHI_DBG("release prod\n");
+ res = ipa_mhi_release_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n",
+ res);
+ goto fail;
+ }
+ IPA_MHI_DBG("wait for cons release\n");
+ res = ipa_mhi_wait_for_cons_release();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_wait_for_cons_release%d\n",
+ res);
+ goto fail;
+ }
+
+ usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
+ IPA_MHI_SUSPEND_SLEEP_MAX);
+
+ IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR(
+ "Error deleting dependency %d->%d, res=%d\n",
+ IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS,
+ res);
+ goto fail;
+ }
+ IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res) {
+ IPA_MHI_ERR(
+ "Error deleting dependency %d->%d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS,
+ res);
+ goto fail;
+ }
+ }
+
+ res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+ if (res) {
+ IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_PROD, res);
+ goto fail;
+ }
+
+ res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_CONS, res);
+ goto fail;
+ }
+
+ return;
+fail:
+ ipa_assert();
+}
+
+static void ipa_mhi_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+ ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
+ ipa_mhi_client_ctx->pm_hdl = ~0;
+
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ ipa_pm_deregister(ipa_mhi_client_ctx->modem_pm_hdl);
+ ipa_mhi_client_ctx->modem_pm_hdl = ~0;
+}
+
/**
* ipa_mhi_destroy() - Destroy MHI IPA
*
@@ -2351,62 +2494,10 @@
ipa_uc_mhi_cleanup();
}
-
- if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED &&
- ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {
- IPA_MHI_DBG("release prod\n");
- res = ipa_mhi_release_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
- goto fail;
- }
- IPA_MHI_DBG("wait for cons release\n");
- res = ipa_mhi_wait_for_cons_release();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n",
- res);
- goto fail;
- }
- usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
- IPA_MHI_SUSPEND_SLEEP_MAX);
-
- IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
- if (res) {
- IPA_MHI_ERR(
- "Error deleting dependency %d->%d, res=%d\n"
- , IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS,
- res);
- goto fail;
- }
- IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res) {
- IPA_MHI_ERR(
- "Error deleting dependency %d->%d, res=%d\n",
- IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS,
- res);
- goto fail;
- }
- }
-
- res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
- if (res) {
- IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
- IPA_RM_RESOURCE_MHI_PROD, res);
- goto fail;
- }
-
- res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
- if (res) {
- IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
- IPA_RM_RESOURCE_MHI_CONS, res);
- goto fail;
- }
+ if (ipa_pm_is_used())
+ ipa_mhi_deregister_pm();
+ else
+ ipa_mhi_delete_rm_resources();
ipa_mhi_debugfs_destroy();
destroy_workqueue(ipa_mhi_client_ctx->wq);
@@ -2420,6 +2511,132 @@
ipa_assert();
}
+static void ipa_mhi_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ unsigned long flags;
+
+ IPA_MHI_FUNC_ENTRY();
+
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ IPA_MHI_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa_mhi_client_ctx->state));
+ spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+ if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED) {
+ ipa_mhi_notify_wakeup();
+ } else if (ipa_mhi_client_ctx->state ==
+ IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
+ /* wakeup event will be trigger after suspend finishes */
+ ipa_mhi_client_ctx->trigger_wakeup = true;
+ }
+ spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+ IPA_MHI_DBG("EXIT");
+}
+
+static int ipa_mhi_register_pm(void)
+{
+ int res;
+ struct ipa_pm_register_params params;
+
+ memset(¶ms, 0, sizeof(params));
+ params.name = "MHI";
+ params.callback = ipa_mhi_pm_cb;
+ params.group = IPA_PM_GROUP_DEFAULT;
+ res = ipa_pm_register(¶ms, &ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_associate_ipa_cons_to_client(ipa_mhi_client_ctx->pm_hdl,
+ IPA_CLIENT_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR("fail to associate cons with PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ res = ipa_pm_set_perf_profile(ipa_mhi_client_ctx->pm_hdl, 1000);
+ if (res) {
+ IPA_MHI_ERR("fail to set perf profile to PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ /* create a modem client for clock scaling */
+ memset(¶ms, 0, sizeof(params));
+ params.name = "MODEM (MHI)";
+ params.group = IPA_PM_GROUP_MODEM;
+ params.skip_clk_vote = true;
+ res = ipa_pm_register(¶ms, &ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to register with PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
+ ipa_mhi_client_ctx->pm_hdl = ~0;
+ return res;
+}
+
+static int ipa_mhi_create_rm_resources(void)
+{
+ int res;
+ struct ipa_rm_create_params mhi_prod_params;
+ struct ipa_rm_create_params mhi_cons_params;
+ struct ipa_rm_perf_profile profile;
+
+ /* Create PROD in IPA RM */
+ memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
+ mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
+ mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
+ mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
+ res = ipa_rm_create_resource(&mhi_prod_params);
+ if (res) {
+ IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
+ goto fail_create_rm_prod;
+ }
+
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = 1000;
+ res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
+ if (res) {
+ IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
+ goto fail_perf_rm_prod;
+ }
+
+ /* Create CONS in IPA RM */
+ memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
+ mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
+ mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
+ mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
+ mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
+ res = ipa_rm_create_resource(&mhi_cons_params);
+ if (res) {
+ IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
+ goto fail_create_rm_cons;
+ }
+
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = 1000;
+ res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
+ if (res) {
+ IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
+ goto fail_perf_rm_cons;
+ }
+fail_perf_rm_cons:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
+fail_create_rm_cons:
+fail_perf_rm_prod:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+fail_create_rm_prod:
+ return res;
+}
+
/**
* ipa_mhi_init() - Initialize IPA MHI driver
* @params: initialization params
@@ -2437,9 +2654,6 @@
int ipa_mhi_init(struct ipa_mhi_init_params *params)
{
int res;
- struct ipa_rm_create_params mhi_prod_params;
- struct ipa_rm_create_params mhi_cons_params;
- struct ipa_rm_perf_profile profile;
IPA_MHI_FUNC_ENTRY();
@@ -2500,43 +2714,14 @@
goto fail_create_wq;
}
- /* Create PROD in IPA RM */
- memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
- mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
- mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
- mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
- res = ipa_rm_create_resource(&mhi_prod_params);
+ if (ipa_pm_is_used())
+ res = ipa_mhi_register_pm();
+ else
+ res = ipa_mhi_create_rm_resources();
if (res) {
- IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
- goto fail_create_rm_prod;
- }
-
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = 1000;
- res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
- if (res) {
- IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
- goto fail_perf_rm_prod;
- }
-
- /* Create CONS in IPA RM */
- memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
- mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
- mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
- mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
- mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
- res = ipa_rm_create_resource(&mhi_cons_params);
- if (res) {
- IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
- goto fail_create_rm_cons;
- }
-
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = 1000;
- res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
- if (res) {
- IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
- goto fail_perf_rm_cons;
+ IPA_MHI_ERR("failed to create RM resources\n");
+ res = -EFAULT;
+ goto fail_rm;
}
/* Initialize uC interface */
@@ -2551,12 +2736,7 @@
IPA_MHI_FUNC_EXIT();
return 0;
-fail_perf_rm_cons:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
-fail_create_rm_cons:
-fail_perf_rm_prod:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
-fail_create_rm_prod:
+fail_rm:
destroy_workqueue(ipa_mhi_client_ctx->wq);
fail_create_wq:
kfree(ipa_mhi_client_ctx);
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
index a15a9d8..e19d297 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
@@ -13,6 +13,7 @@
#include <linux/ipa_uc_offload.h>
#include <linux/msm_ipa.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define IPA_NTN_DMA_POOL_ALIGNMENT 8
#define OFFLOAD_DRV_NAME "ipa_uc_offload"
@@ -69,6 +70,7 @@
char netdev_name[IPA_RESOURCE_NAME_MAX];
ipa_notify_cb notify;
struct completion ntn_completion;
+ u32 pm_hdl;
};
static struct ipa_uc_offload_ctx *ipa_uc_offload_ctx[IPA_UC_MAX_PROT_SIZE];
@@ -113,22 +115,53 @@
return 0;
}
-static int ipa_uc_offload_ntn_reg_intf(
- struct ipa_uc_offload_intf_params *inp,
- struct ipa_uc_offload_out_params *outp,
+static void ipa_uc_offload_ntn_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ /* suspend/resume is not supported */
+ IPA_UC_OFFLOAD_DBG("event = %d\n", event);
+}
+
+static int ipa_uc_offload_ntn_register_pm_client(
struct ipa_uc_offload_ctx *ntn_ctx)
{
- struct ipa_ioc_add_hdr *hdr = NULL;
- struct ipa_tx_intf tx;
- struct ipa_rx_intf rx;
- struct ipa_ioc_tx_intf_prop tx_prop[2];
- struct ipa_ioc_rx_intf_prop rx_prop[2];
- struct ipa_rm_create_params param;
- u32 len;
- int ret = 0;
+ int res;
+ struct ipa_pm_register_params params;
- IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
- inp->netdev_name);
+ memset(¶ms, 0, sizeof(params));
+ params.name = "ETH";
+ params.callback = ipa_uc_offload_ntn_pm_cb;
+ params.user_data = ntn_ctx;
+ params.group = IPA_PM_GROUP_DEFAULT;
+ res = ipa_pm_register(¶ms, &ntn_ctx->pm_hdl);
+ if (res) {
+ IPA_UC_OFFLOAD_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_associate_ipa_cons_to_client(ntn_ctx->pm_hdl,
+ IPA_CLIENT_ETHERNET_CONS);
+ if (res) {
+ IPA_UC_OFFLOAD_ERR("fail to associate cons with PM %d\n", res);
+ ipa_pm_deregister(ntn_ctx->pm_hdl);
+ ntn_ctx->pm_hdl = ~0;
+ return res;
+ }
+
+ return 0;
+}
+
+static void ipa_uc_offload_ntn_deregister_pm_client(
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
+ ipa_pm_deregister(ntn_ctx->pm_hdl);
+}
+static int ipa_uc_offload_ntn_create_rm_resources(
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ int ret;
+ struct ipa_rm_create_params param;
+
memset(¶m, 0, sizeof(param));
param.name = IPA_RM_RESOURCE_ETHERNET_PROD;
param.reg_params.user_data = ntn_ctx;
@@ -147,9 +180,37 @@
ret = ipa_rm_create_resource(¶m);
if (ret) {
IPA_UC_OFFLOAD_ERR("fail to create ETHERNET_CONS resource\n");
- goto fail_create_rm_cons;
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ return -EFAULT;
}
+ return 0;
+}
+
+static int ipa_uc_offload_ntn_reg_intf(
+ struct ipa_uc_offload_intf_params *inp,
+ struct ipa_uc_offload_out_params *outp,
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ struct ipa_ioc_add_hdr *hdr = NULL;
+ struct ipa_tx_intf tx;
+ struct ipa_rx_intf rx;
+ struct ipa_ioc_tx_intf_prop tx_prop[2];
+ struct ipa_ioc_rx_intf_prop rx_prop[2];
+ int ret = 0;
+ u32 len;
+
+
+ IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
+ inp->netdev_name);
+ if (ipa_pm_is_used())
+ ret = ipa_uc_offload_ntn_register_pm_client(ntn_ctx);
+ else
+ ret = ipa_uc_offload_ntn_create_rm_resources(ntn_ctx);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail to create rm resource\n");
+ return -EFAULT;
+ }
memcpy(ntn_ctx->netdev_name, inp->netdev_name, IPA_RESOURCE_NAME_MAX);
ntn_ctx->hdr_len = inp->hdr_info[0].hdr_len;
ntn_ctx->notify = inp->notify;
@@ -228,9 +289,12 @@
fail:
kfree(hdr);
fail_alloc:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS);
-fail_create_rm_cons:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (ipa_pm_is_used()) {
+ ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
+ } else {
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS);
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ }
return ret;
}
@@ -348,25 +412,34 @@
return -EINVAL;
}
- result = ipa_rm_add_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
- if (result) {
- IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n", result);
- return result;
- }
+ if (ipa_pm_is_used()) {
+ result = ipa_pm_activate_sync(ntn_ctx->pm_hdl);
+ if (result) {
+ IPA_UC_OFFLOAD_ERR("fail to activate: %d\n", result);
+ return result;
+ }
+ } else {
+ result = ipa_rm_add_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ if (result) {
+ IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n",
+ result);
+ return result;
+ }
- result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
- if (result == -EINPROGRESS) {
- if (wait_for_completion_timeout(&ntn_ctx->ntn_completion,
- 10*HZ) == 0) {
- IPA_UC_OFFLOAD_ERR("ETH_PROD resource req time out\n");
+ result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (result == -EINPROGRESS) {
+ if (wait_for_completion_timeout(&ntn_ctx->ntn_completion
+ , 10*HZ) == 0) {
+ IPA_UC_OFFLOAD_ERR("ETH_PROD req timeout\n");
+ result = -EFAULT;
+ goto fail;
+ }
+ } else if (result != 0) {
+ IPA_UC_OFFLOAD_ERR("fail to request resource\n");
result = -EFAULT;
goto fail;
}
- } else if (result != 0) {
- IPA_UC_OFFLOAD_ERR("fail to request resource\n");
- result = -EFAULT;
- goto fail;
}
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_UP;
@@ -383,8 +456,9 @@
return 0;
fail:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
return result;
}
@@ -455,6 +529,11 @@
return -EINVAL;
}
+ if (ipa_pm_is_used())
+ return ipa_pm_set_perf_profile(
+ ipa_uc_offload_ctx[IPA_UC_NTN]->pm_hdl,
+ profile->max_supported_bw_mbps);
+
if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
IPA_UC_OFFLOAD_ERR("fail to setup rm perf profile\n");
return -EFAULT;
@@ -471,18 +550,27 @@
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_INITIALIZED;
- ret = ipa_rm_release_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
- if (ret) {
- IPA_UC_OFFLOAD_ERR("fail to release ETHERNET_PROD res: %d\n",
- ret);
- return -EFAULT;
- }
+ if (ipa_pm_is_used()) {
+ ret = ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail to deactivate res: %d\n",
+ ret);
+ return -EFAULT;
+ }
+ } else {
+ ret = ipa_rm_release_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail release ETHERNET_PROD: %d\n",
+ ret);
+ return -EFAULT;
+ }
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
- if (ret) {
- IPA_UC_OFFLOAD_ERR("fail to del dep ETH_PROD->APPS, %d\n", ret);
- return -EFAULT;
+ ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail del dep ETH->APPS, %d\n", ret);
+ return -EFAULT;
+ }
}
ipa_ep_idx_ul = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_PROD);
@@ -539,14 +627,18 @@
int len, result = 0;
struct ipa_ioc_del_hdr *hdr;
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD)) {
- IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD resource\n");
- return -EFAULT;
- }
+ if (ipa_pm_is_used()) {
+ ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
+ } else {
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD)) {
+ IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD\n");
+ return -EFAULT;
+ }
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS)) {
- IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS resource\n");
- return -EFAULT;
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS)) {
+ IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS\n");
+ return -EFAULT;
+ }
}
len = sizeof(struct ipa_ioc_del_hdr) + 2 * sizeof(struct ipa_hdr_del);
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index f5d8d61..745e429 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -119,6 +119,12 @@
bool cons_requested_released;
};
+struct ipa3_usb_pm_context {
+ struct ipa_pm_register_params reg_params;
+ struct work_struct *remote_wakeup_work;
+ u32 hdl;
+};
+
enum ipa3_usb_state {
IPA_USB_INVALID,
IPA_USB_INITIALIZED,
@@ -157,6 +163,7 @@
*/
struct ipa3_usb_transport_type_ctx {
struct ipa3_usb_rm_context rm_ctx;
+ struct ipa3_usb_pm_context pm_ctx;
int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
void *user_data;
enum ipa3_usb_state state;
@@ -362,7 +369,8 @@
ipa3_usb_state_to_string(new_state));
}
- if (state_legal && (new_state == IPA_USB_CONNECTED)) {
+ if (!ipa_pm_is_used() &&
+ state_legal && (new_state == IPA_USB_CONNECTED)) {
rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
if ((rm_ctx->cons_state == IPA_USB_CONS_GRANTED) ||
rm_ctx->cons_requested_released) {
@@ -656,6 +664,30 @@
return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_DPL);
}
+static void ipa3_usb_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ipa3_usb_transport_type_ctx *ttype_ctx =
+ (struct ipa3_usb_transport_type_ctx *)p;
+ unsigned long flags;
+
+ IPA_USB_DBG_LOW("entry\n");
+
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ IPA_USB_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
+ IPA_USB_DBG("state is %s\n",
+ ipa3_usb_state_to_string(ttype_ctx->state));
+ if (ttype_ctx->state == IPA_USB_SUSPENDED)
+ queue_work(ipa3_usb_ctx->wq,
+ ttype_ctx->pm_ctx.remote_wakeup_work);
+ spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
+ IPA_USB_DBG_LOW("exit\n");
+}
+
static char *ipa3_usb_teth_prot_to_string(enum ipa_usb_teth_prot teth_prot)
{
switch (teth_prot) {
@@ -703,6 +735,59 @@
return 0;
}
+static int ipa3_usb_register_pm(enum ipa3_usb_transport_type ttype)
+{
+ struct ipa3_usb_transport_type_ctx *ttype_ctx =
+ &ipa3_usb_ctx->ttype_ctx[ttype];
+ int result;
+
+ memset(&ttype_ctx->pm_ctx.reg_params, 0,
+ sizeof(ttype_ctx->pm_ctx.reg_params));
+ ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
+ "USB DPL" : "USB";
+ ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb;
+ ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx;
+ ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT;
+
+ result = ipa_pm_register(&ttype_ctx->pm_ctx.reg_params,
+ &ttype_ctx->pm_ctx.hdl);
+ if (result) {
+ IPA_USB_ERR("fail to register with PM %d\n", result);
+ goto fail_pm_reg;
+ }
+
+ result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl,
+ (ttype == IPA_USB_TRANSPORT_DPL) ?
+ IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS);
+ if (result) {
+ IPA_USB_ERR("fail to associate cons with PM %d\n", result);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(ttype_ctx->pm_ctx.hdl);
+fail_pm_reg:
+ memset(&ttype_ctx->pm_ctx.reg_params, 0,
+ sizeof(ttype_ctx->pm_ctx.reg_params));
+ return result;
+}
+
+static int ipa3_usb_deregister_pm(enum ipa3_usb_transport_type ttype)
+{
+ struct ipa3_usb_pm_context *pm_ctx =
+ &ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx;
+ int result;
+
+ result = ipa_pm_deregister(pm_ctx->hdl);
+ if (result)
+ return result;
+
+ memset(&pm_ctx->reg_params, 0, sizeof(pm_ctx->reg_params));
+ return 0;
+}
+
static int ipa3_usb_create_rm_resources(enum ipa3_usb_transport_type ttype)
{
struct ipa3_usb_rm_context *rm_ctx;
@@ -802,7 +887,10 @@
}
/* Create IPA RM USB resources */
- result = ipa3_usb_create_rm_resources(ttype);
+ if (ipa_pm_is_used())
+ result = ipa3_usb_register_pm(ttype);
+ else
+ result = ipa3_usb_create_rm_resources(ttype);
if (result) {
IPA_USB_ERR("Failed creating IPA RM USB resources\n");
goto bad_params;
@@ -934,12 +1022,18 @@
teth_prot_init_fail:
if ((IPA3_USB_IS_TTYPE_DPL(ttype))
|| (ipa3_usb_ctx->num_init_prot == 0)) {
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
- ipa_rm_delete_resource(
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
+ false;
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
+ false;
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
- ipa_rm_delete_resource(
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
+ }
}
bad_params:
mutex_unlock(&ipa3_usb_ctx->general_mutex);
@@ -1393,6 +1487,9 @@
{
int res = 0;
+ if (ipa_pm_is_used())
+ return 0;
+
/*
* Add DPL dependency to RM dependency graph, first add_dependency call
* is sync in order to make sure the IPA clocks are up before we
@@ -1572,6 +1669,9 @@
{
int res;
+ if (ipa_pm_is_used())
+ return 0;
+
/* Remove DPL RM dependency */
res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
IPA_RM_RESOURCE_Q6_CONS);
@@ -1699,32 +1799,51 @@
return result;
}
- /* Set RM PROD & CONS perf profile */
- profile.max_supported_bandwidth_mbps =
- params->max_supported_bandwidth_mbps;
- result = ipa_rm_set_perf_profile(
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
- &profile);
- if (result) {
- IPA_USB_ERR("failed to set %s perf profile\n",
- ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
- rm_ctx.prod_params.name));
- return result;
- }
- result = ipa_rm_set_perf_profile(
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
- &profile);
- if (result) {
- IPA_USB_ERR("failed to set %s perf profile\n",
- ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
- rm_ctx.cons_params.name));
- return result;
- }
+ if (ipa_pm_is_used()) {
+ result = ipa_pm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
+ params->max_supported_bandwidth_mbps);
+ if (result) {
+ IPA_USB_ERR("failed to set perf profile\n");
+ return result;
+ }
- /* Request PROD */
- result = ipa3_usb_request_prod(ttype);
- if (result)
- return result;
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ if (result) {
+ IPA_USB_ERR("failed to activate pm\n");
+ return result;
+ }
+ } else {
+ /* Set RM PROD & CONS perf profile */
+ profile.max_supported_bandwidth_mbps =
+ params->max_supported_bandwidth_mbps;
+ result = ipa_rm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
+ &profile);
+ if (result) {
+ IPA_USB_ERR("failed to set %s perf profile\n",
+ ipa_rm_resource_str(ipa3_usb_ctx->
+ ttype_ctx[ttype].
+ rm_ctx.prod_params.name));
+ return result;
+ }
+ result = ipa_rm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
+ &profile);
+ if (result) {
+ IPA_USB_ERR("failed to set %s perf profile\n",
+ ipa_rm_resource_str(ipa3_usb_ctx->
+ ttype_ctx[ttype].
+ rm_ctx.cons_params.name));
+ return result;
+ }
+
+ /* Request PROD */
+ result = ipa3_usb_request_prod(ttype);
+ if (result)
+ return result;
+ }
if (params->teth_prot != IPA_USB_DIAG) {
/* Start UL channel */
@@ -1775,7 +1894,11 @@
ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
}
connect_ul_fail:
- ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ ipa3_usb_release_prod(ttype);
return result;
}
@@ -2224,7 +2347,11 @@
goto bad_params;
if (orig_state != IPA_USB_SUSPENDED) {
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD.\n");
goto bad_params;
@@ -2334,13 +2461,19 @@
(ipa3_usb_ctx->num_init_prot == 0)) {
if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
IPA_USB_ERR("failed to change state to invalid\n");
- ipa_rm_delete_resource(
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
- ipa_rm_delete_resource(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
+ false;
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
- ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
+ false;
+ ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+ }
}
IPA_USB_DBG_LOW("exit\n");
@@ -2400,7 +2533,11 @@
if (result)
goto start_ul;
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD.\n");
goto connect_teth;
@@ -2477,7 +2614,11 @@
}
ipa3_usb_ctx->qmi_req_id++;
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD\n");
goto release_prod_fail;
@@ -2543,7 +2684,11 @@
"DPL channel":"Data Tethering channels");
/* Request USB_PROD */
- result = ipa3_usb_request_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_request_prod(ttype);
if (result)
goto fail_exit;
@@ -2590,7 +2735,11 @@
disconn_teth:
(void)ipa3_usb_disconnect_teth_prot(teth_prot);
release_prod:
- (void)ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ (void)ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ (void)ipa3_usb_release_prod(ttype);
fail_exit:
return result;
}
@@ -2642,7 +2791,11 @@
}
/* Request USB_PROD */
- result = ipa3_usb_request_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_request_prod(ttype);
if (result)
goto prod_req_fail;
@@ -2685,7 +2838,11 @@
IPA_USB_ERR("Error stopping UL channel: %d\n", result);
}
start_ul_fail:
- ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ ipa3_usb_release_prod(ttype);
prod_req_fail:
/* Change state back to prev_state */
if (!ipa3_usb_set_state(prev_state, true, ttype))
@@ -2722,6 +2879,20 @@
ipa3_usb_ctx->dl_data_pending = false;
mutex_init(&ipa3_usb_ctx->general_mutex);
+ if (ipa_pm_is_used()) {
+ struct ipa3_usb_pm_context *pm_ctx;
+
+ pm_ctx =
+ &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
+ pm_ctx->hdl = ~0;
+ pm_ctx->remote_wakeup_work =
+ &ipa3_usb_notify_remote_wakeup_work;
+ pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
+ pm_ctx->hdl = ~0;
+ pm_ctx->remote_wakeup_work =
+ &ipa3_usb_dpl_notify_remote_wakeup_work;
+ }
+
for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
index a623d0b..f0d1102 100644
--- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
@@ -27,6 +27,7 @@
#include <linux/cdev.h>
#include <linux/ipa_odu_bridge.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define ODU_BRIDGE_DRV_NAME "odu_ipa_bridge"
@@ -152,6 +153,7 @@
void *logbuf_low;
struct completion rm_comp;
void (*wakeup_request)(void *);
+ u32 pm_hdl;
};
static struct odu_bridge_ctx *odu_bridge_ctx;
@@ -273,20 +275,22 @@
memset(&odu_prod_params, 0, sizeof(odu_prod_params));
memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params));
- /* Build IPA Resource manager dependency graph */
- ODU_BRIDGE_DBG_LOW("build dependency graph\n");
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ if (!ipa_pm_is_used()) {
+ /* Build IPA Resource manager dependency graph */
+ ODU_BRIDGE_DBG_LOW("build dependency graph\n");
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS) {
- ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
- goto fail_add_dependency_1;
- }
+ if (res && res != -EINPROGRESS) {
+ ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
+ goto fail_add_dependency_1;
+ }
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
IPA_RM_RESOURCE_ODU_ADAPT_CONS);
- if (res && res != -EINPROGRESS) {
- ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
- goto fail_add_dependency_2;
+ if (res && res != -EINPROGRESS) {
+ ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
+ goto fail_add_dependency_2;
+ }
}
/* configure RX (ODU->IPA) EP */
@@ -346,10 +350,12 @@
ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl);
odu_bridge_ctx->odu_prod_hdl = 0;
fail_odu_prod:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
IPA_RM_RESOURCE_ODU_ADAPT_CONS);
fail_add_dependency_2:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_Q6_CONS);
fail_add_dependency_1:
return res;
@@ -397,17 +403,19 @@
ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n");
odu_bridge_ctx->odu_emb_cons_hdl = 0;
- /* Delete IPA Resource manager dependency graph */
- ODU_BRIDGE_DBG("deleting dependency graph\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS)
- ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ if (!ipa_pm_is_used()) {
+ /* Delete IPA Resource manager dependency graph */
+ ODU_BRIDGE_DBG("deleting dependency graph\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res && res != -EINPROGRESS)
+ ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_ODU_ADAPT_CONS);
- if (res && res != -EINPROGRESS)
- ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+ if (res && res != -EINPROGRESS)
+ ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ }
return 0;
}
@@ -1319,24 +1327,58 @@
return 0;
}
-/* IPA Bridge API is the new API which will replaces old odu_bridge API */
-int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+static void ipa_br_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ ODU_BRIDGE_FUNC_ENTRY();
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ ODU_BRIDGE_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ if (odu_bridge_ctx->is_suspended)
+ odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv);
+ ODU_BRIDGE_FUNC_EXIT();
+}
+
+static int ipa_br_register_pm(void)
+{
+ struct ipa_pm_register_params reg_params;
+ int ret;
+
+ memset(®_params, 0, sizeof(reg_params));
+ reg_params.name = "ODU Bridge";
+ reg_params.callback = ipa_br_pm_cb;
+ reg_params.group = IPA_PM_GROUP_DEFAULT;
+
+ ret = ipa_pm_register(®_params,
+ &odu_bridge_ctx->pm_hdl);
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to register with PM %d\n", ret);
+ goto fail_pm_reg;
+ }
+
+ ret = ipa_pm_associate_ipa_cons_to_client(odu_bridge_ctx->pm_hdl,
+ IPA_CLIENT_ODU_EMB_CONS);
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to associate cons with PM %d\n", ret);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
+ odu_bridge_ctx->pm_hdl = ~0;
+fail_pm_reg:
+ return ret;
+}
+
+static int ipa_br_create_rm_resources(void)
{
int ret;
struct ipa_rm_create_params create_params;
- if (!params || !params->wakeup_request || !hdl) {
- ODU_BRIDGE_ERR("NULL arg\n");
- return -EINVAL;
- }
-
-
- ret = odu_bridge_init(¶ms->info);
- if (ret)
- return ret;
-
- odu_bridge_ctx->wakeup_request = params->wakeup_request;
-
/* create IPA RM resources for power management */
init_completion(&odu_bridge_ctx->rm_comp);
memset(&create_params, 0, sizeof(create_params));
@@ -1368,9 +1410,6 @@
goto fail_rm_cons;
}
- /* handle is ignored for now */
- *hdl = 0;
-
return 0;
fail_rm_cons:
@@ -1379,6 +1418,41 @@
fail_add_dep:
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
fail_rm_prod:
+ return ret;
+}
+
+/* IPA Bridge API is the new API which will replaces old odu_bridge API */
+int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+{
+ int ret;
+
+ if (!params || !params->wakeup_request || !hdl) {
+ ODU_BRIDGE_ERR("NULL arg\n");
+ return -EINVAL;
+ }
+
+
+ ret = odu_bridge_init(¶ms->info);
+ if (ret)
+ return ret;
+
+ odu_bridge_ctx->wakeup_request = params->wakeup_request;
+
+ if (ipa_pm_is_used())
+ ret = ipa_br_register_pm();
+ else
+ ret = ipa_br_create_rm_resources();
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to register woth RM/PM %d\n", ret);
+ goto fail_pm;
+ }
+
+ /* handle is ignored for now */
+ *hdl = 0;
+
+ return 0;
+
+fail_pm:
odu_bridge_cleanup();
return ret;
}
@@ -1398,7 +1472,10 @@
return -EFAULT;
}
- ret = ipa_br_request_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_request_prod();
if (ret)
return ret;
@@ -1411,6 +1488,10 @@
struct ipa_rm_perf_profile profile = {0};
int ret;
+ if (ipa_pm_is_used())
+ return ipa_pm_set_perf_profile(odu_bridge_ctx->pm_hdl,
+ bandwidth);
+
profile.max_supported_bandwidth_mbps = bandwidth;
ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_PROD, &profile);
if (ret) {
@@ -1436,7 +1517,10 @@
if (ret)
return ret;
- ret = ipa_br_release_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_release_prod();
if (ret)
return ret;
@@ -1470,7 +1554,10 @@
return ret;
}
- ret = ipa_br_release_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_release_prod();
if (ret) {
ODU_BRIDGE_ERR("failed to release prod %d\n", ret);
ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
@@ -1501,7 +1588,10 @@
return -EFAULT;
}
- ret = ipa_br_request_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_request_prod();
if (ret)
return ret;
@@ -1523,12 +1613,27 @@
}
EXPORT_SYMBOL(ipa_bridge_tx_dp);
-int ipa_bridge_cleanup(u32 hdl)
+static void ipa_br_delete_rm_resources(void)
{
ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_APPS_CONS);
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+}
+
+static void ipa_br_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
+ odu_bridge_ctx->pm_hdl = ~0;
+}
+
+int ipa_bridge_cleanup(u32 hdl)
+{
+ if (ipa_pm_is_used())
+ ipa_br_deregister_pm();
+ else
+ ipa_br_delete_rm_resources();
return odu_bridge_cleanup();
}
EXPORT_SYMBOL(ipa_bridge_cleanup);
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index f62cb27..1c47e69 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -27,6 +26,8 @@
#include <linux/random.h>
#include <linux/rndis_ipa.h>
#include <linux/workqueue.h>
+#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define CREATE_TRACE_POINTS
#include "rndis_ipa_trace.h"
@@ -160,6 +161,7 @@
* state is changed to RNDIS_IPA_CONNECTED_AND_UP
* @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
* @state_lock: used to protect the state variable.
+ * @pm_hdl: handle for IPA PM framework
*/
struct rndis_ipa_dev {
struct net_device *net;
@@ -188,6 +190,7 @@
void (*device_ready_notify)(void);
struct delayed_work xmit_error_delayed_work;
spinlock_t state_lock; /* Spinlock for the state variable.*/
+ u32 pm_hdl;
};
/**
@@ -233,6 +236,8 @@
unsigned long data);
static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
+static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
+static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx);
@@ -701,7 +706,10 @@
return -EINVAL;
}
- result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ result = rndis_ipa_register_pm_client(rndis_ipa_ctx);
+ else
+ result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
if (result) {
RNDIS_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -763,7 +771,10 @@
return 0;
fail:
- rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
+ else
+ rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
fail_create_rm:
return result;
}
@@ -1235,7 +1246,10 @@
rndis_ipa_ctx->net->stats.tx_dropped += outstanding_dropped_pkts;
atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);
- retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ retval = rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
+ else
+ retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
if (retval) {
RNDIS_IPA_ERROR("Fail to clean RM\n");
return retval;
@@ -1772,6 +1786,29 @@
return result;
}
+static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct rndis_ipa_dev *rndis_ipa_ctx = p;
+
+ RNDIS_IPA_LOG_ENTRY();
+
+ if (event != IPA_PM_CLIENT_ACTIVATED) {
+ RNDIS_IPA_ERROR("unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+ RNDIS_IPA_DEBUG("Resource Granted\n");
+
+ if (netif_queue_stopped(rndis_ipa_ctx->net)) {
+ RNDIS_IPA_DEBUG("starting queue\n");
+ netif_start_queue(rndis_ipa_ctx->net);
+ } else {
+ RNDIS_IPA_DEBUG("queue already awake\n");
+ }
+
+ RNDIS_IPA_LOG_EXIT();
+}
+
/**
* rndis_ipa_destroy_rm_resource() - delete the dependency and destroy
* the resource done on rndis_ipa_create_rm_resource()
@@ -1831,6 +1868,33 @@
return result;
}
+static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+
+ pm_reg.name = rndis_ipa_ctx->net->name;
+ pm_reg.user_data = rndis_ipa_ctx;
+ pm_reg.callback = rndis_ipa_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &rndis_ipa_ctx->pm_hdl);
+ if (result) {
+ RNDIS_IPA_ERROR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
+{
+ ipa_pm_deactivate_sync(rndis_ipa_ctx->pm_hdl);
+ ipa_pm_deregister(rndis_ipa_ctx->pm_hdl);
+ rndis_ipa_ctx->pm_hdl = ~0;
+ return 0;
+}
+
/**
* resource_request() - request for the Netdev resource
* @rndis_ipa_ctx: main driver context
@@ -1849,11 +1913,14 @@
int result = 0;
if (!rm_enabled(rndis_ipa_ctx))
- goto out;
- result = ipa_rm_inactivity_timer_request_resource(
+ return result;
+
+ if (ipa_pm_is_used())
+ return ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
+
+ return ipa_rm_inactivity_timer_request_resource(
DRV_RESOURCE_ID);
-out:
- return result;
+
}
/**
@@ -1868,9 +1935,12 @@
static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
{
if (!rm_enabled(rndis_ipa_ctx))
- goto out;
- ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
-out:
+ return;
+ if (ipa_pm_is_used())
+ ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
+ else
+ ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
+
return;
}
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 32c8b25..a487bf4 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -386,4 +386,6 @@
const char *ipa_get_version_string(enum ipa_hw_type ver);
int ipa_start_gsi_channel(u32 clnt_hdl);
+bool ipa_pm_is_used(void);
+
#endif /* _IPA_COMMON_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 9c75202..2f272d2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -411,12 +411,15 @@
{
int i, j;
+ /* prevent multi-threads accessing num_q6_rule */
+ mutex_lock(&add_mux_channel_lock);
if (rule_req->filter_spec_list_valid == true) {
num_q6_rule = rule_req->filter_spec_list_len;
IPAWANDBG("Received (%d) install_flt_req\n", num_q6_rule);
} else {
num_q6_rule = 0;
IPAWANERR("got no UL rules from modem\n");
+ mutex_unlock(&add_mux_channel_lock);
return -EINVAL;
}
@@ -610,9 +613,11 @@
num_q6_rule = 0;
memset(ipa_qmi_ctx->q6_ul_filter_rule, 0,
sizeof(ipa_qmi_ctx->q6_ul_filter_rule));
+ mutex_unlock(&add_mux_channel_lock);
return -EINVAL;
success:
+ mutex_unlock(&add_mux_channel_lock);
return 0;
}
@@ -1621,9 +1626,12 @@
/* already got Q6 UL filter rules*/
if (ipa_qmi_ctx &&
ipa_qmi_ctx->modem_cfg_emb_pipe_flt
- == false)
+ == false) {
+ /* protect num_q6_rule */
+ mutex_lock(&add_mux_channel_lock);
rc = wwan_add_ul_flt_rule_to_ipa();
- else
+ mutex_unlock(&add_mux_channel_lock);
+ } else
rc = 0;
egress_set = true;
if (rc)
diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile
index e3f8d45..5db2545 100644
--- a/drivers/platform/msm/ipa/ipa_v3/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/Makefile
@@ -4,6 +4,6 @@
ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \
ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \
- ipa_hw_stats.o
+ ipa_hw_stats.o ipa_pm.o
obj-$(CONFIG_RMNET_IPA3) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 2210ee7..a52b4e0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -1466,6 +1466,10 @@
}
break;
case IPA_IOC_RM_ADD_DEPENDENCY:
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
sizeof(struct ipa_ioc_rm_dependency))) {
retval = -EFAULT;
@@ -1475,6 +1479,10 @@
rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_RM_DEL_DEPENDENCY:
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
sizeof(struct ipa_ioc_rm_dependency))) {
retval = -EFAULT;
@@ -2350,7 +2358,6 @@
struct ipahal_imm_cmd_register_write reg_write;
struct ipahal_imm_cmd_pyld *cmd_pyld;
int retval;
- struct ipahal_reg_valmask valmask;
desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc),
GFP_KERNEL);
@@ -2365,39 +2372,10 @@
if (ep_idx == -1)
continue;
- if (ipa3_ctx->ep[ep_idx].valid &&
- ipa3_ctx->ep[ep_idx].skip_ep_cfg) {
- BUG_ON(num_descs >= ipa3_ctx->ipa_num_pipes);
-
- reg_write.skip_pipeline_clear = false;
- reg_write.pipeline_clear_options =
- IPAHAL_HPS_CLEAR;
- reg_write.offset =
- ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
- ep_idx);
- ipahal_get_status_ep_valmask(
- ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS),
- &valmask);
- reg_write.value = valmask.val;
- reg_write.value_mask = valmask.mask;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_REGISTER_WRITE, ®_write, false);
- if (!cmd_pyld) {
- IPAERR("fail construct register_write cmd\n");
- BUG();
- }
-
- desc[num_descs].opcode = cmd_pyld->opcode;
- desc[num_descs].type = IPA_IMM_CMD_DESC;
- desc[num_descs].callback = ipa3_destroy_imm;
- desc[num_descs].user1 = cmd_pyld;
- desc[num_descs].pyld = cmd_pyld->data;
- desc[num_descs].len = cmd_pyld->len;
- num_descs++;
- }
-
- /* disable statuses for modem producers */
- if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
+ /* disable statuses for all modem controlled prod pipes */
+ if (IPA_CLIENT_IS_Q6_PROD(client_idx) ||
+ (ipa3_ctx->ep[ep_idx].valid &&
+ ipa3_ctx->ep[ep_idx].skip_ep_cfg)) {
ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
reg_write.skip_pipeline_clear = false;
@@ -3712,6 +3690,53 @@
spin_unlock_irqrestore(&ipa3_ctx->wakelock_ref_cnt.spinlock, flags);
}
+int ipa3_set_clock_plan_from_pm(int idx)
+{
+ u32 clk_rate;
+
+ IPADBG_LOW("idx = %d\n", idx);
+
+ if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
+ IPAERR("bad voltage\n");
+ return -EINVAL;
+ }
+
+ if (idx == 1)
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
+ else if (idx == 2)
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
+ else if (idx == 3)
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
+ else {
+ IPAERR("bad voltage\n");
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (clk_rate == ipa3_ctx->curr_ipa_clk_rate) {
+ IPADBG_LOW("Same voltage\n");
+ return 0;
+ }
+
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
+ ipa3_ctx->curr_ipa_clk_rate = clk_rate;
+ ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
+ IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
+ if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) > 0) {
+ if (ipa3_clk)
+ clk_set_rate(ipa3_clk, ipa3_ctx->curr_ipa_clk_rate);
+ if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl,
+ ipa3_get_bus_vote()))
+ WARN_ON(1);
+ } else {
+ IPADBG_LOW("clocks are gated, not setting rate\n");
+ }
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
+ IPADBG_LOW("Done\n");
+
+ return 0;
+}
+
int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
u32 bandwidth_mbps)
{
@@ -3814,14 +3839,19 @@
u32 i = 0;
int res;
struct ipa_ep_cfg_holb holb_cfg;
+ u32 pipe_bitmask = 0;
IPADBG("interrupt=%d, interrupt_data=%u\n",
interrupt, suspend_data);
memset(&holb_cfg, 0, sizeof(holb_cfg));
holb_cfg.tmr_val = 0;
- for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
+ for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
+ if (ipa3_ctx->use_ipa_pm) {
+ pipe_bitmask |= bmsk;
+ continue;
+ }
if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
/*
* pipe will be unsuspended as part of
@@ -3860,7 +3890,13 @@
}
}
}
- bmsk = bmsk << 1;
+ }
+ if (ipa3_ctx->use_ipa_pm) {
+ res = ipa_pm_handle_suspend(pipe_bitmask);
+ if (res) {
+ IPAERR("ipa_pm_handle_suspend failed %d\n", res);
+ return;
+ }
}
}
@@ -4621,6 +4657,7 @@
ipa3_ctx->ee = resource_p->ee;
ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
+ ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
if (resource_p->ipa_tz_unlock_reg) {
ipa3_ctx->ipa_tz_unlock_reg_num =
@@ -4934,20 +4971,30 @@
wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
- /* Initialize IPA RM (resource manager) */
- result = ipa_rm_initialize();
- if (result) {
- IPAERR("RM initialization failed (%d)\n", -result);
- result = -ENODEV;
- goto fail_ipa_rm_init;
- }
- IPADBG("IPA resource manager initialized");
+ /* Initialize Power Management framework */
+ if (ipa3_ctx->use_ipa_pm) {
+ result = ipa_pm_init(&ipa3_res.pm_init);
+ if (result) {
+ IPAERR("IPA PM initialization failed (%d)\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
+ IPADBG("IPA resource manager initialized");
+ } else {
+ result = ipa_rm_initialize();
+ if (result) {
+ IPAERR("RM initialization failed (%d)\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
+ IPADBG("IPA resource manager initialized");
- result = ipa3_create_apps_resource();
- if (result) {
- IPAERR("Failed to create APPS_CONS resource\n");
- result = -ENODEV;
- goto fail_create_apps_resource;
+ result = ipa3_create_apps_resource();
+ if (result) {
+ IPAERR("Failed to create APPS_CONS resource\n");
+ result = -ENODEV;
+ goto fail_create_apps_resource;
+ }
}
result = ipa3_alloc_pkt_init();
@@ -4998,9 +5045,11 @@
fail_cdev_add:
fail_ipa_init_interrupts:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
+ if (!ipa3_ctx->use_ipa_pm)
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
fail_create_apps_resource:
- ipa_rm_exit();
+ if (!ipa3_ctx->use_ipa_pm)
+ ipa_rm_exit();
fail_ipa_rm_init:
fail_nat_dev_add:
device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
@@ -5069,6 +5118,101 @@
return result;
}
+bool ipa_pm_is_used(void)
+{
+ return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
+static int get_ipa_dts_pm_info(struct platform_device *pdev,
+ struct ipa3_plat_drv_res *ipa_drv_res)
+{
+ int result;
+ int i, j;
+
+ ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-ipa-pm");
+ IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
+ if (!ipa_drv_res->use_ipa_pm)
+ return 0;
+
+ result = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-bus,num-cases",
+ &ipa_drv_res->pm_init.threshold_size);
+ /* No vote is ignored */
+ ipa_drv_res->pm_init.threshold_size -= 2;
+ if (result || ipa_drv_res->pm_init.threshold_size >
+ IPA_PM_THRESHOLD_MAX) {
+ IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
+ ipa_drv_res->pm_init.threshold_size);
+ return -EFAULT;
+ }
+
+ result = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,throughput-threshold",
+ ipa_drv_res->pm_init.default_threshold,
+ ipa_drv_res->pm_init.threshold_size);
+ if (result) {
+ IPAERR("failed to read qcom,throughput-thresholds\n");
+ return -EFAULT;
+ }
+
+ result = of_property_count_strings(pdev->dev.of_node,
+ "qcom,scaling-exceptions");
+ if (result < 0) {
+ IPADBG("no exception list for ipa pm\n");
+ result = 0;
+ }
+
+ if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
+ IPAERR("failed to read qcom,scaling-exceptions\n");
+ return -EFAULT;
+ }
+
+ ipa_drv_res->pm_init.exception_size = result /
+ (ipa_drv_res->pm_init.threshold_size + 1);
+ if (ipa_drv_res->pm_init.exception_size >=
+ IPA_PM_EXCEPTION_MAX) {
+ IPAERR("exception list larger then max %d\n",
+ ipa_drv_res->pm_init.exception_size);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
+ struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
+
+ result = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,scaling-exceptions",
+ i * ipa_drv_res->pm_init.threshold_size,
+ &ex[i].usecase);
+ if (result) {
+ IPAERR("failed to read qcom,scaling-exceptions");
+ return -EFAULT;
+ }
+
+ for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
+ const char *str;
+
+ result = of_property_read_string_index(
+ pdev->dev.of_node,
+ "qcom,scaling-exceptions",
+ i * ipa_drv_res->pm_init.threshold_size + j + 1,
+ &str);
+ if (result) {
+ IPAERR("failed to read qcom,scaling-exceptions"
+ );
+ return -EFAULT;
+ }
+
+ if (kstrtou32(str, 0, &ex[i].threshold[j])) {
+ IPAERR("error str=%s\n", str);
+ return -EFAULT;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int get_ipa_dts_configuration(struct platform_device *pdev,
struct ipa3_plat_drv_res *ipa_drv_res)
{
@@ -5307,6 +5451,14 @@
}
kfree(ipa_tz_unlock_reg);
}
+
+ /* get IPA PM related information */
+ result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
+ if (result) {
+ IPAERR("failed to get pm info from dts %d\n", result);
+ return result;
+ }
+
return 0;
}
@@ -5844,11 +5996,16 @@
}
}
- /*
- * Release transport IPA resource without waiting for inactivity timer
- */
- atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
- ipa3_transport_release_resource(NULL);
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deactivate_all_deferred();
+ } else {
+ /*
+ * Release transport IPA resource without waiting
+ * for inactivity timer
+ */
+ atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
+ ipa3_transport_release_resource(NULL);
+ }
IPADBG("Exit\n");
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 153548b..dabd6a3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -1705,6 +1705,10 @@
{
int result, nbytes, cnt = 0;
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
result = ipa_rm_stat(dbg_buff, IPA_MAX_MSG_LEN);
if (result < 0) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
@@ -1716,6 +1720,45 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa3_pm_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int result, nbytes, cnt = 0;
+
+ if (!ipa3_ctx->use_ipa_pm)
+ return 0;
+
+ result = ipa_pm_stat(dbg_buff, IPA_MAX_MSG_LEN);
+ if (result < 0) {
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "Error in printing PM stat %d\n", result);
+ cnt += nbytes;
+ } else
+ cnt += result;
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+static ssize_t ipa3_pm_ex_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int result, nbytes, cnt = 0;
+
+ if (!ipa3_ctx->use_ipa_pm)
+ return 0;
+
+ result = ipa_pm_exceptions_stat(dbg_buff, IPA_MAX_MSG_LEN);
+ if (result < 0) {
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "Error in printing PM stat %d\n", result);
+ cnt += nbytes;
+ } else
+ cnt += result;
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+
static void ipa_dump_status(struct ipahal_pkt_status *status)
{
IPA_DUMP_STATUS_FIELD(status_opcode);
@@ -1940,6 +1983,15 @@
.read = ipa3_rm_read_stats,
};
+static const struct file_operations ipa3_pm_stats = {
+ .read = ipa3_pm_read_stats,
+};
+
+
+static const struct file_operations ipa3_pm_ex_stats = {
+ .read = ipa3_pm_ex_read_stats,
+};
+
const struct file_operations ipa3_active_clients = {
.read = ipa3_print_active_clients_log,
.write = ipa3_clear_active_clients_log,
@@ -2131,11 +2183,27 @@
goto fail;
}
- dfile_rm_stats = debugfs_create_file("rm_stats",
- read_only_mode, dent, 0, &ipa3_rm_stats);
- if (!dfile_rm_stats || IS_ERR(dfile_rm_stats)) {
- IPAERR("fail to create file for debug_fs rm_stats\n");
- goto fail;
+ if (ipa3_ctx->use_ipa_pm) {
+ file = dfile_rm_stats = debugfs_create_file("pm_stats",
+ read_only_mode, dent, NULL, &ipa3_pm_stats);
+ if (!file || IS_ERR(file)) {
+ IPAERR("fail to create file for debug_fs pm_stats\n");
+ goto fail;
+ }
+
+ file = dfile_rm_stats = debugfs_create_file("pm_ex_stats",
+ read_only_mode, dent, NULL, &ipa3_pm_ex_stats);
+ if (!file || IS_ERR(file)) {
+ IPAERR("fail to create file for debugfs pm_ex_stats\n");
+ goto fail;
+ }
+ } else {
+ dfile_rm_stats = debugfs_create_file("rm_stats",
+ read_only_mode, dent, NULL, &ipa3_rm_stats);
+ if (!dfile_rm_stats || IS_ERR(dfile_rm_stats)) {
+ IPAERR("fail to create file for debug_fs rm_stats\n");
+ goto fail;
+ }
}
dfile_status_stats = debugfs_create_file("status_stats",
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 26d5f5e..7f30a10 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -73,6 +73,8 @@
#define IPA_TX_SEND_COMPL_NOP_DELAY_NS (2 * 1000 * 1000)
+#define IPA_APPS_BW_FOR_PM 700
+
static struct sk_buff *ipa3_get_skb_ipa_rx(unsigned int len, gfp_t flags);
static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys);
@@ -748,7 +750,10 @@
int inactive_cycles = 0;
int cnt;
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_activate_sync(sys->pm_hdl);
+ else
+ IPA_ACTIVE_CLIENTS_INC_SIMPLE();
do {
cnt = ipa3_handle_rx_core(sys, true, true);
if (cnt == 0)
@@ -772,7 +777,10 @@
trace_poll_to_intr3(sys->ep->client);
ipa3_rx_switch_to_intr_mode(sys);
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deferred_deactivate(sys->pm_hdl);
+ else
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
}
static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work)
@@ -799,6 +807,32 @@
return HRTIMER_NORESTART;
}
+static void ipa_pm_sys_pipe_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ipa3_sys_context *sys = (struct ipa3_sys_context *)p;
+
+ switch (event) {
+ case IPA_PM_CLIENT_ACTIVATED:
+ /*
+ * this event is ignored as the sync version of activation
+ * will be used.
+ */
+ break;
+ case IPA_PM_REQUEST_WAKEUP:
+ /*
+ * pipe will be unsuspended as part of
+ * enabling IPA clocks
+ */
+ ipa_pm_activate_sync(sys->pm_hdl);
+ ipa_pm_deferred_deactivate(sys->pm_hdl);
+ break;
+ default:
+ IPAERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+}
+
/**
* ipa3_setup_sys_pipe() - Setup an IPA GPI pipe and perform
* IPA EP configuration
@@ -846,6 +880,9 @@
memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
if (!ep->sys) {
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
ep->sys = kzalloc(sizeof(struct ipa3_sys_context), GFP_KERNEL);
if (!ep->sys) {
IPAERR("failed to sys ctx for client %d\n",
@@ -884,6 +921,35 @@
hrtimer_init(&ep->sys->db_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
ep->sys->db_timer.function = ipa3_ring_doorbell_timer_fn;
+
+ /* create IPA PM resources for handling polling mode */
+ if (ipa3_ctx->use_ipa_pm &&
+ IPA_CLIENT_IS_CONS(sys_in->client)) {
+ pm_reg.name = ipa_clients_strings[sys_in->client];
+ pm_reg.callback = ipa_pm_sys_pipe_cb;
+ pm_reg.user_data = ep->sys;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &ep->sys->pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n",
+ result);
+ goto fail_pm;
+ }
+
+ result = ipa_pm_associate_ipa_cons_to_client(
+ ep->sys->pm_hdl, sys_in->client);
+ if (result) {
+ IPAERR("failed to associate IPA PM client\n");
+ goto fail_gen2;
+ }
+
+ result = ipa_pm_set_perf_profile(ep->sys->pm_hdl,
+ IPA_APPS_BW_FOR_PM);
+ if (result) {
+ IPAERR("failed to set profile IPA PM client\n");
+ goto fail_gen2;
+ }
+ }
} else {
memset(ep->sys, 0, offsetof(struct ipa3_sys_context, ep));
}
@@ -984,6 +1050,9 @@
return 0;
fail_gen2:
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deregister(ep->sys->pm_hdl);
+fail_pm:
destroy_workqueue(ep->sys->repl_wq);
fail_wq2:
destroy_workqueue(ep->sys->wq);
@@ -1402,7 +1471,8 @@
sys = container_of(work, struct ipa3_sys_context, work);
if (sys->ep->napi_enabled) {
- IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
+ if (!ipa3_ctx->use_ipa_pm)
+ IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
sys->ep->client_notify(sys->ep->priv,
IPA_CLIENT_START_POLL, 0);
} else
@@ -3283,11 +3353,48 @@
}
}
+void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
+{
+ bool clk_off;
+
+ atomic_set(&sys->curr_polling_state, 1);
+ ipa3_inc_acquire_wakelock();
+
+ /*
+ * pm deactivate is done in wq context
+ * or after NAPI poll
+ */
+ if (ipa3_ctx->use_ipa_pm) {
+ clk_off = ipa_pm_activate(sys->pm_hdl);
+ if (!clk_off && sys->ep->napi_enabled) {
+ sys->ep->client_notify(sys->ep->priv,
+ IPA_CLIENT_START_POLL, 0);
+ return;
+ }
+ queue_work(sys->wq, &sys->work);
+ return;
+ }
+
+ if (sys->ep->napi_enabled) {
+ struct ipa_active_client_logging_info log;
+
+ IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
+ clk_off = ipa3_inc_client_enable_clks_no_block(
+ &log);
+ if (!clk_off) {
+ sys->ep->client_notify(sys->ep->priv,
+ IPA_CLIENT_START_POLL, 0);
+ return;
+ }
+ }
+
+ queue_work(sys->wq, &sys->work);
+}
+
static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
{
struct ipa3_sys_context *sys;
struct ipa3_rx_pkt_wrapper *rx_pkt_expected, *rx_pkt_rcvd;
- int clk_off;
if (!notify) {
IPAERR("gsi notify is NULL.\n");
@@ -3317,22 +3424,7 @@
/* put the gsi channel into polling mode */
gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
GSI_CHAN_MODE_POLL);
- ipa3_inc_acquire_wakelock();
- atomic_set(&sys->curr_polling_state, 1);
- if (sys->ep->napi_enabled) {
- struct ipa_active_client_logging_info log;
-
- IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
- clk_off = ipa3_inc_client_enable_clks_no_block(
- &log);
- if (!clk_off)
- sys->ep->client_notify(sys->ep->priv,
- IPA_CLIENT_START_POLL, 0);
- else
- queue_work(sys->wq, &sys->work);
- } else {
- queue_work(sys->wq, &sys->work);
- }
+ __ipa_gsi_irq_rx_scedule_poll(sys);
}
break;
default:
@@ -3734,7 +3826,10 @@
if (cnt < weight) {
ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0);
ipa3_rx_switch_to_intr_mode(ep->sys);
- ipa3_dec_client_disable_clks_no_block(&log);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deferred_deactivate(ep->sys->pm_hdl);
+ else
+ ipa3_dec_client_disable_clks_no_block(&log);
}
return cnt;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 4d1baea..3e1d188 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -36,6 +36,7 @@
#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_common_i.h"
#include "ipa_uc_offload_i.h"
+#include "ipa_pm.h"
#define DRV_NAME "ipa"
#define NAT_DEV_NAME "ipaNatTable"
@@ -647,6 +648,7 @@
struct workqueue_struct *wq;
struct workqueue_struct *repl_wq;
struct ipa3_status_stats *status_stat;
+ u32 pm_hdl;
/* ordering is important - other immutable fields go below */
};
@@ -869,6 +871,7 @@
struct ipa3_active_clients {
struct mutex mutex;
atomic_t cnt;
+ int bus_vote_idx;
};
struct ipa3_wakelock_ref_cnt {
@@ -1314,6 +1317,7 @@
struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE];
int num_ipa_cne_evt_req;
struct mutex ipa_cne_evt_lock;
+ bool use_ipa_pm;
};
struct ipa3_plat_drv_res {
@@ -1341,6 +1345,8 @@
bool tethered_flow_control;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
+ bool use_ipa_pm;
+ struct ipa_pm_init_params pm_init;
};
/**
@@ -2226,4 +2232,6 @@
int ipa3_alloc_common_event_ring(void);
int ipa3_allocate_dma_task_for_gsi(void);
void ipa3_free_dma_task_for_gsi(void);
+int ipa3_set_clock_plan_from_pm(int idx);
+void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
new file mode 100644
index 0000000..66c712c
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -0,0 +1,1301 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include "ipa_pm.h"
+#include "ipa_i.h"
+
+static const char *client_state_to_str[IPA_PM_STATE_MAX] = {
+ __stringify(IPA_PM_DEACTIVATED),
+ __stringify(IPA_PM_DEACTIVATE_IN_PROGRESS),
+ __stringify(IPA_PM_ACTIVATE_IN_PROGRESS),
+ __stringify(IPA_PM_ACTIVATED),
+ __stringify(IPA_PM_ACTIVATED_PENDING_DEACTIVATION),
+ __stringify(IPA_PM_ACTIVATED_TIMER_SET),
+ __stringify(IPA_PM_ACTIVATED_PENDING_RESCHEDULE),
+};
+
+static const char *ipa_pm_group_to_str[IPA_PM_GROUP_MAX] = {
+ __stringify(IPA_PM_GROUP_DEFAULT),
+ __stringify(IPA_PM_GROUP_APPS),
+ __stringify(IPA_PM_GROUP_MODEM),
+};
+
+
+#define IPA_PM_DRV_NAME "ipa_pm"
+
+#define IPA_PM_DBG(fmt, args...) \
+ do { \
+ pr_debug(IPA_PM_DRV_NAME " %s:%d " fmt, \
+ __func__, __LINE__, ## args); \
+ IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
+ IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
+ IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+ IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
+ } while (0)
+#define IPA_PM_DBG_LOW(fmt, args...) \
+ do { \
+ pr_debug(IPA_PM_DRV_NAME " %s:%d " fmt, \
+ __func__, __LINE__, ## args); \
+ IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+ IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
+ } while (0)
+#define IPA_PM_ERR(fmt, args...) \
+ do { \
+ pr_err(IPA_PM_DRV_NAME " %s:%d " fmt, \
+ __func__, __LINE__, ## args); \
+ IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
+ IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
+ IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+ IPA_PM_DRV_NAME " %s:%d " fmt, ## args); \
+ } while (0)
+#define IPA_PM_DBG_STATE(hdl, name, state) \
+ IPA_PM_DBG_LOW("Client[%d] %s: %s\n", hdl, name, \
+ client_state_to_str[state])
+
+
+#if IPA_PM_MAX_CLIENTS > 32
+#error max client greater than 32 all bitmask types should be changed
+#endif
+
+/*
+ * struct ipa_pm_exception_list - holds information about an exception
+ * @pending: number of clients in exception that have not yet been adctivated
+ * @bitmask: bitmask of the clients in the exception based on handle
+ * @threshold: the threshold values for the exception
+ */
+struct ipa_pm_exception_list {
+ char clients[IPA_PM_MAX_EX_CL];
+ int pending;
+ u32 bitmask;
+ int threshold[IPA_PM_THRESHOLD_MAX];
+};
+
+/*
+ * struct clk_scaling_db - holds information about threshholds and exceptions
+ * @lock: lock the bitmasks and thresholds
+ * @exception_list: pointer to the list of exceptions
+ * @work: work for clock scaling algorithm
+ * @active_client_bitmask: the bits represent handles in the clients array that
+ * contain non-null client
+ * @threshold_size: size of the throughput threshold
+ * @exception_size: size of the exception list
+ * @cur_vote: idx of the threshold
+ * @default_threshold: the thresholds used if no exception passes
+ * @current_threshold: the current threshold of the clock plan
+ */
+struct clk_scaling_db {
+ spinlock_t lock;
+ struct ipa_pm_exception_list exception_list[IPA_PM_EXCEPTION_MAX];
+ struct work_struct work;
+ u32 active_client_bitmask;
+ int threshold_size;
+ int exception_size;
+ int cur_vote;
+ int default_threshold[IPA_PM_THRESHOLD_MAX];
+ int *current_threshold;
+};
+
+/*
+ * ipa_pm state names
+ *
+ * Timer free states:
+ * @IPA_PM_DEACTIVATED: client starting state when registered
+ * @IPA_PM_DEACTIVATE_IN_PROGRESS: deactivate was called in progress of a client
+ * activating
+ * @IPA_PM_ACTIVATE_IN_PROGRESS: client is being activated by work_queue
+ * @IPA_PM_ACTIVATED: client is activated without any timers
+ *
+ * Timer set states:
+ * @IPA_PM_ACTIVATED_PENDING_DEACTIVATION: moves to deactivate once timer pass
+ * @IPA_PM_ACTIVATED_TIMER_SET: client was activated while timer was set, so
+ * when the timer pass, client will still be activated
+ *@IPA_PM_ACTIVATED_PENDING_RESCHEDULE: state signifying extended timer when
+ * a client is deferred_deactivated when a time ris still active
+ */
+enum ipa_pm_state {
+ IPA_PM_DEACTIVATED,
+ IPA_PM_DEACTIVATE_IN_PROGRESS,
+ IPA_PM_ACTIVATE_IN_PROGRESS,
+ IPA_PM_ACTIVATED,
+ IPA_PM_ACTIVATED_PENDING_DEACTIVATION,
+ IPA_PM_ACTIVATED_TIMER_SET,
+ IPA_PM_ACTIVATED_PENDING_RESCHEDULE,
+};
+
+#define IPA_PM_STATE_ACTIVE(state) \
+ (state == IPA_PM_ACTIVATED ||\
+ state == IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||\
+ state == IPA_PM_ACTIVATED_TIMER_SET ||\
+ state == IPA_PM_ACTIVATED_PENDING_RESCHEDULE)
+
+#define IPA_PM_STATE_IN_PROGRESS(state) \
+ (state == IPA_PM_ACTIVATE_IN_PROGRESS \
+ || state == IPA_PM_DEACTIVATE_IN_PROGRESS)
+
+/*
+ * struct ipa_pm_client - holds information about a specific IPA client
+ * @name: string name of the client
+ * @callback: pointer to the client's callback function
+ * @callback_params: pointer to the client's callback parameters
+ * @state: Activation state of the client
+ * @skip_clk_vote: 0 if client votes for clock when activated, 1 if no vote
+ * @group: the ipa_pm_group the client belongs to
+ * @hdl: handle of the client
+ * @throughput: the throughput of the client for clock scaling
+ * @state_lock: spinlock to lock the pm_states
+ * @activate_work: work for activate (blocking case)
+ * @deactivate work: delayed work for deferred_deactivate function
+ * @complete: generic wait-for-completion handler
+ */
+struct ipa_pm_client {
+ char name[IPA_PM_MAX_EX_CL];
+ void (*callback)(void*, enum ipa_pm_cb_event);
+ void *callback_params;
+ enum ipa_pm_state state;
+ bool skip_clk_vote;
+ int group;
+ int hdl;
+ int throughput;
+ spinlock_t state_lock;
+ struct work_struct activate_work;
+ struct delayed_work deactivate_work;
+ struct completion complete;
+};
+
+/*
+ * struct ipa_pm_ctx - global ctx that will hold the client arrays and tput info
+ * @clients: array to the clients with the handle as its index
+ * @clients_by_pipe: array to the clients with endpoint as the index
+ * @wq: work queue for deferred deactivate, activate, and clk_scaling work
+ 8 @clk_scaling: pointer to clock scaling database
+ * @client_mutex: global mutex to lock the client arrays
+ * @aggragated_tput: aggragated tput value of all valid activated clients
+ * @group_tput: combined throughput for the groups
+ */
+struct ipa_pm_ctx {
+ struct ipa_pm_client *clients[IPA_PM_MAX_CLIENTS];
+ struct ipa_pm_client *clients_by_pipe[IPA3_MAX_NUM_PIPES];
+ struct workqueue_struct *wq;
+ struct clk_scaling_db clk_scaling;
+ struct mutex client_mutex;
+ int aggregated_tput;
+ int group_tput[IPA_PM_GROUP_MAX];
+};
+
+static struct ipa_pm_ctx *ipa_pm_ctx;
+
+/**
+ * pop_max_from_array() -pop the max and move the last element to where the
+ * max was popped
+ * @arr: array to be searched for max
+ * @n: size of the array
+ *
+ * Returns: max value of the array
+ */
+static int pop_max_from_array(int *arr, int *n)
+{
+ int i;
+ int max, max_idx;
+
+ max_idx = *n - 1;
+ max = 0;
+
+ if (*n == 0)
+ return 0;
+
+ for (i = 0; i < *n; i++) {
+ if (arr[i] > max) {
+ max = arr[i];
+ max_idx = i;
+ }
+ }
+ (*n)--;
+ arr[max_idx] = arr[*n];
+
+ return max;
+}
+
+/**
+ * calculate_throughput() - calculate the aggregated throughput
+ * based on active clients
+ *
+ * Returns: aggregated tput value
+ */
+static int calculate_throughput(void)
+{
+ int client_tput[IPA_PM_MAX_CLIENTS] = { 0 };
+ bool group_voted[IPA_PM_GROUP_MAX] = { false };
+ int i, n;
+ int max, second_max, aggregated_tput;
+ struct ipa_pm_client *client;
+
+ /* Create a basic array to hold throughputs*/
+ for (i = 0, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ client = ipa_pm_ctx->clients[i];
+ if (client != NULL && IPA_PM_STATE_ACTIVE(client->state)) {
+ /* default case */
+ if (client->group == IPA_PM_GROUP_DEFAULT) {
+ client_tput[n++] = client->throughput;
+ } else if (group_voted[client->group] == false) {
+ client_tput[n++] = ipa_pm_ctx->group_tput
+ [client->group];
+ group_voted[client->group] = true;
+ }
+ }
+ }
+ /*the array will only use n+1 spots. n will be the last index used*/
+
+ aggregated_tput = 0;
+
+ /**
+ * throughput algorithm:
+ * 1) pop the max and second_max
+ * 2) add the 2nd max to aggregated tput
+ * 3) insert the value of max - 2nd max
+ * 4) repeat until array is of size 1
+ */
+ while (n > 1) {
+ max = pop_max_from_array(client_tput, &n);
+ second_max = pop_max_from_array(client_tput, &n);
+ client_tput[n++] = max - second_max;
+ aggregated_tput += second_max;
+ }
+
+ IPA_PM_DBG_LOW("Aggregated throughput: %d\n", aggregated_tput);
+
+ return aggregated_tput;
+}
+
+/**
+ * deactivate_client() - turn off the bit in the active client bitmask based on
+ * the handle passed in
+ * @hdl: The index of the client to be deactivated
+ */
+static void deactivate_client(u32 hdl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
+ ipa_pm_ctx->clk_scaling.active_client_bitmask &= ~(1 << hdl);
+ spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
+ IPA_PM_DBG_LOW("active bitmask: %x\n",
+ ipa_pm_ctx->clk_scaling.active_client_bitmask);
+}
+
+/**
+ * activate_client() - turn on the bit in the active client bitmask based on
+ * the handle passed in
+ * @hdl: The index of the client to be activated
+ */
+static void activate_client(u32 hdl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
+ ipa_pm_ctx->clk_scaling.active_client_bitmask |= (1 << hdl);
+ spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
+ IPA_PM_DBG_LOW("active bitmask: %x\n",
+ ipa_pm_ctx->clk_scaling.active_client_bitmask);
+}
+
+/**
+ * deactivate_client() - get threshold
+ *
+ * Returns: threshold of the exception that passes or default if none pass
+ */
+static void set_current_threshold(void)
+{
+ int i;
+ struct clk_scaling_db *clk;
+ struct ipa_pm_exception_list *exception;
+ unsigned long flags;
+
+ clk = &ipa_pm_ctx->clk_scaling;
+
+ spin_lock_irqsave(&ipa_pm_ctx->clk_scaling.lock, flags);
+ for (i = 0; i < clk->exception_size; i++) {
+ exception = &clk->exception_list[i];
+ if (exception->pending == 0 && (exception->bitmask
+ & ~clk->active_client_bitmask) == 0) {
+ spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock,
+ flags);
+ clk->current_threshold = exception->threshold;
+ IPA_PM_DBG("Exception %d set\n", i);
+ return;
+ }
+ }
+ clk->current_threshold = clk->default_threshold;
+ spin_unlock_irqrestore(&ipa_pm_ctx->clk_scaling.lock, flags);
+}
+
+/**
+ * do_clk_scaling() - set the clock based on the activated clients
+ *
+ * Returns: 0 if success, negative otherwise
+ */
+static int do_clk_scaling(void)
+{
+ int i, tput;
+ int new_th_idx = 1;
+ struct clk_scaling_db *clk_scaling;
+
+ clk_scaling = &ipa_pm_ctx->clk_scaling;
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_DBG("clock scaling started\n");
+ tput = calculate_throughput();
+ ipa_pm_ctx->aggregated_tput = tput;
+ set_current_threshold();
+
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ for (i = 0; i < clk_scaling->threshold_size; i++) {
+ if (tput > clk_scaling->current_threshold[i])
+ new_th_idx++;
+ }
+
+ IPA_PM_DBG("old idx was at %d\n", ipa_pm_ctx->clk_scaling.cur_vote);
+
+
+ if (ipa_pm_ctx->clk_scaling.cur_vote != new_th_idx) {
+ ipa_pm_ctx->clk_scaling.cur_vote = new_th_idx;
+ ipa3_set_clock_plan_from_pm(ipa_pm_ctx->clk_scaling.cur_vote);
+ }
+
+ IPA_PM_DBG("new idx is at %d\n", ipa_pm_ctx->clk_scaling.cur_vote);
+
+ return 0;
+}
+
+/**
+ * clock_scaling_func() - set the clock on a work queue
+ */
+static void clock_scaling_func(struct work_struct *work)
+{
+ do_clk_scaling();
+}
+
+/**
+ * activate_work_func - activate a client and vote for clock on a work queue
+ */
+static void activate_work_func(struct work_struct *work)
+{
+ struct ipa_pm_client *client;
+ bool dec_clk = false;
+ unsigned long flags;
+
+ client = container_of(work, struct ipa_pm_client, activate_work);
+ if (!client->skip_clk_vote)
+ IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ if (client->state == IPA_PM_ACTIVATE_IN_PROGRESS) {
+ client->state = IPA_PM_ACTIVATED;
+ } else if (client->state == IPA_PM_DEACTIVATE_IN_PROGRESS) {
+ client->state = IPA_PM_DEACTIVATED;
+ dec_clk = true;
+ } else {
+ IPA_PM_ERR("unexpected state %d\n", client->state);
+ WARN_ON(1);
+ }
+ spin_unlock_irqrestore(&client->state_lock, flags);
+
+ complete_all(&client->complete);
+
+ if (dec_clk) {
+ ipa_set_tag_process_before_gating(true);
+ if (!client->skip_clk_vote)
+ IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ return;
+ }
+
+ activate_client(client->hdl);
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ client->callback(client->callback_params, IPA_PM_CLIENT_ACTIVATED);
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ do_clk_scaling();
+}
+
+/**
+ * delayed_deferred_deactivate_work_func - deferred deactivate on a work queue
+ */
+static void delayed_deferred_deactivate_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_pm_client *client;
+ unsigned long flags;
+
+ dwork = container_of(work, struct delayed_work, work);
+ client = container_of(dwork, struct ipa_pm_client, deactivate_work);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ switch (client->state) {
+ case IPA_PM_ACTIVATED_TIMER_SET:
+ client->state = IPA_PM_ACTIVATED;
+ goto bail;
+ case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
+ queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
+ msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
+ client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
+ goto bail;
+ case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
+ client->state = IPA_PM_DEACTIVATED;
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ ipa_set_tag_process_before_gating(true);
+ if (!client->skip_clk_vote)
+ IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+
+ deactivate_client(client->hdl);
+ do_clk_scaling();
+ return;
+ default:
+ IPA_PM_ERR("unexpected state %d\n", client->state);
+ WARN_ON(1);
+ goto bail;
+ }
+
+bail:
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+}
+
+static int find_next_open_array_element(const char *name)
+{
+ int i, n;
+
+ n = -ENOBUFS;
+
+ for (i = IPA_PM_MAX_CLIENTS - 1; i >= 0; i--) {
+ if (ipa_pm_ctx->clients[i] == NULL) {
+ n = i;
+ continue;
+ }
+
+ if (strlen(name) == strlen(ipa_pm_ctx->clients[i]->name))
+ if (!strcmp(name, ipa_pm_ctx->clients[i]->name))
+ return -EEXIST;
+ }
+ return n;
+}
+
+/**
+ * add_client_to_exception_list() - add client to the exception list and
+ * update pending if necessary
+ * @hdl: index of the IPA client
+ *
+ * Returns: 0 if success, negative otherwise
+ */
+static int add_client_to_exception_list(u32 hdl)
+{
+ int i;
+ struct ipa_pm_exception_list *exception;
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
+ exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
+ if (strnstr(exception->clients, ipa_pm_ctx->clients[hdl]->name,
+ strlen(exception->clients))) {
+ exception->pending--;
+
+ if (exception->pending < 0) {
+ WARN_ON(1);
+ exception->pending = 0;
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ return -EPERM;
+ }
+ exception->bitmask |= (1 << hdl);
+ }
+ }
+ IPA_PM_DBG("%s added to exception list\n",
+ ipa_pm_ctx->clients[hdl]->name);
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ return 0;
+}
+
+/**
+ * remove_client_to_exception_list() - remove client from the exception list and
+ * update pending if necessary
+ * @hdl: index of the IPA client
+ *
+ * Returns: 0 if success, negative otherwise
+ */
+static int remove_client_from_exception_list(u32 hdl)
+{
+ int i;
+ struct ipa_pm_exception_list *exception;
+
+ for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
+ exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
+ if (exception->bitmask & (1 << hdl)) {
+ exception->pending++;
+ exception->bitmask &= ~(1 << hdl);
+ }
+ }
+ IPA_PM_DBG("Client %d removed from exception list\n", hdl);
+
+ return 0;
+}
+
+/**
+ * ipa_pm_init() - initialize IPA PM Components
+ * @ipa_pm_init_params: parameters needed to fill exceptions and thresholds
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_init(struct ipa_pm_init_params *params)
+{
+ int i, j;
+ struct clk_scaling_db *clk_scaling;
+
+ if (params == NULL) {
+ IPA_PM_ERR("Invalid Params\n");
+ return -EINVAL;
+ }
+
+ if (params->threshold_size <= 0
+ || params->threshold_size > IPA_PM_THRESHOLD_MAX) {
+ IPA_PM_ERR("Invalid threshold size\n");
+ return -EINVAL;
+ }
+
+ if (params->exception_size < 0
+ || params->exception_size > IPA_PM_EXCEPTION_MAX) {
+ IPA_PM_ERR("Invalid exception size\n");
+ return -EINVAL;
+ }
+
+ IPA_PM_DBG("IPA PM initialization started\n");
+
+ if (ipa_pm_ctx != NULL) {
+ IPA_PM_ERR("Already initialized\n");
+ return -EPERM;
+ }
+
+
+ ipa_pm_ctx = kzalloc(sizeof(*ipa_pm_ctx), GFP_KERNEL);
+ if (!ipa_pm_ctx) {
+ IPA_PM_ERR(":kzalloc err.\n");
+ return -ENOMEM;
+ }
+
+ ipa_pm_ctx->wq = create_singlethread_workqueue("ipa_pm_activate");
+ if (!ipa_pm_ctx->wq) {
+ IPA_PM_ERR("create workqueue failed\n");
+ kfree(ipa_pm_ctx);
+ return -ENOMEM;
+ }
+
+ mutex_init(&ipa_pm_ctx->client_mutex);
+
+ /* Populate and init locks in clk_scaling_db */
+ clk_scaling = &ipa_pm_ctx->clk_scaling;
+ spin_lock_init(&clk_scaling->lock);
+ clk_scaling->threshold_size = params->threshold_size;
+ clk_scaling->exception_size = params->exception_size;
+ INIT_WORK(&clk_scaling->work, clock_scaling_func);
+
+ for (i = 0; i < params->threshold_size; i++)
+ clk_scaling->default_threshold[i] =
+ params->default_threshold[i];
+
+ /* Populate exception list*/
+ for (i = 0; i < params->exception_size; i++) {
+ strlcpy(clk_scaling->exception_list[i].clients,
+ params->exceptions[i].usecase, IPA_PM_MAX_EX_CL);
+ IPA_PM_DBG("Usecase: %s\n", params->exceptions[i].usecase);
+
+ /* Parse the commas to count the size of the clients */
+ for (j = 0; j < IPA_PM_MAX_EX_CL &&
+ clk_scaling->exception_list[i].clients[j]; j++) {
+ if (clk_scaling->exception_list[i].clients[j] == ',')
+ clk_scaling->exception_list[i].pending++;
+ }
+
+ clk_scaling->exception_list[i].pending++;
+ IPA_PM_DBG("Pending: %d\n", clk_scaling->
+ exception_list[i].pending);
+
+ /* populate the threshold */
+ for (j = 0; j < params->threshold_size; j++) {
+ clk_scaling->exception_list[i].threshold[j]
+ = params->exceptions[i].threshold[j];
+ }
+
+ }
+ IPA_PM_DBG("initialization success");
+
+ return 0;
+}
+
+int ipa_pm_destroy(void)
+{
+ IPA_PM_DBG("IPA PM destroy started\n");
+
+ if (ipa_pm_ctx == NULL) {
+ IPA_PM_ERR("Already destroyed\n");
+ return -EPERM;
+ }
+
+ destroy_workqueue(ipa_pm_ctx->wq);
+
+ kfree(ipa_pm_ctx);
+ ipa_pm_ctx = NULL;
+
+ return 0;
+}
+
+/**
+ * ipa_rm_delete_register() - register an IPA PM client with the PM
+ * @register_params: params for a client like throughput, callback, etc.
+ * @hdl: int pointer that will be used as an index to access the client
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: *hdl is replaced with the client index or -EEXIST if
+ * client is already registered
+ */
+int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl)
+{
+ struct ipa_pm_client *client;
+
+ if (params == NULL || hdl == NULL || params->name == NULL
+ || params->callback == NULL) {
+ IPA_PM_ERR("Invalid Params\n");
+ return -EINVAL;
+ }
+
+ IPA_PM_DBG("IPA PM registering client\n");
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+
+ *hdl = find_next_open_array_element(params->name);
+
+ if (*hdl > IPA_CLIENT_MAX) {
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_ERR("client is already registered or array is full\n");
+ return *hdl;
+ }
+
+ ipa_pm_ctx->clients[*hdl] = kzalloc(sizeof
+ (struct ipa_pm_client), GFP_KERNEL);
+ if (!ipa_pm_ctx->clients[*hdl]) {
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_ERR(":kzalloc err.\n");
+ return -ENOMEM;
+ }
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ client = ipa_pm_ctx->clients[*hdl];
+
+ spin_lock_init(&client->state_lock);
+
+ INIT_DELAYED_WORK(&client->deactivate_work,
+ delayed_deferred_deactivate_work_func);
+
+ INIT_WORK(&client->activate_work, activate_work_func);
+
+ /* populate fields */
+ strlcpy(client->name, params->name, IPA_PM_MAX_EX_CL);
+ client->callback = params->callback;
+ client->callback_params = params->user_data;
+ client->group = params->group;
+ client->hdl = *hdl;
+ client->skip_clk_vote = params->skip_clk_vote;
+
+ /* add client to exception list */
+ if (add_client_to_exception_list(*hdl)) {
+ ipa_pm_deregister(*hdl);
+ IPA_PM_ERR("Fail to add client to exception_list\n");
+ return -EPERM;
+ }
+
+ IPA_PM_DBG("IPA PM client registered with handle %d\n", *hdl);
+ return 0;
+}
+
+/**
+ * ipa_pm_deregister() - deregister IPA client from the PM
+ * @hdl: index of the client in the array
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_deregister(u32 hdl)
+{
+ struct ipa_pm_client *client;
+ int i;
+ unsigned long flags;
+
+ if (hdl >= IPA_PM_MAX_CLIENTS) {
+ IPA_PM_ERR("Invalid Param\n");
+ return -EINVAL;
+ }
+
+ if (ipa_pm_ctx->clients[hdl] == NULL) {
+ IPA_PM_ERR("Client is Null\n");
+ return -EINVAL;
+ }
+
+ IPA_PM_DBG("IPA PM deregistering client\n");
+
+ client = ipa_pm_ctx->clients[hdl];
+ spin_lock_irqsave(&client->state_lock, flags);
+ if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ wait_for_completion(&client->complete);
+ spin_lock_irqsave(&client->state_lock, flags);
+ }
+
+ if (IPA_PM_STATE_ACTIVE(client->state)) {
+ IPA_PM_DBG("Activated clients cannot be deregistered");
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return -EPERM;
+ }
+ spin_unlock_irqrestore(&client->state_lock, flags);
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+
+ /* nullify pointers in pipe array */
+ for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
+ if (ipa_pm_ctx->clients_by_pipe[i] == ipa_pm_ctx->clients[hdl])
+ ipa_pm_ctx->clients_by_pipe[i] = NULL;
+ }
+ kfree(client);
+ ipa_pm_ctx->clients[hdl] = NULL;
+
+ remove_client_from_exception_list(hdl);
+ IPA_PM_DBG("IPA PM client %d deregistered\n", hdl);
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ return 0;
+}
+
+/**
+ * ipa_pm_associate_ipa_cons_to_client() - add mapping to pipe with ipa cllent
+ * @hdl: index of the client to be mapped
+ * @consumer: the pipe/consumer name to be pipped to the client
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: multiple pipes are allowed to be mapped to a single client
+ */
+int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer)
+{
+ int idx;
+
+ if (hdl >= IPA_PM_MAX_CLIENTS || consumer < 0 ||
+ consumer >= IPA_CLIENT_MAX) {
+ IPA_PM_ERR("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ idx = ipa_get_ep_mapping(consumer);
+
+ IPA_PM_DBG("Mapping pipe %d to client %d\n", idx, hdl);
+
+ if (idx < 0) {
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_DBG("Pipe is not used\n");
+ return 0;
+ }
+
+ if (ipa_pm_ctx->clients[hdl] == NULL) {
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_ERR("Client is NULL\n");
+ return -EPERM;
+ }
+
+ if (ipa_pm_ctx->clients_by_pipe[idx] != NULL) {
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ IPA_PM_ERR("Pipe is already mapped\n");
+ return -EPERM;
+ }
+ ipa_pm_ctx->clients_by_pipe[idx] = ipa_pm_ctx->clients[hdl];
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ IPA_PM_DBG("Pipe %d is mapped to client %d\n", idx, hdl);
+
+ return 0;
+}
+
+static int ipa_pm_activate_helper(struct ipa_pm_client *client, bool sync)
+{
+ struct ipa_active_client_logging_info log_info;
+ int result = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+
+ if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
+ if (sync) {
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ wait_for_completion(&client->complete);
+ spin_lock_irqsave(&client->state_lock, flags);
+ } else {
+ client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return -EINPROGRESS;
+ }
+ }
+
+ switch (client->state) {
+ case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
+ case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
+ client->state = IPA_PM_ACTIVATED_TIMER_SET;
+ case IPA_PM_ACTIVATED:
+ case IPA_PM_ACTIVATED_TIMER_SET:
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return 0;
+ case IPA_PM_DEACTIVATED:
+ break;
+ default:
+ IPA_PM_ERR("Invalid State\n");
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return -EPERM;
+ }
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+
+ IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, client->name);
+ if (!client->skip_clk_vote) {
+ if (sync) {
+ client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
+ spin_lock_irqsave(&client->state_lock, flags);
+ } else
+ result = ipa3_inc_client_enable_clks_no_block
+ (&log_info);
+ }
+
+ /* we got the clocks */
+ if (result == 0) {
+ client->state = IPA_PM_ACTIVATED;
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ activate_client(client->hdl);
+ if (sync)
+ do_clk_scaling();
+ else
+ queue_work(ipa_pm_ctx->wq,
+ &ipa_pm_ctx->clk_scaling.work);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ return 0;
+ }
+
+ client->state = IPA_PM_ACTIVATE_IN_PROGRESS;
+ init_completion(&client->complete);
+ queue_work(ipa_pm_ctx->wq, &client->activate_work);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+ return -EINPROGRESS;
+}
+
+/**
+ * ipa_pm_activate(): activate ipa client to vote for clock(). Can be called
+ * from atomic context and returns -EINPROGRESS if cannot be done synchronously
+ * @hdl: index of the client in the array
+ *
+ * Returns: 0 on success, -EINPROGRESS if operation cannot be done synchronously
+ * and other negatives on failure
+ */
+int ipa_pm_activate(u32 hdl)
+{
+ if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ IPA_PM_ERR("Invalid Param\n");
+ return -EINVAL;
+ }
+
+ return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], false);
+}
+
+/**
+ * ipa_pm_activate(): activate ipa client to vote for clock synchronously.
+ * Cannot be called from an atomic contex.
+ * @hdl: index of the client in the array
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_activate_sync(u32 hdl)
+{
+ if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ IPA_PM_ERR("Invalid Param\n");
+ return -EINVAL;
+ }
+
+ return ipa_pm_activate_helper(ipa_pm_ctx->clients[hdl], true);
+}
+
+/**
+ * ipa_pm_deferred_deactivate(): schedule a timer to deactivate client and
+ * devote clock. Can be called from atomic context (asynchronously)
+ * @hdl: index of the client in the array
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_deferred_deactivate(u32 hdl)
+{
+ struct ipa_pm_client *client;
+ unsigned long flags;
+
+ if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ IPA_PM_ERR("Invalid Param\n");
+ return -EINVAL;
+ }
+
+ client = ipa_pm_ctx->clients[hdl];
+ IPA_PM_DBG_STATE(hdl, client->name, client->state);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ switch (client->state) {
+ case IPA_PM_ACTIVATE_IN_PROGRESS:
+ client->state = IPA_PM_DEACTIVATE_IN_PROGRESS;
+ case IPA_PM_DEACTIVATED:
+ IPA_PM_DBG_STATE(hdl, client->name, client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return 0;
+ case IPA_PM_ACTIVATED:
+ client->state = IPA_PM_ACTIVATED_PENDING_DEACTIVATION;
+ queue_delayed_work(ipa_pm_ctx->wq, &client->deactivate_work,
+ msecs_to_jiffies(IPA_PM_DEFERRED_TIMEOUT));
+ break;
+ case IPA_PM_ACTIVATED_TIMER_SET:
+ case IPA_PM_ACTIVATED_PENDING_DEACTIVATION:
+ client->state = IPA_PM_ACTIVATED_PENDING_RESCHEDULE;
+ case IPA_PM_DEACTIVATE_IN_PROGRESS:
+ case IPA_PM_ACTIVATED_PENDING_RESCHEDULE:
+ break;
+ }
+ IPA_PM_DBG_STATE(hdl, client->name, client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+
+ return 0;
+}
+
+/**
+ * ipa_pm_deactivate_all_deferred(): Cancel the deferred deactivation timer and
+ * immediately devotes for IPA clocks
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_deactivate_all_deferred(void)
+{
+ int i;
+ bool run_algorithm = false;
+ struct ipa_pm_client *client;
+ unsigned long flags;
+
+ for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ client = ipa_pm_ctx->clients[i];
+
+ if (client == NULL)
+ continue;
+
+ cancel_delayed_work_sync(&client->deactivate_work);
+
+ if (IPA_PM_STATE_IN_PROGRESS(client->state)) {
+ wait_for_completion(&client->complete);
+ continue;
+ }
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
+
+ if (client->state == IPA_PM_ACTIVATED_TIMER_SET) {
+ client->state = IPA_PM_ACTIVATED;
+ IPA_PM_DBG_STATE(client->hdl, client->name,
+ client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ } else if (client->state ==
+ IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||
+ IPA_PM_ACTIVATED_PENDING_RESCHEDULE) {
+ run_algorithm = true;
+ client->state = IPA_PM_DEACTIVATED;
+ IPA_PM_DBG_STATE(client->hdl, client->name,
+ client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ ipa_set_tag_process_before_gating(true);
+ if (!client->skip_clk_vote)
+ IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+ deactivate_client(client->hdl);
+ } else /* if activated or deactivated, we do nothing */
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ }
+
+ if (run_algorithm)
+ do_clk_scaling();
+
+ return 0;
+}
+
+/**
+ * ipa_pm_deactivate_sync(): deactivate ipa client and devote clock. Cannot be
+ * called from atomic context.
+ * @hdl: index of the client in the array
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_deactivate_sync(u32 hdl)
+{
+ struct ipa_pm_client *client = ipa_pm_ctx->clients[hdl];
+ unsigned long flags;
+
+ if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ IPA_PM_ERR("Invalid Param\n");
+ return -EINVAL;
+ }
+
+ cancel_delayed_work_sync(&client->deactivate_work);
+
+ if (IPA_PM_STATE_IN_PROGRESS(client->state))
+ wait_for_completion(&client->complete);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ IPA_PM_DBG_STATE(hdl, client->name, client->state);
+
+ if (client->state == IPA_PM_DEACTIVATED) {
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&client->state_lock, flags);
+
+ /* else case (Deactivates all Activated cases)*/
+ ipa_set_tag_process_before_gating(true);
+ if (!client->skip_clk_vote)
+ IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ client->state = IPA_PM_DEACTIVATED;
+ IPA_PM_DBG_STATE(hdl, client->name, client->state);
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ deactivate_client(hdl);
+ do_clk_scaling();
+
+ return 0;
+}
+
+/**
+ * ipa_pm_handle_suspend(): calls the callbacks of suspended clients to wake up
+ * @pipe_bitmask: the bits represent the indexes of the clients to be woken up
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_handle_suspend(u32 pipe_bitmask)
+{
+ int i;
+ struct ipa_pm_client *client;
+ bool client_notified[IPA_PM_MAX_CLIENTS] = { false };
+
+ IPA_PM_DBG_LOW("bitmask: %d", pipe_bitmask);
+
+ if (pipe_bitmask == 0)
+ return 0;
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ for (i = 0; i < IPA3_MAX_NUM_PIPES; i++) {
+ if (pipe_bitmask & (1 << i)) {
+ client = ipa_pm_ctx->clients_by_pipe[i];
+ if (client && client_notified[client->hdl] == false) {
+ client->callback(client->callback_params,
+ IPA_PM_REQUEST_WAKEUP);
+ client_notified[client->hdl] = true;
+ }
+ }
+ }
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+ return 0;
+}
+
+/**
+ * ipa_pm_set_perf_profile(): Adds/changes the throughput requirement to IPA PM
+ * to be used for clock scaling
+ * @hdl: index of the client in the array
+ * @throughput: the new throughput value to be set for that client
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_pm_set_perf_profile(u32 hdl, int throughput)
+{
+ struct ipa_pm_client *client = ipa_pm_ctx->clients[hdl];
+ unsigned long flags;
+
+ if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL
+ || throughput < 0) {
+ IPA_PM_ERR("Invalid Params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ if (client->group == IPA_PM_GROUP_DEFAULT)
+ IPA_PM_DBG_LOW("Old throughput: %d\n", client->throughput);
+ else
+ IPA_PM_DBG_LOW("old Group %d throughput: %d\n",
+ client->group, ipa_pm_ctx->group_tput[client->group]);
+
+ if (client->group == IPA_PM_GROUP_DEFAULT)
+ client->throughput = throughput;
+ else
+ ipa_pm_ctx->group_tput[client->group] = throughput;
+
+ if (client->group == IPA_PM_GROUP_DEFAULT)
+ IPA_PM_DBG_LOW("New throughput: %d\n", client->throughput);
+ else
+ IPA_PM_DBG_LOW("New Group %d throughput: %d\n",
+ client->group, ipa_pm_ctx->group_tput[client->group]);
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ if (IPA_PM_STATE_ACTIVE(client->state || (client->group !=
+ IPA_PM_GROUP_DEFAULT))) {
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ do_clk_scaling();
+ return 0;
+ }
+ spin_unlock_irqrestore(&client->state_lock, flags);
+
+ return 0;
+}
+
+/**
+ * ipa_pm_stat() - print PM stat
+ * @buf: [in] The user buff used to print
+ * @size: [in] The size of buf
+ * Returns: number of bytes used on success, negative on failure
+ *
+ * This function is called by ipa_debugfs in order to receive
+ * a picture of the clients in the PM and the throughput, threshold and cur vote
+ */
+int ipa_pm_stat(char *buf, int size)
+{
+ struct ipa_pm_client *client;
+ struct clk_scaling_db *clk = &ipa_pm_ctx->clk_scaling;
+ int i, j, tput, cnt = 0, result = 0;
+ unsigned long flags;
+
+ if (!buf || size < 0)
+ return -EINVAL;
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+
+ result = scnprintf(buf + cnt, size - cnt, "\n\nCurrent threshold: [");
+ cnt += result;
+
+ for (i = 0; i < clk->threshold_size; i++) {
+ result = scnprintf(buf + cnt, size - cnt,
+ "%d, ", clk->current_threshold[i]);
+ cnt += result;
+ }
+
+ result = scnprintf(buf + cnt, size - cnt, "\b\b]\n");
+ cnt += result;
+
+ result = scnprintf(buf + cnt, size - cnt,
+ "Aggregated tput: %d, Cur vote: %d",
+ ipa_pm_ctx->aggregated_tput, clk->cur_vote);
+ cnt += result;
+
+ result = scnprintf(buf + cnt, size - cnt, "\n\nRegistered Clients:\n");
+ cnt += result;
+
+
+ for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ client = ipa_pm_ctx->clients[i];
+
+ if (client == NULL)
+ continue;
+
+ spin_lock_irqsave(&client->state_lock, flags);
+ if (client->group == IPA_PM_GROUP_DEFAULT)
+ tput = client->throughput;
+ else
+ tput = ipa_pm_ctx->group_tput[client->group];
+
+ result = scnprintf(buf + cnt, size - cnt,
+ "Client[%d]: %s State:%s\nGroup: %s Throughput: %d Pipes: ",
+ i, client->name, client_state_to_str[client->state],
+ ipa_pm_group_to_str[client->group], tput);
+ cnt += result;
+
+ for (j = 0; j < IPA3_MAX_NUM_PIPES; j++) {
+ if (ipa_pm_ctx->clients_by_pipe[j] == client) {
+ result = scnprintf(buf + cnt, size - cnt,
+ "%d, ", j);
+ cnt += result;
+ }
+ }
+
+ result = scnprintf(buf + cnt, size - cnt, "\b\b\n\n");
+ cnt += result;
+ spin_unlock_irqrestore(&client->state_lock, flags);
+ }
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ return cnt;
+}
+
+/**
+ * ipa_pm_exceptions_stat() - print PM exceptions stat
+ * @buf: [in] The user buff used to print
+ * @size: [in] The size of buf
+ * Returns: number of bytes used on success, negative on failure
+ *
+ * This function is called by ipa_debugfs in order to receive
+ * a full picture of the exceptions in the PM
+ */
+int ipa_pm_exceptions_stat(char *buf, int size)
+{
+ int i, j, cnt = 0, result = 0;
+ struct ipa_pm_exception_list *exception;
+
+ if (!buf || size < 0)
+ return -EINVAL;
+
+ result = scnprintf(buf + cnt, size - cnt, "\n");
+ cnt += result;
+
+ mutex_lock(&ipa_pm_ctx->client_mutex);
+ for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) {
+ exception = &ipa_pm_ctx->clk_scaling.exception_list[i];
+ if (exception == NULL) {
+ result = scnprintf(buf + cnt, size - cnt,
+ "Exception %d is NULL\n\n", i);
+ cnt += result;
+ continue;
+ }
+
+ result = scnprintf(buf + cnt, size - cnt,
+ "Exception %d: %s\nPending: %d Bitmask: %d Threshold: ["
+ , i, exception->clients, exception->pending,
+ exception->bitmask);
+ cnt += result;
+ for (j = 0; j < ipa_pm_ctx->clk_scaling.threshold_size; j++) {
+ result = scnprintf(buf + cnt, size - cnt,
+ "%d, ", exception->threshold[j]);
+ cnt += result;
+ }
+ result = scnprintf(buf + cnt, size - cnt, "\b\b]\n\n");
+ cnt += result;
+ }
+ mutex_unlock(&ipa_pm_ctx->client_mutex);
+
+ return cnt;
+}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
new file mode 100644
index 0000000..ca022b5
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPA_PM_H_
+#define _IPA_PM_H_
+
+#include <linux/msm_ipa.h>
+
+/* internal to ipa */
+#define IPA_PM_MAX_CLIENTS 10
+#define IPA_PM_MAX_EX_CL 64
+#define IPA_PM_THRESHOLD_MAX 2
+#define IPA_PM_EXCEPTION_MAX 2
+#define IPA_PM_DEFERRED_TIMEOUT 100
+#define IPA_PM_STATE_MAX 7
+
+/*
+ * ipa_pm group names
+ *
+ * Default stands for individual clients while other groups share one throughput
+ * Some groups also have special flags like modem which do not vote for clock
+ * but is accounted for in clock scaling while activated
+ */
+enum ipa_pm_group {
+ IPA_PM_GROUP_DEFAULT,
+ IPA_PM_GROUP_APPS,
+ IPA_PM_GROUP_MODEM,
+ IPA_PM_GROUP_MAX,
+};
+
+/*
+ * ipa_pm_cb_event
+ *
+ * specifies what kind of callback is being called.
+ * IPA_PM_CLIENT_ACTIVATED: the client has completed asynchronous activation
+ * IPA_PM_REQUEST_WAKEUP: wake up the client after it has been suspended
+ */
+enum ipa_pm_cb_event {
+ IPA_PM_CLIENT_ACTIVATED,
+ IPA_PM_REQUEST_WAKEUP,
+ IPA_PM_CB_EVENT_MAX,
+};
+
+/*
+ * struct ipa_pm_exception - clients included in exception and its threshold
+ * @usecase: comma separated client names
+ * @threshold: the threshold values for the exception
+ */
+struct ipa_pm_exception {
+ const char *usecase;
+ int threshold[IPA_PM_THRESHOLD_MAX];
+};
+
+/*
+ * struct ipa_pm_init_params - parameters needed for initializng the pm
+ * @default_threshold: the thresholds used if no exception passes
+ * @threshold_size: size of the threshold
+ * @exceptions: list of exceptions for the pm
+ * @exception_size: size of the exception_list
+ */
+struct ipa_pm_init_params {
+ int default_threshold[IPA_PM_THRESHOLD_MAX];
+ int threshold_size;
+ struct ipa_pm_exception exceptions[IPA_PM_EXCEPTION_MAX];
+ int exception_size;
+};
+
+/*
+ * struct ipa_pm_register_params - parameters needed to register a client
+ * @name: name of the client
+ * @callback: pointer to the client's callback function
+ * @user_data: pointer to the client's callback parameters
+ * @group: group number of the client
+ * @skip_clk_vote: 0 if client votes for clock when activated, 1 if no vote
+ */
+struct ipa_pm_register_params {
+ const char *name;
+ void (*callback)(void*, enum ipa_pm_cb_event);
+ void *user_data;
+ enum ipa_pm_group group;
+ bool skip_clk_vote;
+};
+
+int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl);
+int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer);
+int ipa_pm_activate(u32 hdl);
+int ipa_pm_activate_sync(u32 hdl);
+int ipa_pm_deferred_deactivate(u32 hdl);
+int ipa_pm_deactivate_sync(u32 hdl);
+int ipa_pm_set_perf_profile(u32 hdl, int throughput);
+int ipa_pm_deregister(u32 hdl);
+
+/* IPA Internal Functions */
+int ipa_pm_init(struct ipa_pm_init_params *params);
+int ipa_pm_destroy(void);
+int ipa_pm_handle_suspend(u32 pipe_bitmask);
+int ipa_pm_deactivate_all_deferred(void);
+int ipa_pm_stat(char *buf, int size);
+int ipa_pm_exceptions_stat(char *buf, int size);
+
+#endif /* _IPA_PM_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 61bccc6..4e8c233 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1214,7 +1214,6 @@
/* voting for bus BW to ipa_rm*/
int ipa3_vote_for_bus_bw(uint32_t *bw_mbps)
{
- struct ipa_rm_perf_profile profile;
int ret;
if (bw_mbps == NULL) {
@@ -1222,16 +1221,13 @@
return -EINVAL;
}
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = *bw_mbps;
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
- &profile);
+ ret = ipa3_wwan_set_modem_perf_profile(*bw_mbps);
if (ret)
IPAWANERR("Failed to set perf profile to BW %u\n",
- profile.max_supported_bandwidth_mbps);
+ *bw_mbps);
else
IPAWANDBG("Succeeded to set perf profile to BW %u\n",
- profile.max_supported_bandwidth_mbps);
+ *bw_mbps);
return ret;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
index d5d8503..d3a4ba0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
@@ -207,6 +207,10 @@
void ipa3_q6_handshake_complete(bool ssr_bootup);
+int ipa3_wwan_set_modem_perf_profile(int throughput);
+
+int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state);
+
void ipa3_qmi_init(void);
void ipa3_qmi_cleanup(void);
@@ -323,6 +327,11 @@
static inline void ipa3_q6_handshake_complete(bool ssr_bootup) { }
+static inline int ipa3_wwan_set_modem_perf_profile(int throughput)
+{
+ return -EPERM;
+}
+
static inline void ipa3_qmi_init(void)
{
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 5206337..f717264 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4855,11 +4855,8 @@
IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
/* queue a work to start polling if don't have one */
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
- if (!atomic_read(&ep->sys->curr_polling_state)) {
- ipa3_inc_acquire_wakelock();
- atomic_set(&ep->sys->curr_polling_state, 1);
- queue_work(ep->sys->wq, &ep->sys->work);
- }
+ if (!atomic_read(&ep->sys->curr_polling_state))
+ __ipa_gsi_irq_rx_scedule_poll(ep->sys);
}
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index dc71414..74f5bbd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -1961,20 +1961,3 @@
valmask->mask = valmask->val;
}
-
-void ipahal_get_status_ep_valmask(int pipe_num,
- struct ipahal_reg_valmask *valmask)
-{
- if (!valmask) {
- IPAHAL_ERR("Input error\n");
- return;
- }
-
- valmask->val =
- (pipe_num & IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK) <<
- IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT;
-
- valmask->mask =
- IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK <<
- IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT;
-}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index a2864cd..df3c976 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -541,8 +541,6 @@
void ipahal_get_fltrt_hash_flush_valmask(
struct ipahal_reg_fltrt_hash_flush *flush,
struct ipahal_reg_valmask *valmask);
-void ipahal_get_status_ep_valmask(int pipe_num,
- struct ipahal_reg_valmask *valmask);
#endif /* _IPAHAL_REG_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 48be199..f08e1e3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -142,6 +142,9 @@
u32 ipa3_to_apps_hdl;
struct mutex pipe_handle_guard;
struct mutex add_mux_channel_lock;
+ u32 pm_hdl;
+ u32 q6_pm_hdl;
+ u32 q6_teth_pm_hdl;
};
static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
@@ -423,6 +426,8 @@
{
int i, j;
+ /* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */
+ mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
if (rule_req->filter_spec_ex_list_valid == true) {
rmnet_ipa3_ctx->num_q6_rules =
rule_req->filter_spec_ex_list_len;
@@ -431,6 +436,8 @@
} else {
rmnet_ipa3_ctx->num_q6_rules = 0;
IPAWANERR("got no UL rules from modem\n");
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return -EINVAL;
}
@@ -633,9 +640,13 @@
rmnet_ipa3_ctx->num_q6_rules = 0;
memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0,
sizeof(ipa3_qmi_ctx->q6_ul_filter_rule));
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return -EINVAL;
success:
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return 0;
}
@@ -1126,8 +1137,14 @@
send:
/* IPA_RM checking start */
- ret = ipa_rm_inactivity_timer_request_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ipa3_ctx->use_ipa_pm) {
+ /* activate the modem pm for clock scaling */
+ ipa_pm_activate(rmnet_ipa3_ctx->q6_pm_hdl);
+ ret = ipa_pm_activate(rmnet_ipa3_ctx->pm_hdl);
+ } else {
+ ret = ipa_rm_inactivity_timer_request_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
if (ret == -EINPROGRESS) {
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
@@ -1156,9 +1173,15 @@
dev->stats.tx_bytes += skb->len;
ret = NETDEV_TX_OK;
out:
- if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
- ipa_rm_inactivity_timer_release_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
+ } else {
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
+ }
return ret;
}
@@ -1210,9 +1233,15 @@
netif_wake_queue(wwan_ptr->net);
}
- if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
- ipa_rm_inactivity_timer_release_resource(
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
+ } else {
+ ipa_rm_inactivity_timer_release_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
+ }
__netif_tx_unlock_bh(netdev_get_tx_queue(dev, 0));
dev_kfree_skb_any(skb);
}
@@ -1420,8 +1449,13 @@
if (rmnet_ipa3_ctx->num_q6_rules != 0) {
/* already got Q6 UL filter rules*/
- if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false)
+ if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) {
+ /* prevent multi-threads accessing num_q6_rules */
+ mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
+ }
if (rc)
IPAWANERR("install UL rules failed\n");
else
@@ -1845,6 +1879,91 @@
return;
}
}
+
+int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state)
+{
+ if (!state)
+ return -EINVAL;
+
+ if (!ipa_pm_is_used())
+ return 0;
+
+ if (state->up)
+ return ipa_pm_activate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
+ else
+ return ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
+}
+
+/**
+ * ipa3_q6_register_pm - Register modem clients for PM
+ *
+ * This function will register 2 client with IPA PM to represent modem
+ * in clock scaling calculation:
+ * - "EMB MODEM" - this client will be activated with embedded traffic
+ - "TETH MODEM" - this client we be activated by IPACM on offload to
+ modem.
+*/
+static int ipa3_q6_register_pm(void)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = "EMB MODEM";
+ pm_reg.group = IPA_PM_GROUP_MODEM;
+ pm_reg.skip_clk_vote = true;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+
+ pm_reg.name = "TETH MODEM";
+ pm_reg.group = IPA_PM_GROUP_MODEM;
+ pm_reg.skip_clk_vote = true;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_teth_pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void ipa3_q6_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_pm_hdl);
+ ipa_pm_deregister(rmnet_ipa3_ctx->q6_pm_hdl);
+}
+
+int ipa3_wwan_set_modem_perf_profile(int throughput)
+{
+ struct ipa_rm_perf_profile profile;
+ int ret;
+
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl, throughput);
+ if (ret)
+ return ret;
+ return ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl,
+ throughput);
+
+ if (ipa3_ctx->use_ipa_pm) {
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl,
+ throughput);
+ if (ret)
+ return ret;
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl,
+ throughput);
+ } else {
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = throughput;
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
+ &profile);
+ }
+
+ return ret;
+}
+
static int ipa3_q6_initialize_rm(void)
{
struct ipa_rm_create_params create_params;
@@ -2062,6 +2181,120 @@
schedule_work(&ipa3_scheduled_probe);
}
+static void ipa_pm_wwan_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct net_device *dev = (struct net_device *)p;
+ struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
+
+ IPAWANDBG_LOW("event %d\n", event);
+ switch (event) {
+ case IPA_PM_CLIENT_ACTIVATED:
+ if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
+ complete_all(&wwan_ptr->resource_granted_completion);
+ break;
+ }
+ ipa3_rm_resource_granted(dev);
+ break;
+ default:
+ pr_err("%s: unknown event %d\n", __func__, event);
+ break;
+ }
+}
+
+static int ipa3_wwan_register_netdev_pm_client(struct net_device *dev)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = IPA_NETDEV()->name;
+ pm_reg.user_data = dev;
+ pm_reg.callback = ipa_pm_wwan_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static void ipa3_wwan_deregister_netdev_pm_client(void)
+{
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deregister(rmnet_ipa3_ctx->pm_hdl);
+}
+
+static int ipa3_wwan_create_wwan_rm_resource(struct net_device *dev)
+{
+ struct ipa_rm_create_params ipa_rm_params;
+ struct ipa_rm_perf_profile profile;
+ int ret;
+
+ memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
+ ipa_rm_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
+ ipa_rm_params.reg_params.user_data = dev;
+ ipa_rm_params.reg_params.notify_cb = ipa3_rm_notify;
+ ret = ipa_rm_create_resource(&ipa_rm_params);
+ if (ret) {
+ pr_err("%s: unable to create resourse %d in IPA RM\n",
+ __func__, IPA_RM_RESOURCE_WWAN_0_PROD);
+ return ret;
+ }
+ ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_INACTIVITY_TIMER);
+ if (ret) {
+ pr_err("%s: ipa rm timer init failed %d on resourse %d\n",
+ __func__, ret, IPA_RM_RESOURCE_WWAN_0_PROD);
+ goto timer_init_err;
+ }
+ /* add dependency */
+ ret = ipa_rm_add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (ret)
+ goto add_dpnd_err;
+ /* setup Performance profile */
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WWAN_0_PROD,
+ &profile);
+ if (ret)
+ goto set_perf_err;
+
+ return 0;
+
+set_perf_err:
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+add_dpnd_err:
+ ipa_rm_inactivity_timer_destroy(
+ IPA_RM_RESOURCE_WWAN_0_PROD); /* IPA_RM */
+timer_init_err:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ return ret;
+}
+
+static void ipa3_wwan_delete_wwan_rm_resource(void)
+{
+ int ret;
+
+ ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (ret < 0)
+ IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
+ ret);
+ ret = ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ret < 0)
+ IPAWANERR(
+ "Error ipa_rm_inactivity_timer_destroy resource %d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+ ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ret < 0)
+ IPAWANERR("Error deleting resource %d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+}
+
/**
* ipa3_wwan_probe() - Initialized the module and registers as a
* network interface to the network stack
@@ -2079,8 +2312,6 @@
{
int ret, i;
struct net_device *dev;
- struct ipa_rm_create_params ipa_rm_params; /* IPA_RM */
- struct ipa_rm_perf_profile profile; /* IPA_RM */
pr_info("rmnet_ipa3 started initialization\n");
@@ -2174,7 +2405,10 @@
if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
/* IPA_RM configuration starts */
- ret = ipa3_q6_initialize_rm();
+ if (ipa3_ctx->use_ipa_pm)
+ ret = ipa3_q6_register_pm();
+ else
+ ret = ipa3_q6_initialize_rm();
if (ret) {
IPAWANERR("%s: ipa3_q6_initialize_rm failed, ret: %d\n",
__func__, ret);
@@ -2182,36 +2416,14 @@
}
}
- memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
- ipa_rm_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
- ipa_rm_params.reg_params.user_data = dev;
- ipa_rm_params.reg_params.notify_cb = ipa3_rm_notify;
- ret = ipa_rm_create_resource(&ipa_rm_params);
+ if (ipa3_ctx->use_ipa_pm)
+ ret = ipa3_wwan_register_netdev_pm_client(dev);
+ else
+ ret = ipa3_wwan_create_wwan_rm_resource(dev);
if (ret) {
- pr_err("%s: unable to create resourse %d in IPA RM\n",
- __func__, IPA_RM_RESOURCE_WWAN_0_PROD);
- goto create_rsrc_err;
+ IPAWANERR("fail to create/register pm resources\n");
+ goto fail_pm;
}
- ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_INACTIVITY_TIMER);
- if (ret) {
- pr_err("%s: ipa rm timer init failed %d on resourse %d\n",
- __func__, ret, IPA_RM_RESOURCE_WWAN_0_PROD);
- goto timer_init_err;
- }
- /* add dependency */
- ret = ipa_rm_add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret)
- goto add_dpnd_err;
- /* setup Performance profile */
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WWAN_0_PROD,
- &profile);
- if (ret)
- goto set_perf_err;
- /* IPA_RM configuration ends */
/* Enable SG support in netdevice. */
if (ipa3_rmnet_res.ipa_advertise_sg_support)
@@ -2247,28 +2459,18 @@
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
unregister_netdev(dev);
set_perf_err:
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret)
- IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
- ret);
-add_dpnd_err:
- ret = ipa_rm_inactivity_timer_destroy(
- IPA_RM_RESOURCE_WWAN_0_PROD); /* IPA_RM */
- if (ret)
- IPAWANERR("Error ipa_rm_inactivity_timer_destroy %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
-timer_init_err:
- ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret)
- IPAWANERR("Error deleting resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
-create_rsrc_err:
-
- if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
- ipa3_q6_deinitialize_rm();
-
+ if (ipa3_ctx->use_ipa_pm)
+ ipa3_wwan_deregister_netdev_pm_client();
+ else
+ ipa3_wwan_delete_wwan_rm_resource();
+fail_pm:
+ if (ipa3_ctx->use_ipa_pm) {
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deregister_pm();
+ } else {
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deinitialize_rm();
+ }
q6_init_err:
free_netdev(dev);
rmnet_ipa3_ctx->wwan_priv = NULL;
@@ -2304,21 +2506,10 @@
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
unregister_netdev(IPA_NETDEV());
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret < 0)
- IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
- ret);
- ret = ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret < 0)
- IPAWANERR(
- "Error ipa_rm_inactivity_timer_destroy resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
- ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret < 0)
- IPAWANERR("Error deleting resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa3_wwan_deregister_netdev_pm_client();
+ else
+ ipa3_wwan_delete_wwan_rm_resource();
cancel_work_sync(&ipa3_tx_wakequeue_work);
cancel_delayed_work(&ipa_tether_stats_poll_wakequeue_work);
if (IPA_NETDEV())
@@ -2372,23 +2563,26 @@
if (wwan_ptr == NULL) {
IPAWANERR("wwan_ptr is NULL.\n");
ret = 0;
- goto unlock_and_bail;
+ netif_tx_unlock_bh(netdev);
+ goto bail;
}
/* Do not allow A7 to suspend in case there are oustanding packets */
if (atomic_read(&wwan_ptr->outstanding_pkts) != 0) {
IPAWANDBG("Outstanding packets, postponing AP suspend.\n");
ret = -EAGAIN;
- goto unlock_and_bail;
+ netif_tx_unlock_bh(netdev);
+ goto bail;
}
/* Make sure that there is no Tx operation ongoing */
netif_stop_queue(netdev);
- ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- ret = 0;
-
-unlock_and_bail:
netif_tx_unlock_bh(netdev);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
+ else
+ ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ ret = 0;
bail:
IPAWANDBG("Exit with %d\n", ret);
return ret;
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index c7a6186..2e43abf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
@@ -50,6 +50,9 @@
#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
compat_uptr_t)
+#define WAN_IOC_NOTIFY_WAN_STATE32 _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_NOTIFY_WAN_STATE, \
+ compat_uptr_t)
#endif
static unsigned int dev_num = 1;
@@ -316,6 +319,27 @@
}
break;
+ case WAN_IOC_NOTIFY_WAN_STATE:
+ IPAWANDBG_LOW("device %s got WAN_IOC_NOTIFY_WAN_STATE :>>>\n",
+ DRIVER_NAME);
+ pyld_sz = sizeof(struct wan_ioctl_notify_wan_state);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (u8 __user *)arg, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (ipa3_wwan_set_modem_state(
+ (struct wan_ioctl_notify_wan_state *)param)) {
+ IPAWANERR("WAN_IOC_NOTIFY_WAN_STATE failed\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
default:
retval = -ENOTTY;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
index 297f932..7496f28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
@@ -50,6 +50,7 @@
dev_t dev_num;
struct device *dev;
struct cdev cdev;
+ u32 modem_pm_hdl;
};
static struct ipa3_teth_bridge_ctx *ipa3_teth_ctx;
@@ -118,14 +119,25 @@
*/
int ipa3_teth_bridge_disconnect(enum ipa_client_type client)
{
+ int res = 0;
+
TETH_DBG_FUNC_ENTRY();
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_USB_CONS);
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_deactivate_sync(ipa3_teth_ctx->modem_pm_hdl);
+ if (res) {
+ TETH_ERR("fail to deactivate modem %d\n", res);
+ return res;
+ }
+ res = ipa_pm_destroy();
+ } else {
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ }
TETH_DBG_FUNC_EXIT();
- return 0;
+ return res;
}
/**
@@ -140,9 +152,27 @@
int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
{
int res = 0;
+ struct ipa_pm_register_params reg_params;
+
+ memset(®_params, 0, sizeof(reg_params));
TETH_DBG_FUNC_ENTRY();
+ if (ipa_pm_is_used()) {
+ reg_params.name = "MODEM (USB RMNET)";
+ reg_params.group = IPA_PM_GROUP_MODEM;
+ reg_params.skip_clk_vote = true;
+ res = ipa_pm_register(®_params,
+ &ipa3_teth_ctx->modem_pm_hdl);
+ if (res) {
+ TETH_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_activate_sync(ipa3_teth_ctx->modem_pm_hdl);
+ goto bail;
+ }
+
/* Build the dependency graph, first add_dependency call is sync
* in order to make sure the IPA clocks are up before we continue
* and notify the USB driver it may continue.
@@ -234,6 +264,8 @@
res = -ENODEV;
goto fail_cdev_add;
}
+
+ ipa3_teth_ctx->modem_pm_hdl = ~0;
TETH_DBG("Tethering bridge driver init OK\n");
return 0;
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index aafb8fc..707c95e 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -1247,6 +1247,79 @@
}
EXPORT_SYMBOL(geni_se_iommu_free_buf);
+/**
+ * geni_se_dump_dbg_regs() - Print relevant registers that capture most
+ * accurately the state of an SE.
+ * @_dev: Pointer to the SE's device.
+ * @iomem: Base address of the SE's register space.
+ * @ipc: IPC log context handle.
+ *
+ * This function is used to print out all the registers that capture the state
+ * of an SE to help debug any errors.
+ *
+ * Return: None
+ */
+void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
+ void *ipc)
+{
+ u32 m_cmd0 = 0;
+ u32 m_irq_status = 0;
+ u32 geni_status = 0;
+ u32 geni_ios = 0;
+ u32 dma_rx_irq = 0;
+ u32 dma_tx_irq = 0;
+ u32 rx_fifo_status = 0;
+ u32 tx_fifo_status = 0;
+ u32 se_dma_dbg = 0;
+ u32 m_cmd_ctrl = 0;
+ u32 se_dma_rx_len = 0;
+ u32 se_dma_rx_len_in = 0;
+ u32 se_dma_tx_len = 0;
+ u32 se_dma_tx_len_in = 0;
+ struct geni_se_device *geni_se_dev;
+
+ if (!ipc)
+ return;
+
+ geni_se_dev = dev_get_drvdata(rsc->wrapper_dev);
+ if (unlikely(!geni_se_dev || !geni_se_dev->bus_bw))
+ return;
+ mutex_lock(&geni_se_dev->ab_ib_lock);
+ if (unlikely(list_empty(&rsc->ab_list) || list_empty(&rsc->ib_list))) {
+ GENI_SE_DBG(ipc, false, NULL, "%s: Clocks not on\n", __func__);
+ goto exit_geni_se_dump_dbg_regs;
+ }
+ m_cmd0 = geni_read_reg(base, SE_GENI_M_CMD0);
+ m_irq_status = geni_read_reg(base, SE_GENI_M_IRQ_STATUS);
+ geni_status = geni_read_reg(base, SE_GENI_STATUS);
+ geni_ios = geni_read_reg(base, SE_GENI_IOS);
+ dma_rx_irq = geni_read_reg(base, SE_DMA_TX_IRQ_STAT);
+ dma_tx_irq = geni_read_reg(base, SE_DMA_RX_IRQ_STAT);
+ rx_fifo_status = geni_read_reg(base, SE_GENI_RX_FIFO_STATUS);
+ tx_fifo_status = geni_read_reg(base, SE_GENI_TX_FIFO_STATUS);
+ se_dma_dbg = geni_read_reg(base, SE_DMA_DEBUG_REG0);
+ m_cmd_ctrl = geni_read_reg(base, SE_GENI_M_CMD_CTRL_REG);
+ se_dma_rx_len = geni_read_reg(base, SE_DMA_RX_LEN);
+ se_dma_rx_len_in = geni_read_reg(base, SE_DMA_RX_LEN_IN);
+ se_dma_tx_len = geni_read_reg(base, SE_DMA_TX_LEN);
+ se_dma_tx_len_in = geni_read_reg(base, SE_DMA_TX_LEN_IN);
+
+ GENI_SE_DBG(ipc, false, NULL,
+ "%s: m_cmd0:0x%x, m_irq_status:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
+ __func__, m_cmd0, m_irq_status, geni_status, geni_ios);
+ GENI_SE_DBG(ipc, false, NULL,
+ "dma_rx_irq:0x%x, dma_tx_irq:0x%x, rx_fifo_sts:0x%x, tx_fifo_sts:0x%x\n"
+ , dma_rx_irq, dma_tx_irq, rx_fifo_status, tx_fifo_status);
+ GENI_SE_DBG(ipc, false, NULL,
+ "se_dma_dbg:0x%x, m_cmd_ctrl:0x%x, dma_rxlen:0x%x, dma_rxlen_in:0x%x\n",
+ se_dma_dbg, m_cmd_ctrl, se_dma_rx_len, se_dma_rx_len_in);
+ GENI_SE_DBG(ipc, false, NULL,
+ "dma_txlen:0x%x, dma_txlen_in:0x%x\n", se_dma_tx_len, se_dma_tx_len_in);
+exit_geni_se_dump_dbg_regs:
+ mutex_unlock(&geni_se_dev->ab_ib_lock);
+}
+EXPORT_SYMBOL(geni_se_dump_dbg_regs);
+
static const struct of_device_id geni_se_dt_match[] = {
{ .compatible = "qcom,qupv3-geni-se", },
{ .compatible = "qcom,qupv3-geni-se-cb", },
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 7f6d346..f6e81d8 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -348,7 +348,7 @@
}
#define MINIMUM_PARALLEL_FCC_UA 500000
-#define PL_TAPER_WORK_DELAY_MS 100
+#define PL_TAPER_WORK_DELAY_MS 500
#define TAPER_RESIDUAL_PCT 90
static void pl_taper_work(struct work_struct *work)
{
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 5e346dc..7f220c3 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -2943,6 +2943,9 @@
t_predicted_cv, t_predicted = 0;
s64 delta_ms;
+ if (!chip->soc_reporting_ready)
+ return -ENODATA;
+
if (chip->bp.float_volt_uv <= 0) {
pr_err("battery profile is not loaded\n");
return -ENODATA;
@@ -4931,6 +4934,13 @@
static void fg_cleanup(struct fg_chip *chip)
{
+ int i;
+
+ for (i = 0; i < FG_IRQ_MAX; i++) {
+ if (fg_irqs[i].irq)
+ devm_free_irq(chip->dev, fg_irqs[i].irq, chip);
+ }
+
power_supply_unreg_notifier(&chip->nb);
debugfs_remove_recursive(chip->dfs_root);
if (chip->awake_votable)
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 1b890d5..60f4df8 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -2250,12 +2250,6 @@
int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc = 0;
-
- rc = smblib_get_prop_usb_present(chg, val);
- if (rc < 0 || !val->intval)
- return rc;
-
if (!chg->iio.usbin_v_chan ||
PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 1910100..00602ab 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -66,6 +66,9 @@
{
static const char * const strings[] = RNC_STATES;
+ if (state >= ARRAY_SIZE(strings))
+ return "UNKNOWN";
+
return strings[state];
}
#undef C
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index ad33238..8c4641b 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -243,12 +243,15 @@
struct qla_hw_data *ha = vha->hw;
ssize_t rval = 0;
- if (ha->optrom_state != QLA_SREADING)
- return 0;
-
mutex_lock(&ha->optrom_mutex);
+
+ if (ha->optrom_state != QLA_SREADING)
+ goto out;
+
rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
ha->optrom_region_size);
+
+out:
mutex_unlock(&ha->optrom_mutex);
return rval;
@@ -263,14 +266,19 @@
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
- if (ha->optrom_state != QLA_SWRITING)
+ mutex_lock(&ha->optrom_mutex);
+
+ if (ha->optrom_state != QLA_SWRITING) {
+ mutex_unlock(&ha->optrom_mutex);
return -EINVAL;
- if (off > ha->optrom_region_size)
+ }
+ if (off > ha->optrom_region_size) {
+ mutex_unlock(&ha->optrom_mutex);
return -ERANGE;
+ }
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
- mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
mutex_unlock(&ha->optrom_mutex);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 44c466b..ecc6aad 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -142,6 +142,7 @@
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
rwlock_t rq_list_lock; /* protect access to list in req_arr */
+ struct mutex f_mutex; /* protect against changes in this fd */
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve; /* buffer held for this file descriptor */
@@ -155,6 +156,7 @@
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
char mmap_called; /* 0 -> mmap() never called on this fd */
+ char res_in_use; /* 1 -> 'reserve' array in use */
struct kref f_ref;
struct execute_work ew;
} Sg_fd;
@@ -198,7 +200,6 @@
static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request *sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
static Sg_device *sg_get_dev(int dev);
static void sg_device_destroy(struct kref *kref);
@@ -614,6 +615,7 @@
}
buf += SZ_SG_HEADER;
__get_user(opcode, buf);
+ mutex_lock(&sfp->f_mutex);
if (sfp->next_cmd_len > 0) {
cmd_size = sfp->next_cmd_len;
sfp->next_cmd_len = 0; /* reset so only this write() effected */
@@ -622,6 +624,7 @@
if ((opcode >= 0xc0) && old_hdr.twelve_byte)
cmd_size = 12;
}
+ mutex_unlock(&sfp->f_mutex);
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
"sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
/* Determine buffer size. */
@@ -721,7 +724,7 @@
sg_remove_request(sfp, srp);
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */
}
- if (sg_res_in_use(sfp)) {
+ if (sfp->res_in_use) {
sg_remove_request(sfp, srp);
return -EBUSY; /* reserve buffer already being used */
}
@@ -896,7 +899,7 @@
return result;
if (val) {
sfp->low_dma = 1;
- if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+ if ((0 == sfp->low_dma) && !sfp->res_in_use) {
val = (int) sfp->reserve.bufflen;
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
@@ -971,12 +974,18 @@
return -EINVAL;
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
+ mutex_lock(&sfp->f_mutex);
if (val != sfp->reserve.bufflen) {
- if (sg_res_in_use(sfp) || sfp->mmap_called)
+ if (sfp->mmap_called ||
+ sfp->res_in_use) {
+ mutex_unlock(&sfp->f_mutex);
return -EBUSY;
+ }
+
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
}
+ mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_RESERVED_SIZE:
val = min_t(int, sfp->reserve.bufflen,
@@ -1728,13 +1737,22 @@
md = &map_data;
if (md) {
- if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+ mutex_lock(&sfp->f_mutex);
+ if (dxfer_len <= rsv_schp->bufflen &&
+ !sfp->res_in_use) {
+ sfp->res_in_use = 1;
sg_link_reserve(sfp, srp, dxfer_len);
- else {
+ } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
+ mutex_unlock(&sfp->f_mutex);
+ return -EBUSY;
+ } else {
res = sg_build_indirect(req_schp, sfp, dxfer_len);
- if (res)
+ if (res) {
+ mutex_unlock(&sfp->f_mutex);
return res;
+ }
}
+ mutex_unlock(&sfp->f_mutex);
md->pages = req_schp->pages;
md->page_order = req_schp->page_order;
@@ -2025,6 +2043,8 @@
req_schp->sglist_len = 0;
sfp->save_scat_len = 0;
srp->res_used = 0;
+ /* Called without mutex lock to avoid deadlock */
+ sfp->res_in_use = 0;
}
static Sg_request *
@@ -2136,6 +2156,7 @@
rwlock_init(&sfp->rq_list_lock);
kref_init(&sfp->f_ref);
+ mutex_init(&sfp->f_mutex);
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
@@ -2211,20 +2232,6 @@
schedule_work(&sfp->ew.work);
}
-static int
-sg_res_in_use(Sg_fd * sfp)
-{
- const Sg_request *srp;
- unsigned long iflags;
-
- read_lock_irqsave(&sfp->rq_list_lock, iflags);
- for (srp = sfp->headrp; srp; srp = srp->nextrp)
- if (srp->res_used)
- break;
- read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- return srp ? 1 : 0;
-}
-
#ifdef CONFIG_SCSI_PROC_FS
static int
sg_idr_max_id(int id, void *p, void *data)
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 557ca19..11e11e4 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -950,6 +950,10 @@
seq_printf(file, "hba->saved_err = 0x%x\n", hba->saved_err);
seq_printf(file, "hba->saved_uic_err = 0x%x\n", hba->saved_uic_err);
+ seq_printf(file, "power_mode_change_cnt = %d\n",
+ hba->ufs_stats.power_mode_change_cnt);
+ seq_printf(file, "hibern8_exit_cnt = %d\n",
+ hba->ufs_stats.hibern8_exit_cnt);
return 0;
}
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 792ae42..32edd76 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -21,6 +21,7 @@
#define MAX_UFS_QCOM_HOSTS 2
#define MAX_U32 (~(u32)0)
#define MPHY_TX_FSM_STATE 0x41
+#define MPHY_RX_FSM_STATE 0xC1
#define TX_FSM_HIBERN8 0x1
#define HBRN8_POLL_TOUT_MS 100
#define DEFAULT_CLK_RATE_HZ 1000000
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7c5a1bc..f5a6736 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -144,10 +144,11 @@
static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
{
- int ret = 0;
+ int len, ret = 0;
char prop_name[MAX_PROP_SIZE];
struct ufs_vreg *vreg = NULL;
struct device_node *np = dev->of_node;
+ const __be32 *prop;
if (!np) {
dev_err(dev, "%s: non DT initialization\n", __func__);
@@ -186,8 +187,16 @@
vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
} else {
- vreg->min_uV = UFS_VREG_VCC_MIN_UV;
- vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+ prop = of_get_property(np, "vcc-voltage-level", &len);
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_warn(dev, "%s vcc-voltage-level property.\n",
+ prop ? "invalid format" : "no");
+ vreg->min_uV = UFS_VREG_VCC_MIN_UV;
+ vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+ } else {
+ vreg->min_uV = be32_to_cpup(&prop[0]);
+ vreg->max_uV = be32_to_cpup(&prop[1]);
+ }
}
} else if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c132dbc..b6ba4c4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -864,6 +864,24 @@
}
}
+static void ufshcd_print_fsm_state(struct ufs_hba *hba)
+{
+ int err = 0, tx_fsm_val = 0, rx_fsm_val = 0;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
+ dev_err(hba->dev, "%s: TX_FSM_STATE = %u, err = %d\n", __func__,
+ tx_fsm_val, err);
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB_SEL(MPHY_RX_FSM_STATE,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+ &rx_fsm_val);
+ dev_err(hba->dev, "%s: RX_FSM_STATE = %u, err = %d\n", __func__,
+ rx_fsm_val, err);
+}
+
static void ufshcd_print_host_state(struct ufs_hba *hba)
{
if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_STATE_EN))
@@ -888,6 +906,7 @@
hba->capabilities, hba->caps);
dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
hba->dev_info.quirks);
+ ufshcd_print_fsm_state(hba);
}
/**
@@ -4856,6 +4875,7 @@
memcpy(&hba->pwr_info, pwr_mode,
sizeof(struct ufs_pa_layer_attr));
+ hba->ufs_stats.power_mode_change_cnt++;
}
return ret;
@@ -7151,6 +7171,12 @@
} while (err && --retries);
/*
+ * There is no point proceeding even after failing
+ * to recover after multiple retries.
+ */
+ if (err && ufshcd_is_embedded_dev(hba))
+ BUG();
+ /*
* After reset the door-bell might be cleared, complete
* outstanding requests in s/w here.
*/
@@ -7615,9 +7641,6 @@
{
int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist);
- hba->ufs_stats.hibern8_exit_cnt = 0;
- hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0);
-
memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size);
@@ -9689,6 +9712,8 @@
static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
{
+ if (!ufshcd_is_clkscaling_supported(hba))
+ return;
__ufshcd_shutdown_clkscaling(hba);
device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index fc855db..1b21238 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -644,6 +644,7 @@
struct ufshcd_clk_ctx clk_rel;
u32 hibern8_exit_cnt;
ktime_t last_hibern8_exit_tstamp;
+ u32 power_mode_change_cnt;
struct ufs_uic_err_reg_hist pa_err;
struct ufs_uic_err_reg_hist dl_err;
struct ufs_uic_err_reg_hist nl_err;
@@ -1198,6 +1199,14 @@
pwr_info->pwr_tx == FASTAUTO_MODE);
}
+static inline bool ufshcd_is_embedded_dev(struct ufs_hba *hba)
+{
+ if ((hba->dev_info.b_device_sub_class == UFS_DEV_EMBEDDED_BOOTABLE) ||
+ (hba->dev_info.b_device_sub_class == UFS_DEV_EMBEDDED_NON_BOOTABLE))
+ return true;
+ return false;
+}
+
#ifdef CONFIG_DEBUG_FS
static inline void ufshcd_init_req_stats(struct ufs_hba *hba)
{
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index 43f255e..6019e4b 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -604,10 +604,11 @@
static unsigned long glink_qos_calc_rate_kBps(size_t pkt_size,
unsigned long interval_us)
{
- unsigned long rate_kBps, rem;
+ unsigned long rem;
+ uint64_t rate_kBps;
rate_kBps = pkt_size * USEC_PER_SEC;
- rem = do_div(rate_kBps, (interval_us * 1024));
+ rem = do_div(rate_kBps, interval_us * 1024);
return rate_kBps;
}
@@ -5454,8 +5455,8 @@
static void glink_scheduler_eval_prio(struct channel_ctx *ctx,
struct glink_core_xprt_ctx *xprt_ctx)
{
- unsigned long token_end_time;
- unsigned long token_consume_time, rem;
+ unsigned long token_end_time, rem;
+ uint64_t token_consume_time;
unsigned long obs_rate_kBps;
if (ctx->initial_priority == 0)
diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c
index 3863b09..5234580 100644
--- a/drivers/soc/qcom/llcc-sdm845.c
+++ b/drivers/soc/qcom/llcc-sdm845.c
@@ -73,7 +73,7 @@
SCT_ENTRY("display", 16, 16, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY("videofw", 17, 17, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY("modemhp_fix", 20, 20, 1024, 2, 1, 0x0, 0xF00, 0, 0, 1, 1, 0),
- SCT_ENTRY("modem_paging", 21, 21, 1024, 0, 1, 0x0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("modem_paging", 21, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0),
SCT_ENTRY("audiohw", 22, 22, 1024, 1, 1, 0xFFC, 0x2, 0, 0, 1, 1, 0),
};
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 707d9e7..5a110bb 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -566,6 +566,11 @@
bcm_clist_add(node);
}
+ if (!cur_rsc) {
+ MSM_BUS_ERR("%s: Error for cur_rsc is NULL.\n", __func__);
+ return ret;
+ }
+
cur_mbox = cur_rsc->rscdev->mbox;
cur_bcm_clist = cur_rsc->rscdev->bcm_clist;
@@ -1004,6 +1009,7 @@
bus_node_info->fabdev->noc_ops.qos_init(
node_dev,
+ bus_node_info,
bus_node_info->fabdev->qos_base,
bus_node_info->fabdev->base_offset,
bus_node_info->fabdev->qos_off,
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
index 996c719..bdcdf29 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
@@ -15,10 +15,14 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/msm-bus-board.h>
+#include <linux/msm-bus.h>
+#include <linux/spinlock.h>
#include "msm_bus_core.h"
#include "msm_bus_noc.h"
#include "msm_bus_rpmh.h"
+static DEFINE_SPINLOCK(noc_lock);
+
/* NOC_QOS generic */
#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
#define SAT_SCALE 16 /* 16 bytes minimum for saturation */
@@ -29,6 +33,7 @@
#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
#define MIN_SAT_FIELD 1
#define MIN_BW_FIELD 1
+#define MSM_BUS_FAB_MEM_NOC 6152
#define NOC_QOS_REG_BASE(b, o) ((b) + (o))
@@ -102,6 +107,8 @@
NOC_QOS_SATn_SAT_SHFT = 0x0,
};
+static void __iomem *memnoc_qos_base;
+
static int noc_div(uint64_t *a, uint32_t b)
{
if ((*a > 0) && (*a < b)) {
@@ -169,38 +176,10 @@
wmb();
}
-static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off,
- uint32_t mport, uint32_t qos_delta,
- struct msm_bus_noc_limiter *lim, uint32_t lim_en)
+static void noc_enable_qos_limiter(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t lim_en)
{
uint32_t reg_val, val;
-
- reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
- qos_delta));
-
- writel_relaxed((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))),
- NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
-
- /* Ensure we disable limiter before config*/
- wmb();
-
- reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
- qos_delta));
- val = lim->bw << NOC_QOS_LIMITBW_BWn_SHFT;
- writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) |
- (val & NOC_QOS_LIMITBW_BWn_BMSK)),
- NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
-
- reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
- qos_delta));
- val = lim->sat << NOC_QOS_LIMITBW_SATn_SHFT;
- writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) |
- (val & NOC_QOS_LIMITBW_SATn_BMSK)),
- NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
-
- /* Ensure qos limiter settings in place before possibly enabling */
- wmb();
-
reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
qos_delta));
val = lim_en << NOC_QOS_MCTL_LIMIT_ENn_SHFT;
@@ -208,9 +187,50 @@
(val & NOC_QOS_MCTL_LIMIT_ENn_BMSK)),
NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
+ /* Ensure we disable/enable limiter before exiting*/
wmb();
}
+static void noc_set_qos_limit_bw(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t bw)
+{
+ uint32_t reg_val, val;
+ reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+ qos_delta));
+ val = bw << NOC_QOS_LIMITBW_BWn_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) |
+ (val & NOC_QOS_LIMITBW_BWn_BMSK)),
+ NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
+
+ /* Ensure we set limiter bw before exiting*/
+ wmb();
+}
+
+static void noc_set_qos_limit_sat(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t sat)
+{
+ uint32_t reg_val, val;
+ reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+ qos_delta));
+ val = sat << NOC_QOS_LIMITBW_SATn_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) |
+ (val & NOC_QOS_LIMITBW_SATn_BMSK)),
+ NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
+
+ /* Ensure we set limiter sat before exiting*/
+ wmb();
+}
+
+static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta,
+ struct msm_bus_noc_limiter *lim, uint32_t lim_en)
+{
+ noc_enable_qos_limiter(base, qos_off, mport, qos_delta, 0);
+ noc_set_qos_limit_bw(base, qos_off, mport, qos_delta, lim->bw);
+ noc_set_qos_limit_sat(base, qos_off, mport, qos_delta, lim->sat);
+ noc_enable_qos_limiter(base, qos_off, mport, qos_delta, lim_en);
+}
+
static void noc_set_qos_regulator(void __iomem *base, uint32_t qos_off,
uint32_t mport, uint32_t qos_delta,
struct msm_bus_noc_regulator *reg,
@@ -317,6 +337,7 @@
}
static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
+ struct msm_bus_node_device_type *fabdev,
void __iomem *qos_base,
uint32_t qos_off, uint32_t qos_delta,
uint32_t qos_freq)
@@ -324,6 +345,7 @@
struct msm_bus_noc_qos_params *qos_params;
int ret = 0;
int i;
+ unsigned long flags;
qos_params = &info->node_info->qos_params;
@@ -333,6 +355,11 @@
goto err_qos_init;
}
+ spin_lock_irqsave(&noc_lock, flags);
+
+ if (fabdev->node_info->id == MSM_BUS_FAB_MEM_NOC)
+ memnoc_qos_base = qos_base;
+
for (i = 0; i < info->node_info->num_qports; i++) {
noc_set_qos_dflt_prio(qos_base, qos_off,
info->node_info->qport[i],
@@ -356,10 +383,87 @@
qos_delta,
qos_params->urg_fwd_en);
}
+ spin_unlock_irqrestore(&noc_lock, flags);
+
err_qos_init:
return ret;
}
+int msm_bus_noc_throttle_wa(bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&noc_lock, flags);
+
+ if (!memnoc_qos_base) {
+ MSM_BUS_ERR("Memnoc QoS Base address not found!");
+ goto noc_throttle_exit;
+ }
+
+ if (enable) {
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0x1B);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0x1B);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0x30);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0x30);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 1);
+ } else {
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0);
+ }
+
+noc_throttle_exit:
+ spin_unlock_irqrestore(&noc_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(msm_bus_noc_throttle_wa);
+
+int msm_bus_noc_priority_wa(bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&noc_lock, flags);
+ if (!memnoc_qos_base) {
+ MSM_BUS_ERR("Memnoc QoS Base address not found!");
+ goto noc_priority_exit;
+ }
+
+ if (enable)
+ noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0,
+ 0x1000, 7);
+ else
+ noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0,
+ 0x1000, 6);
+noc_priority_exit:
+ spin_unlock_irqrestore(&noc_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(msm_bus_noc_priority_wa);
+
int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
{
if (!bus_dev)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index a9733f1..8929959 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -42,6 +42,7 @@
/* New types introduced for adhoc topology */
struct msm_bus_noc_ops {
int (*qos_init)(struct msm_bus_node_device_type *dev,
+ struct msm_bus_node_device_type *fabdev,
void __iomem *qos_base, uint32_t qos_off,
uint32_t qos_delta, uint32_t qos_freq);
int (*set_bw)(struct msm_bus_node_device_type *dev,
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
index 03042fa..4cff9f2 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
@@ -410,8 +410,10 @@
{
struct rule_node_info *node_it = NULL;
+ mutex_lock(&msm_bus_rules_lock);
list_for_each_entry(node_it, &node_list, link)
print_rules(node_it);
+ mutex_unlock(&msm_bus_rules_lock);
}
void print_rules_buf(char *buf, int max_buf)
@@ -421,6 +423,7 @@
int i;
int cnt = 0;
+ mutex_lock(&msm_bus_rules_lock);
list_for_each_entry(node_it, &node_list, link) {
cnt += scnprintf(buf + cnt, max_buf - cnt,
"\n Now printing rules for Node %d cur_rule %d\n",
@@ -452,6 +455,7 @@
node_rule->rule_ops.mode);
}
}
+ mutex_unlock(&msm_bus_rules_lock);
}
static int copy_rule(struct bus_rule_type *src, struct rules_def *node_rule,
@@ -716,11 +720,12 @@
{
bool ret = false;
+ mutex_lock(&msm_bus_rules_lock);
if (list_empty(&node_list))
ret = false;
else
ret = true;
-
+ mutex_unlock(&msm_bus_rules_lock);
return ret;
}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index f5aff4f..926016f 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -77,9 +77,6 @@
#define MSS_MAGIC 0XAABADEAD
-#define MSS_PDC_OFFSET 8
-#define MSS_PDC_MASK BIT(MSS_PDC_OFFSET)
-
/* Timeout value for MBA boot when minidump is enabled */
#define MBA_ENCRYPTION_TIMEOUT 3000
enum scm_cmd {
@@ -214,13 +211,14 @@
static void pil_mss_pdc_sync(struct q6v5_data *drv, bool pdc_sync)
{
u32 val = 0;
+ u32 mss_pdc_mask = BIT(drv->mss_pdc_offset);
if (drv->pdc_sync) {
val = readl_relaxed(drv->pdc_sync);
if (pdc_sync)
- val |= MSS_PDC_MASK;
+ val |= mss_pdc_mask;
else
- val &= ~MSS_PDC_MASK;
+ val &= ~mss_pdc_mask;
writel_relaxed(val, drv->pdc_sync);
/* Ensure PDC is written before next write */
wmb();
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 7984dfe..e9d3534 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -293,6 +293,13 @@
if (res) {
q6->pdc_sync = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,mss_pdc_offset", &q6->mss_pdc_offset)) {
+ dev_err(&pdev->dev,
+ "Offset for MSS PDC not specified\n");
+ return -EINVAL;
+ }
+
}
q6->alt_reset = NULL;
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 9b4c811..4961b1f 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -74,6 +74,7 @@
bool restart_reg_sec;
bool override_acc;
int override_acc_1;
+ int mss_pdc_offset;
bool ahb_clk_vote;
bool mx_spike_wa;
};
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 417b0b2..c35119c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -572,6 +572,12 @@
/* SDM670 ID */
[336] = {MSM_CPU_SDM670, "SDM670"},
+ /* QCS605 ID */
+ [347] = {MSM_CPU_QCS605, "QCS605"},
+
+ /* SDA670 ID */
+ [337] = {MSM_CPU_SDA670, "SDA670"},
+
/* Uninitialized IDs are not known to run Linux.
* MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
* considered as unknown CPU.
@@ -1434,6 +1440,14 @@
dummy_socinfo.id = 336;
strlcpy(dummy_socinfo.build_id, "sdm670 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sda670()) {
+ dummy_socinfo.id = 337;
+ strlcpy(dummy_socinfo.build_id, "sda670 - ",
+ sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_qcs605()) {
+ dummy_socinfo.id = 347;
+ strlcpy(dummy_socinfo.build_id, "qcs605 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_sdxpoorwills()) {
dummy_socinfo.id = 334;
strlcpy(dummy_socinfo.build_id, "sdxpoorwills - ",
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 2b1456e..c1eafbd 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -494,7 +494,8 @@
SPI_ENGINE_VERSION_MAJOR(version),
SPI_ENGINE_VERSION_MINOR(version),
SPI_ENGINE_VERSION_PATCH(version));
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put_master;
}
spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index de3dc69..e46bc98 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -298,7 +298,7 @@
*/
if (fifo_disable && !dma_chan_valid)
mode = -EINVAL;
- else if (fifo_disable)
+ else if (dma_chan_valid)
mode = GSI_DMA;
else
mode = FIFO_MODE;
@@ -617,30 +617,32 @@
struct spi_message *msg)
{
struct spi_transfer *xfer;
- struct device *gsi_dev = mas->dev;
+ int ret = 0;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->rx_buf) {
- xfer->rx_dma = dma_map_single(gsi_dev, xfer->rx_buf,
+ ret = geni_se_iommu_map_buf(mas->wrapper_dev,
+ &xfer->rx_dma, xfer->rx_buf,
xfer->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(mas->dev, xfer->rx_dma)) {
- dev_err(mas->dev, "Err mapping buf\n");
- return -ENOMEM;
+ if (ret) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Mapping Rx buffer %d\n", __func__, ret);
+ return ret;
}
}
if (xfer->tx_buf) {
- xfer->tx_dma = dma_map_single(gsi_dev,
- (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
- if (dma_mapping_error(gsi_dev, xfer->tx_dma)) {
- dev_err(mas->dev, "Err mapping buf\n");
- dma_unmap_single(gsi_dev, xfer->rx_dma,
- xfer->len, DMA_FROM_DEVICE);
- return -ENOMEM;
+ ret = geni_se_iommu_map_buf(mas->wrapper_dev,
+ &xfer->tx_dma,
+ (void *)xfer->tx_buf,
+ xfer->len, DMA_TO_DEVICE);
+ if (ret) {
+ GENI_SE_ERR(mas->ipc, true, mas->dev,
+ "%s: Mapping Tx buffer %d\n", __func__, ret);
+ return ret;
}
}
};
-
return 0;
}
@@ -648,14 +650,13 @@
struct spi_message *msg)
{
struct spi_transfer *xfer;
- struct device *gsi_dev = mas->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->rx_buf)
- dma_unmap_single(gsi_dev, xfer->rx_dma,
+ geni_se_iommu_unmap_buf(mas->wrapper_dev, &xfer->rx_dma,
xfer->len, DMA_FROM_DEVICE);
if (xfer->tx_buf)
- dma_unmap_single(gsi_dev, xfer->tx_dma,
+ geni_se_iommu_unmap_buf(mas->wrapper_dev, &xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
};
}
@@ -709,7 +710,12 @@
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
int ret = 0;
+ u32 max_speed = spi->cur_msg->spi->max_speed_hz;
+ struct se_geni_rsc *rsc = &mas->spi_rsc;
+ /* Adjust the AB/IB based on the max speed of the slave.*/
+ rsc->ib = max_speed * DEFAULT_BUS_WIDTH;
+ rsc->ab = max_speed * DEFAULT_BUS_WIDTH;
ret = pm_runtime_get_sync(mas->dev);
if (ret < 0) {
dev_err(mas->dev, "Error enabling SE resources\n");
@@ -900,6 +906,7 @@
{
unsigned long timeout;
+ geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
reinit_completion(&mas->xfer_done);
geni_cancel_m_cmd(mas->base);
geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
@@ -986,6 +993,7 @@
}
return ret;
err_gsi_geni_transfer_one:
+ geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
dmaengine_terminate_all(mas->tx);
return ret;
err_fifo_geni_transfer_one:
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c
index ce9dc7e..192661b 100644
--- a/drivers/staging/android/fiq_debugger/fiq_debugger.c
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c
@@ -401,7 +401,7 @@
cmd += 6;
while (*cmd == ' ')
cmd++;
- if ((cmd != '\0') && sysrq_on())
+ if ((*cmd != '\0') && sysrq_on())
kernel_restart(cmd);
else
kernel_restart(NULL);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 616375a..8d67f76 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -48,6 +48,7 @@
#include <linux/fs.h>
#include <linux/cpuset.h>
#include <linux/vmpressure.h>
+#include <linux/freezer.h>
#define CREATE_TRACE_POINTS
#include <trace/events/almk.h>
@@ -116,6 +117,10 @@
static int vmpressure_file_min;
module_param_named(vmpressure_file_min, vmpressure_file_min, int, 0644);
+/* User knob to enable/disable oom reaping feature */
+static int oom_reaper;
+module_param_named(oom_reaper, oom_reaper, int, 0644);
+
enum {
VMPRESSURE_NO_ADJUST = 0,
VMPRESSURE_ADJUST_ENCROACH,
@@ -406,6 +411,14 @@
}
}
+static void mark_lmk_victim(struct task_struct *tsk)
+{
+ struct mm_struct *mm = tsk->mm;
+
+ if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm))
+ atomic_inc(&tsk->signal->oom_mm->mm_count);
+}
+
static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
struct task_struct *tsk;
@@ -524,7 +537,11 @@
send_sig(SIGKILL, selected, 0);
if (selected->mm)
task_set_lmk_waiting(selected);
+ if (oom_reaper)
+ mark_lmk_victim(selected);
task_unlock(selected);
+ if (oom_reaper)
+ wake_oom_reaper(selected);
trace_lowmemory_kill(selected, cache_size, cache_limit, free);
lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
"to free %ldkB on behalf of '%s' (%d) because\n"
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index ec99790..7458df4 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2385,6 +2385,7 @@
continue;
}
+ set_current_state(TASK_RUNNING);
wp = async->buf_write_ptr;
n1 = min(n, async->prealloc_bufsz - wp);
n2 = n - n1;
@@ -2517,6 +2518,8 @@
}
continue;
}
+
+ set_current_state(TASK_RUNNING);
rp = async->buf_read_ptr;
n1 = min(n, async->prealloc_bufsz - rp);
n2 = n - n1;
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 6b99263..598f0fa 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -472,7 +472,7 @@
long m)
{
struct ad2s1210_state *st = iio_priv(indio_dev);
- bool negative;
+ u16 negative;
int ret = 0;
u16 pos;
s16 vel;
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index b432153..0f63a36 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -45,6 +45,7 @@
{USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
{USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
{USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */
{} /* Terminating entry */
};
diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c
index 6370a5e..defffa7 100644
--- a/drivers/staging/wilc1000/linux_wlan.c
+++ b/drivers/staging/wilc1000/linux_wlan.c
@@ -269,23 +269,12 @@
int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
{
- int i = 0;
- int ret = -1;
- struct wilc_vif *vif;
- struct wilc *wilc;
+ struct wilc_vif *vif = netdev_priv(wilc_netdev);
- vif = netdev_priv(wilc_netdev);
- wilc = vif->wilc;
+ memcpy(vif->bssid, bssid, 6);
+ vif->mode = mode;
- for (i = 0; i < wilc->vif_num; i++)
- if (wilc->vif[i]->ndev == wilc_netdev) {
- memcpy(wilc->vif[i]->bssid, bssid, 6);
- wilc->vif[i]->mode = mode;
- ret = 0;
- break;
- }
-
- return ret;
+ return 0;
}
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
@@ -1212,16 +1201,11 @@
void wilc_netdev_cleanup(struct wilc *wilc)
{
- int i = 0;
- struct wilc_vif *vif[NUM_CONCURRENT_IFC];
+ int i;
- if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
+ if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev))
unregister_inetaddr_notifier(&g_dev_notifier);
- for (i = 0; i < NUM_CONCURRENT_IFC; i++)
- vif[i] = netdev_priv(wilc->vif[i]->ndev);
- }
-
if (wilc && wilc->firmware) {
release_firmware(wilc->firmware);
wilc->firmware = NULL;
@@ -1230,7 +1214,7 @@
if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
if (wilc->vif[i]->ndev)
- if (vif[i]->mac_opened)
+ if (wilc->vif[i]->mac_opened)
wilc_mac_close(wilc->vif[i]->ndev);
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
@@ -1278,9 +1262,9 @@
vif->idx = wl->vif_num;
vif->wilc = *wilc;
+ vif->ndev = ndev;
wl->vif[i] = vif;
- wl->vif[wl->vif_num]->ndev = ndev;
- wl->vif_num++;
+ wl->vif_num = i;
ndev->netdev_ops = &wilc_netdev_ops;
{
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 182b2d5..165c46f 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -666,8 +666,11 @@
void prism2_roamed(struct wlandevice *wlandev)
{
- cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
- NULL, 0, NULL, 0, GFP_KERNEL);
+ struct cfg80211_roam_info roam_info = {
+ .bssid = wlandev->bssid,
+ };
+
+ cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
}
/* Structures for declaring wiphy interface */
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 155fe0e..e49fcd5 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -418,6 +418,7 @@
return 0;
}
np->np_thread_state = ISCSI_NP_THREAD_RESET;
+ atomic_inc(&np->np_reset_count);
if (np->np_thread) {
spin_unlock_bh(&np->np_thread_lock);
@@ -2177,6 +2178,7 @@
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
+ kfree(cmd->text_in_ptr);
cmd->text_in_ptr = NULL;
return 0;
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 6128e8e..9ccd5da 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1233,9 +1233,11 @@
flush_signals(current);
spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
+ spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
+ return 1;
} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
spin_unlock_bh(&np->np_thread_lock);
goto exit;
@@ -1268,7 +1270,8 @@
goto exit;
} else if (rc < 0) {
spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
+ np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
iscsit_put_transport(conn->conn_transport);
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 6693d7c..e8efb42 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -490,14 +490,60 @@
static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *);
-static bool iscsi_target_sk_state_check(struct sock *sk)
+static bool __iscsi_target_sk_check_close(struct sock *sk)
{
if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) {
- pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE,"
+ pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE,"
"returning FALSE\n");
- return false;
+ return true;
}
- return true;
+ return false;
+}
+
+static bool iscsi_target_sk_check_close(struct iscsi_conn *conn)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ read_lock_bh(&sk->sk_callback_lock);
+ state = (__iscsi_target_sk_check_close(sk) ||
+ test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+ read_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
+}
+
+static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ read_lock_bh(&sk->sk_callback_lock);
+ state = test_bit(flag, &conn->login_flags);
+ read_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
+}
+
+static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ state = (__iscsi_target_sk_check_close(sk) ||
+ test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+ if (!state)
+ clear_bit(flag, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
}
static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login)
@@ -537,6 +583,20 @@
pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n",
conn, current->comm, current->pid);
+ /*
+ * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready()
+ * before initial PDU processing in iscsi_target_start_negotiation()
+ * has completed, go ahead and retry until it's cleared.
+ *
+ * Otherwise if the TCP connection drops while this is occuring,
+ * iscsi_target_start_negotiation() will detect the failure, call
+ * cancel_delayed_work_sync(&conn->login_work), and cleanup the
+ * remaining iscsi connection resources from iscsi_np process context.
+ */
+ if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) {
+ schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10));
+ return;
+ }
spin_lock(&tpg->tpg_state_lock);
state = (tpg->tpg_state == TPG_STATE_ACTIVE);
@@ -544,26 +604,12 @@
if (!state) {
pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n");
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
+ goto err;
}
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
-
- read_lock_bh(&sk->sk_callback_lock);
- state = iscsi_target_sk_state_check(sk);
- read_unlock_bh(&sk->sk_callback_lock);
-
- if (!state) {
- pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
- }
+ if (iscsi_target_sk_check_close(conn)) {
+ pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
+ goto err;
}
conn->login_kworker = current;
@@ -581,34 +627,29 @@
flush_signals(current);
conn->login_kworker = NULL;
- if (rc < 0) {
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
- }
+ if (rc < 0)
+ goto err;
pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n",
conn, current->comm, current->pid);
rc = iscsi_target_do_login(conn, login);
if (rc < 0) {
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
+ goto err;
} else if (!rc) {
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
-
- write_lock_bh(&sk->sk_callback_lock);
- clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags);
- write_unlock_bh(&sk->sk_callback_lock);
- }
+ if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE))
+ goto err;
} else if (rc == 1) {
iscsi_target_nego_release(conn);
iscsi_post_login_handler(np, conn, zero_tsih);
iscsit_deaccess_np(np, tpg, tpg_np);
}
+ return;
+
+err:
+ iscsi_target_restore_sock_callbacks(conn);
+ iscsi_target_login_drop(conn, login);
+ iscsit_deaccess_np(np, tpg, tpg_np);
}
static void iscsi_target_do_cleanup(struct work_struct *work)
@@ -656,31 +697,54 @@
orig_state_change(sk);
return;
}
+ state = __iscsi_target_sk_check_close(sk);
+ pr_debug("__iscsi_target_sk_close_change: state: %d\n", state);
+
if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {
pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change"
" conn: %p\n", conn);
+ if (state)
+ set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
return;
}
- if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
+ if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n",
conn);
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
return;
}
-
- state = iscsi_target_sk_state_check(sk);
- write_unlock_bh(&sk->sk_callback_lock);
-
- pr_debug("iscsi_target_sk_state_change: state: %d\n", state);
-
- if (!state) {
+ /*
+ * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED,
+ * but only queue conn->login_work -> iscsi_target_do_login_rx()
+ * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared.
+ *
+ * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close()
+ * will detect the dropped TCP connection from delayed workqueue context.
+ *
+ * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial
+ * iscsi_target_start_negotiation() is running, iscsi_target_do_login()
+ * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation()
+ * via iscsi_target_sk_check_and_clear() is responsible for detecting the
+ * dropped TCP connection in iscsi_np process context, and cleaning up
+ * the remaining iscsi connection resources.
+ */
+ if (state) {
pr_debug("iscsi_target_sk_state_change got failed state\n");
- schedule_delayed_work(&conn->login_cleanup_work, 0);
+ set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
+ state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+
+ orig_state_change(sk);
+
+ if (!state)
+ schedule_delayed_work(&conn->login_work, 0);
return;
}
+ write_unlock_bh(&sk->sk_callback_lock);
+
orig_state_change(sk);
}
@@ -945,6 +1009,15 @@
if (iscsi_target_handle_csg_one(conn, login) < 0)
return -1;
if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+ /*
+ * Check to make sure the TCP connection has not
+ * dropped asynchronously while session reinstatement
+ * was occuring in this kthread context, before
+ * transitioning to full feature phase operation.
+ */
+ if (iscsi_target_sk_check_close(conn))
+ return -1;
+
login->tsih = conn->sess->tsih;
login->login_complete = 1;
iscsi_target_restore_sock_callbacks(conn);
@@ -971,21 +1044,6 @@
break;
}
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
- bool state;
-
- read_lock_bh(&sk->sk_callback_lock);
- state = iscsi_target_sk_state_check(sk);
- read_unlock_bh(&sk->sk_callback_lock);
-
- if (!state) {
- pr_debug("iscsi_target_do_login() failed state for"
- " conn: %p\n", conn);
- return -1;
- }
- }
-
return 0;
}
@@ -1252,13 +1310,25 @@
if (conn->sock) {
struct sock *sk = conn->sock->sk;
- write_lock_bh(&sk->sk_callback_lock);
- set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
- write_unlock_bh(&sk->sk_callback_lock);
- }
+ write_lock_bh(&sk->sk_callback_lock);
+ set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
+ set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ /*
+ * If iscsi_target_do_login returns zero to signal more PDU
+ * exchanges are required to complete the login, go ahead and
+ * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection
+ * is still active.
+ *
+ * Otherwise if TCP connection dropped asynchronously, go ahead
+ * and perform connection cleanup now.
+ */
+ ret = iscsi_target_do_login(conn, login);
+ if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU))
+ ret = -1;
- ret = iscsi_target_do_login(conn, login);
- if (ret < 0) {
+ if (ret < 0) {
cancel_delayed_work_sync(&conn->login_work);
cancel_delayed_work_sync(&conn->login_cleanup_work);
iscsi_target_restore_sock_callbacks(conn);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 1949f50..0e2e71f 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -364,7 +364,7 @@
mutex_lock(&tpg->acl_node_mutex);
if (acl->dynamic_node_acl)
acl->dynamic_node_acl = 0;
- list_del(&acl->acl_list);
+ list_del_init(&acl->acl_list);
mutex_unlock(&tpg->acl_node_mutex);
target_shutdown_sessions(acl);
@@ -540,7 +540,7 @@
* in transport_deregister_session().
*/
list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {
- list_del(&nacl->acl_list);
+ list_del_init(&nacl->acl_list);
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index e8a1f5c..bacfa8f 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -465,7 +465,7 @@
}
mutex_lock(&se_tpg->acl_node_mutex);
- list_del(&nacl->acl_list);
+ list_del_init(&nacl->acl_list);
mutex_unlock(&se_tpg->acl_node_mutex);
core_tpg_wait_for_nacl_pr_ref(nacl);
@@ -537,7 +537,7 @@
spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
if (se_nacl->dynamic_stop)
- list_del(&se_nacl->acl_list);
+ list_del_init(&se_nacl->acl_list);
}
mutex_unlock(&se_tpg->acl_node_mutex);
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index d590d24..4e5546e 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -354,7 +354,13 @@
mutex_lock(&hw->access_lock);
for_each_cpu(cpu_idx, &hw->core_map) {
if (cpu_idx == cpu)
- hw->cdev_data[idx].max_freq = freq;
+ /*
+ * If there is no limits restriction for CPU scaling max
+ * frequency, vote for a very high value. This will allow
+ * the CPU to use the boost frequencies.
+ */
+ hw->cdev_data[idx].max_freq =
+ (freq == hw->max_freq) ? U32_MAX : freq;
if (max_freq > hw->cdev_data[idx].max_freq)
max_freq = hw->cdev_data[idx].max_freq;
idx++;
diff --git a/drivers/thermal/qcom/qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling.c
index af82030..e1a01d8 100644
--- a/drivers/thermal/qcom/qmi_cooling.c
+++ b/drivers/thermal/qcom/qmi_cooling.c
@@ -85,6 +85,10 @@
.type = QMI_CDEV_MAX_LIMIT_TYPE,
},
{
+ .dev_name = "modem_skin",
+ .type = QMI_CDEV_MAX_LIMIT_TYPE,
+ },
+ {
.dev_name = "modem_bw",
.type = QMI_CDEV_MAX_LIMIT_TYPE,
},
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 67ed0e8..79788eb 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -127,6 +127,7 @@
} while (0)
#define DMA_RX_BUF_SIZE (2048)
+#define CONSOLE_YIELD_LEN (8 * 1024)
struct msm_geni_serial_port {
struct uart_port uport;
char name[20];
@@ -162,6 +163,7 @@
unsigned int cur_baud;
int ioctl_count;
int edge_count;
+ unsigned int tx_yield_count;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -1083,6 +1085,14 @@
xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
msm_port->xmit_size = 0;
+ if (uart_console(uport) &&
+ (uport->icount.tx - msm_port->tx_yield_count) > CONSOLE_YIELD_LEN) {
+ msm_port->tx_yield_count = uport->icount.tx;
+ msm_geni_serial_stop_tx(uport);
+ uart_write_wakeup(uport);
+ goto exit_handle_tx;
+ }
+
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
if (uart_circ_empty(xmit) && !tx_fifo_status) {
@@ -1254,6 +1264,13 @@
goto exit_geni_serial_isr;
}
+ if (s_irq_status & S_RX_FIFO_WR_ERR_EN) {
+ uport->icount.buf_overrun++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.sirq 0x%x buf_overrun:%d\n",
+ __func__, s_irq_status, uport->icount.buf_overrun);
+ }
+
if (!dma) {
if ((m_irq_status & m_irq_en) &
(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e07fa76..c0f1e46 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1878,7 +1878,7 @@
/* No more submits can occur */
spin_lock_irq(&hcd_urb_list_lock);
rescan:
- list_for_each_entry (urb, &ep->urb_list, urb_list) {
+ list_for_each_entry_reverse(urb, &ep->urb_list, urb_list) {
int is_in;
if (urb->unlinked)
@@ -2532,6 +2532,8 @@
}
if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
hcd = hcd->shared_hcd;
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ set_bit(HCD_FLAG_DEAD, &hcd->flags);
if (hcd->rh_registered) {
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 50679bc..3b0cc03 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4741,7 +4741,8 @@
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
u16 portchange)
{
- int status, i;
+ int status = -ENODEV;
+ int i;
unsigned unit_load;
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
@@ -4945,9 +4946,10 @@
done:
hub_port_disable(hub, port1, 1);
- if (hcd->driver->relinquish_port && !hub->hdev->parent)
- hcd->driver->relinquish_port(hcd, port1);
-
+ if (hcd->driver->relinquish_port && !hub->hdev->parent) {
+ if (status != -ENOTCONN && status != -ENODEV)
+ hcd->driver->relinquish_port(hcd, port1);
+ }
}
/* Handle physical or logical connection change events.
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 3116edf..574da2b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -150,6 +150,9 @@
/* appletouch */
{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */
+ { USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM },
+
/* Avision AV600U */
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
USB_QUIRK_STRING_FETCH_255 },
@@ -249,6 +252,7 @@
{ USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
{ USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
{ USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
+ { USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Optical Mouse M90/M100 */
{ USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 2776cfe..ef9cf4a 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -127,6 +127,22 @@
*/
#define USB_ACPI_LOCATION_VALID (1 << 31)
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+ int raw)
+{
+ struct acpi_device *adev;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ if (acpi_device_adr(adev) == raw)
+ return adev;
+ }
+
+ return acpi_find_child_device(parent, raw, false);
+}
+
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
{
struct usb_device *udev;
@@ -174,8 +190,10 @@
int raw;
raw = usb_hcd_find_raw_port_number(hcd, port1);
- adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev),
- raw, false);
+
+ adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+ raw);
+
if (!adev)
return NULL;
} else {
@@ -186,7 +204,9 @@
return NULL;
acpi_bus_get_device(parent_handle, &adev);
- adev = acpi_find_child_device(adev, port1, false);
+
+ adev = usb_acpi_find_port(adev, port1);
+
if (!adev)
return NULL;
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 1c8d8dc..d316821 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2857,8 +2857,7 @@
}
/*
- * Handle EUD based soft detach/attach event, and force USB high speed mode
- * functionality on receiving soft attach event.
+ * Handle EUD based soft detach/attach event
*
* @nb - notifier handler
* @event - event information i.e. soft detach/attach event
@@ -2877,9 +2876,6 @@
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
- /* Force USB High-Speed enumeration Only */
- dwc->maximum_speed = USB_SPEED_HIGH;
- dbg_event(0xFF, "Speed", dwc->maximum_speed);
mdwc->vbus_active = event;
if (dwc->is_drd && !mdwc->in_restart)
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 8a6ae0b..02adc93 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2155,7 +2155,7 @@
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
struct usb_composite_dev *cdev = get_gadget_data(gadget);
- return sprintf(buf, "%d\n", cdev->suspended);
+ return snprintf(buf, PAGE_SIZE, "%d\n", cdev->suspended);
}
static DEVICE_ATTR_RO(suspended);
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index f910990..d6e77a5 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1533,6 +1533,18 @@
gi = container_of(cdev, struct gadget_info, cdev);
+ /* FIXME: There's a race between usb_gadget_udc_stop() which is likely
+ * to set the gadget driver to NULL in the udc driver and this drivers
+ * gadget disconnect fn which likely checks for the gadget driver to
+ * be a null ptr. It happens that unbind (doing set_gadget_data(NULL))
+ * is called before the gadget driver is set to NULL and the udc driver
+ * calls disconnect fn which results in cdev being a null ptr.
+ */
+ if (cdev == NULL) {
+ WARN(1, "%s: gadget driver already disconnected\n", __func__);
+ return;
+ }
+
/* accessory HID support can be active while the
accessory function is not actually enabled,
so we need to inform it when we are disconnected.
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index a7cb586..9240956 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -864,6 +864,14 @@
.probe = acc_hid_probe,
};
+static void acc_complete_setup_noop(struct usb_ep *ep, struct usb_request *req)
+{
+ /*
+ * Default no-op function when nothing needs to be done for the
+ * setup request
+ */
+}
+
int acc_ctrlrequest(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
@@ -891,6 +899,7 @@
schedule_delayed_work(
&dev->start_work, msecs_to_jiffies(10));
value = 0;
+ cdev->req->complete = acc_complete_setup_noop;
} else if (b_request == ACCESSORY_SEND_STRING) {
dev->string_index = w_index;
cdev->gadget->ep0->driver_data = dev;
@@ -899,10 +908,13 @@
} else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
w_index == 0 && w_length == 0) {
dev->audio_mode = w_value;
+ cdev->req->complete = acc_complete_setup_noop;
value = 0;
} else if (b_request == ACCESSORY_REGISTER_HID) {
+ cdev->req->complete = acc_complete_setup_noop;
value = acc_register_hid(dev, w_value, w_index);
} else if (b_request == ACCESSORY_UNREGISTER_HID) {
+ cdev->req->complete = acc_complete_setup_noop;
value = acc_unregister_hid(dev, w_value);
} else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
spin_lock_irqsave(&dev->lock, flags);
@@ -937,7 +949,7 @@
if (b_request == ACCESSORY_GET_PROTOCOL) {
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
value = sizeof(u16);
-
+ cdev->req->complete = acc_complete_setup_noop;
/* clear any string left over from a previous session */
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
memset(dev->model, 0, sizeof(dev->model));
diff --git a/drivers/usb/gadget/function/f_ccid.h b/drivers/usb/gadget/function/f_ccid.h
index 42a7ebb..935308c 100644
--- a/drivers/usb/gadget/function/f_ccid.h
+++ b/drivers/usb/gadget/function/f_ccid.h
@@ -55,29 +55,29 @@
#define CCID_READ_DTR _IOR('C', 3, int)
struct usb_ccid_notification {
- unsigned char buf[4];
+ __u8 buf[4];
} __packed;
struct ccid_bulk_in_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bStatus;
- unsigned char bError;
- unsigned char bSpecific;
- unsigned char abData[ABDATA_SIZE];
- unsigned char bSizeToSend;
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bStatus;
+ __u8 bError;
+ __u8 bSpecific;
+ __u8 abData[ABDATA_SIZE];
+ __u8 bSizeToSend;
} __packed;
struct ccid_bulk_out_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bSpecific_0;
- unsigned char bSpecific_1;
- unsigned char bSpecific_2;
- unsigned char APDU[ABDATA_SIZE];
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bSpecific_0;
+ __u8 bSpecific_1;
+ __u8 bSpecific_2;
+ __u8 APDU[ABDATA_SIZE];
} __packed;
#endif
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index e908ecf..be22de048 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -386,9 +386,11 @@
ch->priv = priv;
ch->notify = notify;
- spin_lock_irqsave(&ch_lock, flags);
- list_add_tail(&ch->list, &usb_diag_ch_list);
- spin_unlock_irqrestore(&ch_lock, flags);
+ if (!found) {
+ spin_lock_irqsave(&ch_lock, flags);
+ list_add_tail(&ch->list, &usb_diag_ch_list);
+ spin_unlock_irqrestore(&ch_lock, flags);
+ }
return ch;
}
@@ -863,6 +865,7 @@
struct diag_context *dev;
struct usb_diag_ch *_ch;
int found = 0;
+ unsigned long flags;
pr_debug("%s\n", __func__);
@@ -872,9 +875,19 @@
break;
}
}
+
if (!found) {
- pr_err("%s: unable to get diag usb channel\n", __func__);
- return ERR_PTR(-ENODEV);
+ pr_warn("%s: unable to get diag usb channel\n", __func__);
+
+ _ch = kzalloc(sizeof(*_ch), GFP_KERNEL);
+ if (_ch == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ _ch->name = name;
+
+ spin_lock_irqsave(&ch_lock, flags);
+ list_add_tail(&_ch->list, &usb_diag_ch_list);
+ spin_unlock_irqrestore(&ch_lock, flags);
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index ccf9dac..18241f4 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2618,10 +2618,10 @@
info.string_defs = qdss_gsi_string_defs;
info.data_desc = &qdss_gsi_data_intf_desc;
info.data_str_idx = 0;
- info.fs_in_desc = &qdss_gsi_hs_data_desc;
+ info.fs_in_desc = &qdss_gsi_fs_data_desc;
info.hs_in_desc = &qdss_gsi_hs_data_desc;
info.ss_in_desc = &qdss_gsi_ss_data_desc;
- info.fs_desc_hdr = qdss_gsi_hs_data_only_desc;
+ info.fs_desc_hdr = qdss_gsi_fs_data_only_desc;
info.hs_desc_hdr = qdss_gsi_hs_data_only_desc;
info.ss_desc_hdr = qdss_gsi_ss_data_only_desc;
info.in_epname = "gsi-epin";
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 0fe3665..a560083 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -1340,6 +1340,14 @@
.bInterfaceProtocol = 0xff,
};
+static struct usb_endpoint_descriptor qdss_gsi_fs_data_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(64),
+};
+
static struct usb_endpoint_descriptor qdss_gsi_hs_data_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -1364,6 +1372,12 @@
.wBytesPerInterval = 0,
};
+static struct usb_descriptor_header *qdss_gsi_fs_data_only_desc[] = {
+ (struct usb_descriptor_header *) &qdss_gsi_data_intf_desc,
+ (struct usb_descriptor_header *) &qdss_gsi_fs_data_desc,
+ NULL,
+};
+
static struct usb_descriptor_header *qdss_gsi_hs_data_only_desc[] = {
(struct usb_descriptor_header *) &qdss_gsi_data_intf_desc,
(struct usb_descriptor_header *) &qdss_gsi_hs_data_desc,
@@ -1379,7 +1393,7 @@
/* string descriptors: */
static struct usb_string qdss_gsi_string_defs[] = {
- [0].s = "QDSS DATA",
+ [0].s = "Qualcomm DPL Data",
{}, /* end of list */
};
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index ba78e3f..d2cfefa 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -685,21 +685,32 @@
return usb3_req;
}
+static void __usb3_request_done(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req,
+ int status)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
+ usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
+ status);
+ usb3_req->req.status = status;
+ usb3_ep->started = false;
+ list_del_init(&usb3_req->queue);
+ spin_unlock(&usb3->lock);
+ usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
+ spin_lock(&usb3->lock);
+}
+
static void usb3_request_done(struct renesas_usb3_ep *usb3_ep,
struct renesas_usb3_request *usb3_req, int status)
{
struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
unsigned long flags;
- dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
- usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
- status);
- usb3_req->req.status = status;
spin_lock_irqsave(&usb3->lock, flags);
- usb3_ep->started = false;
- list_del_init(&usb3_req->queue);
+ __usb3_request_done(usb3_ep, usb3_req, status);
spin_unlock_irqrestore(&usb3->lock, flags);
- usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
}
static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3)
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c8989c6..5f4ca78 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -98,6 +98,7 @@
AMD_CHIPSET_HUDSON2,
AMD_CHIPSET_BOLTON,
AMD_CHIPSET_YANGTZE,
+ AMD_CHIPSET_TAISHAN,
AMD_CHIPSET_UNKNOWN,
};
@@ -141,6 +142,11 @@
pinfo->sb_type.gen = AMD_CHIPSET_SB700;
else if (rev >= 0x40 && rev <= 0x4f)
pinfo->sb_type.gen = AMD_CHIPSET_SB800;
+ }
+ pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ 0x145c, NULL);
+ if (pinfo->smbus_dev) {
+ pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
} else {
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
@@ -260,11 +266,12 @@
{
/* Make sure amd chipset type has already been initialized */
usb_amd_find_chipset_info();
- if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE)
- return 0;
-
- dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
- return 1;
+ if (amd_chipset.sb_type.gen == AMD_CHIPSET_YANGTZE ||
+ amd_chipset.sb_type.gen == AMD_CHIPSET_TAISHAN) {
+ dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
+ return 1;
+ }
+ return 0;
}
EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk);
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 99beda9..55c624f 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -139,6 +139,7 @@
"Could not flush host TX%d fifo: csr: %04x\n",
ep->epnum, csr))
return;
+ mdelay(1);
}
}
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
index d544b33..02b67ab 100644
--- a/drivers/usb/renesas_usbhs/rcar3.c
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -20,9 +20,13 @@
/* Low Power Status register (LPSTS) */
#define LPSTS_SUSPM 0x4000
-/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */
+/*
+ * USB General control register 2 (UGCTRL2)
+ * Remarks: bit[31:11] and bit[9:6] should be 0
+ */
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
#define UGCTRL2_USB0SEL_OTG 0x00000030
+#define UGCTRL2_VBUSSEL 0x00000400
static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
{
@@ -34,7 +38,8 @@
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
+ usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG |
+ UGCTRL2_VBUSSEL);
if (enable) {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 84b444f..470b17b 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -136,6 +136,7 @@
{ USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */
{ USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */
{ USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */
+ { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index ebe51f11..fe12315 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2025,6 +2025,8 @@
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1db4b61..a51b283 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -49,6 +49,7 @@
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+ { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 09d9be8..3b5a15d 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -27,6 +27,7 @@
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
#define ATEN_PRODUCT_ID 0x2008
+#define ATEN_PRODUCT_UC485 0x2021
#define ATEN_PRODUCT_ID2 0x2118
#define IODATA_VENDOR_ID 0x04bb
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index cbea9f3..cde1153 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -124,9 +124,9 @@
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
"Initio Corporation",
- "",
+ "INIC-3069",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
- US_FL_NO_ATA_1X),
+ US_FL_NO_ATA_1X | US_FL_IGNORE_RESIDUE),
/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 76c1ad9..f8a3839 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1097,6 +1097,13 @@
void __user *argp = (void __user *)arg;
long ret = 0;
+ memset(&var, 0, sizeof(var));
+ memset(&fix, 0, sizeof(fix));
+ memset(&con2fb, 0, sizeof(con2fb));
+ memset(&cmap_from, 0, sizeof(cmap_from));
+ memset(&cmap, 0, sizeof(cmap));
+ memset(&event, 0, sizeof(event));
+
switch (cmd) {
case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info))
diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c
index 4da69db..1bdd02a 100644
--- a/drivers/xen/biomerge.c
+++ b/drivers/xen/biomerge.c
@@ -10,8 +10,7 @@
unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page));
unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page));
- return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&
- ((bfn1 == bfn2) || ((bfn1+1) == bfn2));
+ return bfn1 + PFN_DOWN(vec1->bv_offset + vec1->bv_len) == bfn2;
#else
/*
* XXX: Add support for merging bio_vec when using different page
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 14a37ff..705bb5f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4759,10 +4759,6 @@
else
flush = BTRFS_RESERVE_NO_FLUSH;
spin_lock(&space_info->lock);
- if (can_overcommit(root, space_info, orig, flush)) {
- spin_unlock(&space_info->lock);
- break;
- }
if (list_empty(&space_info->tickets) &&
list_empty(&space_info->priority_tickets)) {
spin_unlock(&space_info->lock);
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 900ffaf..7b79a54 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -188,7 +188,7 @@
/*
* read a single page, without unlocking it.
*/
-static int readpage_nounlock(struct file *filp, struct page *page)
+static int ceph_do_readpage(struct file *filp, struct page *page)
{
struct inode *inode = file_inode(filp);
struct ceph_inode_info *ci = ceph_inode(inode);
@@ -218,7 +218,7 @@
err = ceph_readpage_from_fscache(inode, page);
if (err == 0)
- goto out;
+ return -EINPROGRESS;
dout("readpage inode %p file %p page %p index %lu\n",
inode, filp, page, page->index);
@@ -248,8 +248,11 @@
static int ceph_readpage(struct file *filp, struct page *page)
{
- int r = readpage_nounlock(filp, page);
- unlock_page(page);
+ int r = ceph_do_readpage(filp, page);
+ if (r != -EINPROGRESS)
+ unlock_page(page);
+ else
+ r = 0;
return r;
}
@@ -1235,7 +1238,7 @@
goto retry_locked;
r = writepage_nounlock(page, NULL);
if (r < 0)
- goto fail_nosnap;
+ goto fail_unlock;
goto retry_locked;
}
@@ -1263,11 +1266,14 @@
}
/* we need to read it. */
- r = readpage_nounlock(file, page);
- if (r < 0)
- goto fail_nosnap;
+ r = ceph_do_readpage(file, page);
+ if (r < 0) {
+ if (r == -EINPROGRESS)
+ return -EAGAIN;
+ goto fail_unlock;
+ }
goto retry_locked;
-fail_nosnap:
+fail_unlock:
unlock_page(page);
return r;
}
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 5bc5d37..a2d7997 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -240,13 +240,7 @@
}
}
-static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
-{
- if (!error)
- SetPageUptodate(page);
-}
-
-static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
+static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
{
if (!error)
SetPageUptodate(page);
@@ -274,7 +268,7 @@
return -ENOBUFS;
ret = fscache_read_or_alloc_page(ci->fscache, page,
- ceph_vfs_readpage_complete, NULL,
+ ceph_readpage_from_fscache_complete, NULL,
GFP_KERNEL);
switch (ret) {
@@ -303,7 +297,7 @@
return -ENOBUFS;
ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
- ceph_vfs_readpage_complete_unlock,
+ ceph_readpage_from_fscache_complete,
NULL, mapping_gfp_mask(mapping));
switch (ret) {
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 789ff1d..dd3e236 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -183,15 +183,20 @@
}
/*
+ * Don't allow path components longer than the server max.
* Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix.
*/
static int
-check_name(struct dentry *direntry)
+check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
int i;
+ if (unlikely(direntry->d_name.len >
+ le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
+ return -ENAMETOOLONG;
+
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') {
@@ -489,10 +494,6 @@
return finish_no_open(file, res);
}
- rc = check_name(direntry);
- if (rc)
- return rc;
-
xid = get_xid();
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
@@ -505,6 +506,11 @@
}
tcon = tlink_tcon(tlink);
+
+ rc = check_name(direntry, tcon);
+ if (rc)
+ goto out_free_xid;
+
server = tcon->ses->server;
if (server->ops->new_lease_key)
@@ -765,7 +771,7 @@
}
pTcon = tlink_tcon(tlink);
- rc = check_name(direntry);
+ rc = check_name(direntry, pTcon);
if (rc)
goto lookup_out;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 7c1c6c3..0437e5f 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2930,8 +2930,8 @@
kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
- kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
- kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+ kst->f_bfree = kst->f_bavail =
+ le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
return;
}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index dc0d141..1e1449a 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -84,8 +84,8 @@
#define NUMBER_OF_SMB2_COMMANDS 0x0013
-/* BB FIXME - analyze following length BB */
-#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
+/* 4 len + 52 transform hdr + 64 hdr + 56 create rsp */
+#define MAX_SMB2_HDR_SIZE 0x00b0
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index dc4a34f..5b96ba7 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -524,8 +524,13 @@
wait_queue_head_t *whead;
rcu_read_lock();
- /* If it is cleared by POLLFREE, it should be rcu-safe */
- whead = rcu_dereference(pwq->whead);
+ /*
+ * If it is cleared by POLLFREE, it should be rcu-safe.
+ * If we read NULL we need a barrier paired with
+ * smp_store_release() in ep_poll_callback(), otherwise
+ * we rely on whead->lock.
+ */
+ whead = smp_load_acquire(&pwq->whead);
if (whead)
remove_wait_queue(whead, &pwq->wait);
rcu_read_unlock();
@@ -1010,17 +1015,6 @@
struct eventpoll *ep = epi->ep;
int ewake = 0;
- if ((unsigned long)key & POLLFREE) {
- ep_pwq_from_wait(wait)->whead = NULL;
- /*
- * whead = NULL above can race with ep_remove_wait_queue()
- * which can do another remove_wait_queue() after us, so we
- * can't use __remove_wait_queue(). whead->lock is held by
- * the caller.
- */
- list_del_init(&wait->task_list);
- }
-
spin_lock_irqsave(&ep->lock, flags);
/*
@@ -1102,10 +1096,26 @@
if (pwake)
ep_poll_safewake(&ep->poll_wait);
- if (epi->event.events & EPOLLEXCLUSIVE)
- return ewake;
+ if (!(epi->event.events & EPOLLEXCLUSIVE))
+ ewake = 1;
- return 1;
+ if ((unsigned long)key & POLLFREE) {
+ /*
+ * If we race with ep_remove_wait_queue() it can miss
+ * ->whead = NULL and do another remove_wait_queue() after
+ * us, so we can't use __remove_wait_queue().
+ */
+ list_del_init(&wait->task_list);
+ /*
+ * ->whead != NULL protects us from the race with ep_free()
+ * or ep_remove(), ep_remove_wait_queue() takes whead->lock
+ * held by the caller. Once we nullify it, nothing protects
+ * ep/epi or even wait.
+ */
+ smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
+ }
+
+ return ewake;
}
/*
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 9e77c08..d17d12e 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -469,6 +469,8 @@
lastoff = page_offset(page);
bh = head = page_buffers(page);
do {
+ if (lastoff + bh->b_size <= startoff)
+ goto next;
if (buffer_uptodate(bh) ||
buffer_unwritten(bh)) {
if (whence == SEEK_DATA)
@@ -483,6 +485,7 @@
unlock_page(page);
goto out;
}
+next:
lastoff += bh->b_size;
bh = bh->b_this_page;
} while (bh != head);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index cf68100..95bf466 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1926,7 +1926,8 @@
n_desc_blocks = o_desc_blocks +
le16_to_cpu(es->s_reserved_gdt_blocks);
n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb);
- n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb);
+ n_blocks_count = (ext4_fsblk_t)n_group *
+ EXT4_BLOCKS_PER_GROUP(sb);
n_group--; /* set to last group number */
}
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 75c95659..21d829b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -55,7 +55,7 @@
{
struct fuse_file *ff;
- ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+ ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL);
if (unlikely(!ff))
return NULL;
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index f31fd0d..b1daeaf 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -121,6 +121,7 @@
config PNFS_BLOCK
tristate
depends on NFS_V4_1 && BLK_DEV_DM
+ depends on 64BIT || LBDAF
default NFS_V4
config PNFS_OBJLAYOUT
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index f7a3f6b..9009989 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -30,6 +30,7 @@
{
nfs4_print_deviceid(&mirror_ds->id_node.deviceid);
nfs4_pnfs_ds_put(mirror_ds->ds);
+ kfree(mirror_ds->ds_versions);
kfree_rcu(mirror_ds, id_node.rcu);
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 46ca788..a53b8e0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7410,7 +7410,7 @@
cdata->res.server_scope = NULL;
}
/* Save the EXCHANGE_ID verifier session trunk tests */
- memcpy(clp->cl_confirm.data, cdata->args.verifier->data,
+ memcpy(clp->cl_confirm.data, cdata->args.verifier.data,
sizeof(clp->cl_confirm.data));
}
out:
@@ -7447,7 +7447,6 @@
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
u32 sp4_how, struct rpc_xprt *xprt)
{
- nfs4_verifier verifier;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
.rpc_cred = cred,
@@ -7470,8 +7469,7 @@
if (!calldata)
goto out;
- if (!xprt)
- nfs4_init_boot_verifier(clp, &verifier);
+ nfs4_init_boot_verifier(clp, &calldata->args.verifier);
status = nfs4_init_uniform_client_string(clp);
if (status)
@@ -7516,9 +7514,8 @@
task_setup_data.rpc_xprt = xprt;
task_setup_data.flags =
RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC;
- calldata->args.verifier = &clp->cl_confirm;
- } else {
- calldata->args.verifier = &verifier;
+ memcpy(calldata->args.verifier.data, clp->cl_confirm.data,
+ sizeof(calldata->args.verifier.data));
}
calldata->args.client = clp;
#ifdef CONFIG_NFS_V4_1_MIGRATION
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c9c4d985..5e2724a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1761,7 +1761,7 @@
int len = 0;
encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
- encode_nfs4_verifier(xdr, args->verifier);
+ encode_nfs4_verifier(xdr, &args->verifier);
encode_string(xdr, strlen(args->client->cl_owner_id),
args->client->cl_owner_id);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4e7a56a..2c4f7a2 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -129,7 +129,7 @@
argp->p = page_address(argp->pagelist[0]);
argp->pagelist++;
if (argp->pagelen < PAGE_SIZE) {
- argp->end = argp->p + (argp->pagelen>>2);
+ argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
argp->pagelen = 0;
} else {
argp->end = argp->p + (PAGE_SIZE>>2);
@@ -1246,9 +1246,7 @@
argp->pagelen -= pages * PAGE_SIZE;
len -= pages * PAGE_SIZE;
- argp->p = (__be32 *)page_address(argp->pagelist[0]);
- argp->pagelist++;
- argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
+ next_decode_page(argp);
}
argp->p += XDR_QUADLEN(len);
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
index 6076c34..5ac0b0b 100644
--- a/fs/sdcardfs/file.c
+++ b/fs/sdcardfs/file.c
@@ -104,12 +104,19 @@
{
long err = -ENOTTY;
struct file *lower_file;
+ const struct cred *saved_cred = NULL;
+ struct dentry *dentry = file->f_path.dentry;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
lower_file = sdcardfs_lower_file(file);
/* XXX: use vfs_ioctl if/when VFS exports it */
if (!lower_file || !lower_file->f_op)
goto out;
+
+ /* save current_cred and override it */
+ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+
if (lower_file->f_op->unlocked_ioctl)
err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
@@ -117,6 +124,7 @@
if (!err)
sdcardfs_copy_and_fix_attrs(file_inode(file),
file_inode(lower_file));
+ REVERT_CRED(saved_cred);
out:
return err;
}
@@ -127,15 +135,23 @@
{
long err = -ENOTTY;
struct file *lower_file;
+ const struct cred *saved_cred = NULL;
+ struct dentry *dentry = file->f_path.dentry;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
lower_file = sdcardfs_lower_file(file);
/* XXX: use vfs_ioctl if/when VFS exports it */
if (!lower_file || !lower_file->f_op)
goto out;
+
+ /* save current_cred and override it */
+ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+
if (lower_file->f_op->compat_ioctl)
err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+ REVERT_CRED(saved_cred);
out:
return err;
}
diff --git a/include/asm-generic/topology.h b/include/asm-generic/topology.h
index fc824e2..5d2add1 100644
--- a/include/asm-generic/topology.h
+++ b/include/asm-generic/topology.h
@@ -48,7 +48,11 @@
#define parent_node(node) ((void)(node),0)
#endif
#ifndef cpumask_of_node
-#define cpumask_of_node(node) ((void)node, cpu_online_mask)
+ #ifdef CONFIG_NEED_MULTIPLE_NODES
+ #define cpumask_of_node(node) ((node) == 0 ? cpu_online_mask : cpu_none_mask)
+ #else
+ #define cpumask_of_node(node) ((void)node, cpu_online_mask)
+ #endif
#endif
#ifndef pcibus_to_node
#define pcibus_to_node(bus) ((void)(bus), -1)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 31e1d63..dc81e52 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -60,6 +60,22 @@
#define ALIGN_FUNCTION() . = ALIGN(8)
/*
+ * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which
+ * generates .data.identifier sections, which need to be pulled in with
+ * .data. We don't want to pull in .data..other sections, which Linux
+ * has defined. Same for text and bss.
+ */
+#ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
+#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
+#define DATA_MAIN .data .data.[0-9a-zA-Z_]*
+#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]*
+#else
+#define TEXT_MAIN .text
+#define DATA_MAIN .data
+#define BSS_MAIN .bss
+#endif
+
+/*
* Align to a 32 byte boundary equal to the
* alignment gcc 4.5 uses for a struct
*/
@@ -198,12 +214,9 @@
/*
* .data section
- * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections generates
- * .data.identifier which needs to be pulled in with .data, but don't want to
- * pull in .data..stuff which has its own requirements. Same for bss.
*/
#define DATA_DATA \
- *(.data .data.[0-9a-zA-Z_]*) \
+ *(DATA_MAIN) \
*(.ref.data) \
*(.data..shared_aligned) /* percpu related */ \
MEM_KEEP(init.data) \
@@ -436,16 +449,17 @@
VMLINUX_SYMBOL(__security_initcall_end) = .; \
}
-/* .text section. Map to function alignment to avoid address changes
+/*
+ * .text section. Map to function alignment to avoid address changes
* during second ld run in second ld pass when generating System.map
- * LD_DEAD_CODE_DATA_ELIMINATION option enables -ffunction-sections generates
- * .text.identifier which needs to be pulled in with .text , but some
- * architectures define .text.foo which is not intended to be pulled in here.
- * Those enabling LD_DEAD_CODE_DATA_ELIMINATION must ensure they don't have
- * conflicting section names, and must pull in .text.[0-9a-zA-Z_]* */
+ *
+ * TEXT_MAIN here will match .text.fixup and .text.unlikely if dead
+ * code elimination is enabled, so these sections should be converted
+ * to use ".." first.
+ */
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
- *(.text.hot .text .text.fixup .text.unlikely) \
+ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \
*(.ref.text) \
MEM_KEEP(init.text) \
MEM_KEEP(exit.text) \
@@ -613,7 +627,7 @@
BSS_FIRST_SECTIONS \
*(.bss..page_aligned) \
*(.dynbss) \
- *(.bss .bss.[0-9a-zA-Z_]*) \
+ *(BSS_MAIN) \
*(COMMON) \
}
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index a13b031..3101141 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -40,6 +40,7 @@
*/
s64 min_value;
u64 max_value;
+ bool value_from_signed;
};
enum bpf_stack_slot_type {
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 9ddaf05..6be0299 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -10,7 +10,6 @@
CPUHP_PERF_X86_PREPARE,
CPUHP_PERF_X86_UNCORE_PREP,
CPUHP_PERF_X86_AMD_UNCORE_PREP,
- CPUHP_PERF_X86_RAPL_PREP,
CPUHP_PERF_BFIN,
CPUHP_PERF_POWER,
CPUHP_PERF_SUPERH,
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index bfc204e..cd32a49 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -16,6 +16,19 @@
#ifdef CONFIG_CPUSETS
+/*
+ * Static branch rewrites can happen in an arbitrary order for a given
+ * key. In code paths where we need to loop with read_mems_allowed_begin() and
+ * read_mems_allowed_retry() to get a consistent view of mems_allowed, we need
+ * to ensure that begin() always gets rewritten before retry() in the
+ * disabled -> enabled transition. If not, then if local irqs are disabled
+ * around the loop, we can deadlock since retry() would always be
+ * comparing the latest value of the mems_allowed seqcount against 0 as
+ * begin() still would see cpusets_enabled() as false. The enabled -> disabled
+ * transition should happen in reverse order for the same reasons (want to stop
+ * looking at real value of mems_allowed.sequence in retry() first).
+ */
+extern struct static_key_false cpusets_pre_enable_key;
extern struct static_key_false cpusets_enabled_key;
static inline bool cpusets_enabled(void)
{
@@ -30,12 +43,14 @@
static inline void cpuset_inc(void)
{
+ static_branch_inc(&cpusets_pre_enable_key);
static_branch_inc(&cpusets_enabled_key);
}
static inline void cpuset_dec(void)
{
static_branch_dec(&cpusets_enabled_key);
+ static_branch_dec(&cpusets_pre_enable_key);
}
extern int cpuset_init(void);
@@ -113,7 +128,7 @@
*/
static inline unsigned int read_mems_allowed_begin(void)
{
- if (!cpusets_enabled())
+ if (!static_branch_unlikely(&cpusets_pre_enable_key))
return 0;
return read_seqcount_begin(¤t->mems_allowed_seq);
@@ -127,7 +142,7 @@
*/
static inline bool read_mems_allowed_retry(unsigned int seq)
{
- if (!cpusets_enabled())
+ if (!static_branch_unlikely(&cpusets_enabled_key))
return false;
return read_seqcount_retry(¤t->mems_allowed_seq, seq);
diff --git a/include/linux/dma-mapping-fast.h b/include/linux/dma-mapping-fast.h
index 560f047..64ae548 100644
--- a/include/linux/dma-mapping-fast.h
+++ b/include/linux/dma-mapping-fast.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,19 +41,17 @@
};
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
-int fast_smmu_attach_device(struct device *dev,
+int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping);
-void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping);
+void fast_smmu_release_mapping(struct kref *kref);
#else
-static inline int fast_smmu_attach_device(struct device *dev,
+static inline int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
return -ENODEV;
}
-static inline void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
+static inline void fast_smmu_release_mapping(struct kref *kref)
{
}
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 026aa0a..6d6114a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -941,9 +941,9 @@
/* Page cache limit. The filesystems should put that into their s_maxbytes
limits, otherwise bad things can happen in VM. */
#if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE (((loff_t)PAGE_SIZE << (BITS_PER_LONG-1))-1)
+#define MAX_LFS_FILESIZE ((loff_t)ULONG_MAX << PAGE_SHIFT)
#elif BITS_PER_LONG==64
-#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffffLL)
+#define MAX_LFS_FILESIZE ((loff_t)LLONG_MAX)
#endif
#define FL_POSIX 1
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 0b8aedf..99eb77a 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -142,6 +142,7 @@
DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
DOMAIN_ATTR_CB_STALL_DISABLE,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
DOMAIN_ATTR_MAX,
};
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 37e5178..600c905 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -64,6 +64,7 @@
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
#define __init_memblock __meminit
#define __initdata_memblock __meminitdata
+void memblock_discard(void);
#else
#define __init_memblock
#define __initdata_memblock
@@ -77,8 +78,6 @@
int nid, ulong flags);
phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align);
-phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
-phys_addr_t get_allocated_memblock_memory_regions_info(phys_addr_t *addr);
void memblock_allow_resize(void);
int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
int memblock_add(phys_addr_t base, phys_addr_t size);
@@ -114,6 +113,9 @@
void __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start,
phys_addr_t *out_end);
+void __memblock_free_early(phys_addr_t base, phys_addr_t size);
+void __memblock_free_late(phys_addr_t base, phys_addr_t size);
+
/**
* for_each_mem_range - iterate through memblock areas from type_a and not
* included in type_b. Or just type_a if type_b is NULL.
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3139ea4..5942478 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -515,6 +515,10 @@
*/
bool tlb_flush_pending;
#endif
+#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
+ /* See flush_tlb_batched_pending() */
+ bool tlb_flush_batched;
+#endif
struct uprobes_state uprobes_state;
#ifdef CONFIG_X86_INTEL_MPX
/* address of the bounds directory */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index f214b0c..1e07ed2 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -226,6 +226,7 @@
unsigned int resp_arg;
unsigned int dev_pend_tasks;
bool resp_err;
+ bool skip_err_handling;
int tag; /* used for command queuing */
u8 ctx_id;
};
@@ -543,6 +544,7 @@
unsigned int bus_resume_flags;
#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0)
#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1)
+ bool ignore_bus_resume_flags;
unsigned int sdio_irqs;
struct task_struct *sdio_irq_thread;
diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h
index c298666..a584e0a 100644
--- a/include/linux/msm-bus.h
+++ b/include/linux/msm-bus.h
@@ -130,6 +130,8 @@
uint32_t cl, unsigned int index);
int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle,
uint32_t cl);
+int msm_bus_noc_throttle_wa(bool enable);
+int msm_bus_noc_priority_wa(bool enable);
/* AXI Port configuration APIs */
int msm_bus_axi_porthalt(int master_port);
@@ -211,6 +213,16 @@
return 0;
}
+static inline int msm_bus_noc_throttle_wa(bool enable)
+{
+ return 0;
+}
+
+static inline int msm_bus_noc_priority_wa(bool enable)
+{
+ return 0;
+}
+
#endif
#if defined(CONFIG_OF) && defined(CONFIG_QCOM_BUS_SCALING)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index beb1e10..3bf867a 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1199,7 +1199,7 @@
struct nfs41_exchange_id_args {
struct nfs_client *client;
- nfs4_verifier *verifier;
+ nfs4_verifier verifier;
u32 flags;
struct nfs41_state_protection state_protect;
};
diff --git a/include/linux/oom.h b/include/linux/oom.h
index b986840..5b5d4c7 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -82,6 +82,8 @@
extern void dump_tasks(struct mem_cgroup *memcg,
const nodemask_t *nodemask);
+extern void wake_oom_reaper(struct task_struct *tsk);
+
/* sysctls */
extern int sysctl_oom_dump_tasks;
extern int sysctl_oom_kill_allocating_task;
diff --git a/include/linux/property.h b/include/linux/property.h
index 856e50b..338f9b7 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -33,6 +33,8 @@
DEV_DMA_COHERENT,
};
+struct fwnode_handle *dev_fwnode(struct device *dev);
+
bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval);
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index 6c70444..b83507c 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -340,9 +340,9 @@
__PTR_RING_PEEK_CALL_v; \
})
-static inline void **__ptr_ring_init_queue_alloc(int size, gfp_t gfp)
+static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp)
{
- return kzalloc(ALIGN(size * sizeof(void *), SMP_CACHE_BYTES), gfp);
+ return kcalloc(size, sizeof(void *), gfp);
}
static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
@@ -417,7 +417,8 @@
* In particular if you consume ring in interrupt or BH context, you must
* disable interrupts/BH when doing so.
*/
-static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
+static inline int ptr_ring_resize_multiple(struct ptr_ring **rings,
+ unsigned int nrings,
int size,
gfp_t gfp, void (*destroy)(void *))
{
@@ -425,7 +426,7 @@
void ***queues;
int i;
- queues = kmalloc(nrings * sizeof *queues, gfp);
+ queues = kmalloc_array(nrings, sizeof(*queues), gfp);
if (!queues)
goto noqueues;
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index aa4c1ed..463785d 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -117,6 +117,7 @@
#define SE_HW_PARAM_0 (0xE24)
#define SE_HW_PARAM_1 (0xE28)
#define SE_DMA_GENERAL_CFG (0xE30)
+#define SE_DMA_DEBUG_REG0 (0xE40)
/* GENI_OUTPUT_CTRL fields */
#define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0))
@@ -736,6 +737,22 @@
int geni_se_iommu_free_buf(struct device *wrapper_dev, dma_addr_t *iova,
void *buf, size_t size);
+
+/**
+ * geni_se_dump_dbg_regs() - Print relevant registers that capture most
+ * accurately the state of an SE; meant to be called
+ * in case of errors to help debug.
+ * @_dev: Pointer to the SE's device.
+ * @iomem: Base address of the SE's register space.
+ * @ipc: IPC log context handle.
+ *
+ * This function is used to print out all the registers that capture the state
+ * of an SE to help debug any errors.
+ *
+ * Return: None
+ */
+void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
+ void *ipc);
#else
static inline unsigned int geni_read_reg_nolog(void __iomem *base, int offset)
{
@@ -907,5 +924,10 @@
return -ENXIO;
}
+void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
+ void *ipc)
+{
+}
+
#endif
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a4ea064..e5541af 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -928,6 +928,16 @@
#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */
+#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
+ SIGNAL_STOP_CONTINUED)
+
+static inline void signal_set_stop_flags(struct signal_struct *sig,
+ unsigned int flags)
+{
+ WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
+ sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
+}
+
/* If true, all threads except ->group_exit_task have pending SIGKILL */
static inline int signal_group_exit(const struct signal_struct *sig)
{
@@ -2380,23 +2390,6 @@
}
static inline int pid_alive(const struct task_struct *p);
-static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
-{
- pid_t pid = 0;
-
- rcu_read_lock();
- if (pid_alive(tsk))
- pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
- rcu_read_unlock();
-
- return pid;
-}
-
-static inline pid_t task_ppid_nr(const struct task_struct *tsk)
-{
- return task_ppid_nr_ns(tsk, &init_pid_ns);
-}
static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
struct pid_namespace *ns)
@@ -2431,6 +2424,23 @@
return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, NULL);
}
+static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
+{
+ pid_t pid = 0;
+
+ rcu_read_lock();
+ if (pid_alive(tsk))
+ pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
+ rcu_read_unlock();
+
+ return pid;
+}
+
+static inline pid_t task_ppid_nr(const struct task_struct *tsk)
+{
+ return task_ppid_nr_ns(tsk, &init_pid_ns);
+}
+
/* obsolete, do not use */
static inline pid_t task_pgrp_nr(struct task_struct *tsk)
{
diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h
index f4dfade..be8b902 100644
--- a/include/linux/skb_array.h
+++ b/include/linux/skb_array.h
@@ -162,7 +162,8 @@
}
static inline int skb_array_resize_multiple(struct skb_array **rings,
- int nrings, int size, gfp_t gfp)
+ int nrings, unsigned int size,
+ gfp_t gfp)
{
BUILD_BUG_ON(offsetof(struct skb_array, ring));
return ptr_ring_resize_multiple((struct ptr_ring **)rings,
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 084b12b..4c53635 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -226,7 +226,7 @@
* (PAGE_SIZE*2). Larger requests are passed to the page allocator.
*/
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
-#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT)
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
@@ -239,7 +239,7 @@
* be allocated from the same page.
*/
#define KMALLOC_SHIFT_HIGH PAGE_SHIFT
-#define KMALLOC_SHIFT_MAX 30
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 0a34489..17a33f3 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -23,6 +23,8 @@
extern int snprint_stack_trace(char *buf, size_t size,
struct stack_trace *trace, int spaces);
+#define BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
+
#ifdef CONFIG_USER_STACKTRACE_SUPPORT
extern void save_stack_trace_user(struct stack_trace *trace);
#else
diff --git a/include/linux/string.h b/include/linux/string.h
index 4e510df..0463dfb 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -178,17 +178,6 @@
void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
-__FORTIFY_INLINE char *strcpy(char *p, const char *q)
-{
- size_t p_size = __builtin_object_size(p, 0);
- size_t q_size = __builtin_object_size(q, 0);
- if (p_size == (size_t)-1 && q_size == (size_t)-1)
- return __builtin_strcpy(p, q);
- if (strscpy(p, q, p_size < q_size ? p_size : q_size) < 0)
- fortify_panic(__func__);
- return p;
-}
-
__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
{
size_t p_size = __builtin_object_size(p, 0);
@@ -367,6 +356,18 @@
fortify_panic(__func__);
return __real_kmemdup(p, size, gfp);
}
+
+/* defined after fortified strlen and memcpy to reuse them */
+__FORTIFY_INLINE char *strcpy(char *p, const char *q)
+{
+ size_t p_size = __builtin_object_size(p, 0);
+ size_t q_size = __builtin_object_size(q, 0);
+ if (p_size == (size_t)-1 && q_size == (size_t)-1)
+ return __builtin_strcpy(p, q);
+ memcpy(p, q, strlen(q) + 1);
+ return p;
+}
+
#endif
#endif /* _LINUX_STRING_H_ */
diff --git a/include/linux/usb/ccid_desc.h b/include/linux/usb/ccid_desc.h
index 9a0c726..2e6dbb5 100644
--- a/include/linux/usb/ccid_desc.h
+++ b/include/linux/usb/ccid_desc.h
@@ -86,27 +86,27 @@
* Table 5.1-1 Smart Card Device Class descriptors
*/
struct usb_ccid_class_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType;
- unsigned short bcdCCID;
- unsigned char bMaxSlotIndex;
- unsigned char bVoltageSupport;
- unsigned long dwProtocols;
- unsigned long dwDefaultClock;
- unsigned long dwMaximumClock;
- unsigned char bNumClockSupported;
- unsigned long dwDataRate;
- unsigned long dwMaxDataRate;
- unsigned char bNumDataRatesSupported;
- unsigned long dwMaxIFSD;
- unsigned long dwSynchProtocols;
- unsigned long dwMechanical;
- unsigned long dwFeatures;
- unsigned long dwMaxCCIDMessageLength;
- unsigned char bClassGetResponse;
- unsigned char bClassEnvelope;
- unsigned short wLcdLayout;
- unsigned char bPINSupport;
- unsigned char bMaxCCIDBusySlots;
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u16 bcdCCID;
+ __u8 bMaxSlotIndex;
+ __u8 bVoltageSupport;
+ __u32 dwProtocols;
+ __u32 dwDefaultClock;
+ __u32 dwMaximumClock;
+ __u8 bNumClockSupported;
+ __u32 dwDataRate;
+ __u32 dwMaxDataRate;
+ __u8 bNumDataRatesSupported;
+ __u32 dwMaxIFSD;
+ __u32 dwSynchProtocols;
+ __u32 dwMechanical;
+ __u32 dwFeatures;
+ __u32 dwMaxCCIDMessageLength;
+ __u8 bClassGetResponse;
+ __u8 bClassEnvelope;
+ __u16 wLcdLayout;
+ __u8 bPINSupport;
+ __u8 bMaxCCIDBusySlots;
} __packed;
#endif
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index fc6e221..733a21e 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -311,6 +311,7 @@
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
+ __WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
@@ -409,7 +410,8 @@
* Pointer to the allocated workqueue on success, %NULL on failure.
*/
#define alloc_ordered_workqueue(fmt, flags, args...) \
- alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
+ alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | \
+ __WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
#define create_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 82b4b53..73da337 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -49,6 +49,13 @@
#define CFG80211_REKEY_DATA_KEK_LEN 1
/**
+ * Indicate backport support for the new cfg80211_roamed event which unifies the
+ * old APIs cfg80211_roamed and cfg80211_roamed_bss and takes a structure to
+ * update roam information to the kernel.
+ */
+#define CFG80211_ROAMED_API_UNIFIED 1
+
+/**
* DOC: Introduction
*
* cfg80211 is the configuration API for 802.11 devices in Linux. It bridges
@@ -2661,8 +2668,7 @@
* indication of requesting reassociation.
* In both the driver-initiated and new connect() call initiated roaming
* cases, the result of roaming is indicated with a call to
- * cfg80211_roamed() or cfg80211_roamed_bss().
- * (invoked with the wireless_dev mutex held)
+ * cfg80211_roamed(). (invoked with the wireless_dev mutex held)
* @update_connect_params: Update the connect parameters while connected to a
* BSS. The updated parameters can be used by driver/firmware for
* subsequent BSS selection (roaming) decisions and to form the
@@ -5301,51 +5307,50 @@
}
/**
+ * struct cfg80211_roam_info - driver initiated roaming information
+ *
+ * @channel: the channel of the new AP
+ * @bss: entry of bss to which STA got roamed (may be %NULL if %bssid is set)
+ * @bssid: the BSSID of the new AP (may be %NULL if %bss is set)
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @authorized: true if the 802.1X authentication was done by the driver or is
+ * not needed (e.g., when Fast Transition protocol was used), false
+ * otherwise. Ignored for networks that don't use 802.1X authentication.
+ */
+struct cfg80211_roam_info {
+ struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss;
+ const u8 *bssid;
+ const u8 *req_ie;
+ size_t req_ie_len;
+ const u8 *resp_ie;
+ size_t resp_ie_len;
+ bool authorized;
+};
+
+/**
* cfg80211_roamed - notify cfg80211 of roaming
*
* @dev: network device
- * @channel: the channel of the new AP
- * @bssid: the BSSID of the new AP
- * @req_ie: association request IEs (maybe be %NULL)
- * @req_ie_len: association request IEs length
- * @resp_ie: association response IEs (may be %NULL)
- * @resp_ie_len: assoc response IEs length
+ * @info: information about the new BSS. struct &cfg80211_roam_info.
* @gfp: allocation flags
*
- * It should be called by the underlying driver whenever it roamed
- * from one AP to another while connected.
- */
-void cfg80211_roamed(struct net_device *dev,
- struct ieee80211_channel *channel,
- const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
-
-/**
- * cfg80211_roamed_bss - notify cfg80211 of roaming
- *
- * @dev: network device
- * @bss: entry of bss to which STA got roamed
- * @req_ie: association request IEs (maybe be %NULL)
- * @req_ie_len: association request IEs length
- * @resp_ie: association response IEs (may be %NULL)
- * @resp_ie_len: assoc response IEs length
- * @gfp: allocation flags
- *
- * This is just a wrapper to notify cfg80211 of roaming event with driver
- * passing bss to avoid a race in timeout of the bss entry. It should be
- * called by the underlying driver whenever it roamed from one AP to another
- * while connected. Drivers which have roaming implemented in firmware
- * may use this function to avoid a race in bss entry timeout where the bss
- * entry of the new AP is seen in the driver, but gets timed out by the time
- * it is accessed in __cfg80211_roamed() due to delay in scheduling
+ * This function may be called with the driver passing either the BSSID of the
+ * new AP or passing the bss entry to avoid a race in timeout of the bss entry.
+ * It should be called by the underlying driver whenever it roamed from one AP
+ * to another while connected. Drivers which have roaming implemented in
+ * firmware should pass the bss entry to avoid a race in bss entry timeout where
+ * the bss entry of the new AP is seen in the driver, but gets timed out by the
+ * time it is accessed in __cfg80211_roamed() due to delay in scheduling
* rdev->event_work. In case of any failures, the reference is released
- * either in cfg80211_roamed_bss() or in __cfg80211_romed(), Otherwise,
- * it will be released while diconneting from the current bss.
+ * either in cfg80211_roamed() or in __cfg80211_romed(), Otherwise, it will be
+ * released while diconneting from the current bss.
*/
-void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
+ gfp_t gfp);
/**
* cfg80211_disconnected - notify cfg80211 that connection was dropped
diff --git a/include/net/ip.h b/include/net/ip.h
index 9816365..4ef6792 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -342,7 +342,7 @@
!forwarding)
return dst_mtu(dst);
- return min(dst->dev->mtu, IP_MAX_MTU);
+ return min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
}
static inline unsigned int ip_skb_dst_mtu(struct sock *sk,
@@ -354,7 +354,7 @@
return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
}
- return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
+ return min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU);
}
u32 ip_idents_reserve(u32 hash, int segs);
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index e0f4109..c2aa73e 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -556,7 +556,8 @@
memcpy(stream + lcp_len,
((char *) &iwe->u) + IW_EV_POINT_OFF,
IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
- memcpy(stream + point_len, extra, iwe->u.data.length);
+ if (iwe->u.data.length && extra)
+ memcpy(stream + point_len, extra, iwe->u.data.length);
stream += event_len;
}
return stream;
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e6aa0a2..f18fc1a 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -768,8 +768,11 @@
old = *pold;
*pold = new;
if (old != NULL) {
- qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
+ unsigned int qlen = old->q.qlen;
+ unsigned int backlog = old->qstats.backlog;
+
qdisc_reset(old);
+ qdisc_tree_reduce_backlog(old, qlen, backlog);
}
sch_tree_unlock(sch);
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 31acc3f..61d9ce8 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -460,6 +460,8 @@
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
+ (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\
+ (void *)chunk + end) &&\
pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
pos.v += SCTP_PAD4(ntohs(pos.p->length)))
@@ -470,6 +472,8 @@
#define _sctp_walk_errors(err, chunk_hdr, end)\
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
sizeof(sctp_chunkhdr_t));\
+ ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\
+ (void *)chunk_hdr + end) &&\
(void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
ntohs(err->length) >= sizeof(sctp_errhdr_t); \
err = (sctp_errhdr_t *)((void *)err + SCTP_PAD4(ntohs(err->length))))
diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h
index 50e4b8c..e67ee0e 100644
--- a/include/soc/qcom/memory_dump.h
+++ b/include/soc/qcom/memory_dump.h
@@ -83,6 +83,7 @@
MSM_DUMP_DATA_RPM = 0xEA,
MSM_DUMP_DATA_SCANDUMP = 0xEB,
MSM_DUMP_DATA_RPMH = 0xEC,
+ MSM_DUMP_DATA_POWER_REGS = 0xED,
MSM_DUMP_DATA_TMC_ETF = 0xF0,
MSM_DUMP_DATA_TMC_REG = 0x100,
MSM_DUMP_DATA_LOG_BUF = 0x110,
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index f196d40..71bd075 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -102,6 +102,10 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm845")
#define early_machine_is_sdm670() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm670")
+#define early_machine_is_qcs605() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs605")
+#define early_machine_is_sda670() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda670")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -142,6 +146,8 @@
#define early_machine_is_sdxpoorwills() 0
#define early_machine_is_sdm845() 0
#define early_machine_is_sdm670() 0
+#define early_machine_is_qcs605() 0
+#define early_machine_is_sda670() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -204,6 +210,8 @@
SDX_CPU_SDXPOORWILLS,
MSM_CPU_SDM845,
MSM_CPU_SDM670,
+ MSM_CPU_QCS605,
+ MSM_CPU_SDA670,
};
struct msm_soc_info {
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
index 33b2e75..6021c3a 100644
--- a/include/target/iscsi/iscsi_target_core.h
+++ b/include/target/iscsi/iscsi_target_core.h
@@ -563,6 +563,7 @@
#define LOGIN_FLAGS_READ_ACTIVE 1
#define LOGIN_FLAGS_CLOSED 2
#define LOGIN_FLAGS_READY 4
+#define LOGIN_FLAGS_INITIAL_PDU 8
unsigned long login_flags;
struct delayed_work login_work;
struct delayed_work login_cleanup_work;
@@ -784,6 +785,7 @@
int np_sock_type;
enum np_thread_state_table np_thread_state;
bool enabled;
+ atomic_t np_reset_count;
enum iscsi_timer_flags_table np_login_timer_flags;
u32 np_exports;
enum np_flags_table np_flags;
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index 285508a..1a43659 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -295,6 +295,44 @@
struct sde_drm_de_v1 de;
};
+/* Number of dest scalers supported */
+#define SDE_MAX_DS_COUNT 2
+
+/*
+ * Destination scaler flag config
+ */
+#define SDE_DRM_DESTSCALER_ENABLE 0x1
+#define SDE_DRM_DESTSCALER_SCALE_UPDATE 0x2
+#define SDE_DRM_DESTSCALER_ENHANCER_UPDATE 0x4
+#define SDE_DRM_DESTSCALER_PU_ENABLE 0x8
+
+/**
+ * struct sde_drm_dest_scaler_cfg - destination scaler config structure
+ * @flags: Flag to switch between mode for destination scaler
+ * refer to destination scaler flag config
+ * @index: Destination scaler selection index
+ * @lm_width: Layer mixer width configuration
+ * @lm_height: Layer mixer height configuration
+ * @scaler_cfg: The scaling parameters for all the mode except disable
+ * Userspace pointer to struct sde_drm_scaler_v2
+ */
+struct sde_drm_dest_scaler_cfg {
+ uint32_t flags;
+ uint32_t index;
+ uint32_t lm_width;
+ uint32_t lm_height;
+ uint64_t scaler_cfg;
+};
+
+/**
+ * struct sde_drm_dest_scaler_data - destination scaler data struct
+ * @num_dest_scaler: Number of dest scalers to be configured
+ * @ds_cfg: Destination scaler block configuration
+ */
+struct sde_drm_dest_scaler_data {
+ uint32_t num_dest_scaler;
+ struct sde_drm_dest_scaler_cfg ds_cfg[SDE_MAX_DS_COUNT];
+};
/*
* Define constants for struct sde_drm_csc
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 8c0fc7b..9fbdc11 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -546,6 +546,12 @@
* well to remain backwards compatible.
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
* sent as an event when the card/driver roamed by itself.
+ * When used as an event, and the driver roamed in a network that requires
+ * 802.1X authentication, %NL80211_ATTR_PORT_AUTHORIZED should be set
+ * if the 802.1X authentication was done by the driver or if roaming was
+ * done using Fast Transition protocol (in which case 802.1X authentication
+ * is not needed). If %NL80211_ATTR_PORT_AUTHORIZED is not set, user space
+ * is responsible for the 802.1X authentication.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -2066,6 +2072,10 @@
*
* @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
* This is used with @NL80211_CMD_SET_PMKSA.
+ * @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_ROAMED
+ * notification indicating that that 802.1X authentication was done by
+ * the driver or is not needed (because roaming used the Fast Transition
+ * protocol).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2486,6 +2496,13 @@
NL80211_ATTR_PMK,
+ NL80211_ATTR_SCHED_SCAN_MULTI,
+ NL80211_ATTR_SCHED_SCAN_MAX_REQS,
+
+ NL80211_ATTR_WANT_1X_4WAY_HS,
+ NL80211_ATTR_PMKR0_NAME,
+ NL80211_ATTR_PORT_AUTHORIZED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
index f04ac49..04aaaad 100644
--- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h
+++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
@@ -33,6 +33,7 @@
#define WAN_IOCTL_QUERY_DL_FILTER_STATS 8
#define WAN_IOCTL_ADD_FLT_RULE_EX 9
#define WAN_IOCTL_QUERY_TETHER_STATS_ALL 10
+#define WAN_IOCTL_NOTIFY_WAN_STATE 11
/* User space may not have this defined. */
#ifndef IFNAMSIZ
@@ -126,6 +127,10 @@
uint32_t index;
};
+struct wan_ioctl_notify_wan_state {
+ uint8_t up;
+};
+
#define WAN_IOC_ADD_FLT_RULE _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_ADD_FLT_RULE, \
struct ipa_install_fltr_rule_req_msg_v01 *)
@@ -170,4 +175,8 @@
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
struct wan_ioctl_query_tether_stats_all *)
+#define WAN_IOC_NOTIFY_WAN_STATE _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_NOTIFY_WAN_STATE, \
+ struct wan_ioctl_notify_wan_state *)
+
#endif /* _RMNET_IPA_FD_IOCTL_H */
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 26506d5..d750568 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1126,6 +1126,14 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 114)
+#define V4L2_CID_MPEG_VIDC_VIDEO_FLIP (V4L2_CID_MPEG_MSM_VIDC_BASE + 115)
+enum v4l2_mpeg_vidc_video_flip {
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH = 3,
+};
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 0d302a8..690e1e3 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -457,13 +457,15 @@
list_del(&krule->rlist);
if (list_empty(&watch->rules)) {
+ /*
+ * audit_remove_watch() drops our reference to 'parent' which
+ * can get freed. Grab our own reference to be safe.
+ */
+ audit_get_parent(parent);
audit_remove_watch(watch);
-
- if (list_empty(&parent->watches)) {
- audit_get_parent(parent);
+ if (list_empty(&parent->watches))
fsnotify_destroy_mark(&parent->mark, audit_watch_group);
- audit_put_parent(parent);
- }
+ audit_put_parent(parent);
}
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8ce679d..779c871 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -139,7 +139,7 @@
struct bpf_verifier_stack_elem *next;
};
-#define BPF_COMPLEXITY_LIMIT_INSNS 65536
+#define BPF_COMPLEXITY_LIMIT_INSNS 98304
#define BPF_COMPLEXITY_LIMIT_STACK 1024
struct bpf_call_arg_meta {
@@ -682,12 +682,13 @@
return -EACCES;
}
-static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+static bool __is_pointer_value(bool allow_ptr_leaks,
+ const struct bpf_reg_state *reg)
{
- if (env->allow_ptr_leaks)
+ if (allow_ptr_leaks)
return false;
- switch (env->cur_state.regs[regno].type) {
+ switch (reg->type) {
case UNKNOWN_VALUE:
case CONST_IMM:
return false;
@@ -696,6 +697,11 @@
}
}
+static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+{
+ return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
+}
+
static int check_ptr_alignment(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, int off, int size)
{
@@ -1467,6 +1473,65 @@
return 0;
}
+static int evaluate_reg_imm_alu_unknown(struct bpf_verifier_env *env,
+ struct bpf_insn *insn)
+{
+ struct bpf_reg_state *regs = env->cur_state.regs;
+ struct bpf_reg_state *dst_reg = ®s[insn->dst_reg];
+ struct bpf_reg_state *src_reg = ®s[insn->src_reg];
+ u8 opcode = BPF_OP(insn->code);
+ s64 imm_log2 = __ilog2_u64((long long)dst_reg->imm);
+
+ /* BPF_X code with src_reg->type UNKNOWN_VALUE here. */
+ if (src_reg->imm > 0 && dst_reg->imm) {
+ switch (opcode) {
+ case BPF_ADD:
+ /* dreg += sreg
+ * where both have zero upper bits. Adding them
+ * can only result making one more bit non-zero
+ * in the larger value.
+ * Ex. 0xffff (imm=48) + 1 (imm=63) = 0x10000 (imm=47)
+ * 0xffff (imm=48) + 0xffff = 0x1fffe (imm=47)
+ */
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
+ dst_reg->imm--;
+ break;
+ case BPF_AND:
+ /* dreg &= sreg
+ * AND can not extend zero bits only shrink
+ * Ex. 0x00..00ffffff
+ * & 0x0f..ffffffff
+ * ----------------
+ * 0x00..00ffffff
+ */
+ dst_reg->imm = max(src_reg->imm, 63 - imm_log2);
+ break;
+ case BPF_OR:
+ /* dreg |= sreg
+ * OR can only extend zero bits
+ * Ex. 0x00..00ffffff
+ * | 0x0f..ffffffff
+ * ----------------
+ * 0x0f..00ffffff
+ */
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
+ break;
+ case BPF_SUB:
+ case BPF_MUL:
+ case BPF_RSH:
+ case BPF_LSH:
+ /* These may be flushed out later */
+ default:
+ mark_reg_unknown_value(regs, insn->dst_reg);
+ }
+ } else {
+ mark_reg_unknown_value(regs, insn->dst_reg);
+ }
+
+ dst_reg->type = UNKNOWN_VALUE;
+ return 0;
+}
+
static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
@@ -1475,6 +1540,9 @@
struct bpf_reg_state *src_reg = ®s[insn->src_reg];
u8 opcode = BPF_OP(insn->code);
+ if (BPF_SRC(insn->code) == BPF_X && src_reg->type == UNKNOWN_VALUE)
+ return evaluate_reg_imm_alu_unknown(env, insn);
+
/* dst_reg->type == CONST_IMM here, simulate execution of 'add' insn.
* Don't care about overflow or negative values, just add them
*/
@@ -1530,10 +1598,24 @@
}
/* We don't know anything about what was done to this register, mark it
- * as unknown.
+ * as unknown. Also, if both derived bounds came from signed/unsigned
+ * mixed compares and one side is unbounded, we cannot really do anything
+ * with them as boundaries cannot be trusted. Thus, arithmetic of two
+ * regs of such kind will get invalidated bounds on the dst side.
*/
- if (min_val == BPF_REGISTER_MIN_RANGE &&
- max_val == BPF_REGISTER_MAX_RANGE) {
+ if ((min_val == BPF_REGISTER_MIN_RANGE &&
+ max_val == BPF_REGISTER_MAX_RANGE) ||
+ (BPF_SRC(insn->code) == BPF_X &&
+ ((min_val != BPF_REGISTER_MIN_RANGE &&
+ max_val == BPF_REGISTER_MAX_RANGE) ||
+ (min_val == BPF_REGISTER_MIN_RANGE &&
+ max_val != BPF_REGISTER_MAX_RANGE) ||
+ (dst_reg->min_value != BPF_REGISTER_MIN_RANGE &&
+ dst_reg->max_value == BPF_REGISTER_MAX_RANGE) ||
+ (dst_reg->min_value == BPF_REGISTER_MIN_RANGE &&
+ dst_reg->max_value != BPF_REGISTER_MAX_RANGE)) &&
+ regs[insn->dst_reg].value_from_signed !=
+ regs[insn->src_reg].value_from_signed)) {
reset_reg_range_values(regs, insn->dst_reg);
return;
}
@@ -1542,10 +1624,12 @@
* do our normal operations to the register, we need to set the values
* to the min/max since they are undefined.
*/
- if (min_val == BPF_REGISTER_MIN_RANGE)
- dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
- if (max_val == BPF_REGISTER_MAX_RANGE)
- dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ if (opcode != BPF_SUB) {
+ if (min_val == BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+ if (max_val == BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ }
switch (opcode) {
case BPF_ADD:
@@ -1555,10 +1639,17 @@
dst_reg->max_value += max_val;
break;
case BPF_SUB:
+ /* If one of our values was at the end of our ranges, then the
+ * _opposite_ value in the dst_reg goes to the end of our range.
+ */
+ if (min_val == BPF_REGISTER_MIN_RANGE)
+ dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ if (max_val == BPF_REGISTER_MAX_RANGE)
+ dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
- dst_reg->min_value -= min_val;
+ dst_reg->min_value -= max_val;
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
- dst_reg->max_value -= max_val;
+ dst_reg->max_value -= min_val;
break;
case BPF_MUL:
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
@@ -1808,6 +1899,7 @@
* register as unknown.
*/
if (env->allow_ptr_leaks &&
+ BPF_CLASS(insn->code) == BPF_ALU64 && opcode == BPF_ADD &&
(dst_reg->type == PTR_TO_MAP_VALUE ||
dst_reg->type == PTR_TO_MAP_VALUE_ADJ))
dst_reg->type = PTR_TO_MAP_VALUE_ADJ;
@@ -1876,38 +1968,63 @@
struct bpf_reg_state *false_reg, u64 val,
u8 opcode)
{
+ bool value_from_signed = true;
+ bool is_range = true;
+
switch (opcode) {
case BPF_JEQ:
/* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure.
*/
true_reg->max_value = true_reg->min_value = val;
+ is_range = false;
break;
case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure;
*/
false_reg->max_value = false_reg->min_value = val;
+ is_range = false;
break;
case BPF_JGT:
- /* Unsigned comparison, the minimum value is 0. */
- false_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGT:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGT) {
+ /* Unsigned comparison, the minimum value is 0. */
+ false_reg->min_value = 0;
+ }
/* If this is false then we know the maximum val is val,
* otherwise we know the min val is val+1.
*/
false_reg->max_value = val;
+ false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val + 1;
+ true_reg->value_from_signed = value_from_signed;
break;
case BPF_JGE:
- /* Unsigned comparison, the minimum value is 0. */
- false_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGE:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGE) {
+ /* Unsigned comparison, the minimum value is 0. */
+ false_reg->min_value = 0;
+ }
/* If this is false then we know the maximum value is val - 1,
* otherwise we know the mimimum value is val.
*/
false_reg->max_value = val - 1;
+ false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val;
+ true_reg->value_from_signed = value_from_signed;
break;
default:
break;
@@ -1915,6 +2032,12 @@
check_reg_overflow(false_reg);
check_reg_overflow(true_reg);
+ if (is_range) {
+ if (__is_pointer_value(false, false_reg))
+ reset_reg_range_values(false_reg, 0);
+ if (__is_pointer_value(false, true_reg))
+ reset_reg_range_values(true_reg, 0);
+ }
}
/* Same as above, but for the case that dst_reg is a CONST_IMM reg and src_reg
@@ -1924,39 +2047,64 @@
struct bpf_reg_state *false_reg, u64 val,
u8 opcode)
{
+ bool value_from_signed = true;
+ bool is_range = true;
+
switch (opcode) {
case BPF_JEQ:
/* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure.
*/
true_reg->max_value = true_reg->min_value = val;
+ is_range = false;
break;
case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure;
*/
false_reg->max_value = false_reg->min_value = val;
+ is_range = false;
break;
case BPF_JGT:
- /* Unsigned comparison, the minimum value is 0. */
- true_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGT:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGT) {
+ /* Unsigned comparison, the minimum value is 0. */
+ true_reg->min_value = 0;
+ }
/*
* If this is false, then the val is <= the register, if it is
* true the register <= to the val.
*/
false_reg->min_value = val;
+ false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val - 1;
+ true_reg->value_from_signed = value_from_signed;
break;
case BPF_JGE:
- /* Unsigned comparison, the minimum value is 0. */
- true_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGE:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGE) {
+ /* Unsigned comparison, the minimum value is 0. */
+ true_reg->min_value = 0;
+ }
/* If this is false then constant < register, if it is true then
* the register < constant.
*/
false_reg->min_value = val + 1;
+ false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val;
+ true_reg->value_from_signed = value_from_signed;
break;
default:
break;
@@ -1964,6 +2112,12 @@
check_reg_overflow(false_reg);
check_reg_overflow(true_reg);
+ if (is_range) {
+ if (__is_pointer_value(false, false_reg))
+ reset_reg_range_values(false_reg, 0);
+ if (__is_pointer_value(false, true_reg))
+ reset_reg_range_values(true_reg, 0);
+ }
}
static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
@@ -2390,6 +2544,7 @@
env->explored_states[t + 1] = STATE_LIST_MARK;
} else {
/* conditional jump with two edges */
+ env->explored_states[t] = STATE_LIST_MARK;
ret = push_insn(t, t + 1, FALLTHROUGH, env);
if (ret == 1)
goto peek_stack;
@@ -2548,6 +2703,12 @@
rcur->type != NOT_INIT))
continue;
+ /* Don't care about the reg->id in this case. */
+ if (rold->type == PTR_TO_MAP_VALUE_OR_NULL &&
+ rcur->type == PTR_TO_MAP_VALUE_OR_NULL &&
+ rold->map_ptr == rcur->map_ptr)
+ continue;
+
if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET &&
compare_ptrs_to_packet(rold, rcur))
continue;
@@ -2682,6 +2843,9 @@
goto process_bpf_exit;
}
+ if (need_resched())
+ cond_resched();
+
if (log_level && do_print_state) {
verbose("\nfrom %d to %d:", prev_insn_idx, insn_idx);
print_verifier_state(&env->cur_state);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 7bb21fd..26c624e 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -3508,11 +3508,11 @@
cgrp->subtree_control &= ~disable;
ret = cgroup_apply_control(cgrp);
-
cgroup_finalize_control(cgrp, ret);
+ if (ret)
+ goto out_unlock;
kernfs_activate(cgrp->kn);
- ret = 0;
out_unlock:
cgroup_kn_unlock(of->kn);
return ret ?: nbytes;
@@ -5744,6 +5744,10 @@
if (ss->bind)
ss->bind(init_css_set.subsys[ssid]);
+
+ mutex_lock(&cgroup_mutex);
+ css_populate_dir(init_css_set.subsys[ssid]);
+ mutex_unlock(&cgroup_mutex);
}
/* init_css_set.subsys[] has been updated, re-hash */
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
index 80df048..7dc5b07 100644
--- a/kernel/configs/android-base.config
+++ b/kernel/configs/android-base.config
@@ -37,6 +37,7 @@
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IPV6=y
@@ -140,11 +141,6 @@
CONFIG_PPP_MPPE=y
CONFIG_PREEMPT=y
CONFIG_PROFILING=y
-CONFIG_QFMT_V2=y
-CONFIG_QUOTA=y
-CONFIG_QUOTACTL=y
-CONFIG_QUOTA_NETLINK_INTERFACE=y
-CONFIG_QUOTA_TREE=y
CONFIG_RANDOMIZE_BASE=y
CONFIG_RTC_CLASS=y
CONFIG_RT_GROUP_SCHED=y
@@ -154,7 +150,6 @@
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY_SELINUX=y
CONFIG_STAGING=y
-CONFIG_SYNC=y
CONFIG_TUN=y
CONFIG_UID_SYS_STATS=y
CONFIG_UNIX=y
diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config
index 36ec6c1..da146fa 100644
--- a/kernel/configs/android-recommended.config
+++ b/kernel/configs/android-recommended.config
@@ -107,6 +107,11 @@
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_RAM=y
+CONFIG_QFMT_V2=y
+CONFIG_QUOTA=y
+CONFIG_QUOTACTL=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QUOTA_TREE=y
CONFIG_SCHEDSTATS=y
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_SND=y
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index a99cd8d..d3a7411 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -61,6 +61,7 @@
#include <linux/cgroup.h>
#include <linux/wait.h>
+DEFINE_STATIC_KEY_FALSE(cpusets_pre_enable_key);
DEFINE_STATIC_KEY_FALSE(cpusets_enabled_key);
/* See "Frequency meter" comments, below. */
@@ -1907,6 +1908,7 @@
{
.name = "memory_pressure",
.read_u64 = cpuset_read_u64,
+ .private = FILE_MEMORY_PRESSURE,
},
{
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0d4a401..f6e81b5 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9894,28 +9894,27 @@
goto err_context;
/*
- * Do not allow to attach to a group in a different
- * task or CPU context:
+ * Make sure we're both events for the same CPU;
+ * grouping events for different CPUs is broken; since
+ * you can never concurrently schedule them anyhow.
*/
- if (move_group) {
- /*
- * Make sure we're both on the same task, or both
- * per-cpu events.
- */
- if (group_leader->ctx->task != ctx->task)
- goto err_context;
+ if (group_leader->cpu != event->cpu)
+ goto err_context;
- /*
- * Make sure we're both events for the same CPU;
- * grouping events for different CPUs is broken; since
- * you can never concurrently schedule them anyhow.
- */
- if (group_leader->cpu != event->cpu)
- goto err_context;
- } else {
- if (group_leader->ctx != ctx)
- goto err_context;
- }
+ /*
+ * Make sure we're both on the same task, or both
+ * per-CPU events.
+ */
+ if (group_leader->ctx->task != ctx->task)
+ goto err_context;
+
+ /*
+ * Do not allow to attach to a group in a different task
+ * or CPU context. If we're moving SW events, we'll fix
+ * this up later, so allow that.
+ */
+ if (!move_group && group_leader->ctx != ctx)
+ goto err_context;
/*
* Only a group leader can be exclusive or pinned
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index f9ec9ad..a1de021 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1254,8 +1254,6 @@
void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
{
- newmm->uprobes_state.xol_area = NULL;
-
if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) {
set_bit(MMF_HAS_UPROBES, &newmm->flags);
/* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */
diff --git a/kernel/fork.c b/kernel/fork.c
index 39c0709..610aded 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -745,6 +745,13 @@
#endif
}
+static void mm_init_uprobes_state(struct mm_struct *mm)
+{
+#ifdef CONFIG_UPROBES
+ mm->uprobes_state.xol_area = NULL;
+#endif
+}
+
static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
struct user_namespace *user_ns)
{
@@ -766,11 +773,13 @@
mm_init_cpumask(mm);
mm_init_aio(mm);
mm_init_owner(mm, p);
+ RCU_INIT_POINTER(mm->exe_file, NULL);
mmu_notifier_mm_init(mm);
clear_tlb_flush_pending(mm);
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
mm->pmd_huge_pte = NULL;
#endif
+ mm_init_uprobes_state(mm);
if (current->mm) {
mm->flags = current->mm->flags & MMF_INIT_MASK;
diff --git a/kernel/futex.c b/kernel/futex.c
index 4c6b6e6..88bad86 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -668,13 +668,14 @@
* this reference was taken by ihold under the page lock
* pinning the inode in place so i_lock was unnecessary. The
* only way for this check to fail is if the inode was
- * truncated in parallel so warn for now if this happens.
+ * truncated in parallel which is almost certainly an
+ * application bug. In such a case, just retry.
*
* We are not calling into get_futex_key_refs() in file-backed
* cases, therefore a successful atomic_inc return below will
* guarantee that get_futex_key() will still imply smp_mb(); (B).
*/
- if (WARN_ON_ONCE(!atomic_inc_not_zero(&inode->i_count))) {
+ if (!atomic_inc_not_zero(&inode->i_count)) {
rcu_read_unlock();
put_page(page);
diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c
index 2f9df37..c51a49c 100644
--- a/kernel/gcov/base.c
+++ b/kernel/gcov/base.c
@@ -98,6 +98,12 @@
}
EXPORT_SYMBOL(__gcov_merge_icall_topn);
+void __gcov_exit(void)
+{
+ /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_exit);
+
/**
* gcov_enable_events - enable event reporting through gcov_event()
*
diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c
index 6a5c239..46a18e7 100644
--- a/kernel/gcov/gcc_4_7.c
+++ b/kernel/gcov/gcc_4_7.c
@@ -18,7 +18,9 @@
#include <linux/vmalloc.h>
#include "gcov.h"
-#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
+#if (__GNUC__ >= 7)
+#define GCOV_COUNTERS 9
+#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
#define GCOV_COUNTERS 10
#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
#define GCOV_COUNTERS 9
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 077c87f..f30110e 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -895,13 +895,15 @@
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
- unsigned long flags;
+ unsigned long flags, trigger, tmp;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
+ trigger = irqd_get_trigger_type(&desc->irq_data);
+
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
if (irq_settings_has_no_balance_set(desc))
@@ -913,7 +915,11 @@
if (irq_settings_is_level(desc))
irqd_set(&desc->irq_data, IRQD_LEVEL);
- irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));
+ tmp = irq_settings_get_trigger_mask(desc);
+ if (tmp != IRQ_TYPE_NONE)
+ trigger = tmp;
+
+ irqd_set(&desc->irq_data, trigger);
irq_put_desc_unlock(desc, flags);
}
diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c
index 1a9abc1..259a22a 100644
--- a/kernel/irq/ipi.c
+++ b/kernel/irq/ipi.c
@@ -165,7 +165,7 @@
struct irq_data *data = irq_get_irq_data(irq);
struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL;
- if (!data || !ipimask || cpu > nr_cpu_ids)
+ if (!data || !ipimask || cpu >= nr_cpu_ids)
return INVALID_HWIRQ;
if (!cpumask_test_cpu(cpu, ipimask))
@@ -195,7 +195,7 @@
if (!chip->ipi_send_single && !chip->ipi_send_mask)
return -EINVAL;
- if (cpu > nr_cpu_ids)
+ if (cpu >= nr_cpu_ids)
return -EINVAL;
if (dest) {
diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c
index e99d860..10e6d8b 100644
--- a/kernel/locking/spinlock_debug.c
+++ b/kernel/locking/spinlock_debug.c
@@ -110,38 +110,14 @@
lock->owner_cpu = -1;
}
-static void __spin_lock_debug(raw_spinlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
-
- for (i = 0; i < loops; i++) {
- if (arch_spin_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- spin_bug(lock, "lockup suspected");
-#ifdef CONFIG_SMP
- trigger_all_cpu_backtrace();
-#endif
-
- /*
- * The trylock above was causing a livelock. Give the lower level arch
- * specific lock code a chance to acquire the lock. We have already
- * printed a warning/backtrace at this point. The non-debug arch
- * specific code might actually succeed in acquiring the lock. If it is
- * not successful, the end-result is the same - there is no forward
- * progress.
- */
- arch_spin_lock(&lock->raw_lock);
-}
-
+/*
+ * We are now relying on the NMI watchdog to detect lockup instead of doing
+ * the detection here with an unfair lock which can cause problem of its own.
+ */
void do_raw_spin_lock(raw_spinlock_t *lock)
{
debug_spin_lock_before(lock);
- if (unlikely(!arch_spin_trylock(&lock->raw_lock)))
- __spin_lock_debug(lock);
+ arch_spin_lock(&lock->raw_lock);
debug_spin_lock_after(lock);
}
@@ -179,32 +155,6 @@
#define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
-#if 0 /* __write_lock_debug() can lock up - maybe this can too? */
-static void __read_lock_debug(rwlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
- int print_once = 1;
-
- for (;;) {
- for (i = 0; i < loops; i++) {
- if (arch_read_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- if (print_once) {
- print_once = 0;
- printk(KERN_EMERG "BUG: read-lock lockup on CPU#%d, "
- "%s/%d, %p\n",
- raw_smp_processor_id(), current->comm,
- current->pid, lock);
- dump_stack();
- }
- }
-}
-#endif
-
void do_raw_read_lock(rwlock_t *lock)
{
RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
@@ -254,32 +204,6 @@
lock->owner_cpu = -1;
}
-#if 0 /* This can cause lockups */
-static void __write_lock_debug(rwlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
- int print_once = 1;
-
- for (;;) {
- for (i = 0; i < loops; i++) {
- if (arch_write_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- if (print_once) {
- print_once = 0;
- printk(KERN_EMERG "BUG: write-lock lockup on CPU#%d, "
- "%s/%d, %p\n",
- raw_smp_processor_id(), current->comm,
- current->pid, lock);
- dump_stack();
- }
- }
-}
-#endif
-
void do_raw_write_lock(rwlock_t *lock)
{
debug_write_lock_before(lock);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ccfb9bf..352cfca 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -9620,4 +9620,4 @@
}
#endif /* CONFIG_SCHED_WALT */
-__read_mostly bool sched_predl;
+__read_mostly bool sched_predl = 1;
diff --git a/kernel/signal.c b/kernel/signal.c
index deb04d5..e48668c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -346,7 +346,7 @@
* fresh group stop. Read comment in do_signal_stop() for details.
*/
if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
- sig->flags = SIGNAL_STOP_STOPPED;
+ signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
return true;
}
return false;
@@ -845,7 +845,7 @@
* will take ->siglock, notice SIGNAL_CLD_MASK, and
* notify its parent. See get_signal_to_deliver().
*/
- signal->flags = why | SIGNAL_STOP_CONTINUED;
+ signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
signal->group_stop_count = 0;
signal->group_exit_code = 0;
}
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 843fb50..80aa30d 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1557,7 +1557,7 @@
base->is_idle = false;
} else {
if (!is_max_delta)
- expires = basem + (nextevt - basej) * TICK_NSEC;
+ expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
/*
* If we expect to sleep more than a tick, mark the base idle.
* Also the tick is stopped so any added timer must forward
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5dcb992..41805fb 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -203,10 +203,36 @@
fmt_cnt++;
}
- return __trace_printk(1/* fake ip will not be printed */, fmt,
- mod[0] == 2 ? arg1 : mod[0] == 1 ? (long) arg1 : (u32) arg1,
- mod[1] == 2 ? arg2 : mod[1] == 1 ? (long) arg2 : (u32) arg2,
- mod[2] == 2 ? arg3 : mod[2] == 1 ? (long) arg3 : (u32) arg3);
+/* Horrid workaround for getting va_list handling working with different
+ * argument type combinations generically for 32 and 64 bit archs.
+ */
+#define __BPF_TP_EMIT() __BPF_ARG3_TP()
+#define __BPF_TP(...) \
+ __trace_printk(1 /* Fake ip will not be printed. */, \
+ fmt, ##__VA_ARGS__)
+
+#define __BPF_ARG1_TP(...) \
+ ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_TP(arg1, ##__VA_ARGS__) \
+ : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_TP((long)arg1, ##__VA_ARGS__) \
+ : __BPF_TP((u32)arg1, ##__VA_ARGS__)))
+
+#define __BPF_ARG2_TP(...) \
+ ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG1_TP(arg2, ##__VA_ARGS__) \
+ : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG1_TP((long)arg2, ##__VA_ARGS__) \
+ : __BPF_ARG1_TP((u32)arg2, ##__VA_ARGS__)))
+
+#define __BPF_ARG3_TP(...) \
+ ((mod[2] == 2 || (mod[2] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG2_TP(arg3, ##__VA_ARGS__) \
+ : ((mod[2] == 1 || (mod[2] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG2_TP((long)arg3, ##__VA_ARGS__) \
+ : __BPF_ARG2_TP((u32)arg3, ##__VA_ARGS__)))
+
+ return __BPF_TP_EMIT();
}
static const struct bpf_func_proto bpf_trace_printk_proto = {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4f7ea84..6e432ed 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -876,6 +876,10 @@
function_profile_call(trace->func, 0, NULL, NULL);
+ /* If function graph is shutting down, ret_stack can be NULL */
+ if (!current->ret_stack)
+ return 0;
+
if (index >= 0 && index < FTRACE_RETFUNC_DEPTH)
current->ret_stack[index].subtime = 0;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 66b0714..cddedb5 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -7926,4 +7926,4 @@
}
fs_initcall(tracer_init_tracefs);
-late_initcall(clear_boot_tracer);
+late_initcall_sync(clear_boot_tracer);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 9daa9b3..0193f58 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1926,6 +1926,10 @@
if (err && set_str)
append_filter_err(ps, filter);
}
+ if (err && !set_str) {
+ free_event_filter(filter);
+ filter = NULL;
+ }
create_filter_finish(ps);
*filterp = filter;
diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c
index 0a689bb..305039b 100644
--- a/kernel/trace/tracing_map.c
+++ b/kernel/trace/tracing_map.c
@@ -221,16 +221,19 @@
if (!a)
return;
- if (!a->pages) {
- kfree(a);
- return;
- }
+ if (!a->pages)
+ goto free;
for (i = 0; i < a->n_pages; i++) {
if (!a->pages[i])
break;
free_page((unsigned long)a->pages[i]);
}
+
+ kfree(a->pages);
+
+ free:
+ kfree(a);
}
struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 812b8f8..0e5e54f 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3737,8 +3737,12 @@
return -EINVAL;
/* creating multiple pwqs breaks ordering guarantee */
- if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
- return -EINVAL;
+ if (!list_empty(&wq->pwqs)) {
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+ return -EINVAL;
+
+ wq->flags &= ~__WQ_ORDERED;
+ }
ctx = apply_wqattrs_prepare(wq, attrs);
if (!ctx)
@@ -3922,6 +3926,16 @@
struct workqueue_struct *wq;
struct pool_workqueue *pwq;
+ /*
+ * Unbound && max_active == 1 used to imply ordered, which is no
+ * longer the case on NUMA machines due to per-node pools. While
+ * alloc_ordered_workqueue() is the right way to create an ordered
+ * workqueue, keep the previous behavior to avoid subtle breakages
+ * on NUMA.
+ */
+ if ((flags & WQ_UNBOUND) && max_active == 1)
+ flags |= __WQ_ORDERED;
+
/* see the comment above the definition of WQ_POWER_EFFICIENT */
if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
flags |= WQ_UNBOUND;
@@ -4110,13 +4124,14 @@
struct pool_workqueue *pwq;
/* disallow meddling with max_active for ordered workqueues */
- if (WARN_ON(wq->flags & __WQ_ORDERED))
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
return;
max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
mutex_lock(&wq->mutex);
+ wq->flags &= ~__WQ_ORDERED;
wq->saved_max_active = max_active;
for_each_pwq(pwq, wq)
@@ -5221,7 +5236,7 @@
* attributes breaks ordering guarantee. Disallow exposing ordered
* workqueues.
*/
- if (WARN_ON(wq->flags & __WQ_ORDERED))
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
return -EINVAL;
wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 411b383..2812580 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -145,7 +145,7 @@
config DEBUG_INFO_SPLIT
bool "Produce split debuginfo in .dwo files"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && !FRV
help
Generate debug info into separate .dwo files. This significantly
reduces the build directory size for builds with DEBUG_INFO,
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c
index f344f76..6b2e046 100644
--- a/lib/lz4/lz4hc_compress.c
+++ b/lib/lz4/lz4hc_compress.c
@@ -131,7 +131,7 @@
#endif
int nbattempts = MAX_NB_ATTEMPTS;
size_t repl = 0, ml = 0;
- u16 delta;
+ u16 delta = 0;
/* HC4 match finder */
lz4hc_insert(hc4, ip);
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
index 5a0f75a..eead4b3 100644
--- a/lib/mpi/mpicoder.c
+++ b/lib/mpi/mpicoder.c
@@ -364,11 +364,11 @@
}
miter.consumed = lzeros;
- sg_miter_stop(&miter);
nbytes -= lzeros;
nbits = nbytes * 8;
if (nbits > MAX_EXTERN_MPI_BITS) {
+ sg_miter_stop(&miter);
pr_info("MPI: mpi too large (%u bits)\n", nbits);
return NULL;
}
@@ -376,6 +376,8 @@
if (nbytes > 0)
nbits -= count_leading_zeros(*buff) - (BITS_PER_LONG - 8);
+ sg_miter_stop(&miter);
+
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
val = mpi_alloc(nlimbs);
if (!val)
diff --git a/mm/internal.h b/mm/internal.h
index df6319f..0ee4f54 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -477,6 +477,7 @@
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
void try_to_unmap_flush(void);
void try_to_unmap_flush_dirty(void);
+void flush_tlb_batched_pending(struct mm_struct *mm);
#else
static inline void try_to_unmap_flush(void)
{
@@ -484,7 +485,9 @@
static inline void try_to_unmap_flush_dirty(void)
{
}
-
+static inline void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+}
#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
extern const struct trace_print_flags pageflag_names[];
diff --git a/mm/madvise.c b/mm/madvise.c
index 279627a..088a5b22 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -21,6 +21,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/mmu_notifier.h>
+#include "internal.h"
#include <asm/tlb.h>
@@ -282,6 +283,7 @@
return 0;
orig_pte = pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ flush_tlb_batched_pending(mm);
arch_enter_lazy_mmu_mode();
for (; addr != end; pte++, addr += PAGE_SIZE) {
ptent = *pte;
@@ -329,8 +331,8 @@
pte_offset_map_lock(mm, pmd, addr, &ptl);
goto out;
}
- put_page(page);
unlock_page(page);
+ put_page(page);
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
pte--;
addr -= PAGE_SIZE;
@@ -531,6 +533,8 @@
static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
{
struct page *p;
+ struct zone *zone;
+
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
for (; start < end; start += PAGE_SIZE <<
@@ -559,6 +563,11 @@
if (ret)
return ret;
}
+
+ /* Ensure that all poisoned pages are removed from per-cpu lists */
+ for_each_populated_zone(zone)
+ drain_all_pages(zone);
+
return 0;
}
#endif
diff --git a/mm/memblock.c b/mm/memblock.c
index f1eabcc..3b7d23c 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -301,31 +301,27 @@
}
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
-
-phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
- phys_addr_t *addr)
+/**
+ * Discard memory and reserved arrays if they were allocated
+ */
+void __init memblock_discard(void)
{
- if (memblock.reserved.regions == memblock_reserved_init_regions)
- return 0;
+ phys_addr_t addr, size;
- *addr = __pa(memblock.reserved.regions);
+ if (memblock.reserved.regions != memblock_reserved_init_regions) {
+ addr = __pa(memblock.reserved.regions);
+ size = PAGE_ALIGN(sizeof(struct memblock_region) *
+ memblock.reserved.max);
+ __memblock_free_late(addr, size);
+ }
- return PAGE_ALIGN(sizeof(struct memblock_region) *
- memblock.reserved.max);
+ if (memblock.memory.regions != memblock_memory_init_regions) {
+ addr = __pa(memblock.memory.regions);
+ size = PAGE_ALIGN(sizeof(struct memblock_region) *
+ memblock.memory.max);
+ __memblock_free_late(addr, size);
+ }
}
-
-phys_addr_t __init_memblock get_allocated_memblock_memory_regions_info(
- phys_addr_t *addr)
-{
- if (memblock.memory.regions == memblock_memory_init_regions)
- return 0;
-
- *addr = __pa(memblock.memory.regions);
-
- return PAGE_ALIGN(sizeof(struct memblock_region) *
- memblock.memory.max);
-}
-
#endif
/**
diff --git a/mm/memory.c b/mm/memory.c
index 49d9b42..b5e0ed3 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1124,6 +1124,7 @@
init_rss_vec(rss);
start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
pte = start_pte;
+ flush_tlb_batched_pending(mm);
arch_enter_lazy_mmu_mode();
do {
pte_t ptent = *pte;
@@ -3634,8 +3635,18 @@
* further.
*/
if (unlikely((current->flags & PF_KTHREAD) && !(ret & VM_FAULT_ERROR)
- && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags)))
+ && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags))) {
+
+ /*
+ * We are going to enforce SIGBUS but the PF path might have
+ * dropped the mmap_sem already so take it again so that
+ * we do not break expectations of all arch specific PF paths
+ * and g-u-p
+ */
+ if (ret & VM_FAULT_RETRY)
+ down_read(&vma->vm_mm->mmap_sem);
ret = VM_FAULT_SIGBUS;
+ }
return ret;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 9ff5657..9547583 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -927,11 +927,6 @@
*policy |= (pol->flags & MPOL_MODE_FLAGS);
}
- if (vma) {
- up_read(¤t->mm->mmap_sem);
- vma = NULL;
- }
-
err = 0;
if (nmask) {
if (mpol_store_user_nodemask(pol)) {
diff --git a/mm/migrate.c b/mm/migrate.c
index 4213d27..eb1f043 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -40,6 +40,7 @@
#include <linux/mmu_notifier.h>
#include <linux/page_idle.h>
#include <linux/page_owner.h>
+#include <linux/ptrace.h>
#include <asm/tlbflush.h>
@@ -1665,7 +1666,6 @@
const int __user *, nodes,
int __user *, status, int, flags)
{
- const struct cred *cred = current_cred(), *tcred;
struct task_struct *task;
struct mm_struct *mm;
int err;
@@ -1689,14 +1689,9 @@
/*
* Check if this process has the right to modify the specified
- * process. The right exists if the process has administrative
- * capabilities, superuser privileges or the same
- * userid as the target process.
+ * process. Use the regular "ptrace_may_access()" checks.
*/
- tcred = __task_cred(task);
- if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
- !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) &&
- !capable(CAP_SYS_NICE)) {
+ if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
rcu_read_unlock();
err = -EPERM;
goto out;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 2c40836..1f2c969 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -74,6 +74,7 @@
if (!pte)
return 0;
+ flush_tlb_batched_pending(vma->vm_mm);
arch_enter_lazy_mmu_mode();
do {
oldpte = *pte;
diff --git a/mm/mremap.c b/mm/mremap.c
index 30d7d24..1597671 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -142,6 +142,7 @@
new_ptl = pte_lockptr(mm, new_pmd);
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+ flush_tlb_batched_pending(vma->vm_mm);
arch_enter_lazy_mmu_mode();
for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index e1e8c63..aa59572 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -146,22 +146,6 @@
NULL)
count += __free_memory_core(start, end);
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
- {
- phys_addr_t size;
-
- /* Free memblock.reserved array if it was allocated */
- size = get_allocated_memblock_reserved_regions_info(&start);
- if (size)
- count += __free_memory_core(start, start + size);
-
- /* Free memblock.memory array if it was allocated */
- size = get_allocated_memblock_memory_regions_info(&start);
- if (size)
- count += __free_memory_core(start, start + size);
- }
-#endif
-
return count;
}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 3a22b14..af783a6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -608,18 +608,23 @@
return 0;
}
-static void wake_oom_reaper(struct task_struct *tsk)
+void wake_oom_reaper(struct task_struct *tsk)
{
if (!oom_reaper_th)
return;
+ /* move the lock here to avoid scenario of queuing
+ * the same task by both OOM killer and LMK.
+ */
+ spin_lock(&oom_reaper_lock);
/* tsk is already queued? */
- if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+ if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+ spin_unlock(&oom_reaper_lock);
return;
+ }
get_task_struct(tsk);
- spin_lock(&oom_reaper_lock);
tsk->oom_reaper_list = oom_reaper_list;
oom_reaper_list = tsk;
spin_unlock(&oom_reaper_lock);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3eb5f68..acf411c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1579,6 +1579,10 @@
/* Reinit limits that are based on free pages after the kernel is up */
files_maxfiles_init();
#endif
+#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+ /* Discard memblock private memory */
+ memblock_discard();
+#endif
for_each_populated_zone(zone)
set_zone_contiguous(zone);
@@ -1865,14 +1869,14 @@
#endif
for (page = start_page; page <= end_page;) {
- /* Make sure we are not inadvertently changing nodes */
- VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
if (!pfn_valid_within(page_to_pfn(page))) {
page++;
continue;
}
+ /* Make sure we are not inadvertently changing nodes */
+ VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+
if (!PageBuddy(page)) {
page++;
continue;
@@ -6525,8 +6529,8 @@
}
if (pages && s)
- pr_info("Freeing %s memory: %ldK (%p - %p)\n",
- s, pages << (PAGE_SHIFT - 10), start, end);
+ pr_info("Freeing %s memory: %ldK\n",
+ s, pages << (PAGE_SHIFT - 10));
return pages;
}
@@ -7416,7 +7420,7 @@
/* Make sure the range is really isolated. */
if (test_pages_isolated(outer_start, end, false)) {
- pr_info("%s: [%lx, %lx) PFNs busy\n",
+ pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
__func__, outer_start, end);
ret = -EBUSY;
goto done;
diff --git a/mm/rmap.c b/mm/rmap.c
index dfb19f0..4d19dd1 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -617,6 +617,13 @@
tlb_ubc->flush_required = true;
/*
+ * Ensure compiler does not re-order the setting of tlb_flush_batched
+ * before the PTE is cleared.
+ */
+ barrier();
+ mm->tlb_flush_batched = true;
+
+ /*
* If the PTE was dirty then it's best to assume it's writable. The
* caller must use try_to_unmap_flush_dirty() or try_to_unmap_flush()
* before the page is queued for IO.
@@ -643,6 +650,35 @@
return should_defer;
}
+
+/*
+ * Reclaim unmaps pages under the PTL but do not flush the TLB prior to
+ * releasing the PTL if TLB flushes are batched. It's possible for a parallel
+ * operation such as mprotect or munmap to race between reclaim unmapping
+ * the page and flushing the page. If this race occurs, it potentially allows
+ * access to data via a stale TLB entry. Tracking all mm's that have TLB
+ * batching in flight would be expensive during reclaim so instead track
+ * whether TLB batching occurred in the past and if so then do a flush here
+ * if required. This will cost one additional flush per reclaim cycle paid
+ * by the first operation at risk such as mprotect and mumap.
+ *
+ * This must be called under the PTL so that an access to tlb_flush_batched
+ * that is potentially a "reclaim vs mprotect/munmap/etc" race will synchronise
+ * via the PTL.
+ */
+void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+ if (mm->tlb_flush_batched) {
+ flush_tlb_mm(mm);
+
+ /*
+ * Do not allow the compiler to re-order the clearing of
+ * tlb_flush_batched before the tlb is flushed.
+ */
+ barrier();
+ mm->tlb_flush_batched = false;
+ }
+}
#else
static void set_tlb_ubc_flush_pending(struct mm_struct *mm,
struct page *page, bool writable)
diff --git a/mm/shmem.c b/mm/shmem.c
index 142887f..7a74b6d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1007,7 +1007,11 @@
*/
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) {
spin_lock(&sbinfo->shrinklist_lock);
- if (list_empty(&info->shrinklist)) {
+ /*
+ * _careful to defend against unlocked access to
+ * ->shrink_list in shmem_unused_huge_shrink()
+ */
+ if (list_empty_careful(&info->shrinklist)) {
list_add_tail(&info->shrinklist,
&sbinfo->shrinklist);
sbinfo->shrinklist_len++;
@@ -1774,7 +1778,11 @@
* to shrink under memory pressure.
*/
spin_lock(&sbinfo->shrinklist_lock);
- if (list_empty(&info->shrinklist)) {
+ /*
+ * _careful to defend against unlocked access to
+ * ->shrink_list in shmem_unused_huge_shrink()
+ */
+ if (list_empty_careful(&info->shrinklist)) {
list_add_tail(&info->shrinklist,
&sbinfo->shrinklist);
sbinfo->shrinklist_len++;
@@ -3802,7 +3810,7 @@
}
#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
- if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY)
+ if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)
SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
else
shmem_huge = 0; /* just in case it was patched */
@@ -3863,7 +3871,7 @@
return -EINVAL;
shmem_huge = huge;
- if (shmem_huge < SHMEM_HUGE_DENY)
+ if (shmem_huge > SHMEM_HUGE_DENY)
SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
return count;
}
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index fbf251f..4d6b94d 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,16 +484,16 @@
struct net_device *dev = s->dev;
struct sock *sk = s->sock->sk;
struct sk_buff *skb;
- wait_queue_t wait;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
BT_DBG("");
set_user_nice(current, -15);
- init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&s->terminate))
break;
@@ -515,9 +515,8 @@
break;
netif_wake_queue(dev);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
/* Cleanup session */
@@ -666,7 +665,7 @@
s = __bnep_get_session(req->dst);
if (s) {
atomic_inc(&s->terminate);
- wake_up_process(s->task);
+ wake_up_interruptible(sk_sleep(s->sock->sk));
} else
err = -ENOENT;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 9e59b66..1152ce3 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -280,16 +280,16 @@
struct cmtp_session *session = arg;
struct sock *sk = session->sock->sk;
struct sk_buff *skb;
- wait_queue_t wait;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
BT_DBG("session %p", session);
set_user_nice(current, -15);
- init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&session->terminate))
break;
@@ -306,9 +306,8 @@
cmtp_process_transmit(session);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
down_write(&cmtp_session_sem);
@@ -393,7 +392,7 @@
err = cmtp_attach_device(session);
if (err < 0) {
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+ wake_up_interruptible(sk_sleep(session->sock->sk));
up_write(&cmtp_session_sem);
return err;
}
@@ -431,7 +430,11 @@
/* Stop session thread */
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+
+ /* Ensure session->terminate is updated */
+ smp_mb__after_atomic();
+
+ wake_up_interruptible(sk_sleep(session->sock->sk));
} else
err = -ENOENT;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 0bec458..1fc0764 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -36,6 +36,7 @@
#define VERSION "1.2"
static DECLARE_RWSEM(hidp_session_sem);
+static DECLARE_WAIT_QUEUE_HEAD(hidp_session_wq);
static LIST_HEAD(hidp_session_list);
static unsigned char hidp_keycode[256] = {
@@ -1068,12 +1069,12 @@
* Wake up session thread and notify it to stop. This is asynchronous and
* returns immediately. Call this whenever a runtime error occurs and you want
* the session to stop.
- * Note: wake_up_process() performs any necessary memory-barriers for us.
+ * Note: wake_up_interruptible() performs any necessary memory-barriers for us.
*/
static void hidp_session_terminate(struct hidp_session *session)
{
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+ wake_up_interruptible(&hidp_session_wq);
}
/*
@@ -1180,7 +1181,9 @@
struct sock *ctrl_sk = session->ctrl_sock->sk;
struct sock *intr_sk = session->intr_sock->sk;
struct sk_buff *skb;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ add_wait_queue(&hidp_session_wq, &wait);
for (;;) {
/*
* This thread can be woken up two ways:
@@ -1188,12 +1191,10 @@
* session->terminate flag and wakes this thread up.
* - Via modifying the socket state of ctrl/intr_sock. This
* thread is woken up by ->sk_state_changed().
- *
- * Note: set_current_state() performs any necessary
- * memory-barriers for us.
*/
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&session->terminate))
break;
@@ -1227,11 +1228,22 @@
hidp_process_transmit(session, &session->ctrl_transmit,
session->ctrl_sock);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
+ remove_wait_queue(&hidp_session_wq, &wait);
atomic_inc(&session->terminate);
- set_current_state(TASK_RUNNING);
+
+ /* Ensure session->terminate is updated */
+ smp_mb__after_atomic();
+}
+
+static int hidp_session_wake_function(wait_queue_t *wait,
+ unsigned int mode,
+ int sync, void *key)
+{
+ wake_up_interruptible(&hidp_session_wq);
+ return false;
}
/*
@@ -1244,7 +1256,8 @@
static int hidp_session_thread(void *arg)
{
struct hidp_session *session = arg;
- wait_queue_t ctrl_wait, intr_wait;
+ DEFINE_WAIT_FUNC(ctrl_wait, hidp_session_wake_function);
+ DEFINE_WAIT_FUNC(intr_wait, hidp_session_wake_function);
BT_DBG("session %p", session);
@@ -1254,8 +1267,6 @@
set_user_nice(current, -15);
hidp_set_timer(session);
- init_waitqueue_entry(&ctrl_wait, current);
- init_waitqueue_entry(&intr_wait, current);
add_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait);
add_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
/* This memory barrier is paired with wq_has_sleeper(). See
diff --git a/net/core/dev.c b/net/core/dev.c
index 610e5f8..33cbbe6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2705,7 +2705,7 @@
{
if (tx_path)
return skb->ip_summed != CHECKSUM_PARTIAL &&
- skb->ip_summed != CHECKSUM_NONE;
+ skb->ip_summed != CHECKSUM_UNNECESSARY;
return skb->ip_summed == CHECKSUM_NONE;
}
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index b94b1d2..151e047 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -28,6 +28,7 @@
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
return -EFAULT;
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
if (error)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 9c6fd7f..4d26297 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1965,7 +1965,8 @@
struct sockaddr *sa;
int len;
- len = sizeof(sa_family_t) + dev->addr_len;
+ len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
+ sizeof(*sa));
sa = kmalloc(len, GFP_KERNEL);
if (!sa) {
err = -ENOMEM;
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 1704948..f227f00 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1471,9 +1471,12 @@
* singleton values (which always leads to failure).
* These settings can still (later) be overridden via sockopts.
*/
- if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
- ccid_get_builtin_ccids(&rx.val, &rx.len))
+ if (ccid_get_builtin_ccids(&tx.val, &tx.len))
return -ENOBUFS;
+ if (ccid_get_builtin_ccids(&rx.val, &rx.len)) {
+ kfree(tx.val);
+ return -ENOBUFS;
+ }
if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
!dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 86b0933..8fc1600 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -637,6 +637,7 @@
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+ reqsk_put(req);
return 0;
drop_and_free:
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 2ac9d2a..28e8252 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -380,6 +380,7 @@
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+ reqsk_put(req);
return 0;
drop_and_free:
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 9fe25bf..b68168f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -24,6 +24,7 @@
#include <net/checksum.h>
#include <net/inet_sock.h>
+#include <net/inet_common.h>
#include <net/sock.h>
#include <net/xfrm.h>
@@ -170,6 +171,15 @@
EXPORT_SYMBOL_GPL(dccp_packet_name);
+static void dccp_sk_destruct(struct sock *sk)
+{
+ struct dccp_sock *dp = dccp_sk(sk);
+
+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+ dp->dccps_hc_tx_ccid = NULL;
+ inet_sock_destruct(sk);
+}
+
int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -179,6 +189,7 @@
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
sk->sk_state = DCCP_CLOSED;
sk->sk_write_space = dccp_write_space;
+ sk->sk_destruct = dccp_sk_destruct;
icsk->icsk_sync_mss = dccp_sync_mss;
dp->dccps_mss_cache = 536;
dp->dccps_rate_last = jiffies;
@@ -201,10 +212,7 @@
{
struct dccp_sock *dp = dccp_sk(sk);
- /*
- * DCCP doesn't use sk_write_queue, just sk_send_head
- * for retransmissions
- */
+ __skb_queue_purge(&sk->sk_write_queue);
if (sk->sk_send_head != NULL) {
kfree_skb(sk->sk_send_head);
sk->sk_send_head = NULL;
@@ -222,8 +230,7 @@
dp->dccps_hc_rx_ackvec = NULL;
}
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
- ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
- dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+ dp->dccps_hc_rx_ccid = NULL;
/* clean up feature negotiation state */
dccp_feat_list_purge(&dp->dccps_featneg);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index ceddf42..2b887c5 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1714,6 +1714,13 @@
net->ipv4.sysctl_ip_dynaddr = 0;
net->ipv4.sysctl_ip_early_demux = 1;
+ /* Some igmp sysctl, whose values are always used */
+ net->ipv4.sysctl_igmp_max_memberships = 20;
+ net->ipv4.sysctl_igmp_max_msf = 10;
+ /* IGMP reports for link-local multicast groups are enabled by default */
+ net->ipv4.sysctl_igmp_llm_reports = 1;
+ net->ipv4.sysctl_igmp_qrv = 2;
+
return 0;
}
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 37f4578..c8409ca0 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1320,13 +1320,14 @@
void __init ip_fib_init(void)
{
- rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
- rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
- rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
+ fib_trie_init();
register_pernet_subsys(&fib_net_ops);
+
register_netdevice_notifier(&fib_netdev_notifier);
register_inetaddr_notifier(&fib_inetaddr_notifier);
- fib_trie_init();
+ rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
+ rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
+ rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
}
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 7563831..38c1c97 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1044,15 +1044,17 @@
fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
if (!fi)
goto failure;
- fib_info_cnt++;
if (cfg->fc_mx) {
fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL);
- if (!fi->fib_metrics)
- goto failure;
+ if (unlikely(!fi->fib_metrics)) {
+ kfree(fi);
+ return ERR_PTR(err);
+ }
atomic_set(&fi->fib_metrics->refcnt, 1);
- } else
+ } else {
fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
-
+ }
+ fib_info_cnt++;
fi->fib_net = net;
fi->fib_protocol = cfg->fc_protocol;
fi->fib_scope = cfg->fc_scope;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 19930da..08575e3 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2974,12 +2974,6 @@
goto out_sock;
}
- /* Sysctl initialization */
- net->ipv4.sysctl_igmp_max_memberships = 20;
- net->ipv4.sysctl_igmp_max_msf = 10;
- /* IGMP reports for link-local multicast groups are enabled by default */
- net->ipv4.sysctl_igmp_llm_reports = 1;
- net->ipv4.sysctl_igmp_qrv = 2;
return 0;
out_sock:
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2c18bcf..e60f9fa 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -958,10 +958,12 @@
csummode = CHECKSUM_PARTIAL;
cork->length += length;
- if (((length > mtu) || (skb && skb_is_gso(skb))) &&
+ if ((skb && skb_is_gso(skb)) ||
+ ((length > mtu) &&
+ (skb_queue_len(queue) <= 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
- (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) {
+ (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx)) {
err = ip_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, transhdrlen,
maxfraglen, flags);
@@ -1277,6 +1279,7 @@
return -EINVAL;
if ((size + skb->len > mtu) &&
+ (skb_queue_len(&sk->sk_write_queue) == 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO)) {
if (skb->ip_summed != CHECKSUM_PARTIAL)
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
index fd82202..146d861 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -126,6 +126,8 @@
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb));
+ nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
+
skb_reserve(nskb, LL_MAX_HEADER);
niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
ip4_dst_hoplimit(skb_dst(nskb)));
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 18c6e79..a4faf30 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1253,7 +1253,7 @@
if (mtu)
return mtu;
- mtu = dst->dev->mtu;
+ mtu = READ_ONCE(dst->dev->mtu);
if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
if (rt->rt_uses_gateway && mtu > 576)
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 0dc6286..f56a668 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -334,6 +334,7 @@
treq = tcp_rsk(req);
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->txhash = net_tx_rndhash();
req->mss = mss;
ireq->ir_num = ntohs(th->dest);
ireq->ir_rmt_port = th->source;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 51ac77e..ccc484a 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1010,7 +1010,7 @@
.data = &init_net.ipv4.sysctl_tcp_notsent_lowat,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_douintvec,
},
#ifdef CONFIG_IP_ROUTE_MULTIPATH
{
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 0ea66c2..cb8db34 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -83,7 +83,8 @@
cwnd_gain:10, /* current gain for setting cwnd */
full_bw_cnt:3, /* number of rounds without large bw gains */
cycle_idx:3, /* current index in pacing_gain cycle array */
- unused_b:6;
+ has_seen_rtt:1, /* have we seen an RTT sample yet? */
+ unused_b:5;
u32 prior_cwnd; /* prior cwnd upon entering loss recovery */
u32 full_bw; /* recent bw, to estimate if pipe is full */
};
@@ -182,6 +183,35 @@
return rate >> BW_SCALE;
}
+/* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */
+static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain)
+{
+ u64 rate = bw;
+
+ rate = bbr_rate_bytes_per_sec(sk, rate, gain);
+ rate = min_t(u64, rate, sk->sk_max_pacing_rate);
+ return rate;
+}
+
+/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
+static void bbr_init_pacing_rate_from_rtt(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct bbr *bbr = inet_csk_ca(sk);
+ u64 bw;
+ u32 rtt_us;
+
+ if (tp->srtt_us) { /* any RTT sample yet? */
+ rtt_us = max(tp->srtt_us >> 3, 1U);
+ bbr->has_seen_rtt = 1;
+ } else { /* no RTT sample yet */
+ rtt_us = USEC_PER_MSEC; /* use nominal default RTT */
+ }
+ bw = (u64)tp->snd_cwnd * BW_UNIT;
+ do_div(bw, rtt_us);
+ sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain);
+}
+
/* Pace using current bw estimate and a gain factor. In order to help drive the
* network toward lower queues while maintaining high utilization and low
* latency, the average pacing rate aims to be slightly (~1%) lower than the
@@ -191,12 +221,13 @@
*/
static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)
{
+ struct tcp_sock *tp = tcp_sk(sk);
struct bbr *bbr = inet_csk_ca(sk);
- u64 rate = bw;
+ u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain);
- rate = bbr_rate_bytes_per_sec(sk, rate, gain);
- rate = min_t(u64, rate, sk->sk_max_pacing_rate);
- if (bbr->mode != BBR_STARTUP || rate > sk->sk_pacing_rate)
+ if (unlikely(!bbr->has_seen_rtt && tp->srtt_us))
+ bbr_init_pacing_rate_from_rtt(sk);
+ if (bbr_full_bw_reached(sk) || rate > sk->sk_pacing_rate)
sk->sk_pacing_rate = rate;
}
@@ -769,7 +800,6 @@
{
struct tcp_sock *tp = tcp_sk(sk);
struct bbr *bbr = inet_csk_ca(sk);
- u64 bw;
bbr->prior_cwnd = 0;
bbr->tso_segs_goal = 0; /* default segs per skb until first ACK */
@@ -785,11 +815,8 @@
minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */
- /* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
- bw = (u64)tp->snd_cwnd * BW_UNIT;
- do_div(bw, (tp->srtt_us >> 3) ? : USEC_PER_MSEC);
- sk->sk_pacing_rate = 0; /* force an update of sk_pacing_rate */
- bbr_set_pacing_rate(sk, bw, bbr_high_gain);
+ bbr->has_seen_rtt = 0;
+ bbr_init_pacing_rate_from_rtt(sk);
bbr->restore_cwnd = 0;
bbr->round_start = 0;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3d980d6..491b03a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2561,8 +2561,8 @@
return;
/* Reset cwnd to ssthresh in CWR or Recovery (unless it's undone) */
- if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR ||
- (tp->undo_marker && tp->snd_ssthresh < TCP_INFINITE_SSTHRESH)) {
+ if (tp->snd_ssthresh < TCP_INFINITE_SSTHRESH &&
+ (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || tp->undo_marker)) {
tp->snd_cwnd = tp->snd_ssthresh;
tp->snd_cwnd_stamp = tcp_time_stamp;
}
@@ -3037,8 +3037,7 @@
/* delta may not be positive if the socket is locked
* when the retrans timer fires and is rescheduled.
*/
- if (delta > 0)
- rto = delta;
+ rto = max(delta, 1);
}
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
TCP_RTO_MAX);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e6bf011..a835716 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3344,6 +3344,9 @@
struct sk_buff *buff;
int err;
+ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
+ return -EHOSTUNREACH; /* Routing failure or similar. */
+
tcp_connect_init(sk);
if (unlikely(tp->repair)) {
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 732060d..d3d3ef6 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -686,7 +686,8 @@
goto death;
}
- if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE)
+ if (!sock_flag(sk, SOCK_KEEPOPEN) ||
+ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)))
goto out;
elapsed = keepalive_time_when(tp);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fe24424..7c1f5f6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -818,7 +818,7 @@
if (is_udplite) /* UDP-Lite */
csum = udplite_csum(skb);
- else if (sk->sk_no_check_tx) { /* UDP csum disabled */
+ else if (sk->sk_no_check_tx && !skb_is_gso(skb)) { /* UDP csum off */
skb->ip_summed = CHECKSUM_NONE;
goto send;
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index b2be1d9..6de016f 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -232,7 +232,7 @@
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
/* If there is no outer header we can fake a checksum offload
* due to the fact that we have already done the checksum in
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 4345ee3..ff38959 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -897,6 +897,8 @@
}
nsiblings = iter->rt6i_nsiblings;
fib6_purge_rt(iter, fn, info->nl_net);
+ if (fn->rr_ptr == iter)
+ fn->rr_ptr = NULL;
rt6_release(iter);
if (nsiblings) {
@@ -909,6 +911,8 @@
if (rt6_qualify_for_ecmp(iter)) {
*ins = iter->dst.rt6_next;
fib6_purge_rt(iter, fn, info->nl_net);
+ if (fn->rr_ptr == iter)
+ fn->rr_ptr = NULL;
rt6_release(iter);
nsiblings--;
} else {
@@ -997,7 +1001,7 @@
/* Create subtree root node */
sfn = node_alloc();
if (!sfn)
- goto st_failure;
+ goto failure;
sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
@@ -1013,12 +1017,12 @@
if (IS_ERR(sn)) {
/* If it is failed, discard just allocated
- root, and then (in st_failure) stale node
+ root, and then (in failure) stale node
in main tree.
*/
node_free(sfn);
err = PTR_ERR(sn);
- goto st_failure;
+ goto failure;
}
/* Now link new subtree to main tree */
@@ -1032,7 +1036,7 @@
if (IS_ERR(sn)) {
err = PTR_ERR(sn);
- goto st_failure;
+ goto failure;
}
}
@@ -1074,22 +1078,22 @@
atomic_inc(&pn->leaf->rt6i_ref);
}
#endif
- if (!(rt->dst.flags & DST_NOCACHE))
- dst_free(&rt->dst);
+ goto failure;
}
return err;
-#ifdef CONFIG_IPV6_SUBTREES
- /* Subtree creation failed, probably main tree node
- is orphan. If it is, shoot it.
+failure:
+ /* fn->leaf could be NULL if fn is an intermediate node and we
+ * failed to add the new route to it in both subtree creation
+ * failure and fib6_add_rt2node() failure case.
+ * In both cases, fib6_repair_tree() should be called to fix
+ * fn->leaf.
*/
-st_failure:
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
fib6_repair_tree(info->nl_net, fn);
if (!(rt->dst.flags & DST_NOCACHE))
dst_free(&rt->dst);
return err;
-#endif
}
/*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4403260..821aa0b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -671,8 +671,6 @@
*prevhdr = NEXTHDR_FRAGMENT;
tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
if (!tmp_hdr) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
goto fail;
}
@@ -791,8 +789,6 @@
frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
hroom + troom, GFP_ATOMIC);
if (!frag) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
goto fail;
}
@@ -1384,11 +1380,12 @@
*/
cork->length += length;
- if ((((length + fragheaderlen) > mtu) ||
- (skb && skb_is_gso(skb))) &&
+ if ((skb && skb_is_gso(skb)) ||
+ (((length + fragheaderlen) > mtu) &&
+ (skb_queue_len(queue) <= 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
- (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
+ (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk))) {
err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, exthdrlen,
transhdrlen, mtu, flags, fl6);
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
index 1009040..eedee5d 100644
--- a/net/ipv6/netfilter/nf_reject_ipv6.c
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -157,6 +157,7 @@
fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source;
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
+ fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) {
@@ -180,6 +181,8 @@
skb_dst_set(nskb, dst);
+ nskb->mark = fl6.flowi6_mark;
+
skb_reserve(nskb, hh_len + dst->header_len);
ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
ip6_dst_hoplimit(dst));
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index e9065b8..abb2c30 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -78,7 +78,7 @@
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
- u16 offset = sizeof(struct ipv6hdr);
+ unsigned int offset = sizeof(struct ipv6hdr);
unsigned int packet_len = skb_tail_pointer(skb) -
skb_network_header(skb);
int found_rhdr = 0;
@@ -86,6 +86,7 @@
while (offset <= packet_len) {
struct ipv6_opt_hdr *exthdr;
+ unsigned int len;
switch (**nexthdr) {
@@ -111,7 +112,10 @@
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
offset);
- offset += ipv6_optlen(exthdr);
+ len = ipv6_optlen(exthdr);
+ if (len + offset >= IPV6_MAXPLEN)
+ return -EINVAL;
+ offset += len;
*nexthdr = &exthdr->nexthdr;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 97830a6..a67174e 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -209,6 +209,7 @@
treq->snt_synack.v64 = 0;
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->txhash = net_tx_rndhash();
/*
* We need to lookup the dst_entry to get the correct window size.
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c925fd9..c43ef0c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -915,6 +915,7 @@
*/
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
+ csum = skb->csum;
skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index a2267f8..e7d378c 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -72,7 +72,7 @@
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
/* If there is no outer header we can fake a checksum offload
* due to the fact that we have already done the checksum in
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 391c3cb..101ed6c 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2223,7 +2223,7 @@
{
struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk);
- struct irda_device_list list;
+ struct irda_device_list list = { 0 };
struct irda_device_info *discoveries;
struct irda_ias_set * ias_opt; /* IAS get/query params */
struct ias_object * ias_obj; /* Object in IAS */
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 2e1050e..94bf810 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -228,7 +228,7 @@
#define BROADCAST_ONE 1
#define BROADCAST_REGISTERED 2
#define BROADCAST_PROMISC_ONLY 4
-static int pfkey_broadcast(struct sk_buff *skb,
+static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
int broadcast_flags, struct sock *one_sk,
struct net *net)
{
@@ -278,7 +278,7 @@
rcu_read_unlock();
if (one_sk != NULL)
- err = pfkey_broadcast_one(skb, &skb2, GFP_KERNEL, one_sk);
+ err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
kfree_skb(skb2);
kfree_skb(skb);
@@ -311,7 +311,7 @@
hdr = (struct sadb_msg *) pfk->dump.skb->data;
hdr->sadb_msg_seq = 0;
hdr->sadb_msg_errno = rc;
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = NULL;
}
@@ -355,7 +355,7 @@
hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
sizeof(uint64_t));
- pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+ pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk));
return 0;
}
@@ -1396,7 +1396,7 @@
xfrm_state_put(x);
- pfkey_broadcast(resp_skb, BROADCAST_ONE, sk, net);
+ pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net);
return 0;
}
@@ -1483,7 +1483,7 @@
hdr->sadb_msg_seq = c->seq;
hdr->sadb_msg_pid = c->portid;
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, xs_net(x));
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x));
return 0;
}
@@ -1596,7 +1596,7 @@
out_hdr->sadb_msg_reserved = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, BROADCAST_ONE, sk, sock_net(sk));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
return 0;
}
@@ -1701,8 +1701,8 @@
return -ENOBUFS;
}
- pfkey_broadcast(supp_skb, BROADCAST_REGISTERED, sk, sock_net(sk));
-
+ pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk,
+ sock_net(sk));
return 0;
}
@@ -1720,7 +1720,8 @@
hdr->sadb_msg_errno = (uint8_t) 0;
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk,
+ sock_net(sk));
}
static int key_notify_sa_flush(const struct km_event *c)
@@ -1741,7 +1742,7 @@
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
hdr->sadb_msg_reserved = 0;
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, c->net);
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
return 0;
}
@@ -1798,7 +1799,7 @@
out_hdr->sadb_msg_pid = pfk->dump.msg_portid;
if (pfk->dump.skb)
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = out_skb;
@@ -1886,7 +1887,7 @@
new_hdr->sadb_msg_errno = 0;
}
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, sock_net(sk));
+ pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk));
return 0;
}
@@ -2219,7 +2220,7 @@
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = c->seq;
out_hdr->sadb_msg_pid = c->portid;
- pfkey_broadcast(out_skb, BROADCAST_ALL, NULL, xp_net(xp));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp));
return 0;
}
@@ -2439,7 +2440,7 @@
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp));
err = 0;
out:
@@ -2695,7 +2696,7 @@
out_hdr->sadb_msg_pid = pfk->dump.msg_portid;
if (pfk->dump.skb)
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = out_skb;
@@ -2752,7 +2753,7 @@
hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
hdr->sadb_msg_reserved = 0;
- pfkey_broadcast(skb_out, BROADCAST_ALL, NULL, c->net);
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
return 0;
}
@@ -2814,7 +2815,7 @@
void *ext_hdrs[SADB_EXT_MAX];
int err;
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL),
+ pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
BROADCAST_PROMISC_ONLY, NULL, sock_net(sk));
memset(ext_hdrs, 0, sizeof(ext_hdrs));
@@ -3036,7 +3037,8 @@
out_hdr->sadb_msg_seq = 0;
out_hdr->sadb_msg_pid = 0;
- pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
return 0;
}
@@ -3226,7 +3228,8 @@
xfrm_ctx->ctx_len);
}
- return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
}
static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
@@ -3424,7 +3427,8 @@
n_port->sadb_x_nat_t_port_port = sport;
n_port->sadb_x_nat_t_port_reserved = 0;
- return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
}
#ifdef CONFIG_NET_KEY_MIGRATE
@@ -3616,7 +3620,7 @@
}
/* broadcast migrate message to sockets */
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, &init_net);
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net);
return 0;
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 02bcf00..008299b 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -53,7 +53,11 @@
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[id]);
- BUG_ON(t == NULL);
+ if (!t) {
+ rcu_read_unlock();
+ return NULL;
+ }
+
off = ALIGN(sizeof(struct nf_ct_ext), t->align);
len = off + t->len + var_alloc_len;
alloc_size = t->alloc_size + var_alloc_len;
@@ -88,7 +92,10 @@
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[id]);
- BUG_ON(t == NULL);
+ if (!t) {
+ rcu_read_unlock();
+ return NULL;
+ }
newoff = ALIGN(old->len, t->align);
newlen = newoff + t->len + var_alloc_len;
@@ -175,6 +182,6 @@
RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
update_alloc_size(type);
mutex_unlock(&nf_ct_ext_type_mutex);
- rcu_barrier(); /* Wait for completion of call_rcu()'s */
+ synchronize_rcu();
}
EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 5b9c884..dde64c4 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -225,20 +225,21 @@
.tuple = tuple,
.zone = zone
};
- struct rhlist_head *hl;
+ struct rhlist_head *hl, *h;
hl = rhltable_lookup(&nf_nat_bysource_table, &key,
nf_nat_bysource_params);
- if (!hl)
- return 0;
- ct = container_of(hl, typeof(*ct), nat_bysource);
+ rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) {
+ nf_ct_invert_tuplepr(result,
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ result->dst = tuple->dst;
- nf_ct_invert_tuplepr(result,
- &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- result->dst = tuple->dst;
+ if (in_range(l3proto, l4proto, result, range))
+ return 1;
+ }
- return in_range(l3proto, l4proto, result, range);
+ return 0;
}
/* For [FUTURE] fragmentation handling, we want the least-used
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 1fbe4b6..ade9306 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1597,14 +1597,6 @@
if (sk) {
MT_DEBUG("qtaguid: %p->sk_proto=%u "
"->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
- /*
- * When in TCP_TIME_WAIT the sk is not a "struct sock" but
- * "struct inet_timewait_sock" which is missing fields.
- */
- if (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT) {
- sock_gen_put(sk);
- sk = NULL;
- }
}
return sk;
}
@@ -1697,10 +1689,25 @@
*/
sk = qtaguid_find_sk(skb, par);
/*
- * If we got the socket from the find_sk(), we will need to put
- * it back, as nf_tproxy_get_sock_v4() got it.
+ * TCP_NEW_SYN_RECV are not "struct sock" but "struct request_sock"
+ * where we can get a pointer to a full socket to retrieve uid/gid.
+ * When in TCP_TIME_WAIT, sk is a struct inet_timewait_sock
+ * which is missing fields and does not contain any reference
+ * to a full socket, so just ignore the socket.
*/
- got_sock = sk;
+ if (sk && sk->sk_state == TCP_NEW_SYN_RECV) {
+ sock_gen_put(sk);
+ sk = sk_to_full_sk(sk);
+ } else if (sk && (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT)) {
+ sock_gen_put(sk);
+ sk = NULL;
+ } else {
+ /*
+ * If we got the socket from the find_sk(), we will need to put
+ * it back, as nf_tproxy_get_sock_v4() got it.
+ */
+ got_sock = sk;
+ }
if (sk)
atomic64_inc(&qtu_events.match_found_sk_in_ct);
else
@@ -1710,18 +1717,9 @@
}
MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
- if (sk != NULL) {
- set_sk_callback_lock = true;
- read_lock_bh(&sk->sk_callback_lock);
- MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
- par->hooknum, sk, sk->sk_socket,
- sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
- filp = sk->sk_socket ? sk->sk_socket->file : NULL;
- MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
- par->hooknum, filp ? from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
- }
- if (sk == NULL || sk->sk_socket == NULL) {
+
+ if (sk == NULL) {
/*
* Here, the qtaguid_find_sk() using connection tracking
* couldn't find the owner, so for now we just count them
@@ -1734,9 +1732,7 @@
*/
if (!(info->match & XT_QTAGUID_UID))
account_for_uid(skb, sk, 0, par);
- MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
- par->hooknum,
- sk ? sk->sk_socket : NULL);
+ MT_DEBUG("qtaguid[%d]: leaving (sk=NULL)\n", par->hooknum);
res = (info->match ^ info->invert) == 0;
atomic64_inc(&qtu_events.match_no_sk);
goto put_sock_ret_res;
@@ -1744,16 +1740,7 @@
res = false;
goto put_sock_ret_res;
}
- filp = sk->sk_socket->file;
- if (filp == NULL) {
- MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
- account_for_uid(skb, sk, 0, par);
- res = ((info->match ^ info->invert) &
- (XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
- atomic64_inc(&qtu_events.match_no_sk_file);
- goto put_sock_ret_res;
- }
- sock_uid = filp->f_cred->fsuid;
+ sock_uid = sk->sk_uid;
/*
* TODO: unhack how to force just accounting.
* For now we only do iface stats when the uid-owner is not requested
@@ -1771,8 +1758,8 @@
kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max);
- if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
- uid_lte(filp->f_cred->fsuid, uid_max)) ^
+ if ((uid_gte(sk->sk_uid, uid_min) &&
+ uid_lte(sk->sk_uid, uid_max)) ^
!(info->invert & XT_QTAGUID_UID)) {
MT_DEBUG("qtaguid[%d]: leaving uid not matching\n",
par->hooknum);
@@ -1783,7 +1770,19 @@
if (info->match & XT_QTAGUID_GID) {
kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
-
+ set_sk_callback_lock = true;
+ read_lock_bh(&sk->sk_callback_lock);
+ MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
+ par->hooknum, sk, sk->sk_socket,
+ sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
+ filp = sk->sk_socket ? sk->sk_socket->file : NULL;
+ if (!filp) {
+ res = ((info->match ^ info->invert) & XT_QTAGUID_GID) == 0;
+ atomic64_inc(&qtu_events.match_no_sk_gid);
+ goto put_sock_ret_res;
+ }
+ MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
+ par->hooknum, filp ? from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
gid_lte(filp->f_cred->fsgid, gid_max)) ^
!(info->invert & XT_QTAGUID_GID)) {
@@ -1955,7 +1954,7 @@
"match_found_sk_in_ct=%llu "
"match_found_no_sk_in_ct=%llu "
"match_no_sk=%llu "
- "match_no_sk_file=%llu\n",
+ "match_no_sk_gid=%llu\n",
(u64)atomic64_read(&qtu_events.sockets_tagged),
(u64)atomic64_read(&qtu_events.sockets_untagged),
(u64)atomic64_read(&qtu_events.counter_set_changes),
@@ -1967,7 +1966,7 @@
(u64)atomic64_read(&qtu_events.match_found_sk_in_ct),
(u64)atomic64_read(&qtu_events.match_found_no_sk_in_ct),
(u64)atomic64_read(&qtu_events.match_no_sk),
- (u64)atomic64_read(&qtu_events.match_no_sk_file));
+ (u64)atomic64_read(&qtu_events.match_no_sk_gid));
/* Count the following as part of the last item_index. No need
* to lock the sock_tag_list here since it is already locked when
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
index 8178fbd..c705270 100644
--- a/net/netfilter/xt_qtaguid_internal.h
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -289,10 +289,10 @@
*/
atomic64_t match_no_sk;
/*
- * The file ptr in the sk_socket wasn't there.
+ * The file ptr in the sk_socket wasn't there and we couldn't get GID.
* This might happen for traffic while the socket is being closed.
*/
- atomic64_t match_no_sk_file;
+ atomic64_t match_no_sk_gid;
};
/* Track the set active_set for the given tag. */
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 2b0f0ac..5a58f9f 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -209,6 +209,11 @@
}
create_info = (struct hci_create_pipe_resp *)skb->data;
+ if (create_info->pipe >= NFC_HCI_MAX_PIPES) {
+ status = NFC_HCI_ANY_E_NOK;
+ goto exit;
+ }
+
/* Save the new created pipe and bind with local gate,
* the description for skb->data[3] is destination gate id
* but since we received this cmd from host controller, we
@@ -232,6 +237,11 @@
}
delete_info = (struct hci_delete_pipe_noti *)skb->data;
+ if (delete_info->pipe >= NFC_HCI_MAX_PIPES) {
+ status = NFC_HCI_ANY_E_NOK;
+ goto exit;
+ }
+
hdev->pipes[delete_info->pipe].gate = NFC_HCI_INVALID_GATE;
hdev->pipes[delete_info->pipe].dest_host = NFC_HCI_INVALID_HOST;
break;
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 4e03f64..05d9f42 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1240,6 +1240,7 @@
goto out;
}
+ OVS_CB(skb)->acts_origlen = acts->orig_len;
err = do_execute_actions(dp, skb, key,
acts->actions, acts->actions_len);
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 48386bf..b28e45b 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -1088,8 +1088,8 @@
nla_for_each_nested(a, attr, rem) {
int type = nla_type(a);
- int maxlen = ovs_ct_attr_lens[type].maxlen;
- int minlen = ovs_ct_attr_lens[type].minlen;
+ int maxlen;
+ int minlen;
if (type > OVS_CT_ATTR_MAX) {
OVS_NLERR(log,
@@ -1097,6 +1097,9 @@
type, OVS_CT_ATTR_MAX);
return -EINVAL;
}
+
+ maxlen = ovs_ct_attr_lens[type].maxlen;
+ minlen = ovs_ct_attr_lens[type].minlen;
if (nla_len(a) < minlen || nla_len(a) > maxlen) {
OVS_NLERR(log,
"Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)",
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 4d67ea8..453f806 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -383,7 +383,7 @@
}
static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
- unsigned int hdrlen)
+ unsigned int hdrlen, int actions_attrlen)
{
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
@@ -400,7 +400,7 @@
/* OVS_PACKET_ATTR_ACTIONS */
if (upcall_info->actions_len)
- size += nla_total_size(upcall_info->actions_len);
+ size += nla_total_size(actions_attrlen);
/* OVS_PACKET_ATTR_MRU */
if (upcall_info->mru)
@@ -467,7 +467,8 @@
else
hlen = skb->len;
- len = upcall_msg_size(upcall_info, hlen - cutlen);
+ len = upcall_msg_size(upcall_info, hlen - cutlen,
+ OVS_CB(skb)->acts_origlen);
user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index ab85c1c..e19ace4 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -100,12 +100,14 @@
* @input_vport: The original vport packet came in on. This value is cached
* when a packet is received by OVS.
* @mru: The maximum received fragement size; 0 if the packet is not
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
* @cutlen: The number of bytes from the packet end to be removed.
* fragmented.
*/
struct ovs_skb_cb {
struct vport *input_vport;
u16 mru;
+ u16 acts_origlen;
u32 cutlen;
};
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6a563e6..ae7bfd2 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3698,14 +3698,19 @@
if (optlen != sizeof(val))
return -EINVAL;
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
- return -EBUSY;
if (copy_from_user(&val, optval, sizeof(val)))
return -EFAULT;
if (val > INT_MAX)
return -EINVAL;
- po->tp_reserve = val;
- return 0;
+ lock_sock(sk);
+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+ ret = -EBUSY;
+ } else {
+ po->tp_reserve = val;
+ ret = 0;
+ }
+ release_sock(sk);
+ return ret;
}
case PACKET_LOSS:
{
@@ -4322,7 +4327,7 @@
register_prot_hook(sk);
}
spin_unlock(&po->bind_lock);
- if (closing && (po->tp_version > TPACKET_V2)) {
+ if (pg_vec && (po->tp_version > TPACKET_V2)) {
/* Because we don't support block-based V3 on tx-ring */
if (!tx_ring)
prb_shutdown_retire_blk_timer(po, rb_queue);
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 378c1c9..5003051 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -41,6 +41,7 @@
{
struct xt_tgchk_param par;
struct xt_target *target;
+ struct ipt_entry e = {};
int ret = 0;
target = xt_request_find_target(AF_INET, t->u.user.name,
@@ -49,8 +50,9 @@
return PTR_ERR(target);
t->u.kernel.target = target;
+ memset(&par, 0, sizeof(par));
par.table = table;
- par.entryinfo = NULL;
+ par.entryinfo = &e;
par.target = target;
par.targinfo = t->data;
par.hook_mask = hook;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index daf6624..a74d32e 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -277,9 +277,6 @@
void qdisc_hash_add(struct Qdisc *q)
{
if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
- struct Qdisc *root = qdisc_dev(q)->qdisc;
-
- WARN_ON_ONCE(root == &noop_qdisc);
ASSERT_RTNL();
hash_add_rcu(qdisc_dev(q)->qdisc_hash, &q->hash, q->handle);
}
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index bc5e995..ea8a56f 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -434,6 +434,7 @@
qdisc_drop(head, sch, to_free);
slot_queue_add(slot, skb);
+ qdisc_tree_reduce_backlog(sch, 0, delta);
return NET_XMIT_CN;
}
@@ -465,8 +466,10 @@
/* Return Congestion Notification only if we dropped a packet
* from this flow.
*/
- if (qlen != slot->qlen)
+ if (qlen != slot->qlen) {
+ qdisc_tree_reduce_backlog(sch, 0, dropped - qdisc_pkt_len(skb));
return NET_XMIT_CN;
+ }
/* As we dropped a packet, better let upper stack know this */
qdisc_tree_reduce_backlog(sch, 1, dropped);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 0c09060..ca4a63e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -512,7 +512,9 @@
{
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
+ addr->v6.sin6_flowinfo = 0;
addr->v6.sin6_addr = *saddr;
+ addr->v6.sin6_scope_id = 0;
}
/* Compare addresses exactly.
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a4bc982..266a30c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -408,6 +408,9 @@
dprintk("svc: socket %p(inet %p), busy=%d\n",
svsk, sk,
test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_odata(sk);
if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
svc_xprt_enqueue(&svsk->sk_xprt);
@@ -424,6 +427,9 @@
if (svsk) {
dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_owspace(sk);
svc_xprt_enqueue(&svsk->sk_xprt);
}
@@ -748,8 +754,12 @@
dprintk("svc: socket %p TCP (listen) state change %d\n",
sk, sk->sk_state);
- if (svsk)
+ if (svsk) {
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_odata(sk);
+ }
+
/*
* This callback may called twice when a new connection
* is established as a child socket inherits everything
@@ -782,6 +792,8 @@
if (!svsk)
printk("svc: socket %p: no user data\n", sk);
else {
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_ostate(sk);
if (sk->sk_state != TCP_ESTABLISHED) {
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@ -1368,12 +1380,18 @@
return ERR_PTR(err);
}
- inet->sk_user_data = svsk;
svsk->sk_sock = sock;
svsk->sk_sk = inet;
svsk->sk_ostate = inet->sk_state_change;
svsk->sk_odata = inet->sk_data_ready;
svsk->sk_owspace = inet->sk_write_space;
+ /*
+ * This barrier is necessary in order to prevent race condition
+ * with svc_data_ready(), svc_listen_data_ready() and others
+ * when calling callbacks above.
+ */
+ wmb();
+ inet->sk_user_data = svsk;
/* Initialize the socket */
if (sock->type == SOCK_DGRAM)
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 1fd4647..aedc476 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -258,13 +258,15 @@
arg = nlmsg_new(0, GFP_KERNEL);
if (!arg) {
kfree_skb(msg->rep);
+ msg->rep = NULL;
return -ENOMEM;
}
err = __tipc_nl_compat_dumpit(cmd, msg, arg);
- if (err)
+ if (err) {
kfree_skb(msg->rep);
-
+ msg->rep = NULL;
+ }
kfree_skb(arg);
return err;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index cf7063a..c40f3de 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -221,13 +221,7 @@
union {
struct cfg80211_connect_resp_params cr;
- struct {
- const u8 *req_ie;
- const u8 *resp_ie;
- size_t req_ie_len;
- size_t resp_ie_len;
- struct cfg80211_bss *bss;
- } rm;
+ struct cfg80211_roam_info rm;
struct {
const u8 *ie;
size_t ie_len;
@@ -385,9 +379,7 @@
struct net_device *dev, u16 reason,
bool wextev);
void __cfg80211_roamed(struct wireless_dev *wdev,
- struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len);
+ struct cfg80211_roam_info *info);
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 413deff..cad82a4 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -223,17 +223,16 @@
(5490 - 5710 @ 160), (30), DFS
country BZ:
- (2402 - 2482 @ 40), (36)
- (5170 - 5330 @ 160), (27)
- (5490 - 5730 @ 160), (36)
- (5735 - 5835 @ 80), (36)
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5330 @ 160), (23)
+ (5490 - 5730 @ 160), (30)
+ (5735 - 5835 @ 80), (30)
country CA: DFS-FCC
(2402 - 2472 @ 40), (30)
(5170 - 5250 @ 80), (24), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
- (5490 - 5590 @ 80), (24), DFS
- (5650 - 5730 @ 80), (24), DFS
+ (5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
# 60 gHz band channels 1-3
(57240 - 63720 @ 2160), (40)
@@ -682,7 +681,13 @@
country IN:
(2402 - 2482 @ 40), (20)
(5170 - 5330 @ 160), (23)
- (5735 - 5835 @ 80), (30)
+ (5735 - 5835 @ 80), (33)
+
+country IQ: DFS-ETSI
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5250 @ 80), (23), AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5490 - 5710 @ 160), (30), DFS
country IS: DFS-ETSI
(2402 - 2482 @ 40), (20)
@@ -736,7 +741,6 @@
country JP: DFS-JP
(2402 - 2482 @ 40), (20)
- (2474 - 2494 @ 20), (20), NO-OFDM
(5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR
(5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR
(5490 - 5710 @ 160), (20), DFS
@@ -758,7 +762,7 @@
country KN: DFS-FCC
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
- (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5250 - 5330 @ 80), (30), DFS, AUTO-BW
(5490 - 5710 @ 160), (30), DFS
(5735 - 5815 @ 80), (30)
@@ -1009,7 +1013,7 @@
(5170 - 5250 @ 80), (24), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
(5490 - 5650 @ 160), (24), DFS
- (5735 - 5815 @ 80), (24)
+ (5735 - 5835 @ 80), (24)
# 60 gHz band channels 1-3
(57240 - 63720 @ 2160), (40)
@@ -1089,7 +1093,7 @@
(5490 - 5710 @ 160), (30), DFS
country PA:
- (2402 - 2472 @ 40), (30)
+ (2402 - 2472 @ 40), (36)
(5170 - 5250 @ 80), (23), AUT0-BW
(5250 - 5330 @ 80), (30), AUTO-BW
(5735 - 5835 @ 80), (36)
@@ -1374,9 +1378,9 @@
country TT:
(2402 - 2482 @ 40), (20)
- (5170 - 5330 @ 160), (27)
- (5490 - 5730 @ 160), (36)
- (5735 - 5835 @ 80), (36)
+ (5170 - 5330 @ 160), (24)
+ (5490 - 5730 @ 160), (24)
+ (5735 - 5835 @ 80), (30)
# 60 gHz band channels 1-3, FCC
(57240 - 63720 @ 2160), (40)
@@ -1450,7 +1454,7 @@
country UZ: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
- (5250 - 5330 @ 80), (20), DFS, AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
country VC: DFS-ETSI
(2402 - 2482 @ 40), (20)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ebd9a4b..adf7d03 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13415,14 +13415,14 @@
}
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+ struct net_device *netdev,
+ struct cfg80211_roam_info *info, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
+ const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
- msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
+ msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len, gfp);
if (!msg)
return;
@@ -13435,10 +13435,14 @@
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
- (req_ie &&
- nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
- (resp_ie &&
- nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ (info->req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
+ info->req_ie)) ||
+ (info->resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
+ info->resp_ie)) ||
+ (info->authorized &&
+ nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2a84d18..c9d4805 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -59,9 +59,8 @@
struct cfg80211_connect_resp_params *params,
gfp_t gfp);
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+ struct net_device *netdev,
+ struct cfg80211_roam_info *info, gfp_t gfp);
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u16 reason,
const u8 *ie, size_t ie_len, bool from_ap);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d7e6abc..bb7f5be 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -5,6 +5,7 @@
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009 Intel Corporation. All rights reserved.
+ * Copyright 2017 Intel Deutschland GmbH
*/
#include <linux/etherdevice.h>
@@ -893,9 +894,7 @@
/* Consumes bss object one way or another */
void __cfg80211_roamed(struct wireless_dev *wdev,
- struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len)
+ struct cfg80211_roam_info *info)
{
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
@@ -913,97 +912,85 @@
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
- cfg80211_hold_bss(bss_from_pub(bss));
- wdev->current_bss = bss_from_pub(bss);
+ if (WARN_ON(!info->bss))
+ return;
+
+ cfg80211_hold_bss(bss_from_pub(info->bss));
+ wdev->current_bss = bss_from_pub(info->bss);
nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
- wdev->netdev, bss->bssid,
- req_ie, req_ie_len, resp_ie, resp_ie_len,
- GFP_KERNEL);
+ wdev->netdev, info, GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
- if (req_ie) {
+ if (info->req_ie) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = req_ie_len;
+ wrqu.data.length = info->req_ie_len;
wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
- &wrqu, req_ie);
+ &wrqu, info->req_ie);
}
- if (resp_ie) {
+ if (info->resp_ie) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = resp_ie_len;
+ wrqu.data.length = info->resp_ie_len;
wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
- &wrqu, resp_ie);
+ &wrqu, info->resp_ie);
}
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- memcpy(wdev->wext.prev_bssid, bss->bssid, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN);
+ memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN);
wdev->wext.prev_bssid_valid = true;
wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
#endif
return;
out:
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, info->bss);
}
-void cfg80211_roamed(struct net_device *dev,
- struct ieee80211_channel *channel,
- const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_bss *bss;
-
- bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
- wdev->ssid_len,
- wdev->conn_bss_type, IEEE80211_PRIVACY_ANY);
- if (WARN_ON(!bss))
- return;
-
- cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie,
- resp_ie_len, gfp);
-}
-EXPORT_SYMBOL(cfg80211_roamed);
-
-/* Consumes bss object one way or another */
-void cfg80211_roamed_bss(struct net_device *dev,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, gfp_t gfp)
+/* Consumes info->bss object one way or another */
+void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
+ gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
- if (WARN_ON(!bss))
+ if (!info->bss) {
+ info->bss = cfg80211_get_bss(wdev->wiphy, info->channel,
+ info->bssid, wdev->ssid,
+ wdev->ssid_len,
+ wdev->conn_bss_type,
+ IEEE80211_PRIVACY_ANY);
+ }
+
+ if (WARN_ON(!info->bss))
return;
- ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len, gfp);
if (!ev) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, info->bss);
return;
}
ev->type = EVENT_ROAMED;
ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
- ev->rm.req_ie_len = req_ie_len;
- memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
- ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
- ev->rm.resp_ie_len = resp_ie_len;
- memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
- ev->rm.bss = bss;
+ ev->rm.req_ie_len = info->req_ie_len;
+ memcpy((void *)ev->rm.req_ie, info->req_ie, info->req_ie_len);
+ ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + info->req_ie_len;
+ ev->rm.resp_ie_len = info->resp_ie_len;
+ memcpy((void *)ev->rm.resp_ie, info->resp_ie, info->resp_ie_len);
+ ev->rm.bss = info->bss;
+ ev->rm.authorized = info->authorized;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
queue_work(cfg80211_wq, &rdev->event_work);
}
-EXPORT_SYMBOL(cfg80211_roamed_bss);
+EXPORT_SYMBOL(cfg80211_roamed);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8ac413f..a4ab20a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -953,9 +953,7 @@
ev->cr.status == WLAN_STATUS_SUCCESS);
break;
case EVENT_ROAMED:
- __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
- ev->rm.req_ie_len, ev->rm.resp_ie,
- ev->rm.resp_ie_len);
+ __cfg80211_roamed(wdev, &ev->rm);
break;
case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e26b515..8ce5711 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3308,9 +3308,15 @@
struct xfrm_state *x_new[XFRM_MAX_DEPTH];
struct xfrm_migrate *mp;
+ /* Stage 0 - sanity checks */
if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
goto out;
+ if (dir >= XFRM_POLICY_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+
/* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a7e27e1..b2bba35 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1695,6 +1695,10 @@
struct sk_buff *skb;
int err;
+ err = verify_policy_dir(dir);
+ if (err)
+ return ERR_PTR(err);
+
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOMEM);
@@ -2216,6 +2220,10 @@
int n = 0;
struct net *net = sock_net(skb->sk);
+ err = verify_policy_dir(pi->dir);
+ if (err)
+ return err;
+
if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL;
@@ -2331,6 +2339,11 @@
{
struct net *net = &init_net;
struct sk_buff *skb;
+ int err;
+
+ err = verify_policy_dir(dir);
+ if (err)
+ return err;
skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
if (skb == NULL)
@@ -2985,6 +2998,11 @@
static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
{
+ int err;
+
+ err = verify_policy_dir(dir);
+ if (err)
+ return err;
switch (c->event) {
case XFRM_MSG_NEWPOLICY:
diff --git a/sound/core/control.c b/sound/core/control.c
index fb096cb..995cde4 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1156,7 +1156,7 @@
mutex_lock(&ue->card->user_ctl_lock);
change = ue->tlv_data_size != size;
if (!change)
- change = memcmp(ue->tlv_data, new_data, size);
+ change = memcmp(ue->tlv_data, new_data, size) != 0;
kfree(ue->tlv_data);
ue->tlv_data = new_data;
ue->tlv_data_size = size;
diff --git a/sound/core/info.c b/sound/core/info.c
index 2ffa3fa..08558ae 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -735,8 +735,11 @@
INIT_LIST_HEAD(&entry->children);
INIT_LIST_HEAD(&entry->list);
entry->parent = parent;
- if (parent)
+ if (parent) {
+ mutex_lock(&parent->access);
list_add_tail(&entry->list, &parent->children);
+ mutex_unlock(&parent->access);
+ }
return entry;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index f3b1d7f..67c4c68 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1502,16 +1502,11 @@
static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
{
struct snd_seq_queue_info *info = arg;
- int result;
struct snd_seq_queue *q;
- result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
- if (result < 0)
- return result;
-
- q = queueptr(result);
- if (q == NULL)
- return -EINVAL;
+ q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
info->queue = q->queue;
info->locked = q->locked;
@@ -1521,7 +1516,7 @@
if (!info->name[0])
snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
strlcpy(q->name, info->name, sizeof(q->name));
- queuefree(q);
+ snd_use_lock_free(&q->use_lock);
return 0;
}
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 450c518..79e0c56 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -184,22 +184,26 @@
static void queue_use(struct snd_seq_queue *queue, int client, int use);
/* allocate a new queue -
- * return queue index value or negative value for error
+ * return pointer to new queue or ERR_PTR(-errno) for error
+ * The new queue's use_lock is set to 1. It is the caller's responsibility to
+ * call snd_use_lock_free(&q->use_lock).
*/
-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
{
struct snd_seq_queue *q;
q = queue_new(client, locked);
if (q == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
q->info_flags = info_flags;
queue_use(q, client, 1);
+ snd_use_lock_use(&q->use_lock);
if (queue_list_add(q) < 0) {
+ snd_use_lock_free(&q->use_lock);
queue_delete(q);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- return q->queue;
+ return q;
}
/* delete a queue - queue must be owned by the client */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 30c8111..7190934 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -71,7 +71,7 @@
/* create new queue (constructor) */
-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
/* delete queue (destructor) */
int snd_seq_queue_delete(int client, int queueid);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index f0e4d50..066b5df 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -210,9 +210,14 @@
*/
void fw_iso_resources_free(struct fw_iso_resources *r)
{
- struct fw_card *card = fw_parent_device(r->unit)->card;
+ struct fw_card *card;
int bandwidth, channel;
+ /* Not initialized. */
+ if (r->unit == NULL)
+ return;
+ card = fw_parent_device(r->unit)->card;
+
mutex_lock(&r->mutex);
if (r->allocated) {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c15c51b..f2e4e99 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -854,6 +854,7 @@
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bb1aad3..6f337f0 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2233,6 +2233,7 @@
SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 10c2a564..1ac96ef 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3833,6 +3833,9 @@
}
}
+ regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
+ RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
+
if (rt5645->pdata.jd_invert) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index be6290d..bd8f34a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -212,6 +212,7 @@
pr_debug("%s Don't close BE\n", __func__);
continue;
}
+
snd_soc_dapm_stream_event(be, dir, event);
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 9e7861a..6c3d62f 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -554,6 +554,8 @@
if (size < sizeof(scale))
return -ENOMEM;
+ if (cval->min_mute)
+ scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
scale[2] = cval->dBmin;
scale[3] = cval->dBmax;
if (copy_to_user(_tlv, scale, sizeof(scale)))
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3417ef3..2b4b067 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -64,6 +64,7 @@
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
+ u8 min_mute;
void *private_data;
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 04991b0..5d2fc5f 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1873,6 +1873,12 @@
if (unitid == 7 && cval->control == UAC_FU_VOLUME)
snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
break;
+ /* lowest playback value is muted on C-Media devices */
+ case USB_ID(0x0d8c, 0x000c):
+ case USB_ID(0x0d8c, 0x0014):
+ if (strstr(kctl->id.name, "Playback"))
+ cval->min_mute = 1;
+ break;
}
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index eb4b9f7..286efc3 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1142,6 +1142,7 @@
case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
@@ -1308,10 +1309,13 @@
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
- /* Zoom R16/24 needs a tiny delay here, otherwise requests like
- * get/set frequency return as failed despite actually succeeding.
+ /* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here,
+ * otherwise requests like get/set frequency return as failed despite
+ * actually succeeding.
*/
- if (chip->usb_id == USB_ID(0x1686, 0x00dd) &&
+ if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
+ chip->usb_id == USB_ID(0x046d, 0x0a46) ||
+ chip->usb_id == USB_ID(0x0b0e, 0x0349)) &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(1);
}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6c50d9f..6a6f44d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -163,7 +163,7 @@
/* A file path -- this is an offline module */
if (module && strchr(module, '/'))
- return machine__findnew_module_map(host_machine, 0, module);
+ return dso__new_map(module);
if (!module)
module = "kernel";
@@ -173,6 +173,7 @@
if (strncmp(pos->dso->short_name + 1, module,
pos->dso->short_name_len - 2) == 0 &&
module[pos->dso->short_name_len - 2] == '\0') {
+ map__get(pos);
return pos;
}
}
@@ -188,15 +189,6 @@
return kernel_get_module_map(target);
}
-static void put_target_map(struct map *map, bool user)
-{
- if (map && user) {
- /* Only the user map needs to be released */
- map__put(map);
- }
-}
-
-
static int convert_exec_to_group(const char *exec, char **result)
{
char *ptr1, *ptr2, *exec_copy;
@@ -412,7 +404,7 @@
}
out:
- put_target_map(map, uprobes);
+ map__put(map);
return ret;
}
@@ -2944,7 +2936,7 @@
}
out:
- put_target_map(map, pev->uprobes);
+ map__put(map);
free(syms);
return ret;
@@ -3437,10 +3429,7 @@
return ret;
/* Get a symbol map */
- if (user)
- map = dso__new_map(target);
- else
- map = kernel_get_module_map(target);
+ map = get_target_map(target, user);
if (!map) {
pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
return -EINVAL;
@@ -3472,9 +3461,7 @@
}
end:
- if (user) {
- map__put(map);
- }
+ map__put(map);
exit_probe_symbol_maps();
return ret;
diff --git a/tools/testing/selftests/ntb/ntb_test.sh b/tools/testing/selftests/ntb/ntb_test.sh
index a676d3e..b3c48fc 100755
--- a/tools/testing/selftests/ntb/ntb_test.sh
+++ b/tools/testing/selftests/ntb/ntb_test.sh
@@ -305,7 +305,7 @@
echo "Running remote perf test $WITH DMA"
write_file "" $REMOTE_PERF/run
echo -n " "
- read_file $LOCAL_PERF/run
+ read_file $REMOTE_PERF/run
echo " Passed"
_modprobe -r ntb_perf
@@ -326,6 +326,10 @@
link_test $LOCAL_TOOL $REMOTE_TOOL
link_test $REMOTE_TOOL $LOCAL_TOOL
+ #Ensure the link is up on both sides before continuing
+ write_file Y $LOCAL_TOOL/link_event
+ write_file Y $REMOTE_TOOL/link_event
+
for PEER_TRANS in $(ls $LOCAL_TOOL/peer_trans*); do
PT=$(basename $PEER_TRANS)
write_file $MW_SIZE $LOCAL_TOOL/$PT